Fix timeline strings (#1209)

- make it possible to translate *full* strings, not only "fragments" (see labels strings)
- use indexed parameters
- *never* concatenate strings

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1209
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
qwerty287 2022-09-19 06:10:05 +02:00 committed by M M Arif
parent 385147f235
commit 5c28637c42
2 changed files with 88 additions and 85 deletions

View File

@ -394,23 +394,24 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
//timelineLine2.setVisibility(View.GONE);
}
StringBuilder informationBuilder = null;
StringBuilder infoBuilder = null;
if(issueComment.getCreatedAt() != null) {
if(timeFormat.equals("pretty")) {
informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "pretty", context));
infoBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "pretty", context));
information.setOnClickListener(v -> TimeHelper.customDateFormatForToastDateFormat(issueComment.getCreatedAt()));
}
else if(timeFormat.equals("normal")) {
informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "normal", context));
infoBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "normal", context));
}
if(!issueComment.getCreatedAt().equals(issueComment.getUpdatedAt())) {
if(informationBuilder != null) {
informationBuilder.append(context.getString(R.string.colorfulBulletSpan)).append(context.getString(R.string.modifiedText));
if(infoBuilder != null) {
infoBuilder.append(context.getString(R.string.colorfulBulletSpan)).append(context.getString(R.string.modifiedText));
}
}
}
String info = infoBuilder.toString();
// label view in timeline
if(issueComment.getType().equalsIgnoreCase("label")) {
@ -424,27 +425,26 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
.buildRoundRect(issueComment.getLabel().getName(), color, AppUtil.getPixelsFromDensity(context, 18));
TextView textView = new TextView(context);
String startText;
String endText = context.getString(R.string.timelineLabelEnd, informationBuilder);
String text;
if(issueComment.getBody().equals("")) {
startText = context.getString(R.string.timelineRemovedLabelStart, issueComment.getUser().getLogin());
text = context.getString(R.string.timelineRemovedLabel, issueComment.getUser().getLogin(), info);
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
else {
startText = context.getString(R.string.timelineAddedLabelStart, issueComment.getUser().getLogin());
text = context.getString(R.string.timelineAddedLabel, issueComment.getUser().getLogin(), info);
}
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_tag));
SpannableString spannableString = new SpannableString(startText + " " + endText);
SpannableString spannableString = new SpannableString(text.replace('|', ' '));
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan image = new ImageSpan(drawable);
new Handler().postDelayed(() -> {
spannableString.setSpan(image, startText.length(), startText.length() + 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
spannableString.setSpan(image, text.indexOf('|'), text.indexOf('|') + 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
timelineData.addView(textView);
}, 250);
@ -471,7 +471,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
commitText = context.getResources().getString(R.string.commitText).toLowerCase();
}
String commitString = context.getString(R.string.timelineAddedCommit, issueComment.getUser().getLogin()) + commitText + " " + informationBuilder;
String commitString = context.getString(R.string.timelineAddedCommit, issueComment.getUser().getLogin(), commitText, info);
start.setText(HtmlCompat.fromHtml(commitString, HtmlCompat.FROM_HTML_MODE_LEGACY));
start.setTextSize(fontSize);
@ -516,19 +516,19 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
if(issueComment.isRemovedAssignee()) {
if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) {
start.setText(context.getString(R.string.timelineAssigneesRemoved, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineAssigneesRemoved, issueComment.getUser().getLogin(), info));
}
else {
start.setText(context.getString(R.string.timelineAssigneesUnassigned, issueComment.getAssignee().getLogin(), issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineAssigneesUnassigned, issueComment.getAssignee().getLogin(), issueComment.getUser().getLogin(), info));
}
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
else {
if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) {
start.setText(context.getString(R.string.timelineAssigneesSelfAssigned, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineAssigneesSelfAssigned, issueComment.getUser().getLogin(), info));
}
else {
start.setText(context.getString(R.string.timelineAssigneesAssigned, issueComment.getAssignee().getLogin(), issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineAssigneesAssigned, issueComment.getAssignee().getLogin(), issueComment.getUser().getLogin(), info));
}
}
start.setTextSize(fontSize);
@ -542,10 +542,10 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getMilestone() != null) {
start.setText(context.getString(R.string.timelineMilestoneAdded, issueComment.getUser().getLogin(), issueComment.getMilestone().getTitle(), informationBuilder));
start.setText(context.getString(R.string.timelineMilestoneAdded, issueComment.getUser().getLogin(), issueComment.getMilestone().getTitle(), info));
}
else {
start.setText(context.getString(R.string.timelineMilestoneRemoved, issueComment.getUser().getLogin(), issueComment.getOldMilestone().getTitle(), informationBuilder));
start.setText(context.getString(R.string.timelineMilestoneRemoved, issueComment.getUser().getLogin(), issueComment.getOldMilestone().getTitle(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -561,14 +561,14 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
if(issue.getIssueType().equalsIgnoreCase("Issue")) {
if(issueComment.getType().equals("close")) {
start.setText(context.getString(R.string.timelineStatusClosedIssue, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineStatusClosedIssue, issueComment.getUser().getLogin(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
else if(issueComment.getType().equalsIgnoreCase("reopen")) {
start.setText(context.getString(R.string.timelineStatusReopenedIssue, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineStatusReopenedIssue, issueComment.getUser().getLogin(), info));
}
else if(issueComment.getType().equalsIgnoreCase("commit_ref")) {
String commitString = context.getString(R.string.timelineStatusRefIssue, issueComment.getUser().getLogin()) + "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightBlue, null) + "'>" + context.getResources().getString(R.string.commitText).toLowerCase() + "</font> " + informationBuilder;
String commitString = context.getString(R.string.timelineStatusRefIssue, issueComment.getUser().getLogin(), ResourcesCompat.getColor(context.getResources(), R.color.lightBlue, null), context.getResources().getString(R.string.commitText).toLowerCase(), info);
start.setText(HtmlCompat.fromHtml(commitString, HtmlCompat.FROM_HTML_MODE_LEGACY));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark));
@ -582,17 +582,17 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
}
else if(issue.getIssueType().equalsIgnoreCase("Pull")) {
if(issueComment.getType().equalsIgnoreCase("close")) {
start.setText(context.getString(R.string.timelineStatusClosedPr, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineStatusClosedPr, issueComment.getUser().getLogin(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
else if(issueComment.getType().equalsIgnoreCase("merge_pull")) {
start.setText(context.getString(R.string.timelineStatusMergedPr, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineStatusMergedPr, issueComment.getUser().getLogin(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconPrMergedColor, null));
}
else if(issueComment.getType().equalsIgnoreCase("commit_ref")) {
String commitString = context.getString(R.string.timelineStatusRefPr, issueComment.getUser().getLogin()) + "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightBlue, null) + "'>" + context.getResources().getString(R.string.commitText).toLowerCase() + "</font> " + informationBuilder;
String commitString = context.getString(R.string.timelineStatusRefPr, issueComment.getUser().getLogin(), ResourcesCompat.getColor(context.getResources(), R.color.lightBlue, null), context.getResources().getString(R.string.commitText).toLowerCase(), info);
start.setText(HtmlCompat.fromHtml(commitString, HtmlCompat.FROM_HTML_MODE_LEGACY));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark));
@ -603,7 +603,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
});
}
else {
start.setText(context.getString(R.string.timelineStatusReopenedPr, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineStatusReopenedPr, issueComment.getUser().getLogin(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request));
}
}
@ -625,7 +625,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
timelineDividerView.setVisibility(View.GONE);
}
else if(issueComment.getType().equalsIgnoreCase("review_request")) {
start.setText(context.getString(R.string.timelineReviewRequest, issueComment.getUser().getLogin(), issueComment.getAssignee().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineReviewRequest, issueComment.getUser().getLogin(), issueComment.getAssignee().getLogin(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_unwatch));
}
start.setTextSize(fontSize);
@ -636,7 +636,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
else if(issueComment.getType().equalsIgnoreCase("change_title")) {
TextView start = new TextView(context);
start.setText(context.getString(R.string.timelineChangeTitle, issueComment.getUser().getLogin(), issueComment.getOldTitle(), issueComment.getNewTitle(), informationBuilder));
start.setText(context.getString(R.string.timelineChangeTitle, issueComment.getUser().getLogin(), issueComment.getOldTitle(), issueComment.getNewTitle(), info));
start.setTextSize(fontSize);
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_edit));
@ -648,11 +648,11 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getType().equalsIgnoreCase("lock")) {
start.setText(context.getString(R.string.timelineLocked, issueComment.getUser().getLogin(), issueComment.getBody(), informationBuilder));
start.setText(context.getString(R.string.timelineLocked, issueComment.getUser().getLogin(), issueComment.getBody(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_lock));
}
else if(issueComment.getType().equalsIgnoreCase("unlock")) {
start.setText(context.getString(R.string.timelineUnlocked, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineUnlocked, issueComment.getUser().getLogin(), info));
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_key));
}
start.setTextSize(fontSize);
@ -665,10 +665,10 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getType().equalsIgnoreCase("add_dependency")) {
start.setText(context.getString(R.string.timelineDependencyAdded, issueComment.getUser().getLogin(), issueComment.getDependentIssue().getNumber(), informationBuilder));
start.setText(context.getString(R.string.timelineDependencyAdded, issueComment.getUser().getLogin(), issueComment.getDependentIssue().getNumber(), info));
}
else if(issueComment.getType().equalsIgnoreCase("remove_dependency")) {
start.setText(context.getString(R.string.timelineDependencyRemoved, issueComment.getUser().getLogin(), issueComment.getDependentIssue().getNumber(), informationBuilder));
start.setText(context.getString(R.string.timelineDependencyRemoved, issueComment.getUser().getLogin(), issueComment.getDependentIssue().getNumber(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -682,10 +682,10 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getProjectId() > 0) {
start.setText(context.getString(R.string.timelineProjectAdded, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineProjectAdded, issueComment.getUser().getLogin(), info));
}
else {
start.setText(context.getString(R.string.timelineProjectRemoved, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineProjectRemoved, issueComment.getUser().getLogin(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -698,15 +698,16 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
// TODO pretty-print
if(issueComment.getType().equalsIgnoreCase("added_deadline")) {
start.setText(context.getString(R.string.timelineDueDateAdded, issueComment.getUser().getLogin(), issueComment.getBody(), informationBuilder));
start.setText(context.getString(R.string.timelineDueDateAdded, issueComment.getUser().getLogin(), issueComment.getBody(), info));
}
else if(issueComment.getType().equalsIgnoreCase("modified_deadline")) {
start.setText(
context.getString(R.string.timelineDueDateModified, issueComment.getUser().getLogin(), issueComment.getBody().split("\\|")[0], issueComment.getBody().split("\\|")[1], informationBuilder));
context.getString(R.string.timelineDueDateModified, issueComment.getUser().getLogin(), issueComment.getBody().split("\\|")[0], issueComment.getBody().split("\\|")[1], info));
}
else if(issueComment.getType().equalsIgnoreCase("removed_deadline")) {
start.setText(context.getString(R.string.timelineDueDateRemoved, issueComment.getUser().getLogin(), issueComment.getBody(), informationBuilder));
start.setText(context.getString(R.string.timelineDueDateRemoved, issueComment.getUser().getLogin(), issueComment.getBody(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -720,10 +721,10 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getType().equalsIgnoreCase("change_target_branch")) {
start.setText(context.getString(R.string.timelineBranchChanged, issueComment.getUser().getLogin(), issueComment.getOldRef(), issueComment.getNewRef(), informationBuilder));
start.setText(context.getString(R.string.timelineBranchChanged, issueComment.getUser().getLogin(), issueComment.getOldRef(), issueComment.getNewRef(), info));
}
else if(issueComment.getType().equalsIgnoreCase("delete_branch")) {
start.setText(context.getString(R.string.timelineBranchDeleted, issueComment.getUser().getLogin(), issueComment.getOldRef(), informationBuilder));
start.setText(context.getString(R.string.timelineBranchDeleted, issueComment.getUser().getLogin(), issueComment.getOldRef(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -738,20 +739,20 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
TextView start = new TextView(context);
if(issueComment.getType().equalsIgnoreCase("start_tracking")) {
start.setText(context.getString(R.string.timelineTimeTrackingStart, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineTimeTrackingStart, issueComment.getUser().getLogin(), info));
}
else if(issueComment.getType().equalsIgnoreCase("stop_tracking")) {
start.setText(context.getString(R.string.timelineTimeTrackingStop, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineTimeTrackingStop, issueComment.getUser().getLogin(), info));
}
else if(issueComment.getType().equalsIgnoreCase("cancel_tracking")) {
start.setText(context.getString(R.string.timelineTimeTrackingCancel, issueComment.getUser().getLogin(), informationBuilder));
start.setText(context.getString(R.string.timelineTimeTrackingCancel, issueComment.getUser().getLogin(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
else if(issueComment.getType().equalsIgnoreCase("add_time_manual")) {
start.setText(context.getString(R.string.timelineTimeTrackingAddManualTime, issueComment.getUser().getLogin(), issueComment.getBody(), informationBuilder));
start.setText(context.getString(R.string.timelineTimeTrackingAddManualTime, issueComment.getUser().getLogin(), issueComment.getBody(), info));
}
else if(issueComment.getType().equalsIgnoreCase("delete_time_manual")) {
start.setText(context.getString(R.string.timelineTimeTrackingDeleteManualTime, issueComment.getUser().getLogin(), issueComment.getBody(), informationBuilder));
start.setText(context.getString(R.string.timelineTimeTrackingDeleteManualTime, issueComment.getUser().getLogin(), issueComment.getBody(), info));
timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null));
}
start.setTextSize(fontSize);
@ -766,18 +767,18 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
RecyclerView recyclerView = new RecyclerView(context);
if(issueComment.getType().equalsIgnoreCase("change_issue_ref")) {
String text = context.getString(R.string.timelineChangeIssueRef, issueComment.getUser().getLogin(), issueComment.getNewRef(), informationBuilder);
String text = context.getString(R.string.timelineChangeIssueRef, issueComment.getUser().getLogin(), issueComment.getNewRef(), info);
Markdown.render(context, EmojiParser.parseToUnicode(text), recyclerView, issue.getRepository());
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_branch));
}
else if(issueComment.getType().equalsIgnoreCase("comment_ref") || issueComment.getType().equalsIgnoreCase("issue_ref") || issueComment.getType().equalsIgnoreCase("pull_ref")) {
if(issue.getIssueType().equalsIgnoreCase("Issue")) {
String text = context.getString(R.string.timelineRefIssue, issueComment.getUser().getLogin(), issueComment.getRefIssue().getNumber(), informationBuilder);
String text = context.getString(R.string.timelineRefIssue, issueComment.getUser().getLogin(), issueComment.getRefIssue().getNumber(), info);
Markdown.render(context, EmojiParser.parseToUnicode(text), recyclerView, issue.getRepository());
}
else if(issue.getIssueType().equalsIgnoreCase("Pull")) {
String text = context.getString(R.string.timelineRefPr, issueComment.getUser().getLogin(), issueComment.getRefIssue().getNumber(), informationBuilder);
String text = context.getString(R.string.timelineRefPr, issueComment.getUser().getLogin(), issueComment.getRefIssue().getNumber(), info);
Markdown.render(context, EmojiParser.parseToUnicode(text), recyclerView, issue.getRepository());
}
timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark));
@ -809,7 +810,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
Markdown.render(context, EmojiParser.parseToUnicode(issueComment.getBody()), comment, issue.getRepository());
information.setText(informationBuilder);
information.setText(info);
Bundle bundle1 = new Bundle();
bundle1.putAll(bundle);

View File

@ -792,43 +792,45 @@
<string name="openInCodeEditor">Open in Code Editor</string>
<!-- timeline -->
<string name="timelineAddedLabelStart">%s added the\u0020</string>
<string name="timelineRemovedLabelStart">%s removed the\u0020</string>
<string name="timelineLabelEnd">\u0020label %s</string>
<string name="timelineAddedCommit">%s added\u0020</string>
<string name="timelineAssigneesRemoved">%s removed their assignment %s</string>
<string name="timelineAssigneesUnassigned">%s was unassigned by %s %s</string>
<string name="timelineAssigneesSelfAssigned">%s self-assigned this %s</string>
<string name="timelineAssigneesAssigned">%s was assigned by %s %s</string>
<string name="timelineMilestoneAdded">%s added this to the %s milestone %s</string>
<string name="timelineMilestoneRemoved">%s removed this from the %s milestone %s</string>
<string name="timelineStatusClosedIssue">%s closed this issue %s</string>
<string name="timelineStatusReopenedIssue">%s reopened this issue %s</string>
<string name="timelineStatusRefIssue">%s referenced this issue from a \u0020</string>
<string name="timelineStatusClosedPr">%s closed this pull request %s</string>
<string name="timelineStatusMergedPr">%s merged this pull request %s</string>
<string name="timelineStatusRefPr">%s referenced this pull request from a\u0020</string>
<string name="commitText">commit</string>
<string name="timelineStatusReopenedPr">%s reopened this pull request %s</string>
<string name="timelineReviewRequest">%s requested review from %s %s</string>
<string name="timelineChangeTitle">%s changed title from %s to %s %s</string>
<string name="timelineLocked">%s locked as %s and limited conversation to collaborators %s</string>
<string name="timelineUnlocked">%s unlocked this conversation %s</string>
<string name="timelineDependencyAdded">%s added a new dependency #%d %s</string>
<string name="timelineDependencyRemoved">%s removed a dependency #%d %s</string>
<string name="timelineProjectAdded">%s added this to a project %s</string>
<string name="timelineProjectRemoved">%s removed this from a project %s</string>
<string name="timelineDueDateAdded">%s added the due date %s %s</string>
<string name="timelineDueDateModified">%s modified the due date to %s from %s %s</string>
<string name="timelineDueDateRemoved">%s removed the due date %s %s</string>
<string name="timelineBranchChanged">%s changed target branch from %s to %s %s</string>
<string name="timelineBranchDeleted">%s deleted branch %s %s</string>
<string name="timelineTimeTrackingStart">%s started working %s</string>
<string name="timelineTimeTrackingStop">%s stopped time tracking %s</string>
<string name="timelineTimeTrackingCancel">%s cancelled time tracking %s</string>
<string name="timelineTimeTrackingAddManualTime">%s added spent time %s %s</string>
<string name="timelineTimeTrackingDeleteManualTime">%s deleted spent time %s %s</string>
<string name="timelineChangeIssueRef">%s added reference %s %s</string>
<string name="timelineRefIssue">%s referenced this issue in #%d %s</string>
<string name="timelineRefPr">%s referenced this pull request in #%d %s</string>
<string name="timelineAddedCommit">%1$s added %2$s %3$s</string>
<!-- the | is replaced by the label -->
<string name="timelineAddedLabel">%1$s added the | label %2$s</string>
<!-- the | is replaced by the label -->
<string name="timelineRemovedLabel">%1$s removed the | label %2$s</string>
<string name="timelineAssigneesRemoved">%1$s removed their assignment %2$s</string>
<string name="timelineAssigneesUnassigned">%1$s was unassigned by %2$s %3$s</string>
<string name="timelineAssigneesSelfAssigned">%1$s self-assigned this %2$s</string>
<string name="timelineAssigneesAssigned">%1$s was assigned by %2$s %3$s</string>
<string name="timelineMilestoneAdded">%1$s added this to the %2$s milestone %3$s</string>
<string name="timelineMilestoneRemoved">%1$s removed this from the %2$s milestone %3$s</string>
<string name="timelineStatusClosedIssue">%1$s closed this issue %2$s</string>
<string name="timelineStatusReopenedIssue">%1$s reopened this issue %2$s</string>
<string name="timelineStatusReopenedPr">%1$s reopened this pull request %2$s</string>
<string name="timelineStatusClosedPr">%1$s closed this pull request %2$s</string>
<string name="timelineStatusMergedPr">%1$s merged this pull request %2$s</string>
<string name="timelineStatusRefPr"><![CDATA[%1$s referenced this pull request from a <font color=\'%2$d\'>%3$s</font> %4$s]]>]</string>
<string name="timelineReviewRequest">%1$s requested review from %2$s %3$s</string>
<string name="timelineChangeTitle">%1$s changed title from %2$s to %3$s %4$s</string>
<string name="timelineLocked">%1$s locked as %2$s and limited conversation to collaborators %3$s</string>
<string name="timelineUnlocked">%1$s unlocked this conversation %2$s</string>
<string name="timelineDependencyAdded">%1$s added a new dependency #%2$d %3$s</string>
<string name="timelineDependencyRemoved">%1$s removed a dependency #%2$d %3$s</string>
<string name="timelineProjectAdded">%1$s added this to a project %2$s</string>
<string name="timelineProjectRemoved">%1$s removed this from a project %2$s</string>
<string name="timelineDueDateAdded">%1$s added the due date %2$s %3$s</string>
<string name="timelineDueDateModified">%1$s modified the due date to %2$s from %3$s %4$s</string>
<string name="timelineDueDateRemoved">%1$s removed the due date %2$s %3$s</string>
<string name="timelineBranchChanged">%1$s changed target branch from %2$s to %3$s %4$s</string>
<string name="timelineBranchDeleted">%1$s deleted branch %2$s %3$s</string>
<string name="timelineTimeTrackingStart">%1$s started working %2$s</string>
<string name="timelineTimeTrackingStop">%1$s stopped time tracking %2$s</string>
<string name="timelineTimeTrackingCancel">%1$s cancelled time tracking %2$s</string>
<string name="timelineTimeTrackingAddManualTime">%1$s added spent time %2$s %3$s</string>
<string name="timelineTimeTrackingDeleteManualTime">%1$s deleted spent time %2$s %3$s</string>
<string name="timelineChangeIssueRef">%1$s added reference %2$s %3$s</string>
<string name="timelineRefIssue">%1$s referenced this issue in #%2$d %3$s</string>
<string name="timelineRefPr">%1$s referenced this pull request in #%2$d %3$s</string>
<string name="timelineStatusRefIssue"><![CDATA[%1$s referenced this issue from a <font color=\'%2$d\'>%3$s</font> %4$s]]>]</string>
</resources>