Skip to contentSkip to conversation

i18n for git-am, git-rebase and git-merge

PATCH Superseded Jiang Xin 3 participants 15 messages Jun 15, 2016 Kbuild

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Jiang Xin

author
#0 lore raw

v4 cover i18n for git-am, git-rebase and git-merge

Marked messages for translation in git-am, git-rebase, and git-merge. Also fixed affected test cases when turn GETTEXT_POISON switch on.

Jiang Xin (7):
i18n: New keywords for xgettext extraction from sh
i18n: rebase: mark strings for translation
i18n: Rewrite gettext messages start with dash Remove obsolete LONG_USAGE which breaks xgettext
i18n: am: mark more strings for translation Remove dead code which contains bad gettext block
i18n: merge-recursive: mark strings for translation

 Makefile                             |   3 +-
 git-am.sh                            |  20 ++---
 git-rebase.sh                        |  89 ++++++++-------------
 git-submodule.sh                     |   2 +-
 merge-recursive.c                    | 148 +++++++++++++++++++----------------
 t/t0201-gettext-fallbacks.sh         |   8 +-
 t/t3400-rebase.sh                    |   8 +-
 t/t3404-rebase-interactive.sh        |   2 +-
 t/t3406-rebase-message.sh            |   2 +-
 t/t6022-merge-rename.sh              |  16 ++--
 t/t6042-merge-rename-corner-cases.sh |   2 +-
 11 files changed, 143 insertions(+), 157 deletions(-)
Signature · 1 line
1.7.12.rc0.16.gf4916ac
author
#1 lore raw

PATCH v4 1/7 i18n: New keywords for xgettext extraction from sh

Since we have additional shell wrappers (gettextln and eval_gettextln) for gettext, we need to take into account these wrappers when running 'make pot' to extract messages from shell scripts.

---
 Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Makefile +2 -1
index b0b34..d3cd9 100644
@@ -2387,7 +2387,8 @@ XGETTEXT_FLAGS = \
 	--from-code=UTF-8
 XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
 	--keyword=_ --keyword=N_ --keyword="Q_:1,2"
-XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell
+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)
Signature · 1 line
1.7.12.rc0.16.gf4916ac
author
#2 lore raw

PATCH v4 2/7 i18n: rebase: mark strings for translation

Mark strings in git-rebase.sh for translation. Jonathan offers a help for reorgnization of the resolvemsg variable in 'git-rebase.sh', since there is a likely message in git-am.sh, I update it in this commit for consistency. And so does to 't/t0201-gettext-fallbacks.sh'.

Some test scripts are affected by this update, and would fail if tested with GETTEXT_POISON switch turned on. Using i18n-specific test functions, such as test_i18ngrep, in the related test scripts will fix these issues.

---
 git-am.sh                    |  6 ++---
 git-rebase.sh                | 64 +++++++++++++++++++++++---------------------
 t/t0201-gettext-fallbacks.sh |  8 +++---
 t/t3400-rebase.sh            |  8 +++---
 t/t3406-rebase-message.sh    |  2 +-
 5 files changed, 46 insertions(+), 42 deletions(-)
git-am.sh +3 -3
index c02e6..8961a 100755
@@ -102,9 +102,9 @@ stop_here_user_resolve () {
 	    printf '%s\n' "$resolvemsg"
 	    stop_here $1
     fi
-    eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\".
-If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
-To restore the original branch and stop patching run \"\$cmdline --abort\"."
+    eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\".
+If you prefer to skip this patch, run \"\$cmdline --skip\" instead.
+To restore the original branch and stop patching, run \"\$cmdline --abort\"."
 
     stop_here $1
 }
git-rebase.sh +34 -30

184 lines not on this page · raw message

t/t0201-gettext-fallbacks.sh +4 -4
index 52b1c..5d80a 100755
@@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v
 test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' '
     cmdline="git am" &&
     export cmdline;
-    printf "When you have resolved this problem run git am --resolved." >expect &&
-    eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual
+    printf "When you have resolved this problem, run git am --resolved." >expect &&
+    eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual
     test_i18ncmp expect actual
 '
 
 test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' '
     cmdline="git am" &&
     export cmdline;
-    printf "When you have resolved this problem run \"git am --resolved\"." >expect &&
-    eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual
+    printf "When you have resolved this problem, run \"git am --resolved\"." >expect &&
+    eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual
     test_i18ncmp expect actual
 '
 
t/t3400-rebase.sh +4 -4
index 7788a..1de0e 100755
@@ -68,24 +68,24 @@ test_expect_success 'rebase against master' '
 
 test_expect_success 'rebase against master twice' '
 	git rebase master >out &&
-	grep "Current branch my-topic-branch is up to date" out
+	test_i18ngrep "Current branch my-topic-branch is up to date" out
 '
 
 test_expect_success 'rebase against master twice with --force' '
 	git rebase --force-rebase master >out &&
-	grep "Current branch my-topic-branch is up to date, rebase forced" out
+	test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out
 '
 
 test_expect_success 'rebase against master twice from another branch' '
 	git checkout my-topic-branch^ &&
 	git rebase master my-topic-branch >out &&
-	grep "Current branch my-topic-branch is up to date" out
+	test_i18ngrep "Current branch my-topic-branch is up to date" out
 '
 
 test_expect_success 'rebase fast-forward to master' '
 	git checkout my-topic-branch^ &&
 	git rebase my-topic-branch >out &&
-	grep "Fast-forwarded HEAD to my-topic-branch" out
+	test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out
 '
 
 test_expect_success 'the rebase operation should not have destroyed author information' '
t/t3406-rebase-message.sh +1 -1
index 68983..6eb28 100755
@@ -64,7 +64,7 @@ test_expect_success 'rebase -n overrides config rebase.stat config' '
 
 test_expect_success 'rebase --onto outputs the invalid ref' '
 	test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err &&
-	grep "invalid-ref" err
+	test_i18ngrep "invalid-ref" err
 '
 
 test_done
Signature · 1 line
1.7.12.rc0.16.gf4916ac
#3 lore raw

Re: [PATCH v4 2/7] i18n: rebase: mark strings for translation

(cc-ing Duy because of a mention of his nice GETTEXT_POISON tweak[*]) Hi,

Quoted 4 lines · Jiang Xin

Mark strings in git-rebase.sh for translation. Jonathan offers a help for reorgnization of the resolvemsg variable in 'git-rebase.sh', since there is a likely message in git-am.sh, I update it in this commit for consistency. And so does to 't/t0201-gettext-fallbacks.sh'.

Ah. Looks like I tweaked the comma usage and sentence structure a little. Sorry, force of habit --- I shouldn't have.

Quoted 4 lines

Some test scripts are affected by this update, and would fail if tested with GETTEXT_POISON switch turned on. Using i18n-specific test functions, such as test_i18ngrep, in the related test scripts will fix these issues.

If we're going to keep the changes together, here's how I would phrase the commit message:

Mark messages in git-rebase.sh for translation. While doing this it was noticed that the comma usage and sentence structure of the resolvemsg was not quite right, so correct that and its cousins in git-am.sh and t/t0201-gettext-fallbacks.sh at the same time.

Some tests would start to fail with GETTEXT_POISON turned on after this update. Use test_i18ncmp and test_i18ngrep where appropriate to mark strings that should only be checked in the C locale output to avoid such issues.

Quoted 3 lines

I haven't tested or reviewed this patch in detail, so even though it looks good, I'd prefer it not to have my Reviewed-by. (See Documentation/SubmittingPatches: '"Reviewed-by:", unlike the other extra tags, can only be offered by the reviewer'.) If you'd like to credit my help, something like "With advice from Jonathan." would be fine.

[...]

t/t3406-rebase-message.sh test_expect_success 'rebase -n overrides config rebase.stat config' ' · line 68

Quoted 9 lines
t/t3406-rebase-message.sh +1 -1
@@ -64,7 +64,7 @@ test_expect_success 'rebase -n overrides config rebase.stat config' '
 
 test_expect_success 'rebase --onto outputs the invalid ref' '
 	test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err &&
-	grep "invalid-ref" err
+	test_i18ngrep "invalid-ref" err
 '

Could we add a comment so others do not have to wonder what human-readable message prompts the test_i18ngrep here? e.g

# "Does not point to a valid commit: invalid-ref" #
# NEEDSWORK: This "grep" is fine in real non-C locales, but # GETTEXT_POISON poisons the refname along with the enclosing # error message.
test_i18ngrep invalid-ref err

In the long run we may be able to turn this back to a "grep" again, since any reasonable translation will keep the $onto_name somewhere in the message. But changing it to test_i18ngrep for now is the right thing to do, until something like Duy's more sophisticated version of GETTEXT_POISON arrives. (<-- [*])

Thanks,
Jonathan

author
#4 lore raw

Re: [PATCH v4 2/7] i18n: rebase: mark strings for translation

2012/7/25 Jonathan Nieder <[email protected]>:

Quoted 6 lines

I haven't tested or reviewed this patch in detail, so even though it looks good, I'd prefer it not to have my Reviewed-by. (See Documentation/SubmittingPatches: '"Reviewed-by:", unlike the other extra tags, can only be offered by the reviewer'.) If you'd like to credit my help, something like "With advice from Jonathan." would be fine.

How about Acked-by: ?

Signature · 1 line
Jiang Xin
#5 lore raw

Re: [PATCH v4 2/7] i18n: rebase: mark strings for translation

Quoted 10 lines · Jiang Xin

2012/7/25 Jonathan Nieder <[email protected]>:

Quoted 6 lines

I haven't tested or reviewed this patch in detail, so even though it looks good, I'd prefer it not to have my Reviewed-by. (See Documentation/SubmittingPatches: '"Reviewed-by:", unlike the other extra tags, can only be offered by the reviewer'.) If you'd like to credit my help, something like "With advice from Jonathan." would be fine.

How about Acked-by: ?

I'm not area expert so my ack wouldn't count for "git rebase" or i18n, anyway. I'm also fine with going unsung --- too many names add up to so much noise, and in general there are some names (author, bug reporter, and so on) that are important and shouldn't be drowned out.

author
#6 lore raw

PATCH v4 3/7 i18n: Rewrite gettext messages start with dash

In reply to Jiang Xin

Gettext message in a shell script should not start with '-', one workaround is adding '--' between gettext and the message, like:

    gettext -- "--exec option ..."

But due to a bug in the xgettext extraction, xgettext can not extract the actual message for this case. Rewriting the message is a simpler and better solution.

---
 git-rebase.sh                 | 2 +-
 git-submodule.sh              | 2 +-
 t/t3404-rebase-interactive.sh | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
git-rebase.sh +1 -1
index 8710d..705bd 100755
@@ -317,7 +317,7 @@ test $# -gt 2 && usage
 if test -n "$cmd" &&
    test "$interactive_rebase" != explicit
 then
-	die "$(gettext -- "--exec option must be used with --interactive option")"
+	die "$(gettext "The --exec option must be used with the --interactive option")"
 fi
 
 if test -n "$action"
git-submodule.sh +1 -1
index dba4d..5b019 100755
@@ -748,7 +748,7 @@ cmd_summary() {
 	if [ -n "$files" ]
 	then
 		test -n "$cached" &&
-		die "$(gettext -- "--cached cannot be used with --files")"
+		die "$(gettext "The --cached option cannot be used with the --files option")"
 		diff_cmd=diff-files
 		head=
 	fi
t/t3404-rebase-interactive.sh +1 -1
index 8078..f206a 100755
@@ -858,7 +858,7 @@ test_expect_success 'rebase -ix with --autosquash' '
 test_expect_success 'rebase --exec without -i shows error message' '
 	git reset --hard execute &&
 	test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
-	echo "--exec option must be used with --interactive option" >expected &&
+	echo "The --exec option must be used with the --interactive option" >expected &&
 	test_i18ncmp expected actual
 '
 
Signature · 1 line
1.7.12.rc0.16.gf4916ac
author
#7 lore raw

PATCH v4 4/7 Remove obsolete LONG_USAGE which breaks xgettext

The obsolete LONG_USAGE variable has the following message in it:

    A'\''--B'\''--C'\''

And such complex LONG_USAGE message will breaks xgettext when extracting l10n messages. But if single quotes are removed from the message, xgettext works fine on 'git-rebase.sh'.

Since there is a modern OPTIONS_SPEC variable in use in this script, it's safe to remove the obsolete USAGE and LONG_USAGE variables.

---
 git-rebase.sh | 25 -------------------------
 1 file changed, 25 deletions(-)
git-rebase.sh +0 -25
index 705bd..0e6fd 100755
@@ -3,31 +3,6 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [--exec | -x <cmd>] [-v] [--force-rebase | -f]
-       [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
-LONG_USAGE='git-rebase replaces <branch> with a new branch of the
-same name.  When the --onto option is provided the new branch starts
-out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
-It then attempts to create a new commit for each commit from the original
-<branch> that does not exist in the <upstream> branch.
-
-It is possible that a merge failure will prevent this process from being
-completely automatic.  You will have to resolve any such merge failure
-and run git rebase --continue.  Another option is to bypass the commit
-that caused the merge failure with git rebase --skip.  To check out the
-original <branch> and remove the .git/rebase-apply working files, use the
-command git rebase --abort instead.
-
-Note that if <branch> is not specified on the command line, the
-currently checked out branch is used.
-
-Example:       git-rebase master~1 topic
-
-	A---B---C topic                   A'\''--B'\''--C'\'' topic
-       /                   -->           /
-  D---E---F---G master          D---E---F---G master
-'
-
 SUBDIRECTORY_OK=Yes
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
Signature · 1 line
1.7.12.rc0.16.gf4916ac
author
#8 lore raw

PATCH v4 5/7 i18n: am: mark more strings for translation

Mark strings in 'git-am.sh' for translation. In the last chunk, I changed '$1' to '-b/--binary' for this reason:

* First, if there is a variable in the l10n message, we could not use gettext. Because the variable will be expanded (evaluated) and will never match the entry in the po file.

* Second, if there is a positional parameter ($1, $2,...) in the message, we could not use eval_gettext either. Because eval_gettext may be a wapper for gettext, and the positional parameter would loose it's original context.

Also reduce one indentation level for one gettextln clause introduced in commit de88c1c.

---
 git-am.sh | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
git-am.sh +5 -6
index 8961a..3f654 100755
@@ -92,7 +92,7 @@ safe_to_abort () {
 	then
 		return 0
 	fi
-		gettextln "You seem to have moved HEAD since the last 'am' failure.
+	gettextln "You seem to have moved HEAD since the last 'am' failure.
 Not rewinding to ORIG_HEAD" >&2
 	return 1
 }
@@ -136,7 +136,7 @@ fall_back_3way () {
     git write-tree >"$dotest/patch-merge-base+" ||
     cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")"
 
-    say Using index info to reconstruct a base tree...
+    say "$(gettext "Using index info to reconstruct a base tree...")"
 
     cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"'
 
@@ -176,8 +176,7 @@ It does not apply to blobs recorded in its index.")"
     fi
     git-merge-recursive $orig_tree -- HEAD $his_tree || {
 	    git rerere $allow_rerere_autoupdate
-	    echo Failed to merge in the changes.
-	    exit 1
+	    die "$(gettext "Failed to merge in the changes.")"
     }
     unset GITHEAD_$his_tree
 }
@@ -387,8 +386,8 @@ do
 	-i|--interactive)
 		interactive=t ;;
 	-b|--binary)
-		echo >&2 "The $1 option has been a no-op for long time, and"
-		echo >&2 "it will be removed. Please do not use it anymore."
+		echo >&2 $(gettext "The -b/--binary option has been a no-op for long time, and
+it will be removed. Please do not use it anymore.")
 		;;
 	-3|--3way)
 		threeway=t ;;
Signature · 1 line
1.7.12.rc0.16.gf4916ac
Reviewed-by on v4 5/7
#9 lore raw

Re: [PATCH v4 5/7] i18n: am: mark more strings for translation

Quoted 11 lines · Jiang Xin

Mark strings in 'git-am.sh' for translation. In the last chunk, I changed '$1' to '-b/--binary' for this reason:

* First, if there is a variable in the l10n message, we could not use gettext. Because the variable will be expanded (evaluated) and will never match the entry in the po file.

* Second, if there is a positional parameter ($1, $2,...) in the message, we could not use eval_gettext either. Because eval_gettext may be a wapper for gettext, and the positional parameter would loose it's original context.

Yes, I think it's a good change.

Quoted 2 lines
git-am.sh +0 -0

[...]

git-am.sh do · line 390

Quoted 8 lines
git-am.sh +2 -2
@@ -387,8 +386,8 @@ do
 	-i|--interactive)
 		interactive=t ;;
 	-b|--binary)
-		echo >&2 "The $1 option has been a no-op for long time, and"
-		echo >&2 "it will be removed. Please do not use it anymore."
+		echo >&2 $(gettext "The -b/--binary option has been a no-op for long time, and
+it will be removed. Please do not use it anymore.")

Could this be simplified to

		gettextln >&2 'The -b/--binary option...

... any more.'

or

gettextln 'The -b/--binary option ...
... any more.' >&2

or would that confuse xgettext? That would be more comforting than "echo" because if the translated string includes backslashes then the behavior of echo can be unpredictable.

Sorry I missed that last time.

The rest is indeed

Thanks.

#10 lore raw

Re: [PATCH v4 5/7] i18n: am: mark more strings for translation

In reply to Jiang Xin

Sorry to be so nit-picky, but ...

Quoted 12 lines · Jiang Xin

Mark strings in 'git-am.sh' for translation. In the last chunk, I changed '$1' to '-b/--binary' for this reason:

* First, if there is a variable in the l10n message, we could not use gettext. Because the variable will be expanded (evaluated) and will never match the entry in the po file.

* Second, if there is a positional parameter ($1, $2,...) in the message, we could not use eval_gettext either. Because eval_gettext may be a wapper for gettext, and the positional parameter would loose it's original context.

... here you should s/it's/its/.

Regards,
Stefano

author
#11 lore raw

Re: [PATCH v4 5/7] i18n: am: mark more strings for translation

2012/7/25 Stefano Lattarini <[email protected]>:

Quoted 6 lines
Quoted 5 lines

* Second, if there is a positional parameter ($1, $2,...) in the message, we could not use eval_gettext either. Because eval_gettext may be a wapper for gettext, and the positional parameter would loose it's original context.

... here you should s/it's/its/.

OMG. You find what some grammer/spelling checking website hasn't. If there are no other serious problems, I won't make noises (send another series of patches) to this list, should I?

Signature · 1 line
Jiang Xin
author
#12 lore raw

PATCH v4 6/7 Remove dead code which contains bad gettext block

In reply to Jiang Xin

Found this dead code when I examine gettext messages in shell scripts start with dash ('-' or '--'). An error will be raised for this case, like:

    $ gettext "-d option is no longer supported.  Do not use."
    gettext: missing arguments

Indead, this code has been left as dead for a long time, as Junathan points out:

The git am -d/--dotest option has errored out with a message since e72c7406 (am: remove support for -d .dotest, 2008-03-04). The error message about lack of support was eliminated along with other cleanups (probably by mistake) a year later by removing the option from the option table in 98ef23b3 (git-am:
minor cleanups, 2009-01-28).

But the code to handle -d and --dotest stayed around even though ever since then it could not be tripped. Remove this dead code.

---
 git-am.sh | 3 ---
 1 file changed, 3 deletions(-)
git-am.sh +0 -3
index 3f654..c81a2 100755
@@ -413,9 +413,6 @@ it will be removed. Please do not use it anymore.")
 		abort=t ;;
 	--rebasing)
 		rebasing=t threeway=t ;;
-	-d|--dotest)
-		die "$(gettext "-d option is no longer supported.  Do not use.")"
-		;;
 	--resolvemsg)
 		shift; resolvemsg=$1 ;;
 	--whitespace|--directory|--exclude|--include)
Signature · 1 line
1.7.12.rc0.16.gf4916ac
Reviewed-by on v4 6/7
#13 lore raw

Re: [PATCH v4 6/7] Remove dead code which contains bad gettext block

Quoted 9 lines · Jiang Xin

Found this dead code when I examine gettext messages in shell scripts start with dash ('-' or '--'). An error will be raised for this case, like:

    $ gettext "-d option is no longer supported.  Do not use."
    gettext: missing arguments

Indead, this code has been left as dead for a long time, as Junathan points out:

Jonathan, not Junathan. :)

Quoted 11 lines

The git am -d/--dotest option has errored out with a message since e72c7406 (am: remove support for -d .dotest, 2008-03-04). The error message about lack of support was eliminated along with other cleanups (probably by mistake) a year later by removing the option from the option table in 98ef23b3 (git-am:
minor cleanups, 2009-01-28).

But the code to handle -d and --dotest stayed around even though ever since then it could not be tripped. Remove this dead code.

Your explanation is certainly clearer than mine. So: yes, for what it's worth this is

author
#14 lore raw

PATCH v4 7/7 i18n: merge-recursive: mark strings for translation

In reply to Jiang Xin

Mark strings in merge-recursive for translation.

Some test scripts are affected by this update, and would fail if tested with GETTEXT_POISON switch turned on. Using i18n-specific test functions, such as test_i18ngrep, in the related test scripts will fix these issues.

---
 merge-recursive.c                    | 148 +++++++++++++++++++----------------
 t/t6022-merge-rename.sh              |  16 ++--
 t/t6042-merge-rename-corner-cases.sh |   2 +-
 3 files changed, 88 insertions(+), 78 deletions(-)
merge-recursive.c +79 -69
index 68093..8903 100644
@@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
 	else {
 		printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 		if (parse_commit(commit) != 0)
-			printf("(bad commit)\n");
+			printf(_("(bad commit)\n"));
 		else {
 			const char *title;
 			int len = find_commit_subject(commit->buffer, &title);
@@ -203,7 +203,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 	struct cache_entry *ce;
 	ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
 	if (!ce)
-		return error("addinfo_cache failed for path '%s'", path);
+		return error(_("addinfo_cache failed for path '%s'"), path);
 	return add_cache_entry(ce, options);
 }
 
@@ -265,7 +265,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
 	if (!cache_tree_fully_valid(active_cache_tree) &&
 	    cache_tree_update(active_cache_tree,
 			      active_cache, active_nr, 0) < 0)
-		die("error building trees");
+		die(_("error building trees"));
 
 	result = lookup_tree(active_cache_tree->sha1);
 
@@ -494,7 +494,7 @@ static struct string_list *get_renames(struct merge_options *o,
 	opts.show_rename_progress = o->show_rename_progress;
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 	if (diff_setup_done(&opts) < 0)
-		die("diff setup failed");
+		die(_("diff setup failed"));
 	diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
 	diffcore_std(&opts);
 	if (opts.needed_rename_limit > o->needed_rename_limit)
@@ -624,7 +624,7 @@ static void flush_buffer(int fd, const char *buf, unsigned long size)
 				break;
 			die_errno("merge-recursive");
 		} else if (!ret) {
-			die("merge-recursive: disk full?");
+			die(_("merge-recursive: disk full?"));
 		}
 		size -= ret;
 		buf += ret;
@@ -687,7 +687,7 @@ static int would_lose_untracked(const char *path)
 static int make_room_for_path(struct merge_options *o, const char *path)
 {
 	int status, i;
-	const char *msg = "failed to create path '%s'%s";
+	const char *msg = _("failed to create path '%s'%s");
 
 	/* Unlink any D/F conflict files that are in the way */
 	for (i = 0; i < o->df_conflict_file_set.nr; i++) {
@@ -698,7 +698,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
 		    path[df_pathlen] == '/' &&
 		    strncmp(path, df_path, df_pathlen) == 0) {
 			output(o, 3,
-			       "Removing %s to make room for subdirectory\n",
+			       _("Removing %s to make room for subdirectory\n"),
 			       df_path);
 			unlink(df_path);
 			unsorted_string_list_delete_item(&o->df_conflict_file_set,
@@ -712,7 +712,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
 	if (status) {
 		if (status == -3) {
 			/* something else exists */
-			error(msg, path, ": perhaps a D/F conflict?");
+			error(msg, path, _(": perhaps a D/F conflict?"));
 			return -1;
 		}
 		die(msg, path, "");
@@ -723,7 +723,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
 	 * tracking it.
 	 */
 	if (would_lose_untracked(path))
-		return error("refusing to lose untracked file at '%s'",
+		return error(_("refusing to lose untracked file at '%s'"),
 			     path);
 
 	/* Successful unlink is good.. */
@@ -733,7 +733,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
 	if (errno == ENOENT)
 		return 0;
 	/* .. but not some other error (who really cares what?) */
-	return error(msg, path, ": perhaps a D/F conflict?");
+	return error(msg, path, _(": perhaps a D/F conflict?"));
 }
 
 static void update_file_flags(struct merge_options *o,
@@ -763,9 +763,9 @@ static void update_file_flags(struct merge_options *o,
 
 		buf = read_sha1_file(sha, &type, &size);
 		if (!buf)
-			die("cannot read object %s '%s'", sha1_to_hex(sha), path);
+			die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path);
 		if (type != OBJ_BLOB)
-			die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+			die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path);
 		if (S_ISREG(mode)) {
 			struct strbuf strbuf = STRBUF_INIT;
 			if (convert_to_working_tree(path, buf, size, &strbuf)) {
@@ -788,7 +788,7 @@ static void update_file_flags(struct merge_options *o,
 				mode = 0666;
 			fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
 			if (fd < 0)
-				die_errno("failed to open '%s'", path);
+				die_errno(_("failed to open '%s'"), path);
 			flush_buffer(fd, buf, size);
 			close(fd);
 		} else if (S_ISLNK(mode)) {
@@ -796,10 +796,10 @@ static void update_file_flags(struct merge_options *o,
 			safe_create_leading_directories_const(path);
 			unlink(path);
 			if (symlink(lnk, path))
-				die_errno("failed to symlink '%s'", path);
+				die_errno(_("failed to symlink '%s'"), path);
 			free(lnk);
 		} else
-			die("do not know what to do with %06o %s '%s'",
+			die(_("do not know what to do with %06o %s '%s'"),
 			    mode, sha1_to_hex(sha), path);
 		free(buf);
 	}
@@ -936,11 +936,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
 						  branch1, branch2);
 
 			if ((merge_status < 0) || !result_buf.ptr)
-				die("Failed to execute internal merge");
+				die(_("Failed to execute internal merge"));
 
 			if (write_sha1_file(result_buf.ptr, result_buf.size,
 					    blob_type, result.sha))
-				die("Unable to add %s to database",
+				die(_("Unable to add %s to database"),
 				    a->path);
 
 			free(result_buf.ptr);
@@ -956,7 +956,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
 			if (!sha_eq(a->sha1, b->sha1))
 				result.clean = 0;
 		} else {
-			die("unsupported object type in the tree");
+			die(_("unsupported object type in the tree"));
 		}
 	}
 
@@ -1034,22 +1034,32 @@ static void handle_change_delete(struct merge_options *o,
 		remove_file_from_cache(path);
 		update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
 	} else if (!a_sha) {
-		output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-		       "and %s in %s. Version %s of %s left in tree%s%s.",
-		       change, path, o->branch1,
-		       change_past, o->branch2, o->branch2, path,
-		       NULL == renamed ? "" : " at ",
-		       NULL == renamed ? "" : renamed);
-		update_file(o, 0, b_sha, b_mode, renamed ? renamed : path);
+		if (!renamed) {
+			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+			       "and %s in %s. Version %s of %s left in tree."),
+			       change, path, o->branch1, change_past,
+			       o->branch2, o->branch2, path);
+			update_file(o, 0, b_sha, b_mode, path);
+		} else {
+			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+			       "and %s in %s. Version %s of %s left in tree at %s."),
+			       change, path, o->branch1, change_past,
+			       o->branch2, o->branch2, path, renamed);
+			update_file(o, 0, b_sha, b_mode, renamed);
+		}
 	} else {
-		output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-		       "and %s in %s. Version %s of %s left in tree%s%s.",
-		       change, path, o->branch2,
-		       change_past, o->branch1, o->branch1, path,
-		       NULL == renamed ? "" : " at ",
-		       NULL == renamed ? "" : renamed);
-		if (renamed)
+		if (!renamed) {
+			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+			       "and %s in %s. Version %s of %s left in tree."),
+			       change, path, o->branch2, change_past,
+			       o->branch1, o->branch1, path);
+		} else {
+			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+			       "and %s in %s. Version %s of %s left in tree at %s."),
+			       change, path, o->branch2, change_past,
+			       o->branch1, o->branch1, path, renamed);
 			update_file(o, 0, a_sha, a_mode, renamed);
+		}
 		/*
 		 * No need to call update_file() on path when !renamed, since
 		 * that would needlessly touch path.  We could call
@@ -1085,7 +1095,7 @@ static void conflict_rename_delete(struct merge_options *o,
 			     orig->sha1, orig->mode,
 			     a_sha, a_mode,
 			     b_sha, b_mode,
-			     "rename", "renamed");
+			     _("rename"), _("renamed"));
 
 	if (o->call_depth) {
 		remove_file_from_cache(dest->path);
@@ -1141,7 +1151,7 @@ static void handle_file(struct merge_options *o,
 	} else {
 		if (dir_in_way(rename->path, !o->call_depth)) {
 			dst_name = unique_path(o, rename->path, cur_branch);
-			output(o, 1, "%s is a directory in %s adding as %s instead",
+			output(o, 1, _("%s is a directory in %s adding as %s instead"),
 			       rename->path, other_branch, dst_name);
 		}
 	}
@@ -1163,12 +1173,12 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
 	struct diff_filespec *a = ci->pair1->two;
 	struct diff_filespec *b = ci->pair2->two;
 
-	output(o, 1, "CONFLICT (rename/rename): "
+	output(o, 1, _("CONFLICT (rename/rename): "
 	       "Rename \"%s\"->\"%s\" in branch \"%s\" "
-	       "rename \"%s\"->\"%s\" in \"%s\"%s",
+	       "rename \"%s\"->\"%s\" in \"%s\"%s"),
 	       one->path, a->path, ci->branch1,
 	       one->path, b->path, ci->branch2,
-	       o->call_depth ? " (left unresolved)" : "");
+	       o->call_depth ? _(" (left unresolved)") : "");
 	if (o->call_depth) {
 		struct merge_file_info mfi;
 		struct diff_filespec other;
@@ -1222,9 +1232,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
 	struct merge_file_info mfi_c1;
 	struct merge_file_info mfi_c2;
 
-	output(o, 1, "CONFLICT (rename/rename): "
+	output(o, 1, _("CONFLICT (rename/rename): "
 	       "Rename %s->%s in %s. "
-	       "Rename %s->%s in %s",
+	       "Rename %s->%s in %s"),
 	       a->path, c1->path, ci->branch1,
 	       b->path, c2->path, ci->branch2);
 
@@ -1252,7 +1262,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
 	} else {
 		char *new_path1 = unique_path(o, path, ci->branch1);
 		char *new_path2 = unique_path(o, path, ci->branch2);
-		output(o, 1, "Renaming %s to %s and %s to %s instead",
+		output(o, 1, _("Renaming %s to %s and %s to %s instead"),
 		       a->path, new_path1, b->path, new_path2);
 		remove_file(o, 0, path, 0);
 		update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
@@ -1451,8 +1461,8 @@ static int process_renames(struct merge_options *o,
 			} else if (!sha_eq(dst_other.sha1, null_sha1)) {
 				clean_merge = 0;
 				try_merge = 1;
-				output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. "
-				       "%s added in %s",
+				output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
+				       "%s added in %s"),
 				       ren1_src, ren1_dst, branch1,
 				       ren1_dst, branch2);
 				if (o->call_depth) {
@@ -1461,12 +1471,12 @@ static int process_renames(struct merge_options *o,
 							 ren1->pair->two->sha1, ren1->pair->two->mode,
 							 dst_other.sha1, dst_other.mode,
 							 branch1, branch2);
-					output(o, 1, "Adding merged %s", ren1_dst);
+					output(o, 1, _("Adding merged %s"), ren1_dst);
 					update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
 					try_merge = 0;
 				} else {
 					char *new_path = unique_path(o, ren1_dst, branch2);
-					output(o, 1, "Adding as %s instead", new_path);
+					output(o, 1, _("Adding as %s instead"), new_path);
 					update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
 					free(new_path);
 				}
@@ -1517,10 +1527,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst)
 	unsigned long size;
 	buf = read_sha1_file(sha1, &type, &size);
 	if (!buf)
-		return error("cannot read object %s", sha1_to_hex(sha1));
+		return error(_("cannot read object %s"), sha1_to_hex(sha1));
 	if (type != OBJ_BLOB) {
 		free(buf);
-		return error("object %s is not a blob", sha1_to_hex(sha1));
+		return error(_("object %s is not a blob"), sha1_to_hex(sha1));
 	}
 	strbuf_attach(dst, buf, size, size + 1);
 	return 0;
@@ -1568,7 +1578,7 @@ static void handle_modify_delete(struct merge_options *o,
 			     o_sha, o_mode,
 			     a_sha, a_mode,
 			     b_sha, b_mode,
-			     "modify", "modified");
+			     _("modify"), _("modified"));
 }
 
 static int merge_content(struct merge_options *o,
@@ -1578,14 +1588,14 @@ static int merge_content(struct merge_options *o,
 			 unsigned char *b_sha, int b_mode,
 			 struct rename_conflict_info *rename_conflict_info)
 {
-	const char *reason = "content";
+	const char *reason = _("content");
 	const char *path1 = NULL, *path2 = NULL;
 	struct merge_file_info mfi;
 	struct diff_filespec one, a, b;
 	unsigned df_conflict_remains = 0;
 
 	if (!o_sha) {
-		reason = "add/add";
+		reason = _("add/add");
 		o_sha = (unsigned char *)null_sha1;
 	}
 	one.path = a.path = b.path = (char *)path;
@@ -1619,7 +1629,7 @@ static int merge_content(struct merge_options *o,
 	if (mfi.clean && !df_conflict_remains &&
 	    sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) {
 		int path_renamed_outside_HEAD;
-		output(o, 3, "Skipped %s (merged same as existing)", path);
+		output(o, 3, _("Skipped %s (merged same as existing)"), path);
 		/*
 		 * The content merge resulted in the same file contents we
 		 * already had.  We can return early if those file contents
@@ -1633,12 +1643,12 @@ static int merge_content(struct merge_options *o,
 			return mfi.clean;
 		}
 	} else
-		output(o, 2, "Auto-merging %s", path);
+		output(o, 2, _("Auto-merging %s"), path);
 
 	if (!mfi.clean) {
 		if (S_ISGITLINK(mfi.mode))
-			reason = "submodule";
-		output(o, 1, "CONFLICT (%s): Merge conflict in %s",
+			reason = _("submodule");
+		output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
 				reason, path);
 		if (rename_conflict_info && !df_conflict_remains)
 			update_stages(path, &one, &a, &b);
@@ -1664,7 +1674,7 @@ static int merge_content(struct merge_options *o,
 
 		}
 		new_path = unique_path(o, path, rename_conflict_info->branch1);
-		output(o, 1, "Adding as %s instead", new_path);
+		output(o, 1, _("Adding as %s instead"), new_path);
 		update_file(o, 0, mfi.sha, mfi.mode, new_path);
 		free(new_path);
 		mfi.clean = 0;
@@ -1728,7 +1738,7 @@ static int process_entry(struct merge_options *o,
 			/* Deleted in both or deleted in one and
 			 * unchanged in the other */
 			if (a_sha)
-				output(o, 2, "Removing %s", path);
+				output(o, 2, _("Removing %s"), path);
 			/* do not touch working file if it did not exist */
 			remove_file(o, 1, path, !a_sha);
 		} else {
@@ -1753,19 +1763,19 @@ static int process_entry(struct merge_options *o,
 			other_branch = o->branch2;
 			mode = a_mode;
 			sha = a_sha;
-			conf = "file/directory";
+			conf = _("file/directory");
 		} else {
 			add_branch = o->branch2;
 			other_branch = o->branch1;
 			mode = b_mode;
 			sha = b_sha;
-			conf = "directory/file";
+			conf = _("directory/file");
 		}
 		if (dir_in_way(path, !o->call_depth)) {
 			char *new_path = unique_path(o, path, add_branch);
 			clean_merge = 0;
-			output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
-			       "Adding %s as %s",
+			output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
+			       "Adding %s as %s"),
 			       conf, path, other_branch, path, new_path);
 			if (o->call_depth)
 				remove_file_from_cache(path);
@@ -1774,7 +1784,7 @@ static int process_entry(struct merge_options *o,
 				remove_file_from_cache(path);
 			free(new_path);
 		} else {
-			output(o, 2, "Adding %s", path);
+			output(o, 2, _("Adding %s"), path);
 			/* do not overwrite file if already present */
 			update_file_flags(o, sha, mode, path, 1, !a_sha);
 		}
@@ -1791,7 +1801,7 @@ static int process_entry(struct merge_options *o,
 		 */
 		remove_file(o, 1, path, !a_mode);
 	} else
-		die("Fatal merge failure, shouldn't happen.");
+		die(_("Fatal merge failure, shouldn't happen."));
 
 	return clean_merge;
 }
@@ -1810,7 +1820,7 @@ int merge_trees(struct merge_options *o,
 	}
 
 	if (sha_eq(common->object.sha1, merge->object.sha1)) {
-		output(o, 0, "Already up-to-date!");
+		output(o, 0, _("Already up-to-date!"));
 		*result = head;
 		return 1;
 	}
@@ -1819,7 +1829,7 @@ int merge_trees(struct merge_options *o,
 
 	if (code != 0) {
 		if (show(o, 4) || o->call_depth)
-			die("merging of trees %s and %s failed",
+			die(_("merging of trees %s and %s failed"),
 			    sha1_to_hex(head->object.sha1),
 			    sha1_to_hex(merge->object.sha1));
 		else
@@ -1849,7 +1859,7 @@ int merge_trees(struct merge_options *o,
 		for (i = 0; i < entries->nr; i++) {
 			struct stage_data *e = entries->items[i].util;
 			if (!e->processed)
-				die("Unprocessed path??? %s",
+				die(_("Unprocessed path??? %s"),
 				    entries->items[i].string);
 		}
 
@@ -1894,7 +1904,7 @@ int merge_recursive(struct merge_options *o,
 	int clean;
 
 	if (show(o, 4)) {
-		output(o, 4, "Merging:");
+		output(o, 4, _("Merging:"));
 		output_commit_title(o, h1);
 		output_commit_title(o, h2);
 	}
@@ -1905,7 +1915,7 @@ int merge_recursive(struct merge_options *o,
 	}
 
 	if (show(o, 5)) {
-		output(o, 5, "found %u common ancestor(s):", commit_list_count(ca));
+		output(o, 5, _("found %u common ancestor(s):"), commit_list_count(ca));
 		for (iter = ca; iter; iter = iter->next)
 			output_commit_title(o, iter->item);
 	}
@@ -1941,7 +1951,7 @@ int merge_recursive(struct merge_options *o,
 		o->call_depth--;
 
 		if (!merged_common_ancestors)
-			die("merge returned no commit");
+			die(_("merge returned no commit"));
 	}
 
 	discard_cache();
@@ -1998,7 +2008,7 @@ int merge_recursive_generic(struct merge_options *o,
 		for (i = 0; i < num_base_list; ++i) {
 			struct commit *base;
 			if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i]))))
-				return error("Could not parse object '%s'",
+				return error(_("Could not parse object '%s'"),
 					sha1_to_hex(base_list[i]));
 			commit_list_insert(base, &ca);
 		}
@@ -2010,7 +2020,7 @@ int merge_recursive_generic(struct merge_options *o,
 	if (active_cache_changed &&
 			(write_cache(index_fd, active_cache, active_nr) ||
 			 commit_locked_index(lock)))
-		return error("Unable to write index.");
+		return error(_("Unable to write index."));
 
 	return clean ? 0 : 1;
 }
t/t6022-merge-rename.sh +8 -8
index 11042..c680f 100755
@@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' '
 	rm -f A M N &&
 	git reset --hard &&
 	git checkout change+rename &&
-	GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
+	GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
 	git reset --hard HEAD^ &&
 	git checkout change &&
-	GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
+	GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
 '
 
 test_expect_success 'setup for rename + d/f conflicts' '
@@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
 	git checkout -q renamed-file-has-no-conflicts^0 &&
 	test_must_fail git merge --strategy=recursive dir-in-way >output &&
 
-	grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
-	grep "Auto-merging dir" output &&
-	grep "Adding as dir~HEAD instead" output &&
+	test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+	test_i18ngrep "Auto-merging dir" output &&
+	test_i18ngrep "Adding as dir~HEAD instead" output &&
 
 	test 3 -eq "$(git ls-files -u | wc -l)" &&
 	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
@@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' '
 	test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
 
 	! grep "error: refusing to lose untracked file at" errors &&
-	grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
-	grep "Auto-merging dir" output &&
-	grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
+	test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+	test_i18ngrep "Auto-merging dir" output &&
+	test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
 
 	test 3 -eq "$(git ls-files -u | wc -l)" &&
 	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
t/t6042-merge-rename-corner-cases.sh +1 -1
index 466fa3..4115 100755
@@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 	git checkout B^0 &&
 
 	test_must_fail git merge -s recursive C^0 >out &&
-	grep "CONFLICT (rename/rename)" out &&
+	test_i18ngrep "CONFLICT (rename/rename)" out &&
 
 	test 2 -eq $(git ls-files -s | wc -l) &&
 	test 2 -eq $(git ls-files -u | wc -l) &&
Signature · 1 line
1.7.12.rc0.16.gf4916ac