threads / patch / 42369

patch, 21 partsi18n: builtin/remote.c: fix mark for translation

Subject: [PATCH 01/21] i18n: builtin/remote.c: fix mark for translation

## tl;dr

42 messages between May 18, 2016 and May 23, 2016. Diffs are folded; open one to read it.

replies: 41people: 4as markdown or json

Vasco Almeida· May 18, 2016, 15:27 UTC · lore

[PATCH 00/21] i18n and tests updates

Marks several messages for translation and updates tests to pass under GETTEXT_POISON. Some tests were updated to fit previous i18n marks, others were updated to fit marks made by these patches. Patches that only touch test file refer to marks done in commits previous to these ones.

Vasco Almeida (21):
  i18n: builtin/remote.c: fix mark for translation
  i18n: advice: mark string about detached head for translation
  i18n: advice: internationalize message for conflicts
  i18n: transport: mark strings for translation
  i18n: sequencer: mark entire sentences for translation
  i18n: sequencer: mark string for translation
  i18n: merge-octopus: mark messages for translation
  merge-octupus: use die shell function from git-sh-setup.sh
  i18n: rebase: fix marked string to use eval_gettext variant
  i18n: rebase: mark placeholder for translation
  i18n: bisect: simplify error message for i18n
  t6030: update to use test_i18ncmp
  i18n: git-sh-setup.sh: mark strings for translation
  i18n: rebase-interactive: mark strings for translation
  i18n: rebase-interactive: mark here-doc strings for translation
  i18n: rebase-interactive: mark comments of squash for translation
  tests: use test_i18n* functions to suppress false positives
  tests: unpack-trees: update to use test_i18n* functions
  t9003: become resilient to GETTEXT_POISON
  t4153: fix negated test_i18ngrep call
  t5523: use test_i18ngrep for negation
 Makefile                             |   5 +-
 advice.c                             |  21 ++-
 builtin/pull.c                       |   2 +-
 builtin/remote.c                     |   6 +-
 git-bisect.sh                        |   5 +-
 git-merge-octopus.sh                 |  24 ++--
 git-rebase--interactive.sh           | 270 +++++++++++++++++++++--------------
 git-rebase.sh                        |   4 +-
 git-sh-i18n.sh                       |   4 +
 git-sh-setup.sh                      |  56 ++++++--
 sequencer.c                          |  13 +-
 t/lib-rebase.sh                      |   1 +
 t/t0008-ignores.sh                   |   4 +-
 t/t1011-read-tree-sparse-checkout.sh |   2 +-
 t/t1300-repo-config.sh               |   8 +-
 t/t1307-config-blob.sh               |   2 +-
 t/t1308-config-set.sh                |   4 +-
 t/t1400-update-ref.sh                |   2 +-
 t/t2010-checkout-ambiguous.sh        |   2 +-
 t/t2018-checkout-branch.sh           |   2 +-
 t/t3200-branch.sh                    |   6 +-
 t/t3201-branch-contains.sh           |   2 +-
 t/t3320-notes-merge-worktrees.sh     |   2 +-
 t/t3400-rebase.sh                    |   4 +-
 t/t3404-rebase-interactive.sh        |  18 +--
 t/t4153-am-resume-override-opts.sh   |   2 +-
 t/t5505-remote.sh                    |   2 +-
 t/t5510-fetch.sh                     |   2 +-
 t/t5520-pull.sh                      |   2 +-
 t/t5523-push-upstream.sh             |  12 +-
 t/t5536-fetch-conflicts.sh           |   4 +-
 t/t6030-bisect-porcelain.sh          |   4 +-
 t/t6301-for-each-ref-errors.sh       |  10 +-
 t/t7063-status-untracked-cache.sh    |   2 +-
 t/t7102-reset.sh                     |   4 +-
 t/t7400-submodule-basic.sh           |   2 +-
 t/t7403-submodule-sync.sh            |   4 +-
 t/t7406-submodule-update.sh          |  10 +-
 t/t7508-status.sh                    |   4 +-
 t/t7607-merge-overwrite.sh           |   2 +-
 t/t9003-help-autocorrect.sh          |   8 +-
 transport.c                          |  20 +--
 42 files changed, 337 insertions(+), 226 deletions(-)
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

The second string inside _() was not being extracted for translation by xgettext, meaning that, although the string was passed to gettext, there was no translation available.

Mark each individual string instead of marking the result of ternary if.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 builtin/remote.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
Show changes to builtin/remote.c +3 −3
diff --git a/builtin/remote.c b/builtin/remote.c
index d33766b..ae74da6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -963,9 +963,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
-			"rebases interactively onto remote %s" :
-			"rebases onto remote %s"), merge->items[0].string);
+		printf_ln(branch_info->rebase == INTERACTIVE_REBASE
+			  ? _("rebases interactively onto remote %s")
+			  : _("rebases onto remote %s"), merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf_ln(_(" merges with remote %s"), merge->items[0].string);
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 02/21] i18n: advice: mark string about detached head for translation

Mark string with advice seen by the user when in detached head.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 advice.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to advice.c +2 −2
diff --git a/advice.c b/advice.c
index 4dc5cf1..703a847 100644
--- a/advice.c
+++ b/advice.c
@@ -107,13 +107,13 @@ void NORETURN die_conclude_merge(void)
 void detach_advice(const char *new_name)
 {
 	const char fmt[] =
-	"Note: checking out '%s'.\n\n"
+	N_("Note: checking out '%s'.\n\n"
 	"You are in 'detached HEAD' state. You can look around, make experimental\n"
 	"changes and commit them, and you can discard any commits you make in this\n"
 	"state without impacting any branches by performing another checkout.\n\n"
 	"If you want to create a new branch to retain commits you create, you may\n"
 	"do so (now or later) by using -b with the checkout command again. Example:\n\n"
-	"  git checkout -b <new-branch-name>\n\n";
+	"  git checkout -b <new-branch-name>\n\n");
 
 	fprintf(stderr, fmt, new_name);
 }
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 03/21] i18n: advice: internationalize message for conflicts

Mark message for translation telling the user she has conflicts to resolve. Expose each particular use case, in order to enable translating entire sentences which would facilitate translating into other languages.

Change "Pull" to lowercase to match other messages.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 advice.c        | 17 +++++++++++++++--
 builtin/pull.c  |  2 +-
 t/t5520-pull.sh |  2 +-
 3 files changed, 17 insertions(+), 4 deletions(-)
Show changes to 3 files +17 −4

advice.c, builtin/pull.c, t/t5520-pull.sh

diff --git a/advice.c b/advice.c
index 703a847..bc531fc 100644
--- a/advice.c
+++ b/advice.c
@@ -79,7 +79,20 @@ int git_default_advice_config(const char *var, const char *value)
 
 int error_resolve_conflict(const char *me)
 {
-	error("%s is not possible because you have unmerged files.", me);
+	if (!strcmp(me, "cherry-pick"))
+		error(_("cherry-pick is not possible because you have unmerged files."));
+	else if (!strcmp(me, "commit"))
+		error(_("commit is not possible because you have unmerged files."));
+	else if (!strcmp(me, "merge"))
+		error(_("merge is not possible because you have unmerged files."));
+	else if (!strcmp(me, "pull"))
+		error(_("pull is not possible because you have unmerged files."));
+	else if (!strcmp(me, "revert"))
+		error(_("revert is not possible because you have unmerged files."));
+	else
+		error(_("%s is not possible because you have unmerged files."),
+			me);
+
 	if (advice_resolve_conflict)
 		/*
 		 * Message used both when 'git commit' fails and when
@@ -93,7 +106,7 @@ int error_resolve_conflict(const char *me)
 void NORETURN die_resolve_conflict(const char *me)
 {
 	error_resolve_conflict(me);
-	die("Exiting because of an unresolved conflict.");
+	die(_("Exiting because of an unresolved conflict."));
 }
 
 void NORETURN die_conclude_merge(void)
diff --git a/builtin/pull.c b/builtin/pull.c
index 1d7333c..a980dcf 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -852,7 +852,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	git_config(git_pull_config, NULL);
 
 	if (read_cache_unmerged())
-		die_resolve_conflict("Pull");
+		die_resolve_conflict("pull");
 
 	if (file_exists(git_path("MERGE_HEAD")))
 		die_conclude_merge();
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 739c089..61beff6 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -211,7 +211,7 @@ test_expect_success 'fail if the index has unresolved entries' '
 	test -n "$(git ls-files -u)" &&
 	cp file expected &&
 	test_must_fail git pull . second 2>err &&
-	test_i18ngrep "Pull is not possible because you have unmerged files" err &&
+	test_i18ngrep "pull is not possible because you have unmerged files" err &&
 	test_cmp expected file &&
 	git add file &&
 	test -z "$(git ls-files -u)" &&
-- 
2.7.3
Eric Sunshine· May 18, 2016, 19:24 UTC · re: Vasco Almeida · lore

Re: [PATCH 03/21] i18n: advice: internationalize message for conflicts

On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 27 quoted lines
> Mark message for translation telling the user she has conflicts to
> resolve. Expose each particular use case, in order to enable translating
> entire sentences which would facilitate translating into other
> languages.
>
> Change "Pull" to lowercase to match other messages.
>
> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
> ---
> diff --git a/advice.c b/advice.c
> @@ -79,7 +79,20 @@ int git_default_advice_config(const char *var, const char *value)
>  int error_resolve_conflict(const char *me)
>  {
> -       error("%s is not possible because you have unmerged files.", me);
> +       if (!strcmp(me, "cherry-pick"))
> +               error(_("cherry-pick is not possible because you have unmerged files."));
> +       else if (!strcmp(me, "commit"))
> +               error(_("commit is not possible because you have unmerged files."));
> +       else if (!strcmp(me, "merge"))
> +               error(_("merge is not possible because you have unmerged files."));
> +       else if (!strcmp(me, "pull"))
> +               error(_("pull is not possible because you have unmerged files."));
> +       else if (!strcmp(me, "revert"))
> +               error(_("revert is not possible because you have unmerged files."));
> +       else
> +               error(_("%s is not possible because you have unmerged files."),
> +                       me);

Despite the commit message, I still don't understand this change. 'me' is a literal git command which shouldn't be translated, so how is this helping?

Vasco Almeida· May 18, 2016, 21:00 UTC · re: Eric Sunshine · lore

Re: [PATCH 03/21] i18n: advice: internationalize message for conflicts

Às 19:24 de 18-05-2016, Eric Sunshine escreveu:
Show 33 quoted lines
> On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>> Mark message for translation telling the user she has conflicts to
>> resolve. Expose each particular use case, in order to enable translating
>> entire sentences which would facilitate translating into other
>> languages.
>>
>> Change "Pull" to lowercase to match other messages.
>>
>> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
>> ---
>> diff --git a/advice.c b/advice.c
>> @@ -79,7 +79,20 @@ int git_default_advice_config(const char *var, const char *value)
>>  int error_resolve_conflict(const char *me)
>>  {
>> -       error("%s is not possible because you have unmerged files.", me);
>> +       if (!strcmp(me, "cherry-pick"))
>> +               error(_("cherry-pick is not possible because you have unmerged files."));
>> +       else if (!strcmp(me, "commit"))
>> +               error(_("commit is not possible because you have unmerged files."));
>> +       else if (!strcmp(me, "merge"))
>> +               error(_("merge is not possible because you have unmerged files."));
>> +       else if (!strcmp(me, "pull"))
>> +               error(_("pull is not possible because you have unmerged files."));
>> +       else if (!strcmp(me, "revert"))
>> +               error(_("revert is not possible because you have unmerged files."));
>> +       else
>> +               error(_("%s is not possible because you have unmerged files."),
>> +                       me);
> 
> Despite the commit message, I still don't understand this change. 'me'
> is a literal git command which shouldn't be translated, so how is this
> helping?
> 

I saw it as an operation that could be translated, not necessary a git command - just happens to be so. Now that you mention, I can see this patch doesn't had much value from that point of view.

On the other hand, I can translate the sentence, including the command name. Something I couldn't before and I would likely do it to be consistent with other translations I've done and also because, as a user, I would like to read the entire sentence in my language.

I have few experience in i18n and l10n, but often I realize I'm making assumptions about other languages that are not true. Some translations, say Chinese or Bulgarian that have their own writing systems, might translate that command word to something to their writing. Others might agglutinate the command word with some suffix. I can't say for sure because I don't know those languages, but it's possible.

Maybe the first paragraph can give you a better understanding of the issue: http://www.gnu.org/software/gettext/manual/html_node/Names.html

Junio C Hamano· May 18, 2016, 21:31 UTC · re: Vasco Almeida · lore

Re: [PATCH 03/21] i18n: advice: internationalize message for conflicts

Vasco Almeida <vascomalmeida@sapo.pt> writes:
Show 10 quoted lines
>>> +       else
>>> +               error(_("%s is not possible because you have unmerged files."),
>>> +                       me);
>> 
>> Despite the commit message, I still don't understand this change. 'me'
>> is a literal git command which shouldn't be translated, so how is this
>> helping?
>> 
> I saw it as an operation that could be translated, not necessary a git
> command

The intention of who wrote this message was to tell this to the user:

    Running the command '$X' is not possible in this situation.

implying "Don't type '$X' again; it is futile. Correct the unmerged status first".

Our subcommand names are English verbs, because they are designed to be easily understandable by English speakers, so we do not exactly say "Running the command 'commit'" in the message. Instead we say "commit is not possible..." for brevity.

Languages, if their grammatical rules do not allow a subcommand name in the place in a straight-translation of that original sentence, are allowed to (and encouraged to) translate the original "%s is not possible" as if it were "Running the command '%s' is not possible". That is what good translaters would do anyway.

So for this (and 05/21 for the same reasons), I do not think we want to split and duplicate the messages.

Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 04/21] i18n: transport: mark strings for translation

Mark one printf string and one error string for translation.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 transport.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
Show changes to transport.c +10 −10
diff --git a/transport.c b/transport.c
index 095e61f..59b911e 100644
--- a/transport.c
+++ b/transport.c
@@ -59,7 +59,7 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
 				localname + 11, transport->remote->name,
 				remotename);
 		else
-			printf("Would set upstream of '%s' to '%s' of '%s'\n",
+			printf(_("Would set upstream of '%s' to '%s' of '%s'\n"),
 				localname + 11, remotename + 11,
 				transport->remote->name);
 	}
@@ -148,7 +148,7 @@ static int set_git_option(struct git_transport_options *opts,
 			char *end;
 			opts->depth = strtol(value, &end, 0);
 			if (*end)
-				die("transport: invalid depth option '%s'", value);
+				die(_("transport: invalid depth option '%s'"), value);
 		}
 		return 0;
 	}
@@ -767,19 +767,19 @@ static void die_with_unpushed_submodules(struct string_list *needs_pushing)
 {
 	int i;
 
-	fprintf(stderr, "The following submodule paths contain changes that can\n"
-			"not be found on any remote:\n");
+	fprintf(stderr, _("The following submodule paths contain changes that can\n"
+			"not be found on any remote:\n"));
 	for (i = 0; i < needs_pushing->nr; i++)
 		printf("  %s\n", needs_pushing->items[i].string);
-	fprintf(stderr, "\nPlease try\n\n"
-			"	git push --recurse-submodules=on-demand\n\n"
-			"or cd to the path and use\n\n"
-			"	git push\n\n"
-			"to push them to a remote.\n\n");
+	fprintf(stderr, _("\nPlease try\n\n"
+			  "	git push --recurse-submodules=on-demand\n\n"
+			  "or cd to the path and use\n\n"
+			  "	git push\n\n"
+			  "to push them to a remote.\n\n"));
 
 	string_list_clear(needs_pushing, 0);
 
-	die("Aborting.");
+	die(_("Aborting."));
 }
 
 static int run_pre_push_hook(struct transport *transport,
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 05/21] i18n: sequencer: mark entire sentences for translation

Mark entire sentences of error message rather than assembling one using placeholders (e.g. "Cannot %s during a %s"). That would facilitate translation work.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 sequencer.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
Show changes to sequencer.c +8 −3
diff --git a/sequencer.c b/sequencer.c
index 4687ad4..88a7c78 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -697,9 +697,14 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
 	 * opts; we don't support arbitrary instructions
 	 */
 	if (action != opts->action) {
-		const char *action_str;
-		action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
-		error(_("Cannot %s during a %s"), action_str, action_name(opts));
+		if (action == REPLAY_REVERT)
+		      error((opts->action == REPLAY_REVERT)
+			    ? _("Cannot revert during a another revert.")
+			    : _("Cannot revert during a cherry-pick."));
+		else
+		      error((opts->action == REPLAY_REVERT)
+			    ? _("Cannot cherry-pick during a revert.")
+			    : _("Cannot cherry-pick during another cherry-pick."));
 		return NULL;
 	}
 
-- 
2.7.3
Eric Sunshine· May 18, 2016, 19:28 UTC · re: Vasco Almeida · lore

Re: [PATCH 05/21] i18n: sequencer: mark entire sentences for translation

On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 22 quoted lines
> Mark entire sentences of error message rather than assembling one using
> placeholders (e.g. "Cannot %s during a %s"). That would facilitate
> translation work.
>
> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
> ---
> diff --git a/sequencer.c b/sequencer.c
> @@ -697,9 +697,14 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
>         if (action != opts->action) {
> -               const char *action_str;
> -               action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
> -               error(_("Cannot %s during a %s"), action_str, action_name(opts));
> +               if (action == REPLAY_REVERT)
> +                     error((opts->action == REPLAY_REVERT)
> +                           ? _("Cannot revert during a another revert.")
> +                           : _("Cannot revert during a cherry-pick."));
> +               else
> +                     error((opts->action == REPLAY_REVERT)
> +                           ? _("Cannot cherry-pick during a revert.")
> +                           : _("Cannot cherry-pick during another cherry-pick."));
>                 return NULL;
>         }

Similar to my comment on patch 3/21, since the "actions" are literal git commands, it's not clear why this change is helpful. Perhaps the commit message needs to do a better job of persuading the reader?

Vasco Almeida· May 18, 2016, 21:02 UTC · re: Eric Sunshine · lore

Re: [PATCH 05/21] i18n: sequencer: mark entire sentences for translation

Às 19:28 de 18-05-2016, Eric Sunshine escreveu:
Show 28 quoted lines
> On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>> Mark entire sentences of error message rather than assembling one using
>> placeholders (e.g. "Cannot %s during a %s"). That would facilitate
>> translation work.
>>
>> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
>> ---
>> diff --git a/sequencer.c b/sequencer.c
>> @@ -697,9 +697,14 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
>>         if (action != opts->action) {
>> -               const char *action_str;
>> -               action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
>> -               error(_("Cannot %s during a %s"), action_str, action_name(opts));
>> +               if (action == REPLAY_REVERT)
>> +                     error((opts->action == REPLAY_REVERT)
>> +                           ? _("Cannot revert during a another revert.")
>> +                           : _("Cannot revert during a cherry-pick."));
>> +               else
>> +                     error((opts->action == REPLAY_REVERT)
>> +                           ? _("Cannot cherry-pick during a revert.")
>> +                           : _("Cannot cherry-pick during another cherry-pick."));
>>                 return NULL;
>>         }
> 
> Similar to my comment on patch 3/21, since the "actions" are literal
> git commands, it's not clear why this change is helpful. Perhaps the
> commit message needs to do a better job of persuading the reader?
> 

I agree, I should have explained why this way. As I tried to explain on patch 3/21, it concerns a) we can't assume what and how does the translator translates into her language, so b) give translations freedom to choose.

Ævar Arnfjörð Bjarmason· May 21, 2016, 13:15 UTC · re: Vasco Almeida · lore

Re: [PATCH 05/21] i18n: sequencer: mark entire sentences for translation

On Wed, May 18, 2016 at 11:02 PM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 33 quoted lines
> Às 19:28 de 18-05-2016, Eric Sunshine escreveu:
>> On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>>> Mark entire sentences of error message rather than assembling one using
>>> placeholders (e.g. "Cannot %s during a %s"). That would facilitate
>>> translation work.
>>>
>>> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
>>> ---
>>> diff --git a/sequencer.c b/sequencer.c
>>> @@ -697,9 +697,14 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
>>>         if (action != opts->action) {
>>> -               const char *action_str;
>>> -               action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
>>> -               error(_("Cannot %s during a %s"), action_str, action_name(opts));
>>> +               if (action == REPLAY_REVERT)
>>> +                     error((opts->action == REPLAY_REVERT)
>>> +                           ? _("Cannot revert during a another revert.")
>>> +                           : _("Cannot revert during a cherry-pick."));
>>> +               else
>>> +                     error((opts->action == REPLAY_REVERT)
>>> +                           ? _("Cannot cherry-pick during a revert.")
>>> +                           : _("Cannot cherry-pick during another cherry-pick."));
>>>                 return NULL;
>>>         }
>>
>> Similar to my comment on patch 3/21, since the "actions" are literal
>> git commands, it's not clear why this change is helpful. Perhaps the
>> commit message needs to do a better job of persuading the reader?
>>
> I agree, I should have explained why this way. As I tried to explain on
> patch 3/21, it concerns a) we can't assume what and how does the
> translator translates into her language, so b) give translations freedom
> to choose.

For what it's worth I agree with you and disagree with Eric here and Junio in the "[PATCH 03/21] i18n: advice: internationalize message for conflicts" thread.

Of course there's a trade-off in source code verbosity when you have to change every occurance of (pseudocode):

    "our %s failed" # %s can be revert or merge
to:
    if (action == "merge")
        gettext("our merge failed")
    elsif (action == "revert")
        gettext("our revert failed")

But forcing the translator to turn every such occurrence that flows naturally in English into "the '%s' command failed" leads to a worse translation.

For example, if I ever get around to doing the Icelandic translation which I've had on my backlog I might translate something like this:

    "You can merge or revert this commit"
    "To merge run 'git merge $commit', to revert run 'git revert $commit'"
    # Subsequently
    "The %s failed" # for %s = merge || revert
As:
    "Þú getur getur framkvæmt samruna á þessari breytingu, eða afturkallað hana"
    "Til að framkvæma samruna keyrðu 'git merge $commit', til að
afturkalla 'git revert $commit'"
    # Subsequently
    "Samruninn mistókst þegar við keyrðum 'merge' skipunina".
    "Afturköllunnin mistókst þegar við keyrðum 'revert' skipunina"

I.e. even though you might be running "git merge" or "git revert" the UI is talking about those terms in the translated using native terms for the action of merging or reverting, but referring to the literal command names in English.

Not accepting changes like these means you have to translate this sort of stuff like:

    # Same as the above
    "Þú getur getur framkvæmt samruna á þessari breytingu, eða
afturkallað hana".
    "Til að framkvæma samruna keyrðu 'git merge $commit', til að
afturkalla 'git revert $commit'"
    # Subsequently
    "Okkur tókst ekki að keyra 'git %s' skipunina" # %s = merge || revert

It just doesn't flow as well, and leads to a more verbose translation. Now instead of referring to the translated verb I'd already established I have to just refer to literal command names.

Both this change and the change you submitted in <1463585274-9027-4-git-send-email-vascomalmeida@sapo.pt> and Junio didn't like in <xmqqd1ojqciz.fsf@gitster.mtv.corp.google.com> are actual examples of cases where if I was (finally getting of my ass to) doing the Icelandic translation I'd take advantage of this.

Junio C Hamano· May 23, 2016, 00:44 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: [PATCH 05/21] i18n: sequencer: mark entire sentences for translation

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
Show 29 quoted lines
> For what it's worth I agree with you and disagree with Eric here and
> Junio in the "[PATCH 03/21] i18n: advice: internationalize message for
> conflicts" thread.
>
> Of course there's a trade-off in source code verbosity when you have
> to change every occurance of (pseudocode):
>
>     "our %s failed" # %s can be revert or merge
>
> to:
>
>     if (action == "merge")
>         gettext("our merge failed")
>     elsif (action == "revert")
>         gettext("our revert failed")
>
> But forcing the translator to turn every such occurrence that flows
> naturally in English into "the '%s' command failed" leads to a worse
> translation.
>
> For example, if I ever get around to doing the Icelandic translation
> which I've had on my backlog I might translate something like this:
> ...
> I.e. even though you might be running "git merge" or "git revert" the
> UI is talking about those terms in the translated using native terms
> for the action of merging or reverting, but referring to the literal
> command names in English.
> ...
> It just doesn't flow as well, and leads to a more verbose translation.

OK. I couldn't judge your example in Icelandic, but I have enough trust in you to believe your conclusion ;-).

Show 8 quoted lines
> Now instead of referring to the translated verb I'd already
> established I have to just refer to literal command names.
>
> Both this change and the change you submitted in
> <1463585274-9027-4-git-send-email-vascomalmeida@sapo.pt> and Junio
> didn't like in <xmqqd1ojqciz.fsf@gitster.mtv.corp.google.com> are
> actual examples of cases where if I was (finally getting of my ass to)
> doing the Icelandic translation I'd take advantage of this.
Eric Sunshine· May 23, 2016, 01:00 UTC · re: Junio C Hamano · lore

Re: [PATCH 05/21] i18n: sequencer: mark entire sentences for translation

On Sun, May 22, 2016 at 8:44 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 33 quoted lines
> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>> For what it's worth I agree with you and disagree with Eric here and
>> Junio in the "[PATCH 03/21] i18n: advice: internationalize message for
>> conflicts" thread.
>>
>> Of course there's a trade-off in source code verbosity when you have
>> to change every occurance of (pseudocode):
>>
>>     "our %s failed" # %s can be revert or merge
>>
>> to:
>>
>>     if (action == "merge")
>>         gettext("our merge failed")
>>     elsif (action == "revert")
>>         gettext("our revert failed")
>>
>> But forcing the translator to turn every such occurrence that flows
>> naturally in English into "the '%s' command failed" leads to a worse
>> translation.
>>
>> For example, if I ever get around to doing the Icelandic translation
>> which I've had on my backlog I might translate something like this:
>> ...
>> I.e. even though you might be running "git merge" or "git revert" the
>> UI is talking about those terms in the translated using native terms
>> for the action of merging or reverting, but referring to the literal
>> command names in English.
>> ...
>> It just doesn't flow as well, and leads to a more verbose translation.
>
> OK.  I couldn't judge your example in Icelandic, but I have enough
> trust in you to believe your conclusion ;-).

I have no problem viewing the issue from either side (the sentence referencing a *literal* command or the *action* of the command), and understood that it could go either way when I wrote the review. What threw me was that 3/21 seemed to be using the literal command in the strings rather than the action, despite the commit message. For instance:

    error(_("commit is not possible because ..."));
    error(_("merge is not possible because ..."));
    error(_("pull is not possible because ..."));
    error(_("revert is not possible because ..."));

In each case, the first word looks like a git command; it's not particularly grammatically correct. Had Vasco instead changed them to:

    committing is not possible...
    merging is not possible...
    pulling is not possible...
    reverting is not posible...
then the issue likely would never have come up.
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 06/21] i18n: sequencer: mark string for translation

Mark informative string "<action_name>: fast-forward" for translation.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 sequencer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to sequencer.c +1 −1
diff --git a/sequencer.c b/sequencer.c
index 88a7c78..57b3671 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -225,7 +225,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 	if (checkout_fast_forward(from, to, 1))
 		exit(128); /* the callee should have complained already */
 
-	strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
+	strbuf_addf(&sb, _("%s: fast-forward"), action_name(opts));
 
 	transaction = ref_transaction_begin(&err);
 	if (!transaction ||
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 07/21] i18n: merge-octopus: mark messages for translation

Mark messages in git-merge-octopus.sh for translation.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-merge-octopus.sh | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)
Show changes to git-merge-octopus.sh +10 −8
diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index dc2fd1b..89e967a 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -5,6 +5,8 @@
 # Resolve two or more trees.
 #
 
+. git-sh-i18n
+
 LF='
 '
 
@@ -46,7 +48,7 @@ esac
 
 if ! git diff-index --quiet --cached HEAD --
 then
-    echo "Error: Your local changes to the following files would be overwritten by merge"
+    gettextln "Error: Your local changes to the following files would be overwritten by merge"
     git diff-index --cached --name-only HEAD -- | sed -e 's/^/    /'
     exit 2
 fi
@@ -61,8 +63,8 @@ do
 		# We allow only last one to have a hand-resolvable
 		# conflicts.  Last round failed and we still had
 		# a head to merge.
-		echo "Automated merge did not work."
-		echo "Should not be doing an Octopus."
+		gettextln "Automated merge did not work."
+		gettextln "Should not be doing an Octopus."
 		exit 2
 	esac
 
@@ -73,11 +75,11 @@ do
 		eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name}
 	fi
 	common=$(git merge-base --all $SHA1 $MRC) ||
-		die "Unable to find common commit with $pretty_name"
+		die "$(eval_gettext "Unable to find common commit with \$pretty_name")"
 
 	case "$LF$common$LF" in
 	*"$LF$SHA1$LF"*)
-		echo "Already up-to-date with $pretty_name"
+		eval_gettextln "Already up-to-date with \$pretty_name"
 		continue
 		;;
 	esac
@@ -89,7 +91,7 @@ do
 		# tree as the intermediate result of the merge.
 		# We still need to count this as part of the parent set.
 
-		echo "Fast-forwarding to: $pretty_name"
+		eval_gettextln "Fast-forwarding to: \$pretty_name"
 		git read-tree -u -m $head $SHA1 || exit
 		MRC=$SHA1 MRT=$(git write-tree)
 		continue
@@ -97,12 +99,12 @@ do
 
 	NON_FF_MERGE=1
 
-	echo "Trying simple merge with $pretty_name"
+	eval_gettextln "Trying simple merge with \$pretty_name"
 	git read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
 	next=$(git write-tree 2>/dev/null)
 	if test $? -ne 0
 	then
-		echo "Simple merge did not work, trying automatic merge."
+		gettextln "Simple merge did not work, trying automatic merge."
 		git-merge-index -o git-merge-one-file -a ||
 		OCTOPUS_FAILURE=1
 		next=$(git write-tree 2>/dev/null)
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 08/21] merge-octupus: use die shell function from git-sh-setup.sh

Source git-sh-setup in order to use die shell function from git-sh-setup.sh library instead of using the one defined in git-merge-octopus.sh. Remove the former die function.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-merge-octopus.sh | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
Show changes to git-merge-octopus.sh +1 −5
diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 89e967a..d79fc84 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -5,16 +5,12 @@
 # Resolve two or more trees.
 #
 
+. git-sh-setup
 . git-sh-i18n
 
 LF='
 '
 
-die () {
-    echo >&2 "$*"
-    exit 1
-}
-
 # The first parameters up to -- are merge bases; the rest are heads.
 bases= head= remotes= sep_seen=
 for arg
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 09/21] i18n: rebase: fix marked string to use eval_gettext variant

The string message marked for translation should use eval_gettext variant instead of the gettext one, since we want to dollar-substitute $head_name in the result.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-rebase.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to git-rebase.sh +1 −1
diff --git a/git-rebase.sh b/git-rebase.sh
index 44ede36..1fadc04 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -154,7 +154,7 @@ move_to_original_branch () {
 		git symbolic-ref \
 			-m "rebase finished: returning to $head_name" \
 			HEAD $head_name ||
-		die "$(gettext "Could not move back to $head_name")"
+		die "$(eval_gettext "Could not move back to \$head_name")"
 		;;
 	esac
 }
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 10/21] i18n: rebase: mark placeholder for translation

Mark placeholder "<branch>" in git-rebase.sh for translation. The string containing the named placeholder is passed to shell function error_on_missing_default_upstream in git-parse-remote.sh which uses it to display a command hint for the user.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-rebase.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to git-rebase.sh +1 −1
diff --git a/git-rebase.sh b/git-rebase.sh
index 1fadc04..9ba21ab 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -449,7 +449,7 @@ then
 		then
 			. git-parse-remote
 			error_on_missing_default_upstream "rebase" "rebase" \
-				"against" "git rebase <branch>"
+				"against" "git rebase $(gettext '<branch>')"
 		fi
 
 		test "$fork_point" = auto && fork_point=t
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 11/21] i18n: bisect: simplify error message for i18n

The message was not being extracted by xgettext, although it was marked for translation, seemingly because it contained a command substitution. Moreover, eval_gettext should be used instead of gettext for strings with substitution.

See step 4. of section 15.5.2.1 Preparing Shell Scripts for Internationalization from gettext manual [1]: "Simplify translatable strings so that they don't contain command substitution ("`...`" or "$(...)") [...]"

[1] http://www.gnu.org/software/gettext/manual/gettext.html#Preparing-Shell-Scripts
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-bisect.sh | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to git-bisect.sh +3 −2
diff --git a/git-bisect.sh b/git-bisect.sh
index 5d1cb00..737bf05 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -277,8 +277,9 @@ bisect_state() {
 	0,*)
 		die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
 	1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip)
-		rev=$(git rev-parse --verify $(bisect_head)) ||
-			die "$(gettext "Bad rev input: $(bisect_head)")"
+		bisected_head=$(bisect_head)
+		rev=$(git rev-parse --verify "$bisected_head") ||
+			die "$(eval_gettext "Bad rev input: \$bisected_head")"
 		bisect_write "$state" "$rev"
 		check_expected_revs "$rev" ;;
 	2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 12/21] t6030: update to use test_i18ncmp

Since the git bisect output tested here is subject to translation, the helper function test_i18ncmp should be used over test_cmp.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t6030-bisect-porcelain.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to t/t6030-bisect-porcelain.sh +2 −2
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index e74662b..7012011 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -803,7 +803,7 @@ test_expect_success 'bisect terms needs 0 or 1 argument' '
 	test_must_fail git bisect terms 1 2 &&
 	test_must_fail git bisect terms 2>actual &&
 	echo "no terms defined" >expected &&
-	test_cmp expected actual
+	test_i18ncmp expected actual
 '
 
 test_expect_success 'bisect terms shows good/bad after start' '
@@ -875,7 +875,7 @@ test_expect_success 'bisect start --term-* does store terms' '
 	Your current terms are two for the old state
 	and one for the new state.
 	EOF
-	test_cmp expected actual &&
+	test_i18ncmp expected actual &&
 	git bisect terms --term-bad >actual &&
 	echo one >expected &&
 	test_cmp expected actual &&
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 13/21] i18n: git-sh-setup.sh: mark strings for translation

Positional arguments, such as $0, $1, etc, need to be stored on shell variables for use in translatable strings, according to gettext manual.

Add git-sh-setup.sh to LOCALIZED_SH variable in Makefile to enable extraction of string marked for translation by xgettext.

Although git-sh-setup.sh is a shell library to be sourced by other shell scripts, it is necessary to source git-sh-i18n at this point, because some scripts don't do it themselves. Not sourcing git-sh-i18n would lead to failure due to, for instance, gettextln not being found.

Source "$(git --exec-path)"/git-sh-i18n instead of simply git-sh-i18n, because latter case would fail test t2300-cd-to-toplevel.sh.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 Makefile        |  4 +++-
 git-sh-setup.sh | 56 ++++++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 45 insertions(+), 15 deletions(-)
Show changes to 2 files +45 −15

Makefile, git-sh-setup.sh

diff --git a/Makefile b/Makefile
index bc3d41e..d31fcf2 100644
--- a/Makefile
+++ b/Makefile
@@ -2062,7 +2062,9 @@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
 	--keyword=gettextln --keyword=eval_gettextln
 XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
 LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
-LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh
+LOCALIZED_SH = $(SCRIPT_SH)
+LOCALIZED_SH += git-parse-remote.sh
+LOCALIZED_SH += git-sh-setup.sh
 LOCALIZED_PERL = $(SCRIPT_PERL)
 
 ifdef XGETTEXT_INCLUDE_TESTS
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index c48139a..55efa23 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -2,6 +2,10 @@
 # to set up some variables pointing at the normal git directories and
 # a few helper shell functions.
 
+# Some shell scripts source git-sh-setup (i.e. this scriplet) but
+# don't source git-sh-i18n which is needed here for gettext support.
+. "$(git --exec-path)"/git-sh-i18n
+
 # Having this variable in your environment would break scripts because
 # you would cause "cd" to be taken to unexpected places.  If you
 # like CDPATH, define it for your interactive shell sessions without
@@ -83,14 +87,14 @@ if test -n "$OPTIONS_SPEC"; then
 else
 	dashless=$(basename -- "$0" | sed -e 's/-/ /')
 	usage() {
-		die "usage: $dashless $USAGE"
+		die "$(gettext usage:) $dashless $USAGE"
 	}
 
 	if [ -z "$LONG_USAGE" ]
 	then
-		LONG_USAGE="usage: $dashless $USAGE"
+		LONG_USAGE="$(gettext usage:) $dashless $USAGE"
 	else
-		LONG_USAGE="usage: $dashless $USAGE
+		LONG_USAGE="$(gettext usage:) $dashless $USAGE
 
 $LONG_USAGE"
 	fi
@@ -182,48 +186,72 @@ is_bare_repository () {
 cd_to_toplevel () {
 	cdup=$(git rev-parse --show-toplevel) &&
 	cd "$cdup" || {
-		echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+		gettextln "Cannot chdir to \$cdup, the toplevel of the working tree" >&2
 		exit 1
 	}
 }
 
 require_work_tree_exists () {
+	program_name=$0
 	if test "z$(git rev-parse --is-bare-repository)" != zfalse
 	then
-		die "fatal: $0 cannot be used without a working tree."
+		die "$(gettext "fatal: \$program_name cannot be used without a working tree.")"
 	fi
 }
 
 require_work_tree () {
+	program_name=$0
 	test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ||
-	die "fatal: $0 cannot be used without a working tree."
+		die "$(gettext "fatal: \$program_name cannot be used without a working tree.")"
 }
 
 require_clean_work_tree () {
+	action=$1
+	hint=$2
 	git rev-parse --verify HEAD >/dev/null || exit 1
 	git update-index -q --ignore-submodules --refresh
 	err=0
 
 	if ! git diff-files --quiet --ignore-submodules
 	then
-		echo >&2 "Cannot $1: You have unstaged changes."
+		case "$action" in
+		rebase)
+			gettextln "Cannot rebase: You have unstaged changes." >&2
+			;;
+		"pull with rebase")
+			gettextln "Cannot pull with rebase: You have unstaged changes." >&2
+			;;
+		*)
+			eval_gettextln "Cannot \$action: You have unstaged changes." >&2
+			;;
+		esac
 		err=1
 	fi
 
 	if ! git diff-index --cached --quiet --ignore-submodules HEAD --
 	then
-		if [ $err = 0 ]
+		if test $err = 0
 		then
-		    echo >&2 "Cannot $1: Your index contains uncommitted changes."
+			case "$action" in
+			rebase)
+				gettextln "Cannot rebase: Your index contains uncommitted changes." >&2
+				;;
+			"pull with rebase")
+				gettextln "Cannot pull with rebase: Your index contains uncommitted changes." >&2
+				;;
+			*)
+				eval_gettextln "Cannot \$action: Your index contains uncommitted changes." >&2
+				;;
+			esac
 		else
-		    echo >&2 "Additionally, your index contains uncommitted changes."
+		    gettextln "Additionally, your index contains uncommitted changes." >&2
 		fi
 		err=1
 	fi
 
-	if [ $err = 1 ]
+	if test $err = 1
 	then
-		test -n "$2" && echo >&2 "$2"
+		test -n "$hint" && echo "$2" >&2
 		exit 1
 	fi
 }
@@ -336,12 +364,12 @@ git_dir_init () {
 	then
 		test -z "$(git rev-parse --show-cdup)" || {
 			exit=$?
-			echo >&2 "You need to run this command from the toplevel of the working tree."
+			gettextln "You need to run this command from the toplevel of the working tree." >&2
 			exit $exit
 		}
 	fi
 	test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
-		echo >&2 "Unable to determine absolute path of git directory"
+		gettextln "Unable to determine absolute path of git directory" >&2
 		exit 1
 	}
 	: ${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 14/21] i18n: rebase-interactive: mark strings for translation

Mark strings in git-rebase--interactive.sh for translation. There is no need to source git-sh-i18n since git-rebase.sh already does so.

Add git-rebase--interactive.sh to LOCALIZED_SH in Makefile in order to enabled extracting strings marked for translation by xgettext.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 Makefile                   |   1 +
 git-rebase--interactive.sh | 171 ++++++++++++++++++++++++---------------------
 2 files changed, 92 insertions(+), 80 deletions(-)
Show changes to 2 files +92 −80

Makefile, git-rebase--interactive.sh

diff --git a/Makefile b/Makefile
index d31fcf2..c22c6f2 100644
--- a/Makefile
+++ b/Makefile
@@ -2064,6 +2064,7 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
 LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
 LOCALIZED_SH = $(SCRIPT_SH)
 LOCALIZED_SH += git-parse-remote.sh
+LOCALIZED_SH += git-rebase--interactive.sh
 LOCALIZED_SH += git-sh-setup.sh
 LOCALIZED_PERL = $(SCRIPT_PERL)
 
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 1c6dfb6..5ce5b1f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -128,7 +128,7 @@ mark_action_done () {
 	if test "$last_count" != "$new_count"
 	then
 		last_count=$new_count
-		printf "Rebasing (%d/%d)\r" $new_count $total
+		printf "$(gettext Rebasing) (%d/%d)\r" $new_count $total
 		test -z "$verbose" || echo
 	fi
 }
@@ -201,11 +201,13 @@ exit_with_patch () {
 	make_patch $1
 	git rev-parse --verify HEAD > "$amend"
 	gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
-	warn "You can amend the commit now, with"
+	# TRANSLATORS: after this line is a command to be issued by the user
+	warn "$(gettext "You can amend the commit now, with")"
 	warn
 	warn "	git commit --amend $gpg_sign_opt_quoted"
 	warn
-	warn "Once you are satisfied with your changes, run"
+	# TRANSLATORS: after this line is a command to be issued by the user
+	warn "$(gettext "Once you are satisfied with your changes, run")"
 	warn
 	warn "	git rebase --continue"
 	warn
@@ -222,9 +224,10 @@ has_action () {
 }
 
 is_empty_commit() {
-	tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null ||
-		die "$1: not a commit that can be picked")
-	ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null ||
+	sha1=$1
+	tree=$(git rev-parse -q --verify "$sha1"^{tree} 2>/dev/null ||
+		die "$(eval_gettext "\$sha1: not a commit that can be picked")")
+	ptree=$(git rev-parse -q --verify "$sha1"^^{tree} 2>/dev/null ||
 		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)
 	test "$tree" = "$ptree"
 }
@@ -261,7 +264,7 @@ pick_one () {
 
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
-	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+	output git rev-parse --verify $sha1 || die "$(eval_gettext "Invalid commit name: \$sha1")"
 
 	if is_empty_commit "$sha1"
 	then
@@ -303,7 +306,7 @@ pick_one_preserving_merges () {
 				git rev-parse HEAD > "$rewritten"/$current_commit
 			done <"$state_dir"/current-commit
 			rm "$state_dir"/current-commit ||
-			die "Cannot write current commit's replacement sha1"
+				die "$(gettext "Cannot write current commit's replacement sha1")"
 		fi
 	fi
 
@@ -355,9 +358,9 @@ pick_one_preserving_merges () {
 	done
 	case $fast_forward in
 	t)
-		output warn "Fast-forward to $sha1"
+		output warn "$(eval_gettext "Fast-forward to \$sha1")"
 		output git reset --hard $sha1 ||
-			die "Cannot fast-forward to $sha1"
+			die "$(eval_gettext "Cannot fast-forward to \$sha1")"
 		;;
 	f)
 		first_parent=$(expr "$new_parents" : ' \([^ ]*\)')
@@ -366,12 +369,12 @@ pick_one_preserving_merges () {
 		then
 			# detach HEAD to current parent
 			output git checkout $first_parent 2> /dev/null ||
-				die "Cannot move HEAD to $first_parent"
+				die "$(eval_gettext "Cannot move HEAD to \$first_parent")"
 		fi
 
 		case "$new_parents" in
 		' '*' '*)
-			test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
+			test "a$1" = a-n && die "$(eval_gettext "Refusing to squash a merge: \$sha1")"
 
 			# redo merge
 			author_script_content=$(get_author_ident_from_commit $sha1)
@@ -385,7 +388,7 @@ pick_one_preserving_merges () {
 				$merge_args $strategy_args -m "$msg_content" $new_parents'
 			then
 				printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
-				die_with_patch $sha1 "Error redoing merge $sha1"
+				die_with_patch $sha1 "$(eval_gettext "Error redoing merge \$sha1")"
 			fi
 			echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
 			;;
@@ -393,7 +396,7 @@ pick_one_preserving_merges () {
 			output eval git cherry-pick \
 				${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
 				"$strategy_args" "$@" ||
-				die_with_patch $sha1 "Could not pick $sha1"
+				die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
 			;;
 		esac
 		;;
@@ -460,12 +463,14 @@ peek_next_command () {
 # messages, effectively causing the combined commit to be used as the
 # new basis for any further squash/fixups.  Args: sha1 rest
 die_failed_squash() {
+	sha1=$1
+	rest=$2
 	mv "$squash_msg" "$msg" || exit
 	rm -f "$fixup_msg"
 	cp "$msg" "$GIT_DIR"/MERGE_MSG || exit
 	warn
-	warn "Could not apply $1... $2"
-	die_with_patch $1 ""
+	warn "$(eval_gettext "Could not apply \$sha1... \$rest")"
+	die_with_patch $sha1 ""
 }
 
 flush_rewritten_pending() {
@@ -489,6 +494,8 @@ record_in_rewritten() {
 }
 
 do_pick () {
+	sha1=$1
+	rest=$2
 	if test "$(git rev-parse HEAD)" = "$squash_onto"
 	then
 		# Set the correct commit message and author info on the
@@ -500,15 +507,15 @@ do_pick () {
 		# resolve before manually running git commit --amend then git
 		# rebase --continue.
 		git commit --allow-empty --allow-empty-message --amend \
-			   --no-post-rewrite -n -q -C $1 &&
-			pick_one -n $1 &&
+			   --no-post-rewrite -n -q -C $sha1 &&
+			pick_one -n $sha1 &&
 			git commit --allow-empty --allow-empty-message \
-				   --amend --no-post-rewrite -n -q -C $1 \
+				   --amend --no-post-rewrite -n -q -C $sha1 \
 				   ${gpg_sign_opt:+"$gpg_sign_opt"} ||
-			die_with_patch $1 "Could not apply $1... $2"
+				   die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")"
 	else
-		pick_one $1 ||
-			die_with_patch $1 "Could not apply $1... $2"
+		pick_one $sha1 ||
+			die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")"
 	fi
 }
 
@@ -536,10 +543,11 @@ do_next () {
 		mark_action_done
 		do_pick $sha1 "$rest"
 		git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
-			warn "Could not amend commit after successfully picking $sha1... $rest"
-			warn "This is most likely due to an empty commit message, or the pre-commit hook"
-			warn "failed. If the pre-commit hook failed, you may need to resolve the issue before"
-			warn "you are able to reword the commit."
+			warn "$(eval_gettext "\
+Could not amend commit after successfully picking \$sha1... \$rest
+This is most likely due to an empty commit message, or the pre-commit hook
+failed. If the pre-commit hook failed, you may need to resolve the issue before
+you are able to reword the commit.")"
 			exit_with_patch $sha1 1
 		}
 		record_in_rewritten $sha1
@@ -550,7 +558,7 @@ do_next () {
 		mark_action_done
 		do_pick $sha1 "$rest"
 		sha1_abbrev=$(git rev-parse --short $sha1)
-		warn "Stopped at $sha1_abbrev... $rest"
+		warn "$(eval_gettext "Stopped at \$sha1_abbrev... \$rest")"
 		exit_with_patch $sha1 0
 		;;
 	squash|s|fixup|f)
@@ -565,7 +573,7 @@ do_next () {
 		comment_for_reflog $squash_style
 
 		test -f "$done" && has_action "$done" ||
-			die "Cannot '$squash_style' without a previous commit"
+			die "$(eval_gettext "Cannot '\$squash_style' without a previous commit")"
 
 		mark_action_done
 		update_squash_messages $squash_style $sha1
@@ -607,7 +615,7 @@ do_next () {
 	x|"exec")
 		read -r command rest < "$todo"
 		mark_action_done
-		printf 'Executing: %s\n' "$rest"
+		printf "$(gettext Executing:) %s\n" "$rest"
 		"${SHELL:-@SHELL_PATH@}" -c "$rest" # Actual execution
 		status=$?
 		# Run in subshell because require_clean_work_tree can die.
@@ -615,11 +623,12 @@ do_next () {
 		(require_clean_work_tree "rebase" 2>/dev/null) || dirty=t
 		if test "$status" -ne 0
 		then
-			warn "Execution failed: $rest"
+			warn "$(gettext "Execution failed:") $rest"
 			test "$dirty" = f ||
-			warn "and made changes to the index and/or the working tree"
+				warn "$(gettext "and made changes to the index and/or the working tree")"
 
-			warn "You can fix the problem, and then run"
+			# TRANSLATORS: after this line is a command to be issued by the user
+			warn "$(gettext "You can fix the problem, and then run")"
 			warn
 			warn "	git rebase --continue"
 			warn
@@ -630,9 +639,11 @@ do_next () {
 			exit "$status"
 		elif test "$dirty" = t
 		then
-			warn "Execution succeeded: $rest"
-			warn "but left changes to the index and/or the working tree"
-			warn "Commit or stash your changes, and then run"
+			# TRANSLATORS: after these lines is a command to be issued by the user
+			warn "$(eval_gettext "\
+Execution succeeded: \$rest
+but left changes to the index and/or the working tree
+Commit or stash your changes, and then run")"
 			warn
 			warn "	git rebase --continue"
 			warn
@@ -640,8 +651,8 @@ do_next () {
 		fi
 		;;
 	*)
-		warn "Unknown command: $command $sha1 $rest"
-		fixtodo="Please fix this using 'git rebase --edit-todo'."
+		warn "$(gettext "Unknown command:") $command $sha1 $rest"
+		fixtodo="$(gettext "Please fix this using 'git rebase --edit-todo'.")"
 		if git rev-parse --verify -q "$sha1" >/dev/null
 		then
 			die_with_patch $sha1 "$fixtodo"
@@ -676,7 +687,7 @@ do_next () {
 		"$hook" rebase < "$rewritten_list"
 		true # we don't care if this hook failed
 	fi &&
-	warn "Successfully rebased and updated $head_name."
+		warn "$(eval_gettext "Successfully rebased and updated \$head_name.")"
 
 	return 1 # not failure; just to break the do_rest loop
 }
@@ -723,7 +734,7 @@ skip_unnecessary_picks () {
 		record_in_rewritten "$onto"
 		;;
 	esac ||
-	die "Could not skip unnecessary pick commands"
+		die "$(gettext "Could not skip unnecessary pick commands")"
 }
 
 transform_todo_ids () {
@@ -881,9 +892,9 @@ check_commit_sha () {
 	if test $badsha -ne 0
 	then
 		line="$(sed -n -e "${2}p" "$3")"
-		warn "Warning: the SHA-1 is missing or isn't" \
-			"a commit in the following line:"
-		warn " - $line"
+		warn "$(eval_gettext "\
+Warning: the SHA-1 is missing or isn't a commit in the following line:
+ - \$line")"
 		warn
 	fi
 
@@ -914,9 +925,9 @@ check_bad_cmd_and_sha () {
 			;;
 		*)
 			line="$(sed -n -e "${lineno}p" "$1")"
-			warn "Warning: the command isn't recognized" \
-				"in the following line:"
-			warn " - $line"
+			warn "$(eval_gettext "\
+Warning: the command isn't recognized in the following line:
+ - \$line")"
 			warn
 			retval=1
 			;;
@@ -953,7 +964,7 @@ warn_lines () {
 # Switch to the branch in $into and notify it in the reflog
 checkout_onto () {
 	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
-	output git checkout $onto || die_abort "could not detach HEAD"
+	output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
 	git update-ref ORIG_HEAD $orig_head
 }
 
@@ -991,28 +1002,26 @@ check_todo_list () {
 		then
 			test "$check_level" = error && raise_error=t
 
-			warn "Warning: some commits may have been dropped" \
-				"accidentally."
-			warn "Dropped commits (newer to older):"
+			warn "$(gettext "\
+Warning: some commits may have been dropped accidentally.
+Dropped commits (newer to older):")"
 
 			# Make the list user-friendly and display
 			opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"
 			git rev-list $opt <"$todo".miss | warn_lines
 
-			warn "To avoid this message, use \"drop\" to" \
-				"explicitly remove a commit."
-			warn
-			warn "Use 'git config rebase.missingCommitsCheck' to change" \
-				"the level of warnings."
-			warn "The possible behaviours are: ignore, warn, error."
+			warn "$(gettext "\
+To avoid this message, use \"drop\" to explicitly remove a commit.
+
+Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
+The possible behaviours are: ignore, warn, error.")"
 			warn
 		fi
 		;;
 	ignore)
 		;;
 	*)
-		warn "Unrecognized setting $check_level for option" \
-			"rebase.missingCommitsCheck. Ignoring."
+		warn "$(eval_gettext "Unrecognized setting \$check_level for option rebase.missingCommitsCheck. Ignoring.")"
 		;;
 	esac
 
@@ -1029,8 +1038,8 @@ check_todo_list () {
 		# placed before the commit of the next action
 		checkout_onto
 
-		warn "You can fix this with 'git rebase --edit-todo'."
-		die "Or you can abort the rebase with 'git rebase --abort'."
+		warn "$(gettext "You can fix this with 'git rebase --edit-todo'.")"
+		die "$(gettext "Or you can abort the rebase with 'git rebase --abort'.")"
 	fi
 }
 
@@ -1054,41 +1063,43 @@ continue)
 
 		test ! -f "$GIT_DIR"/CHERRY_PICK_HEAD ||
 		rm "$GIT_DIR"/CHERRY_PICK_HEAD ||
-		die "Could not remove CHERRY_PICK_HEAD"
+		die "$(gettext "Could not remove CHERRY_PICK_HEAD")"
 	else
 		if ! test -f "$author_script"
 		then
 			gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
-			die "You have staged changes in your working tree. If these changes are meant to be
+			die "$(eval_gettext "\
+You have staged changes in your working tree.
+If these changes are meant to be
 squashed into the previous commit, run:
 
-  git commit --amend $gpg_sign_opt_quoted
+  git commit --amend \$gpg_sign_opt_quoted
 
 If they are meant to go into a new commit, run:
 
-  git commit $gpg_sign_opt_quoted
+  git commit \$gpg_sign_opt_quoted
 
 In both case, once you're done, continue with:
 
   git rebase --continue
-"
+")"
 		fi
 		. "$author_script" ||
-			die "Error trying to find the author identity to amend commit"
+			die "$(gettext "Error trying to find the author identity to amend commit")"
 		if test -f "$amend"
 		then
 			current_head=$(git rev-parse --verify HEAD)
 			test "$current_head" = $(cat "$amend") ||
-			die "\
-You have uncommitted changes in your working tree. Please, commit them
-first and then run 'git rebase --continue' again."
+			die "$(gettext "\
+You have uncommitted changes in your working tree. Please commit them
+first and then run 'git rebase --continue' again.")"
 			do_with_author git commit --amend --no-verify -F "$msg" -e \
 				${gpg_sign_opt:+"$gpg_sign_opt"} ||
-				die "Could not commit staged changes."
+				die "$(gettext "Could not commit staged changes.")"
 		else
 			do_with_author git commit --no-verify -F "$msg" -e \
 				${gpg_sign_opt:+"$gpg_sign_opt"} ||
-				die "Could not commit staged changes."
+				die "$(gettext "Could not commit staged changes.")"
 		fi
 	fi
 
@@ -1121,7 +1132,7 @@ To continue rebase after editing, run:
 EOF
 
 	git_sequence_editor "$todo" ||
-		die "Could not execute editor"
+		die "$(gettext "Could not execute editor")"
 	expand_todo_ids
 
 	exit
@@ -1129,7 +1140,7 @@ EOF
 esac
 
 git var GIT_COMMITTER_IDENT >/dev/null ||
-	die "You need to set your committer info first"
+	die "$(gettext "You need to set your committer info first")"
 
 comment_for_reflog start
 
@@ -1137,15 +1148,15 @@ if test ! -z "$switch_to"
 then
 	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
 	output git checkout "$switch_to" -- ||
-	die "Could not checkout $switch_to"
+		die "$(eval_gettext "Could not checkout \$switch_to")"
 
 	comment_for_reflog start
 fi
 
-orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
-mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
+orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
+mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
 
-: > "$state_dir"/interactive || die "Could not mark as interactive"
+: > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
 write_basic_state
 if test t = "$preserve_merges"
 then
@@ -1155,12 +1166,12 @@ then
 		for c in $(git merge-base --all $orig_head $upstream)
 		do
 			echo $onto > "$rewritten"/$c ||
-				die "Could not init rewritten commits"
+				die "$(gettext "Could not init rewritten commits")"
 		done
 	else
 		mkdir "$rewritten" &&
 		echo $onto > "$rewritten"/root ||
-			die "Could not init rewritten commits"
+			die "$(gettext "Could not init rewritten commits")"
 	fi
 	# No cherry-pick because our first pass is to determine
 	# parents to rewrite and skipping dropped commits would
@@ -1270,7 +1281,7 @@ EOF
 
 if test -z "$keep_empty"
 then
-	printf '%s\n' "$comment_char Note that empty commits are commented out" >>"$todo"
+	printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo"
 fi
 
 
@@ -1280,7 +1291,7 @@ has_action "$todo" ||
 cp "$todo" "$todo".backup
 collapse_todo_ids
 git_sequence_editor "$todo" ||
-	die_abort "Could not execute editor"
+	die_abort "$(gettext "Could not execute editor")"
 
 has_action "$todo" ||
 	return 2
-- 
2.7.3
Eric Sunshine· May 19, 2016, 17:49 UTC · re: Vasco Almeida · lore

Re: [PATCH 14/21] i18n: rebase-interactive: mark strings for translation

On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 5 quoted lines
> Mark strings in git-rebase--interactive.sh for translation. There is no
> need to source git-sh-i18n since git-rebase.sh already does so.
>
> Add git-rebase--interactive.sh to LOCALIZED_SH in Makefile in order to
> enabled extracting strings marked for translation by xgettext.
s/enabled/enable/
> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Ævar Arnfjörð Bjarmason· May 21, 2016, 12:57 UTC · re: Vasco Almeida · lore

Re: [PATCH 14/21] i18n: rebase-interactive: mark strings for translation

On Wed, May 18, 2016 at 5:27 PM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
> Mark strings in git-rebase--interactive.sh for translation. There is no
> need to source git-sh-i18n since git-rebase.sh already does so.
Cool, thanks for working on this.
Show 11 quoted lines
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -128,7 +128,7 @@ mark_action_done () {
>         if test "$last_count" != "$new_count"
>         then
>                 last_count=$new_count
> -               printf "Rebasing (%d/%d)\r" $new_count $total
> +               printf "$(gettext Rebasing) (%d/%d)\r" $new_count $total
>                 test -z "$verbose" || echo
>         fi
>  }

Things like these should be converted into something you can pass to eval_gettext. I.e. For any message the translator needs to be able to translate the whole message. Consider e.g. RTL languages where the (%d/%d) will be on the right-hand-side of the message.

Show 16 quoted lines
> @@ -201,11 +201,13 @@ exit_with_patch () {
>         make_patch $1
>         git rev-parse --verify HEAD > "$amend"
>         gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
> -       warn "You can amend the commit now, with"
> +       # TRANSLATORS: after this line is a command to be issued by the user
> +       warn "$(gettext "You can amend the commit now, with")"
>         warn
>         warn "  git commit --amend $gpg_sign_opt_quoted"
>         warn
> -       warn "Once you are satisfied with your changes, run"
> +       # TRANSLATORS: after this line is a command to be issued by the user
> +       warn "$(gettext "Once you are satisfied with your changes, run")"
>         warn
>         warn "  git rebase --continue"
>         warn

Stuff like this should be one big call to gettext. I.e. everything from "You can amend" up to and including "--continue". Even if the translators probably don't want to change the order here it helps a lot to have the extra context. I.e. do it like ...

Show 15 quoted lines
> @@ -536,10 +543,11 @@ do_next () {
>                 mark_action_done
>                 do_pick $sha1 "$rest"
>                 git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
> -                       warn "Could not amend commit after successfully picking $sha1... $rest"
> -                       warn "This is most likely due to an empty commit message, or the pre-commit hook"
> -                       warn "failed. If the pre-commit hook failed, you may need to resolve the issue before"
> -                       warn "you are able to reword the commit."
> +                       warn "$(eval_gettext "\
> +Could not amend commit after successfully picking \$sha1... \$rest
> +This is most likely due to an empty commit message, or the pre-commit hook
> +failed. If the pre-commit hook failed, you may need to resolve the issue before
> +you are able to reword the commit.")"
>                         exit_with_patch $sha1 1
>                 }
... this! :)
Show 9 quoted lines
> @@ -607,7 +615,7 @@ do_next () {
>         x|"exec")
>                 read -r command rest < "$todo"
>                 mark_action_done
> -               printf 'Executing: %s\n' "$rest"
> +               printf "$(gettext Executing:) %s\n" "$rest"
>                 "${SHELL:-@SHELL_PATH@}" -c "$rest" # Actual execution
>                 status=$?
>                 # Run in subshell because require_clean_work_tree can die.

Ditto my first comment about the whole thing needing to be a call to eval_gettext. I.e. also that " %s" part.

Show 21 quoted lines
> -                       warn "You can fix the problem, and then run"
> +                       # TRANSLATORS: after this line is a command to be issued by the user
> +                       warn "$(gettext "You can fix the problem, and then run")"
>                         warn
>                         warn "  git rebase --continue"
>                         warn
> @@ -630,9 +639,11 @@ do_next () {
>                         exit "$status"
>                 elif test "$dirty" = t
>                 then
> -                       warn "Execution succeeded: $rest"
> -                       warn "but left changes to the index and/or the working tree"
> -                       warn "Commit or stash your changes, and then run"
> +                       # TRANSLATORS: after these lines is a command to be issued by the user
> +                       warn "$(eval_gettext "\
> +Execution succeeded: \$rest
> +but left changes to the index and/or the working tree
> +Commit or stash your changes, and then run")"
>                         warn
>                         warn "  git rebase --continue"
>                         warn

Both ditto the above. I.e. just include the command to be issued in the message. Then you can also skip the TRANSLATORS comment since this won't be confusing to them anymore.

Show 32 quoted lines
> @@ -991,28 +1002,26 @@ check_todo_list () {
>                 then
>                         test "$check_level" = error && raise_error=t
>
> -                       warn "Warning: some commits may have been dropped" \
> -                               "accidentally."
> -                       warn "Dropped commits (newer to older):"
> +                       warn "$(gettext "\
> +Warning: some commits may have been dropped accidentally.
> +Dropped commits (newer to older):")"
>
>                         # Make the list user-friendly and display
>                         opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"
>                         git rev-list $opt <"$todo".miss | warn_lines
>
> -                       warn "To avoid this message, use \"drop\" to" \
> -                               "explicitly remove a commit."
> -                       warn
> -                       warn "Use 'git config rebase.missingCommitsCheck' to change" \
> -                               "the level of warnings."
> -                       warn "The possible behaviours are: ignore, warn, error."
> +                       warn "$(gettext "\
> +To avoid this message, use \"drop\" to explicitly remove a commit.
> +
> +Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
> +The possible behaviours are: ignore, warn, error.")"
>                         warn
>                 fi
>                 ;;
>         ignore)
>                 ;;
>         *)

Making this into one big eval_gettext where we stash away those "newer to older" commits into a variable would be easier on translators, but maybe there are performance considerations and we could just live with two messages. Not sure how large this list might get in practice.

I haven't tried to apply & run this patch. But aside from the chunks I commented on the rest of this looks fine to me.

Vasco Almeida· May 21, 2016, 14:05 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: [PATCH 14/21] i18n: rebase-interactive: mark strings for translation

Às 12:57 de 21-05-2016, Ævar Arnfjörð Bjarmason escreveu:
Show 21 quoted lines
> On Wed, May 18, 2016 at 5:27 PM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>> > Mark strings in git-rebase--interactive.sh for translation. There is no
>> > need to source git-sh-i18n since git-rebase.sh already does so.
> Cool, thanks for working on this.
> 
>> > --- a/git-rebase--interactive.sh
>> > +++ b/git-rebase--interactive.sh
>> > @@ -128,7 +128,7 @@ mark_action_done () {
>> >         if test "$last_count" != "$new_count"
>> >         then
>> >                 last_count=$new_count
>> > -               printf "Rebasing (%d/%d)\r" $new_count $total
>> > +               printf "$(gettext Rebasing) (%d/%d)\r" $new_count $total
>> >                 test -z "$verbose" || echo
>> >         fi
>> >  }
> Things like these should be converted into something you can pass to
> eval_gettext. I.e. For any message the translator needs to be able to
> translate the whole message. Consider e.g. RTL languages where the
> (%d/%d) will be on the right-hand-side of the message.
> 
One more thing I haven't anticipated. Thank you for pointing it out.
I'll take this and the other comments in consideration for the next re-roll.
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 15/21] i18n: rebase-interactive: mark here-doc strings for translation

Use pipe to send gettext output to git stripspace instead of the original method of using shell here-document, because command substitution '$(...)' would not take place inside the here-documents. The exception is the case of the last here-document redirecting to cat, in which commands substitution works and, thus, is preserved in this commit.

t3404: adapt test to the strings newly marked for translation Test t3404-rebase-interactive.sh would fail under GETTEXT_POISON unless using test_i18ngrep.

Add eval_ngettext dummy function to be called by tests when running under GETTEXT_POISON. Otherwise, tests would fail under gettext poison because that function could not be found.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-rebase--interactive.sh    | 30 +++++++++++++++---------------
 git-sh-i18n.sh                |  4 ++++
 t/t3404-rebase-interactive.sh | 14 +++++++-------
 3 files changed, 26 insertions(+), 22 deletions(-)
Show changes to 3 files +26 −22

git-rebase--interactive.sh, git-sh-i18n.sh, t/t3404-rebase-interactive.sh

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5ce5b1f..933fcd2 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -144,29 +144,28 @@ reschedule_last_action () {
 }
 
 append_todo_help () {
-	git stripspace --comment-lines >>"$todo" <<\EOF
-
+	gettext "
 Commands:
  p, pick = use commit
  r, reword = use commit, but edit the commit message
  e, edit = use commit, but stop for amending
  s, squash = use commit, but meld into previous commit
- f, fixup = like "squash", but discard this commit's log message
+ f, fixup = like \"squash\", but discard this commit's log message
  x, exec = run command (the rest of the line) using shell
  d, drop = remove commit
 
 These lines can be re-ordered; they are executed from top to bottom.
+" | git stripspace --comment-lines >>"$todo"
 
-EOF
 	if test $(get_missing_commit_check_level) = error
 	then
-		git stripspace --comment-lines >>"$todo" <<\EOF
+		gettext "
 Do not remove any line. Use 'drop' explicitly to remove a commit.
-EOF
+" | git stripspace --comment-lines >>"$todo"
 	else
-		git stripspace --comment-lines >>"$todo" <<\EOF
+		gettext "
 If you remove a line here THAT COMMIT WILL BE LOST.
-EOF
+" | git stripspace --comment-lines >>"$todo"
 	fi
 }
 
@@ -1123,13 +1122,12 @@ edit-todo)
 	mv -f "$todo".new "$todo"
 	collapse_todo_ids
 	append_todo_help
-	git stripspace --comment-lines >>"$todo" <<\EOF
-
+	gettext "
 You are editing the todo file of an ongoing interactive rebase.
 To continue rebase after editing, run:
     git rebase --continue
 
-EOF
+" | git stripspace --comment-lines >>"$todo"
 
 	git_sequence_editor "$todo" ||
 		die "$(gettext "Could not execute editor")"
@@ -1270,14 +1268,16 @@ todocount=${todocount##* }
 
 cat >>"$todo" <<EOF
 
-$comment_char Rebase $shortrevisions onto $shortonto ($todocount command(s))
+$comment_char $(eval_ngettext \
+	"Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
+	"Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
+	"$todocount")
 EOF
 append_todo_help
-git stripspace --comment-lines >>"$todo" <<\EOF
-
+gettext "
 However, if you remove everything, the rebase will be aborted.
 
-EOF
+" | git stripspace --comment-lines >>"$todo"
 
 if test -z "$keep_empty"
 then
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
index e6c3116..c14c303 100644
--- a/git-sh-i18n.sh
+++ b/git-sh-i18n.sh
@@ -64,6 +64,10 @@ poison)
 	eval_gettext () {
 		printf "%s" "# GETTEXT POISON #"
 	}
+
+	eval_ngettext () {
+		printf "%s" "# GETTEXT POISON #"
+	}
 	;;
 *)
 	gettext () {
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 66348f1..f4ccd10 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -540,7 +540,7 @@ test_expect_success 'clean error after failed "exec"' '
 	echo "edited again" > file7 &&
 	git add file7 &&
 	test_must_fail git rebase --continue 2>error &&
-	grep "You have staged changes in your working tree." error
+	test_i18ngrep "You have staged changes in your working tree." error
 '
 
 test_expect_success 'rebase a detached HEAD' '
@@ -1060,7 +1060,7 @@ test_expect_success 'todo count' '
 	EOF
 	test_set_editor "$(pwd)/dump-raw.sh" &&
 	git rebase -i HEAD~4 >actual &&
-	grep "^# Rebase ..* onto ..* ([0-9]" actual
+	test_i18ngrep "^# Rebase ..* onto ..* ([0-9]" actual
 '
 
 test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
@@ -1160,7 +1160,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
 	FAKE_LINES="1 2 3 4" \
 		git rebase -i --root 2>actual &&
 	test D = $(git cat-file commit HEAD | sed -ne \$p) &&
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 cat >expect <<EOF
@@ -1181,7 +1181,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
 	set_fake_editor &&
 	FAKE_LINES="1 2 3 4" \
 		git rebase -i --root 2>actual &&
-	test_cmp expect actual &&
+	test_i18ncmp expect actual &&
 	test D = $(git cat-file commit HEAD | sed -ne \$p)
 '
 
@@ -1205,7 +1205,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
 	set_fake_editor &&
 	test_must_fail env FAKE_LINES="1 2 4" \
 		git rebase -i --root 2>actual &&
-	test_cmp expect actual &&
+	test_i18ncmp expect actual &&
 	cp .git/rebase-merge/git-rebase-todo.backup \
 		.git/rebase-merge/git-rebase-todo &&
 	FAKE_LINES="1 2 drop 3 4 drop 5" \
@@ -1228,7 +1228,7 @@ test_expect_success 'static check of bad command' '
 	set_fake_editor &&
 	test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
 		git rebase -i --root 2>actual &&
-	test_cmp expect actual &&
+	test_i18ncmp expect actual &&
 	FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo &&
 	git rebase --continue &&
 	test E = $(git cat-file commit HEAD | sed -ne \$p) &&
@@ -1263,7 +1263,7 @@ test_expect_success 'static check of bad SHA-1' '
 	set_fake_editor &&
 	test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \
 		git rebase -i --root 2>actual &&
-	test_cmp expect actual &&
+	test_i18ncmp expect actual &&
 	FAKE_LINES="1 2 4 5 6" git rebase --edit-todo &&
 	git rebase --continue &&
 	test E = $(git cat-file commit HEAD | sed -ne \$p)
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 16/21] i18n: rebase-interactive: mark comments of squash for translation

Mark comment messages of squash/fixup file ($squash_msg) for translation.

Helper functions this_nth_commit_message and skip_nth_commit_message replace the previous method of making the comment messages (such as "This is the 2nd commit message:") aided by nth_string helper function. This step was taken as a workaround to enabled translation of entire sentences. However, doesn't change any text seen in English by the user, except for string "The first commit's message is:" which was changed to match the style of other instances.

The test t3404-rebase-interactive.sh resorts to set_fake_editor which didn't account for GETTEXT_POISON. Fix it by assuming success when we find dummy gettext poison output where was supposed to find the first comment line "This is a combination of $count commits.".

For that same message, use plural aware eval_ngettext instead of eval_gettext, since other languages have more complex plural forms.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 git-rebase--interactive.sh | 69 +++++++++++++++++++++++++++++++++++++---------
 t/lib-rebase.sh            |  1 +
 2 files changed, 57 insertions(+), 13 deletions(-)
Show changes to 2 files +57 −13

git-rebase--interactive.sh, t/lib-rebase.sh

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 933fcd2..b04389b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -402,12 +402,52 @@ pick_one_preserving_merges () {
 	esac
 }
 
-nth_string () {
-	case "$1" in
-	*1[0-9]|*[04-9]) echo "$1"th;;
-	*1) echo "$1"st;;
-	*2) echo "$1"nd;;
-	*3) echo "$1"rd;;
+this_nth_commit_message () {
+	n=$1
+	case "$n" in
+	1) gettext "This is the 1st commit message:";;
+	2) gettext "This is the 2nd commit message:";;
+	3) gettext "This is the 3rd commit message:";;
+	4) gettext "This is the 4th commit message:";;
+	5) gettext "This is the 5th commit message:";;
+	6) gettext "This is the 6th commit message:";;
+	7) gettext "This is the 7th commit message:";;
+	8) gettext "This is the 8th commit message:";;
+	9) gettext "This is the 9th commit message:";;
+	10) gettext "This is the 10th commit message:";;
+	# TRANSLATORS: if the language you are translating into
+	# doesn't allow you to compose a sentence in this fashion,
+	# consider translating as if this and the following few strings
+	# were "This is the commit message ${n}:"
+	*1[0-9]|*[04-9]) eval_gettext "This is the \${n}th commit message:";;
+	*1) eval_gettext "This is the \${n}st commit message:";;
+	*2) eval_gettext "This is the \${n}nd commit message:";;
+	*3) eval_gettext "This is the \${n}rd commit message:";;
+	*) eval_gettext "This is the commit message \${n}:";;
+	esac
+}
+skip_nth_commit_message () {
+	n=$1
+	case "$n" in
+	1) gettext "The 1st commit message will be skipped:";;
+	2) gettext "The 2nd commit message will be skipped:";;
+	3) gettext "The 3rd commit message will be skipped:";;
+	4) gettext "The 4th commit message will be skipped:";;
+	5) gettext "The 5th commit message will be skipped:";;
+	6) gettext "The 6th commit message will be skipped:";;
+	7) gettext "The 7th commit message will be skipped:";;
+	8) gettext "The 8th commit message will be skipped:";;
+	9) gettext "The 9th commit message will be skipped:";;
+	10) gettext "The 10th commit message will be skipped:";;
+	# TRANSLATORS: if the language you are translating into
+	# doesn't allow you to compose a sentence in this fashion,
+	# consider translating as if this and the following few strings
+	# were "The commit message ${n} will be skipped:"
+	*1[0-9]|*[04-9]) eval_gettext "The \${n}th commit message will be skipped:";;
+	*1) eval_gettext "The \${n}st commit message will be skipped:";;
+	*2) eval_gettext "The \${n}nd commit message will be skipped:";;
+	*3) eval_gettext "The \${n}rd commit message will be skipped:";;
+	*) eval_gettext "The commit message \${n} will be skipped:";;
 	esac
 }
 
@@ -415,20 +455,23 @@ update_squash_messages () {
 	if test -f "$squash_msg"; then
 		mv "$squash_msg" "$squash_msg".bak || exit
 		count=$(($(sed -n \
-			-e "1s/^. This is a combination of \(.*\) commits\./\1/p" \
+			-e "1s/^$comment_char.*\([0-9][0-9]*\).*/\1/p" \
 			-e "q" < "$squash_msg".bak)+1))
 		{
-			printf '%s\n' "$comment_char This is a combination of $count commits."
+			printf '%s\n' "$comment_char $(eval_ngettext \
+				"This is a combination of \$count commit." \
+				"This is a combination of \$count commits." \
+				$count)"
 			sed -e 1d -e '2,/^./{
 				/^$/d
 			}' <"$squash_msg".bak
 		} >"$squash_msg"
 	else
-		commit_message HEAD > "$fixup_msg" || die "Cannot write $fixup_msg"
+		commit_message HEAD > "$fixup_msg" || die "$(gettext "Cannot write \$fixup_msg")"
 		count=2
 		{
-			printf '%s\n' "$comment_char This is a combination of 2 commits."
-			printf '%s\n' "$comment_char The first commit's message is:"
+			printf '%s\n' "$comment_char $(gettext "This is a combination of 2 commits.")"
+			printf '%s\n' "$comment_char $(gettext "This is the 1st commit message:")"
 			echo
 			cat "$fixup_msg"
 		} >"$squash_msg"
@@ -437,13 +480,13 @@ update_squash_messages () {
 	squash)
 		rm -f "$fixup_msg"
 		echo
-		printf '%s\n' "$comment_char This is the $(nth_string $count) commit message:"
+		printf '%s\n' "$comment_char $(this_nth_commit_message $count)"
 		echo
 		commit_message $2
 		;;
 	fixup)
 		echo
-		printf '%s\n' "$comment_char The $(nth_string $count) commit message will be skipped:"
+		printf '%s\n' "$comment_char $(skip_nth_commit_message $count)"
 		echo
 		# Change the space after the comment character to TAB:
 		commit_message $2 | git stripspace --comment-lines | sed -e 's/ /	/'
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 9a96e15..25a77ee 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -29,6 +29,7 @@ set_fake_editor () {
 	*/COMMIT_EDITMSG)
 		test -z "$EXPECT_HEADER_COUNT" ||
 			test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
+			test "# # GETTEXT POISON #" = "$(sed -n '1p' < "$1")" ||
 			exit
 		test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
 		test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 17/21] tests: use test_i18n* functions to suppress false positives

The test functions test_i18ncmp and test_i18ngrep pretend success if run under GETTEXT_POISON. By using those functions to test output which is correctly marked as translatable, enables one to detect if the strings newly marked for translation are from plumbing output. If they are indeed from plumbing, the test would fail, and the string should be unmarked, since it is not seen by users.

Thus, it is productive to not have false positives when running the test under GETTEXT_POISON. This commit replaces normal test functions by their i18n aware variants in use-cases know to be correctly marked for translation, suppressing false positives.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t0008-ignores.sh                |  4 ++--
 t/t1300-repo-config.sh            |  8 ++++----
 t/t1307-config-blob.sh            |  2 +-
 t/t1308-config-set.sh             |  4 ++--
 t/t1400-update-ref.sh             |  2 +-
 t/t2010-checkout-ambiguous.sh     |  2 +-
 t/t2018-checkout-branch.sh        |  2 +-
 t/t3200-branch.sh                 |  6 +++---
 t/t3201-branch-contains.sh        |  2 +-
 t/t3320-notes-merge-worktrees.sh  |  2 +-
 t/t5505-remote.sh                 |  2 +-
 t/t5510-fetch.sh                  |  2 +-
 t/t5523-push-upstream.sh          |  4 ++--
 t/t5536-fetch-conflicts.sh        |  4 ++--
 t/t6301-for-each-ref-errors.sh    | 10 +++++-----
 t/t7063-status-untracked-cache.sh |  2 +-
 t/t7102-reset.sh                  |  4 ++--
 t/t7400-submodule-basic.sh        |  2 +-
 t/t7403-submodule-sync.sh         |  4 ++--
 t/t7406-submodule-update.sh       | 10 +++++-----
 t/t7508-status.sh                 |  4 ++--
 21 files changed, 41 insertions(+), 41 deletions(-)
Show changes to 21 files +41 −41

t/t0008-ignores.sh, t/t1300-repo-config.sh, t/t1307-config-blob.sh, t/t1308-config-set.sh, t/t1400-update-ref.sh, t/t2010-checkout-ambiguous.sh, t/t2018-checkout-branch.sh, t/t3200-branch.sh, t/t3201-branch-contains.sh, t/t3320-notes-merge-worktrees.sh, t/t5505-remote.sh, t/t5510-fetch.sh, t/t5523-push-upstream.sh, t/t5536-fetch-conflicts.sh, t/t6301-for-each-ref-errors.sh, t/t7063-status-untracked-cache.sh, t/t7102-reset.sh, t/t7400-submodule-basic.sh, t/t7403-submodule-sync.sh, t/t7406-submodule-update.sh, t/t7508-status.sh

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 89544dd..43aa2bd 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -34,7 +34,7 @@ expect_from_stdin () {
 test_stderr () {
 	expected="$1"
 	expect_in stderr "$1" &&
-	test_cmp "$HOME/expected-stderr" "$HOME/stderr"
+	test_i18ncmp "$HOME/expected-stderr" "$HOME/stderr"
 }
 
 broken_c_unquote () {
@@ -47,7 +47,7 @@ broken_c_unquote_verbose () {
 
 stderr_contains () {
 	regexp="$1"
-	if grep "$regexp" "$HOME/stderr"
+	if test_i18ngrep "$regexp" "$HOME/stderr"
 	then
 		return 0
 	else
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index d934a24..923bfc5 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -886,7 +886,7 @@ test_expect_success !MINGW 'get --path copes with unset $HOME' '
 		git config --get --path path.normal >>result &&
 		git config --get --path path.trailingtilde >>result
 	) &&
-	grep "[Ff]ailed to expand.*~/" msg &&
+	test_i18ngrep "[Ff]ailed to expand.*~/" msg &&
 	test_cmp expect result
 '
 
@@ -1126,7 +1126,7 @@ test_expect_success 'barf on syntax error' '
 	key garbage
 	EOF
 	test_must_fail git config --get section.key >actual 2>error &&
-	grep " line 3 " error
+	test_i18ngrep " line 3 " error
 '
 
 test_expect_success 'barf on incomplete section header' '
@@ -1136,7 +1136,7 @@ test_expect_success 'barf on incomplete section header' '
 	key = value
 	EOF
 	test_must_fail git config --get section.key >actual 2>error &&
-	grep " line 2 " error
+	test_i18ngrep " line 2 " error
 '
 
 test_expect_success 'barf on incomplete string' '
@@ -1146,7 +1146,7 @@ test_expect_success 'barf on incomplete string' '
 	key = "value string
 	EOF
 	test_must_fail git config --get section.key >actual 2>error &&
-	grep " line 3 " error
+	test_i18ngrep " line 3 " error
 '
 
 test_expect_success 'urlmatch' '
diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh
index 3c6791e..4079fef 100755
--- a/t/t1307-config-blob.sh
+++ b/t/t1307-config-blob.sh
@@ -64,7 +64,7 @@ test_expect_success 'parse errors in blobs are properly attributed' '
 
 	# just grep for our token as the exact error message is likely to
 	# change or be internationalized
-	grep "HEAD:config" err
+	test_i18ngrep "HEAD:config" err
 '
 
 test_expect_success 'can parse blob ending with CR' '
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 005d66d..cd62063 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -197,14 +197,14 @@ test_expect_success 'proper error on error in default config files' '
 	echo "[" >>.git/config &&
 	echo "fatal: bad config line 34 in file .git/config" >expect &&
 	test_expect_code 128 test-config get_value foo.bar 2>actual &&
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 test_expect_success 'proper error on error in custom config files' '
 	echo "[" >>syntax-error &&
 	echo "fatal: bad config line 1 in file syntax-error" >expect &&
 	test_expect_code 128 test-config configset_get_value foo.bar syntax-error 2>actual &&
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 test_expect_success 'check line errors for malformed values' '
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index af1b20d..75fa654 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -361,7 +361,7 @@ test_expect_success 'stdin test setup' '
 
 test_expect_success '-z fails without --stdin' '
 	test_must_fail git update-ref -z $m $m $m 2>err &&
-	grep "usage: git update-ref" err
+	test_i18ngrep "usage: git update-ref" err
 '
 
 test_expect_success 'stdin works with no input' '
diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh
index 87bdf9c..e76e84a 100755
--- a/t/t2010-checkout-ambiguous.sh
+++ b/t/t2010-checkout-ambiguous.sh
@@ -49,7 +49,7 @@ test_expect_success 'disambiguate checking out from a tree-ish' '
 
 test_expect_success 'accurate error message with more than one ref' '
 	test_must_fail git checkout HEAD master -- 2>actual &&
-	grep 2 actual &&
+	test_i18ngrep 2 actual &&
 	test_i18ngrep "one reference expected, 2 given" actual
 '
 
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 2741262..2131fb2 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -124,7 +124,7 @@ test_expect_success 'checkout -b to @{-1} fails with the right branch name' '
 	git checkout branch2 &&
 	echo  >expect "fatal: A branch named '\''branch1'\'' already exists." &&
 	test_must_fail git checkout -b @{-1} 2>actual &&
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 test_expect_success 'checkout -B to an existing branch resets branch to HEAD' '
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index f3e3b6c..ac9c764 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -550,7 +550,7 @@ If you wanted to make '"'master'"' track '"'origin/master'"', do this:
     git branch -d origin/master
     git branch --set-upstream-to origin/master
 EOF
-	test_cmp expected actual
+	test_i18ncmp expected actual
 '
 
 test_expect_success '--set-upstream with two args only shows the deprecation message' '
@@ -559,7 +559,7 @@ test_expect_success '--set-upstream with two args only shows the deprecation mes
 	cat >expected <<EOF &&
 The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
 EOF
-	test_cmp expected actual
+	test_i18ncmp expected actual
 '
 
 test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' '
@@ -568,7 +568,7 @@ test_expect_success '--set-upstream with one arg only shows the deprecation mess
 	cat >expected <<EOF &&
 The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
 EOF
-	test_cmp expected actual
+	test_i18ncmp expected actual
 '
 
 test_expect_success '--set-upstream-to notices an error to set branch as own upstream' '
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 912a663..7f3ec47 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -156,7 +156,7 @@ test_expect_success 'branch --merged with --verbose' '
 	* topic  2c939f4 [ahead 1] foo
 	  zzz    c77a0a9 second on master
 	EOF
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 test_done
diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh
index 1f71d58..522157b 100755
--- a/t/t3320-notes-merge-worktrees.sh
+++ b/t/t3320-notes-merge-worktrees.sh
@@ -52,7 +52,7 @@ test_expect_success 'merge z into y while mid-merge in another workdir fails' '
 		cd worktree &&
 		git config core.notesRef refs/notes/y &&
 		test_must_fail git notes merge z 2>err &&
-		grep "A notes merge into refs/notes/y is already in-progress at" err
+		test_i18ngrep "A notes merge into refs/notes/y is already in-progress at" err
 	) &&
 	test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF
 '
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index dd2e6ce..8198d8e 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1182,7 +1182,7 @@ test_expect_success 'extra args: setup' '
 test_extra_arg () {
 	test_expect_success "extra args: $*" "
 		test_must_fail git remote $* bogus_extra_arg 2>actual &&
-		grep '^usage:' actual
+		test_i18ngrep '^usage:' actual
 	"
 }
 
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 454d896..88076da 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -644,7 +644,7 @@ test_expect_success 'fetch --prune prints the remotes url' '
 		git fetch --prune origin 2>&1 | head -n1 >../actual
 	) &&
 	echo "From ${D}/." >expect &&
-	test_cmp expect actual
+	test_i18ncmp expect actual
 '
 
 test_expect_success 'branchname D/F conflict resolved by --prune' '
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index 3683df1..4a7b98b 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -75,7 +75,7 @@ test_expect_success TTY 'progress messages go to tty' '
 	ensure_fresh_upstream &&
 
 	test_terminal git push -u upstream master >out 2>err &&
-	grep "Writing objects" err
+	test_i18ngrep "Writing objects" err
 '
 
 test_expect_success 'progress messages do not go to non-tty' '
@@ -91,7 +91,7 @@ test_expect_success 'progress messages go to non-tty (forced)' '
 
 	# force progress messages to stderr, even though it is non-tty
 	git push -u --progress upstream master >out 2>err &&
-	grep "Writing objects" err
+	test_i18ngrep "Writing objects" err
 '
 
 test_expect_success TTY 'push -q suppresses progress' '
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 6c5d3a4..2e42cf3 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -22,8 +22,8 @@ verify_stderr () {
 	cat >expected &&
 	# We're not interested in the error
 	# "fatal: The remote end hung up unexpectedly":
-	grep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort &&
-	test_cmp expected actual
+	test_i18ngrep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort &&
+	test_i18ncmp expected actual
 }
 
 test_expect_success 'setup' '
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index cdb67a0..c734ce2 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -20,8 +20,8 @@ test_expect_success 'Broken refs are reported correctly' '
 	test_when_finished "rm -f .git/$r" &&
 	echo "warning: ignoring broken ref $r" >broken-err &&
 	git for-each-ref >out 2>err &&
-	test_cmp full-list out &&
-	test_cmp broken-err err
+	test_i18ncmp full-list out &&
+	test_i18ncmp broken-err err
 '
 
 test_expect_success 'NULL_SHA1 refs are reported correctly' '
@@ -31,10 +31,10 @@ test_expect_success 'NULL_SHA1 refs are reported correctly' '
 	echo "warning: ignoring broken ref $r" >zeros-err &&
 	git for-each-ref >out 2>err &&
 	test_cmp full-list out &&
-	test_cmp zeros-err err &&
+	test_i18ncmp zeros-err err &&
 	git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err &&
 	test_cmp brief-list brief-out &&
-	test_cmp zeros-err brief-err
+	test_i18ncmp zeros-err brief-err
 '
 
 test_expect_success 'Missing objects are reported correctly' '
@@ -43,7 +43,7 @@ test_expect_success 'Missing objects are reported correctly' '
 	test_when_finished "rm -f .git/$r" &&
 	echo "fatal: missing object $MISSING for $r" >missing-err &&
 	test_must_fail git for-each-ref 2>err &&
-	test_cmp missing-err err &&
+	test_i18ncmp missing-err err &&
 	(
 		cat brief-list &&
 		echo "$MISSING $r"
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index a971884..38b3890 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -643,7 +643,7 @@ test_expect_success 'test ident field is working' '
 	cp -R done dthree dtwo four three ../other_worktree &&
 	GIT_WORK_TREE=../other_worktree git status 2>../err &&
 	echo "warning: Untracked cache is disabled on this system or location." >../expect &&
-	test_cmp ../expect ../err
+	test_i18ncmp ../expect ../err
 '
 
 test_done
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 98bcfe2..86f23be 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -66,14 +66,14 @@ test_expect_success 'reset --hard message' '
 	hex=$(git log -1 --format="%h") &&
 	git reset --hard > .actual &&
 	echo HEAD is now at $hex $(commit_msg) > .expected &&
-	test_cmp .expected .actual
+	test_i18ncmp .expected .actual
 '
 
 test_expect_success 'reset --hard message (ISO8859-1 logoutputencoding)' '
 	hex=$(git log -1 --format="%h") &&
 	git -c "i18n.logOutputEncoding=$test_encoding" reset --hard > .actual &&
 	echo HEAD is now at $hex $(commit_msg $test_encoding) > .expected &&
-	test_cmp .expected .actual
+	test_i18ncmp .expected .actual
 '
 
 >.diff_expect
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 3570f7b..b77cce8 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -942,7 +942,7 @@ test_expect_success 'submodule deinit from subdirectory' '
 		cd sub &&
 		git submodule deinit ../init >../output
 	) &&
-	grep "\\.\\./init" output &&
+	test_i18ngrep "\\.\\./init" output &&
 	test -z "$(git config --get-regexp "submodule\.example\.")" &&
 	test -n "$(git config --get-regexp "submodule\.example2\.")" &&
 	test -f example2/.git &&
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 79bc135..b8690b1 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -157,7 +157,7 @@ test_expect_success '"git submodule sync" should update submodule URLs - subdire
 		cd sub &&
 		git submodule sync >../../output
 	) &&
-	grep "\\.\\./submodule" output &&
+	test_i18ngrep "\\.\\./submodule" output &&
 	test -d "$(
 		cd super-clone/submodule &&
 		git config remote.origin.url
@@ -188,7 +188,7 @@ test_expect_success '"git submodule sync --recursive" should update all submodul
 		cd sub &&
 		git submodule sync --recursive >../../output
 	) &&
-	grep "\\.\\./submodule/sub-submodule" output &&
+	test_i18ngrep "\\.\\./submodule/sub-submodule" output &&
 	test -d "$(
 		cd super-clone/submodule &&
 		git config remote.origin.url
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 5f27879..88e9750 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -136,8 +136,8 @@ test_expect_success 'submodule update --init --recursive from subdirectory' '
 	 cd tmp &&
 	 git submodule update --init --recursive ../super >../../actual 2>../../actual2
 	) &&
-	test_cmp expect actual &&
-	test_cmp expect2 actual2
+	test_i18ncmp expect actual &&
+	test_i18ncmp expect2 actual2
 '
 
 apos="'";
@@ -370,7 +370,7 @@ test_expect_success 'submodule update - command in .git/config catches failure'
 	(cd super &&
 	 test_must_fail git submodule update submodule 2>../actual
 	) &&
-	test_cmp actual expect
+	test_i18ncmp actual expect
 '
 
 cat << EOF >expect
@@ -388,7 +388,7 @@ test_expect_success 'submodule update - command in .git/config catches failure -
 	 mkdir tmp && cd tmp &&
 	 test_must_fail git submodule update ../submodule 2>../../actual
 	) &&
-	test_cmp actual expect
+	test_i18ncmp actual expect
 '
 
 cat << EOF >expect
@@ -408,7 +408,7 @@ test_expect_success 'recursive submodule update - command in .git/config catches
 	 mkdir -p tmp && cd tmp &&
 	 test_must_fail git submodule update --recursive ../super 2>../../actual
 	) &&
-	test_cmp actual expect
+	test_i18ncmp actual expect
 '
 
 test_expect_success 'submodule init does not copy command into .git/config' '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index c3ed7cb..b3bdd16 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1377,7 +1377,7 @@ EOF
 	git config --add -f .gitmodules submodule.subname.ignore all &&
 	git config --add -f .gitmodules submodule.subname.path sm &&
 	git status > output &&
-	test_cmp expect output &&
+	test_i18ncmp expect output &&
 	git config -f .gitmodules  --remove-section submodule.subname
 '
 
@@ -1387,7 +1387,7 @@ test_expect_success '.git/config ignore=all suppresses unstaged submodule summar
 	git config --add submodule.subname.ignore all &&
 	git config --add submodule.subname.path sm &&
 	git status > output &&
-	test_cmp expect output &&
+	test_i18ncmp expect output &&
 	git config --remove-section submodule.subname &&
 	git config -f .gitmodules  --remove-section submodule.subname
 '
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 18/21] tests: unpack-trees: update to use test_i18n* functions

Use functions test_i18ncmp and test_i18ngrep to successfully pass tests running under GETTEXT_POISON.

The output strings compared to in these test were marked for translation in ed47fdf ("i18n: unpack-trees: mark strings for translation", 2016-04-09) and later improved in 2e3926b ("i18n: unpack-trees: avoid substituting only a verb in sentences", 2016-05-12).

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t1011-read-tree-sparse-checkout.sh | 2 +-
 t/t3400-rebase.sh                    | 4 ++--
 t/t3404-rebase-interactive.sh        | 4 ++--
 t/t7607-merge-overwrite.sh           | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)
Show changes to 4 files +6 −6

t/t1011-read-tree-sparse-checkout.sh, t/t3400-rebase.sh, t/t3404-rebase-interactive.sh, t/t7607-merge-overwrite.sh

diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 0c74bee..3583105 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -247,7 +247,7 @@ error: The following untracked working tree files would be overwritten by checko
 Please move or remove them before you can switch branches.
 Aborting
 EOF
-	test_cmp expected actual
+	test_i18ncmp expected actual
 '
 
 test_expect_success 'checkout without --ignore-skip-worktree-bits' '
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 47b5682..f5fd15e 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -136,8 +136,8 @@ test_expect_success 'setup: recover' '
 test_expect_success 'Show verbose error when HEAD could not be detached' '
 	>B &&
 	test_must_fail git rebase topic 2>output.err >output.out &&
-	grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
-	grep B output.err
+	test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" output.err &&
+	test_i18ngrep B output.err
 '
 rm -f B
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index f4ccd10..8ac1868 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -219,9 +219,9 @@ test_expect_success 'abort with error when new base cannot be checked out' '
 	git commit -m "remove file in base" &&
 	set_fake_editor &&
 	test_must_fail git rebase -i master > output 2>&1 &&
-	grep "The following untracked working tree files would be overwritten by checkout:" \
+	test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" \
 		output &&
-	grep "file1" output &&
+	test_i18ngrep "file1" output &&
 	test_path_is_missing .git/rebase-merge &&
 	git reset --hard HEAD^
 '
diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh
index 758a623..e8ec54c 100755
--- a/t/t7607-merge-overwrite.sh
+++ b/t/t7607-merge-overwrite.sh
@@ -125,7 +125,7 @@ test_expect_success 'will not overwrite untracked file in leading path' '
 	cp important sub &&
 	cp important sub2 &&
 	test_must_fail git merge sub 2>out &&
-	test_cmp out expect &&
+	test_i18ncmp out expect &&
 	test_path_is_missing .git/MERGE_HEAD &&
 	test_cmp important sub &&
 	test_cmp important sub2 &&
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 19/21] t9003: become resilient to GETTEXT_POISON

The test t9003-help-autocorrect.sh fails when run under GETTEXT_POISON, because it's expecting to filter out the original output. Accommodate gettext poison case by also filtering out the default simulated output.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t9003-help-autocorrect.sh | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
Show changes to t/t9003-help-autocorrect.sh +6 −2
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index dfe95c9..f6f6c92 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -31,10 +31,14 @@ test_expect_success 'autocorrect showing candidates' '
 	git config help.autocorrect 0 &&
 
 	test_must_fail git lfg 2>actual &&
-	sed -e "1,/^Did you mean this/d" actual | grep lgf &&
+	sed -e "1,/^Did you mean this/d" actual |
+	sed -e "/GETTEXT POISON/d" actual |
+	grep lgf &&
 
 	test_must_fail git distimdist 2>actual &&
-	sed -e "1,/^Did you mean this/d" actual | grep distimdistim
+	sed -e "1,/^Did you mean this/d" actual |
+	sed -e "/GETTEXT POISON/d" actual |
+	grep distimdistim
 '
 
 test_expect_success 'autocorrect running commands' '
-- 
2.7.3
Eric Sunshine· May 19, 2016, 18:34 UTC · re: Vasco Almeida · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 14 quoted lines
> The test t9003-help-autocorrect.sh fails when run under GETTEXT_POISON,
> because it's expecting to filter out the original output. Accommodate
> gettext poison case by also filtering out the default simulated output.
>
> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
> ---
> diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
> @@ -31,10 +31,14 @@ test_expect_success 'autocorrect showing candidates' '
>         git config help.autocorrect 0 &&
>
>         test_must_fail git lfg 2>actual &&
> -       sed -e "1,/^Did you mean this/d" actual | grep lgf &&
> +       sed -e "1,/^Did you mean this/d" actual |
> +       sed -e "/GETTEXT POISON/d" actual |
Why not do so with a single sed invocation?
   sed -e "..." -e "..." |
Show 6 quoted lines
> +       grep lgf &&
>
>         test_must_fail git distimdist 2>actual &&
> -       sed -e "1,/^Did you mean this/d" actual | grep distimdistim
> +       sed -e "1,/^Did you mean this/d" actual |
> +       sed -e "/GETTEXT POISON/d" actual |
Ditto.
> +       grep distimdistim
>  '
Vasco Almeida· May 19, 2016, 21:31 UTC · re: Eric Sunshine · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Às 18:34 de 19-05-2016, Eric Sunshine escreveu:
Show 31 quoted lines
> On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>> The test t9003-help-autocorrect.sh fails when run under GETTEXT_POISON,
>> because it's expecting to filter out the original output. Accommodate
>> gettext poison case by also filtering out the default simulated output.
>>
>> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
>> ---
>> diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
>> @@ -31,10 +31,14 @@ test_expect_success 'autocorrect showing candidates' '
>>         git config help.autocorrect 0 &&
>>
>>         test_must_fail git lfg 2>actual &&
>> -       sed -e "1,/^Did you mean this/d" actual | grep lgf &&
>> +       sed -e "1,/^Did you mean this/d" actual |
>> +       sed -e "/GETTEXT POISON/d" actual |
> 
> Why not do so with a single sed invocation?
> 
>    sed -e "..." -e "..." |
> 
>> +       grep lgf &&
>>
>>         test_must_fail git distimdist 2>actual &&
>> -       sed -e "1,/^Did you mean this/d" actual | grep distimdistim
>> +       sed -e "1,/^Did you mean this/d" actual |
>> +       sed -e "/GETTEXT POISON/d" actual |
> 
> Ditto.
> 
>> +       grep distimdistim
>>  '
I tried but it seems not to work.
Actually I did this wrong, I haven't thought this through.

Under gettext poison: sed -e "1,/^Did you mean this/d" removes all lines, gives no output. And then the one second, sed -e "/GETTEXT POISON/d", outputs "lgf" as expected.

But running normally (without gettext poison): 1st sed outputs "lgf" as expected And then second one output the entire 'actual' file, like if it were cat, undoing the first sed.

I think the sed here is superfluous in the first place. Should we remove it? If it weren't the case of gettext poison it was ok to have sed there, but it makes the test fail under gettext poison.

Eric Sunshine· May 20, 2016, 03:30 UTC · re: Vasco Almeida · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

[cc:+junio]
On Thu, May 19, 2016 at 5:31 PM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
Show 28 quoted lines
> Às 18:34 de 19-05-2016, Eric Sunshine escreveu:
>> On Wed, May 18, 2016 at 11:27 AM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:
>>> -       sed -e "1,/^Did you mean this/d" actual | grep lgf &&
>>> +       sed -e "1,/^Did you mean this/d" actual |
>>> +       sed -e "/GETTEXT POISON/d" actual |
>>> +       grep distimdistim
>>
>> Why not do so with a single sed invocation?
>>
>>    sed -e "..." -e "..." |
>
> I tried but it seems not to work.
>
> Actually I did this wrong, I haven't thought this through.
>
> Under gettext poison:
> sed -e "1,/^Did you mean this/d" removes all lines, gives no output.
> And then the one second, sed -e "/GETTEXT POISON/d", outputs "lgf" as
> expected.
>
> But running normally (without gettext poison):
> 1st sed outputs "lgf" as expected
> And then second one output the entire 'actual' file, like if it were
> cat, undoing the first sed.
>
> I think the sed here is superfluous in the first place.
> Should we remove it? If it weren't the case of gettext poison it was ok
> to have sed there, but it makes the test fail under gettext poison.
Indeed, the sed seems superfluous. The output of the test command is:
    git: 'lfg' is not a git command. See 'git --help'.
    Did you mean this?
        lgf

And, the grep'd string, "lgf" only appears once, so grep alone should be sufficient to verify expected behavior. Likewise for the other case of misspelled "distimdist" and grep'd "distimdistim" which appears only once.

I agree that the simplest fix to make GETTEXT_POISON work is to drop the sed invocation.

Anyhow, I've cc:'d the author of 9d1d2b7 (git: remove an early return from save_env_before_alias(), 2016-01-26) which introduced it.

Junio C Hamano· May 20, 2016, 16:39 UTC · re: Eric Sunshine · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Eric Sunshine <sunshine@sunshineco.com> writes:
Show 11 quoted lines
> [cc:+junio]
>
> Indeed, the sed seems superfluous. The output of the test command is:
>
>     git: 'lfg' is not a git command. See 'git --help'.
>
>     Did you mean this?
>         lgf
>
> And, the grep'd string, "lgf" only appears once, so grep alone should
> be sufficient to verify expected behavior.

We want to see the string appear after "Did you mean this?" and we do not want to be fooled by a future change in the early part of the message, which may contain a substring l-g-f that does not have anything to do with the alias we are looking for.

And the way you express "I do not care anything above this line" is to say "sed -e '1,/^that line/d'".

Of course, if you use this with POISON, you'd need to consider that "Did you mean this" would not be a good marker to identify where the introductory text we want to ignore ends. You'd need to find a different mechanism to exclude the introductory text if you want to retain the future-proofing the existing "sed -e" gave us.

Perhaps discarding up to the first blank line (i.e. assuming that we would not remove that blank, and also assuming that we will not rephrase "Did you mean this?") may be a good alternative.

Or assuming that the explanatory text would not begin its lines with a tab, i.e.

	grep '^	lgf$' actual

(the space between '^' and 'l' above is a TAB) without using test_i18ngrep?

I think I like that the best among what I can think of offhand.
Eric Sunshine· May 20, 2016, 17:22 UTC · re: Junio C Hamano · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

On Fri, May 20, 2016 at 12:39 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 24 quoted lines
> Eric Sunshine <sunshine@sunshineco.com> writes:
>> Indeed, the sed seems superfluous. The output of the test command is:
>>
>>     git: 'lfg' is not a git command. See 'git --help'.
>>
>>     Did you mean this?
>>         lgf
>>
>> And, the grep'd string, "lgf" only appears once, so grep alone should
>> be sufficient to verify expected behavior.
>
> Perhaps discarding up to the first blank line (i.e. assuming that we
> would not remove that blank, and also assuming that we will not
> rephrase "Did you mean this?") may be a good alternative.
>
> Or assuming that the explanatory text would not begin its lines with
> a tab, i.e.
>
>         grep '^ lgf$' actual
>
> (the space between '^' and 'l' above is a TAB) without using
> test_i18ngrep?
>
> I think I like that the best among what I can think of offhand.
Yep, I also considered both of these approaches and favored the latter, as well.
Vasco Almeida· May 20, 2016, 17:39 UTC · re: Junio C Hamano · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Às 16:39 de 20-05-2016, Junio C Hamano escreveu:
Show 29 quoted lines
> We want to see the string appear after "Did you mean this?" and we
> do not want to be fooled by a future change in the early part of the
> message, which may contain a substring l-g-f that does not have
> anything to do with the alias we are looking for.
> 
> And the way you express "I do not care anything above this line" is
> to say "sed -e '1,/^that line/d'".
> 
> Of course, if you use this with POISON, you'd need to consider that
> "Did you mean this" would not be a good marker to identify where the
> introductory text we want to ignore ends.  You'd need to find a
> different mechanism to exclude the introductory text if you want to
> retain the future-proofing the existing "sed -e" gave us.
> 
> Perhaps discarding up to the first blank line (i.e. assuming that we
> would not remove that blank, and also assuming that we will not
> rephrase "Did you mean this?") may be a good alternative.
> 
> Or assuming that the explanatory text would not begin its lines with
> a tab, i.e.
> 
> 	grep '^	lgf$' actual
> 
> (the space between '^' and 'l' above is a TAB) without using
> test_i18ngrep?
> 
> I think I like that the best among what I can think of offhand.
> 
> 

Alternatively, we could leave sed alone as it were before this patch and use test_i18ngrep instead of grep to fake success under GETTEXT_POISON. I think I prefer this way. What do you think?

Junio C Hamano· May 20, 2016, 17:50 UTC · re: Vasco Almeida · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Vasco Almeida <vascomalmeida@sapo.pt> writes:
> Alternatively, we could leave sed alone as it were before this patch and
> use test_i18ngrep instead of grep to fake success under GETTEXT_POISON.
> I think I prefer this way. What do you think?

That is equivalent to saying that "we would translate 'lgf' to end-user's language", which does not make much sense to me.

Wouldn't the introductory explanation, up to "Did you mean this?", be the only thing that is translated?

Junio C Hamano· May 20, 2016, 17:59 UTC · re: Junio C Hamano · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Junio C Hamano <gitster@pobox.com> writes:
Show 11 quoted lines
> Vasco Almeida <vascomalmeida@sapo.pt> writes:
>
>> Alternatively, we could leave sed alone as it were before this patch and
>> use test_i18ngrep instead of grep to fake success under GETTEXT_POISON.
>> I think I prefer this way. What do you think?
>
> That is equivalent to saying that "we would translate 'lgf' to
> end-user's language", which does not make much sense to me.
>
> Wouldn't the introductory explanation, up to "Did you mean this?",
> be the only thing that is translated?
I just checked the code ;-)  We do this:
	fprintf_ln(stderr,
		   Q_("\nDid you mean this?",
		      "\nDid you mean one of these?",
		   n));
	for (i = 0; i < n; i++)
		fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);

Using test_i18ngrep would mean we would not be able to catch a potential future bug that does an equivalent of

	for (i = 0; i < n; i++)
		fprintf(stderr, "\t%s\n", _(main_cmds.names[i]->name));

in the loop, i.e. marking something that is not meant to be translated as translatable.

As long as translators do not translate "Did you mean..." to begin a line with a tab (which I do not think there is any reason to), it is going to work reliably to grep for "^ lgf$" here, and it will catch such a potential future bug under GETTEXT_POISON build.

Vasco Almeida· May 20, 2016, 18:21 UTC · re: Junio C Hamano · lore

Re: [PATCH 19/21] t9003: become resilient to GETTEXT_POISON

Às 17:59 de 20-05-2016, Junio C Hamano escreveu:
> As long as translators do not translate "Did you mean..." to begin a
> line with a tab (which I do not think there is any reason to), it is
> going to work reliably to grep for "^ lgf$" here, and it will catch
> such a potential future bug under GETTEXT_POISON build.

Translations don't affect the tests since they're run with C locale. I think all tests source test-lib.sh which does:

	# For repeatability, reset the environment to known value.
	# TERM is sanitized below, after saving color control sequences.
	LANG=C
	LC_ALL=C
	PAGER=cat
	TZ=UTC
	export LANG LC_ALL PAGER TZ

So, I'll remove sed command and use grep the way you said it, in the next re-roll.

Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 20/21] t4153: fix negated test_i18ngrep call

The function test_i18ngrep fakes success when run under GETTEXT_POISON. Hence, running in the following manner will always fail under gettext poison:

	! test_i18ngrep expected actual
Use correct syntax: test_i18ngrep ! expected actual

For other instance of this issue see 41ca19b ("tests: fix negated test_i18ngrep calls", 2014-08-13).

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t4153-am-resume-override-opts.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to t/t4153-am-resume-override-opts.sh +1 −1
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
index 7c013d8..8ea22d1 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -53,7 +53,7 @@ test_expect_success '--no-quiet overrides --quiet' '
 	# Applying side1 will be quiet.
 	test_must_fail git am --quiet side[123].eml >out &&
 	test_path_is_dir .git/rebase-apply &&
-	! test_i18ngrep "^Applying: " out &&
+	test_i18ngrep ! "^Applying: " out &&
 	echo side1 >file &&
 	git add file &&
 
-- 
2.7.3
Vasco Almeida· May 18, 2016, 15:27 UTC · re: Vasco Almeida · lore

[PATCH 21/21] t5523: use test_i18ngrep for negation

Replace the first form by the second one:
	! grep expected actual
	test_i18ngrep ! expected actual

The latter syntax is supported by test_i18ngrep defined in t/test-lib.sh.

Although the test already passes whether GETTEXT_POSION is enabled, use the i18n grep variant for the sake of consistency and also to make obvious that those strings are subject to i18n.

Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
---
 t/t5523-push-upstream.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Show changes to t/t5523-push-upstream.sh +4 −4
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index 4a7b98b..d6981ba 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -83,7 +83,7 @@ test_expect_success 'progress messages do not go to non-tty' '
 
 	# skip progress messages, since stderr is non-tty
 	git push -u upstream master >out 2>err &&
-	! grep "Writing objects" err
+	test_i18ngrep ! "Writing objects" err
 '
 
 test_expect_success 'progress messages go to non-tty (forced)' '
@@ -98,15 +98,15 @@ test_expect_success TTY 'push -q suppresses progress' '
 	ensure_fresh_upstream &&
 
 	test_terminal git push -u -q upstream master >out 2>err &&
-	! grep "Writing objects" err
+	test_i18ngrep ! "Writing objects" err
 '
 
 test_expect_success TTY 'push --no-progress suppresses progress' '
 	ensure_fresh_upstream &&
 
 	test_terminal git push -u --no-progress upstream master >out 2>err &&
-	! grep "Unpacking objects" err &&
-	! grep "Writing objects" err
+	test_i18ngrep ! "Unpacking objects" err &&
+	test_i18ngrep ! "Writing objects" err
 '
 
 test_expect_success TTY 'quiet push' '
-- 
2.7.3

← back to recent threads