{"thread":{"id":"23941","subject":"[PATCH/RFC 0/5] Add internationalization support to Git","startedAt":"2010-05-29T22:45:20Z","lastAt":"2010-06-02T22:33:13Z","messageCount":56,"participants":["Ævar Arnfjörð Bjarmason","Jonathan Nieder","Jakub Narebski","Johannes Sixt","Peter Krefting"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"142541","messageId":"1275173125-21010-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":null,"subject":"[PATCH/RFC 0/5] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:20Z","receivedAt":"2010-05-29T22:45:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Here's an updated version of the patch series begun by Jeff Epler to\nmake Git optionally translatable with GNU gettext. I'm submitting it\nnow because I'd like to get some comments on the approach, and\nspecifically whether something like this is likely to be accepted into\nGit.\n\nChanges since the initial submission:\n\n  * Merged in changes to wt-status.c from the master branch\n\n  * Made Gettext play nice with the build system (.gitignore & make\n    clean)\n\n  * Added support for making Git's shell scripts translatable by\n    importing the gettext functions in git-sh-setup.sh, or supplying\n    replacements if they don't work. Comments from shellscript-savy\n    list members about whether the fallbacks work on odd non-GNU\n    shells are especially welcome.\n\n    I made three strings in git-pull.sh translatable as a proof of\n    concept. One problem that I ran into is that xgettext(1) seems\n    very particular when picking up translation strings. It accepts\n    this:\n\n        gettext \"hello world\"; echo\n\n    but not this:\n\n        die gettext \"hello world\"; die\n\n    or this:\n\n        gettext <<\"END\";\nhello world\nEND\n\n    Maybe there's a way to make it play nice. But I just used a large\n    multiline string as a workaround. I don't know what to do about\n    'die gettext' other than define a 'die_gettext' wrapper function\n    and use `xgettext --keyword=die_gettext'.\n\n  * There's now a skeleton is.po file. It just has one string\n    translated. I can't figure out what to call any of the Git core\n    concepts so I'm stuck :)\n\nNext up:\n\n  * Perl support. I haven't yet found what the best way of using\n    libintl from Perl would be. GNU recommends Locale::TextDomain, but\n    Debian only seems to have Locale::gettext which is a more\n    lightweight wrapper.\n\n    In any case I can write a wrapper for those/the shell command and\n    fall back on the hardcoded strings like the C/Shell code does.\n\nMost importantly. If there are any interested list members that want\nto translate Git, it's now ready for translators. You just have to add\na po/$lang.po file with your favorite editor and Git's build system\nwill install it.\n\nOne thing I haven't done is to try to go ahead and make massive\nchanges to the Git source code to make everything translatable. Due to\ntheir nature it's a big headache to maintain changes like that if\nanything moves upstream.\n\nOf course that's subject to change if other people are interested in\ncontributing.\n\nFor reference, here's the branch on GitHub I'm hacking this in,\npatches welcome:\n\n    http://github.com/avar/git/compare/master...topic/git-gettext\n\nJeff Epler (1):\n  Add infrastructure for translating Git with gettext\n\nÆvar Arnfjörð Bjarmason (4):\n  gitignore: Ignore files generated by gettext\n  Makefile: Remove Gettext files on make clean\n  gettext: Add a skeleton po/is.po\n  Add infrastructure to make shellscripts translatable\n\n .gitignore      |    1 +\n Makefile        |   35 +++++++-\n gettext.c       |   17 ++++\n gettext.h       |   15 +++\n git-pull.sh     |   15 ++--\n git-sh-setup.sh |   33 +++++++\n git.c           |    3 +\n po/.gitignore   |    1 +\n po/is.po        |  288 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n wt-status.c     |  129 +++++++++++++------------\n 10 files changed, 465 insertions(+), 72 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n"},{"id":"142544","messageId":"1275173125-21010-2-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH 1/5] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:21Z","receivedAt":"2010-05-29T22:45:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Jeff Epler <jepler@unpythonic.net>\n\nChange the build process to use GNU's libintl if it's available. If\nnot we define our own skeleton replacement functions which degrade\ngracefully to English.\n\nSigned-off-by: Jeff Epler <jepler@unpythonic.net>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile    |   26 ++++++++++++\n gettext.c   |   17 ++++++++\n gettext.h   |   15 +++++++\n git.c       |    3 +\n wt-status.c |  129 ++++++++++++++++++++++++++++++-----------------------------\n 5 files changed, 126 insertions(+), 64 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n\ndiff --git a/Makefile b/Makefile\nindex d5d6565..7989121 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -297,6 +297,8 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n PTHREAD_LIBS = -lpthread\n+XGETTEXT = xgettext\n+MSGFMT = msgfmt\n \n export TCL_PATH TCLTK_PATH\n \n@@ -523,6 +525,7 @@ LIB_H += userdiff.h\n LIB_H += utf8.h\n LIB_H += xdiff-interface.h\n LIB_H += xdiff/xdiff.h\n+LIB_H += gettext.h\n \n LIB_OBJS += abspath.o\n LIB_OBJS += advice.o\n@@ -564,6 +567,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gettext.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\n@@ -1386,6 +1390,12 @@ ifdef USE_NED_ALLOCATOR\n        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n+ifdef NO_GETTEXT\n+\tCOMPAT_CFLAGS += -DNO_GETTEXT\n+else\n+\tLIBINTL = -lintl\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1415,6 +1425,7 @@ ifndef V\n \tQUIET_BUILT_IN = @echo '   ' BUILTIN $@;\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_SUBDIR0  = +@subdir=\n \tQUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \\\n \t\t\t $(MAKE) $(PRINT_DIR) -C $$subdir\n@@ -1442,6 +1453,7 @@ gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n@@ -1868,6 +1880,17 @@ cscope:\n \t$(RM) cscope*\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n+pot:\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+all:: $(MOFILES)\n+share/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t@mkdir -p $(dir $@)\n+\t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n+\n ### Detect prefix changes\n TRACK_CFLAGS = $(subst ','\\'',$(ALL_CFLAGS)):\\\n              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n@@ -1980,6 +2003,9 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n+\t(cd share && tar cf - locale) | \\\n+\t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\ndiff --git a/gettext.c b/gettext.c\nnew file mode 100644\nindex 0000000..aadce19\n--- /dev/null\n+++ b/gettext.c\n@@ -0,0 +1,17 @@\n+#ifdef NO_GETTEXT\n+void git_setup_gettext() {}\n+#else\n+#include \"exec_cmd.h\"\n+#include <libintl.h>\n+#include <stdlib.h>\n+\n+void git_setup_gettext() {\n+    const char *podir = system_path(\"share/locale\");\n+    if(!podir) return;\n+    char *ret = bindtextdomain(\"git\", podir);\n+    free((void*)podir);\n+    ret = setlocale(LC_MESSAGES, \"\");\n+    ret = setlocale(LC_CTYPE, \"\");\n+    ret = textdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nnew file mode 100644\nindex 0000000..8b221b4\n--- /dev/null\n+++ b/gettext.h\n@@ -0,0 +1,15 @@\n+#ifndef GETTEXT_H\n+#define GETTEXT_H\n+\n+void git_setup_gettext();\n+\n+#ifdef NO_GETTEXT\n+#define _(s) (s)\n+#define N_(s) (s)\n+#else\n+#include <libintl.h>\n+#define _(s) gettext(s)\n+#define N_(s) (s)\n+#endif\n+\n+#endif\ndiff --git a/git.c b/git.c\nindex 99f0363..d749eab 100644\n--- a/git.c\n+++ b/git.c\n@@ -3,6 +3,7 @@\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"run-command.h\"\n+#include \"gettext.h\"\n \n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\\n\"\n@@ -490,6 +491,8 @@ int main(int argc, const char **argv)\n \tif (!cmd)\n \t\tcmd = \"git-help\";\n \n+\tgit_setup_gettext();\n+\n \t/*\n \t * \"git-xxxx\" is the same as \"git xxxx\", but we obviously:\n \t *\ndiff --git a/wt-status.c b/wt-status.c\nindex 14e0acc..70b4293 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"run-command.h\"\n #include \"remote.h\"\n+#include \"gettext.h\"\n \n static char default_wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL, /* WT_STATUS_HEADER */\n@@ -49,33 +50,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Unmerged paths:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t;\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changes to be committed:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_dirty_header(struct wt_status *s,\n@@ -84,17 +85,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changed but not updated:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changed but not updated:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (!has_deleted)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to update what will be committed)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add <file>...\\\" to update what will be committed)\"));\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n \tif (has_dirty_submodules)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (commit or discard the untracked or modified content in submodules)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_other_header(struct wt_status *s,\n@@ -102,16 +103,16 @@ static void wt_status_print_other_header(struct wt_status *s,\n \t\t\t\t\t const char *how)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n-\tcolor_fprintf_ln(s->fp, c, \"# %s files:\", what);\n+\tcolor_fprintf_ln(s->fp, c, _(\"# %s files:\"), what);\n \tif (!advice_status_hints)\n \t\treturn;\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\", how);\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_trailer(struct wt_status *s)\n {\n-\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n }\n \n #define quote_path quote_path_relative\n@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,\n \tconst char *c = color(WT_STATUS_UNMERGED, s);\n \tstruct wt_status_change_data *d = it->util;\n \tstruct strbuf onebuf = STRBUF_INIT;\n-\tconst char *one, *how = \"bug\";\n+\tconst char *one, *how = _(\"bug\");\n \n \tone = quote_path(it->string, -1, &onebuf, s->prefix);\n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (d->stagemask) {\n-\tcase 1: how = \"both deleted:\"; break;\n-\tcase 2: how = \"added by us:\"; break;\n-\tcase 3: how = \"deleted by them:\"; break;\n-\tcase 4: how = \"added by them:\"; break;\n-\tcase 5: how = \"deleted by us:\"; break;\n-\tcase 6: how = \"both added:\"; break;\n-\tcase 7: how = \"both modified:\"; break;\n+\tcase 1: how = _(\"both deleted:\"); break;\n+\tcase 2: how = _(\"added by us:\"); break;\n+\tcase 3: how = _(\"deleted by them:\"); break;\n+\tcase 4: how = _(\"added by them:\"); break;\n+\tcase 5: how = _(\"deleted by us:\"); break;\n+\tcase 6: how = _(\"both added:\"); break;\n+\tcase 7: how = _(\"both modified:\"); break;\n \t}\n-\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n+\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n \tstrbuf_release(&onebuf);\n }\n \n@@ -161,13 +162,13 @@ static void wt_status_print_change_data(struct wt_status *s,\n \t\tbreak;\n \tcase WT_STATUS_CHANGED:\n \t\tif (d->new_submodule_commits || d->dirty_submodule) {\n-\t\t\tstrbuf_addstr(&extra, \" (\");\n+\t\t\tstrbuf_addstr(&extra, _(\" (\"));\n \t\t\tif (d->new_submodule_commits)\n-\t\t\t\tstrbuf_addf(&extra, \"new commits, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"new commits, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n-\t\t\t\tstrbuf_addf(&extra, \"modified content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"modified content, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n-\t\t\t\tstrbuf_addf(&extra, \"untracked content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"untracked content, \"));\n \t\t\tstrbuf_setlen(&extra, extra.len - 2);\n \t\t\tstrbuf_addch(&extra, ')');\n \t\t}\n@@ -178,40 +179,40 @@ static void wt_status_print_change_data(struct wt_status *s,\n \tone = quote_path(one_name, -1, &onebuf, s->prefix);\n \ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"new file:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"copied:     %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"deleted:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"modified:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"renamed:    %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"typechange: %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unknown:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unmerged:   %s\"), one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", status);\n+\t\tdie(_(\"bug: unhandled diff status %c\"), status);\n \t}\n \tif (extra.len) {\n-\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"), extra.buf);\n \t\tstrbuf_release(&extra);\n \t}\n-\tfprintf(s->fp, \"\\n\");\n+\tfprintf(s->fp, _(\"\\n\"));\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)\n \tconst char *branch_color = color(WT_STATUS_HEADER, s);\n \n \tif (s->branch) {\n-\t\tconst char *on_what = \"On branch \";\n+\t\tconst char *on_what = _(\"On branch \");\n \t\tconst char *branch_name = s->branch;\n \t\tif (!prefixcmp(branch_name, \"refs/heads/\"))\n \t\t\tbranch_name += 11;\n \t\telse if (!strcmp(branch_name, \"HEAD\")) {\n \t\t\tbranch_name = \"\";\n \t\t\tbranch_color = color(WT_STATUS_NOBRANCH, s);\n-\t\t\ton_what = \"Not currently on any branch.\";\n+\t\t\ton_what = _(\"Not currently on any branch.\");\n \t\t}\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"# \");\n \t\tcolor_fprintf_ln(s->fp, branch_color, \"%s%s\", on_what, branch_name);\n@@ -634,9 +635,9 @@ void wt_status_print(struct wt_status *s)\n \t}\n \n \tif (s->is_initial) {\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"# Initial commit\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n \t}\n \n \twt_status_print_updated(s);\n@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_submodule_summary(s, 1);  /* unstaged */\n \t}\n \tif (s->show_untracked_files) {\n-\t\twt_status_print_other(s, &s->untracked, \"Untracked\", \"add\");\n+\t\twt_status_print_other(s, &s->untracked, _(\"Untracked\"), _(\"add\"));\n \t\tif (s->show_ignored_files)\n-\t\t\twt_status_print_other(s, &s->ignored, \"Ignored\", \"add -f\");\n+\t\t\twt_status_print_other(s, &s->ignored, _(\"Ignored\"), _(\"add -f\"));\n \t} else if (s->commitable)\n-\t\tfprintf(s->fp, \"# Untracked files not listed%s\\n\",\n+\t\tfprintf(s->fp, _(\"# Untracked files not listed%s\\n\"),\n \t\t\tadvice_status_hints\n-\t\t\t? \" (use -u option to show untracked files)\" : \"\");\n+\t\t\t? _(\" (use -u option to show untracked files)\") : \"\");\n \n \tif (s->verbose)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tfprintf(s->fp, \"# No changes\\n\");\n+\t\t\tfprintf(s->fp, _(\"# No changes\\n\"));\n \t\telse if (s->nowarn)\n \t\t\t; /* nothing */\n \t\telse if (s->workdir_dirty)\n-\t\t\tprintf(\"no changes added to commit%s\\n\",\n+\t\t\tprintf(_(\"no changes added to commit%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\") : \"\");\n \t\telse if (s->untracked.nr)\n-\t\t\tprintf(\"nothing added to commit but untracked files present%s\\n\",\n+\t\t\tprintf(_(\"nothing added to commit but untracked files present%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (s->is_initial)\n \t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (create/copy files and use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (create/copy files and use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (!s->show_untracked_files)\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (use -u to show untracked files)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (use -u to show untracked files)\") : \"\");\n \t\telse\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (working directory clean)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (working directory clean)\") : \"\");\n \t}\n }\n \n-- \n1.7.1.242.ge2b63.dirty\n"},{"id":"142542","messageId":"1275173125-21010-3-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH 2/5] gitignore: Ignore files generated by gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:22Z","receivedAt":"2010-05-29T22:45:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"  - Ignore po/git.pot which is autogenerated by a manual run of the\n    Makefile. We're only interested in tracking the po/*.po files.\n\n  - Ignore the /share/ directory. It's created during installation and\n    contains gettext-related files to be installed.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore    |    1 +\n po/.gitignore |    1 +\n 2 files changed, 2 insertions(+), 0 deletions(-)\n create mode 100644 po/.gitignore\n\ndiff --git a/.gitignore b/.gitignore\nindex 14e2b6b..d22c0e5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -204,3 +204,4 @@\n *.pdb\n /Debug/\n /Release/\n+/share/\ndiff --git a/po/.gitignore b/po/.gitignore\nnew file mode 100644\nindex 0000000..221000e\n--- /dev/null\n+++ b/po/.gitignore\n@@ -0,0 +1 @@\n+/*.pot\n-- \n1.7.1.242.ge2b63.dirty\n"},{"id":"142543","messageId":"1275173125-21010-4-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH 3/5] Makefile: Remove Gettext files on make clean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:23Z","receivedAt":"2010-05-29T22:45:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the automatically generated po/git.pot and share/\nfiles. They're created by the gettext installation process.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 7989121..4de0627 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2153,6 +2153,10 @@ ifndef NO_TCLTK\n \t$(MAKE) -C git-gui clean\n endif\n \t$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS\n+ifndef NO_GETTEXT\n+\t$(RM) po/git.pot\n+\t$(RM) -r share/\n+endif\n \n .PHONY: all install clean strip\n .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell\n-- \n1.7.1.242.ge2b63.dirty\n"},{"id":"142545","messageId":"1275173125-21010-5-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH 4/5] gettext: Add a skeleton po/is.po","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:24Z","receivedAt":"2010-05-29T22:45:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n po/is.po |  288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 288 insertions(+), 0 deletions(-)\n create mode 100644 po/is.po\n\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..4aac4e9\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,288 @@\n+# SOME DESCRIPTIVE TITLE.\n+# Copyright (C) YEAR Free Software Foundation, Inc.\n+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n+#\n+#, fuzzy\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: PACKAGE VERSION\\n\"\n+\"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\\n\"\n+\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n+\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=CHARSET\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\n+# SOME DESCRIPTIVE TITLE.#~ \n+# Copyright (C) YEAR Free Software Foundation, Inc.#~ \n+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.#~ \n+##~ \n+#, fuzzy#~ \n+msgid \"\"#~ \n+msgstr \"\"#~ \n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2010-05-29 21:17+0000\\n\"\n+\"PO-Revision-Date: \\n\"\n+\"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n+\"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"X-Poedit-Language: English\\n\"\n+\"X-Poedit-SourceCharset: utf-8\\n\"\n+\n+#: wt-status.c:53\n+msgid \"# Unmerged paths:\"\n+msgstr \"\"\n+\n+#: wt-status.c:59 wt-status.c:76\n+#, c-format\n+msgid \"#   (use \\\"git reset %s <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:61 wt-status.c:78\n+msgid \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:62\n+msgid \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"\n+msgstr \"\"\n+\n+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110\n+#: wt-status.c:115 wt-status.c:638 wt-status.c:640\n+msgid \"#\"\n+msgstr \"\"\n+\n+#: wt-status.c:70\n+msgid \"# Changes to be committed:\"\n+msgstr \"\"\n+\n+#: wt-status.c:88\n+msgid \"# Changed but not updated:\"\n+msgstr \"\"\n+\n+#: wt-status.c:92\n+msgid \"#   (use \\\"git add <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:94\n+msgid \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:95\n+msgid \"\"\n+\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working \"\n+\"directory)\"\n+msgstr \"\"\n+\n+#: wt-status.c:97\n+msgid \"#   (commit or discard the untracked or modified content in submodules)\"\n+msgstr \"\"\n+\n+#: wt-status.c:106\n+#, c-format\n+msgid \"# %s files:\"\n+msgstr \"\"\n+\n+#: wt-status.c:109\n+#, c-format\n+msgid \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:126\n+msgid \"bug\"\n+msgstr \"\"\n+\n+#: wt-status.c:129 wt-status.c:182\n+msgid \"#\\t\"\n+msgstr \"\"\n+\n+#: wt-status.c:131\n+msgid \"both deleted:\"\n+msgstr \"\"\n+\n+#: wt-status.c:132\n+msgid \"added by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:133\n+msgid \"deleted by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:134\n+msgid \"added by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:135\n+msgid \"deleted by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:136\n+msgid \"both added:\"\n+msgstr \"\"\n+\n+#: wt-status.c:137\n+msgid \"both modified:\"\n+msgstr \"\"\n+\n+#: wt-status.c:139\n+#, c-format\n+msgid \"%-20s%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:165\n+msgid \" (\"\n+msgstr \"\"\n+\n+#: wt-status.c:167\n+msgid \"new commits, \"\n+msgstr \"\"\n+\n+#: wt-status.c:169\n+msgid \"modified content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:171\n+msgid \"untracked content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:185\n+#, c-format\n+msgid \"new file:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:188\n+#, c-format\n+msgid \"copied:     %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:191\n+#, c-format\n+msgid \"deleted:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:194\n+#, c-format\n+msgid \"modified:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:197\n+#, c-format\n+msgid \"renamed:    %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:200\n+#, c-format\n+msgid \"typechange: %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:203\n+#, c-format\n+msgid \"unknown:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:206\n+#, c-format\n+msgid \"unmerged:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:209\n+#, c-format\n+msgid \"bug: unhandled diff status %c\"\n+msgstr \"\"\n+\n+#: wt-status.c:212\n+#, c-format\n+msgid \"%s\"\n+msgstr \"\"\n+\n+#: wt-status.c:215\n+#, c-format\n+msgid \"\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:622\n+msgid \"On branch \"\n+msgstr \"Á greininni \"\n+\n+#: wt-status.c:629\n+msgid \"Not currently on any branch.\"\n+msgstr \"Ekki á neinni grein.\"\n+\n+#: wt-status.c:639\n+msgid \"# Initial commit\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"Untracked\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"add\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"Ignored\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"add -f\"\n+msgstr \"\"\n+\n+#: wt-status.c:655\n+#, c-format\n+msgid \"# Untracked files not listed%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:657\n+msgid \" (use -u option to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:663\n+#, c-format\n+msgid \"# No changes\\n\"\n+msgstr \"# Engar breytingar\\n\"\n+\n+#: wt-status.c:667\n+#, c-format\n+msgid \"no changes added to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:669\n+msgid \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\"\n+msgstr \"\"\n+\n+#: wt-status.c:671\n+#, c-format\n+msgid \"nothing added to commit but untracked files present%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:673\n+msgid \" (use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:676\n+msgid \" (create/copy files and use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:678 wt-status.c:681\n+#, c-format\n+msgid \"nothing to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:679\n+msgid \" (use -u to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:682\n+msgid \" (working directory clean)\"\n+msgstr \"\"\n+\n+#: git-pull.sh:124\n+msgid \"Fetching tags only, you probably meant:\"\n+msgstr \"\"\n+\n+#: git-pull.sh:125\n+msgid \"  git fetch --tags\"\n+msgstr \"\"\n-- \n1.7.1.242.ge2b63.dirty\n"},{"id":"142546","messageId":"1275173125-21010-6-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH 5/5] Add infrastructure to make shellscripts translatable","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-29T22:45:25Z","receivedAt":"2010-05-29T22:45:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use GNU's gettext.sh in git-sh-setup if it's available, otherwise\nfallback on our own custom functions.\n\nA couple of strings in git-pull.sh are now translatable as a proof of\nconcept, including a multiline string.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile        |    7 +++++--\n git-pull.sh     |   15 ++++++++-------\n git-sh-setup.sh |   33 +++++++++++++++++++++++++++++++++\n 3 files changed, 46 insertions(+), 9 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 4de0627..dce2faa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -272,6 +272,7 @@ mandir = share/man\n infodir = share/info\n gitexecdir = libexec/git-core\n sharedir = $(prefix)/share\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ifeq ($(prefix),/usr)\n@@ -285,7 +286,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir\n+export prefix bindir sharedir localedir sysconfdir\n \n CC = gcc\n AR = ar\n@@ -1455,6 +1456,7 @@ htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n+LOCALEDIR_SQ = $(subst ','\\'',$(localedir))\n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n PYTHON_PATH_SQ = $(subst ','\\'',$(PYTHON_PATH))\n@@ -1548,6 +1550,7 @@ $(RM) $@ $@+ && \\\n sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n+    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \\\n     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \\\n     -e $(BROKEN_PATH_FIX) \\\n     $@.sh >$@+\n@@ -1881,7 +1884,7 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 1a4729f..22a6da2 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -121,8 +121,8 @@ error_on_no_merge_candidates () {\n \tdo\n \t\tcase \"$opt\" in\n \t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"Fetching tags only, you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n+\t\t\tgettext \"Fetching tags only, you probably meant:\"; echo\n+\t\t\tgettext \"  git fetch --tags\"; echo\n \t\t\texit 1\n \t\tesac\n \tdone\n@@ -154,11 +154,12 @@ error_on_no_merge_candidates () {\n \t\techo \"a branch. Because this is not the default configured remote\"\n \t\techo \"for your current branch, you must specify a branch on the command line.\"\n \telif [ -z \"$curr_branch\" ]; then\n-\t\techo \"You are not currently on a branch, so I cannot use any\"\n-\t\techo \"'branch.<branchname>.merge' in your configuration file.\"\n-\t\techo \"Please specify which remote branch you want to use on the command\"\n-\t\techo \"line and try again (e.g. 'git pull <repository> <refspec>').\"\n-\t\techo \"See git-pull(1) for details.\"\n+        gettext \"You are not currently on a branch, so I cannot use any\n+'branch.<branchname>.merge' in your configuration file.\n+Please specify which remote branch you want to use on the command\n+line and try again (e.g. 'git pull <repository> <refspec>').\n+See git-pull(1) for details.\";\n+        echo\n \telif [ -z \"$upstream\" ]; then\n \t\techo \"You asked me to pull without telling me which branch you\"\n \t\techo \"want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in\"\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex 6131670..c8010f2 100644\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -211,3 +211,36 @@ case $(uname -s) in\n \t}\n \t;;\n esac\n+\n+# Try to use libintl's gettext.sh, or fall back to English if we\n+# can't.\n+. gettext.sh\n+if test $? -ne 0\n+then\n+    TEXTDOMAIN=git\n+    export TEXDTOMAIN\n+    TEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+    export TEXTDOMAINDIR\n+else\n+    # Since GNU gettext.sh isn't available we'll have to define our\n+    # own dummy functions.\n+\n+    # This code adapted from NessusClient-1.0.2's nessusclient-mkcert\n+    # by Michel Arboi <arboi@alussinan.org>. The original code is\n+    # under the GPLv2.\n+\n+    # Not everyone has echo -n\n+    case $(echo -n) in\n+        \\-n)    Xn=   ; Xc='\\c' ;;\n+        *)      Xn=-n ; Xc=\n+    esac\n+\n+    gettext () {\n+        echo $Xn \"$1\" $Xc\n+    }\n+\n+    eval_gettext () {\n+        eval_gettext_var=\"echo $1\"\n+        echo $Xn `eval $eval_gettext_var` $Xc\n+    }\n+fi\n-- \n1.7.1.242.ge2b63.dirty\n"},{"id":"142549","messageId":"20100530014607.GA27387@progeny.tock","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC 0/5] Add internationalization support to Git","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-05-30T01:46:07Z","receivedAt":"2010-05-30T01:46:07Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi Ævar,\n\nÆvar Arnfjörð Bjarmason wrote:\n\n>     I made three strings in git-pull.sh translatable as a proof of\n>     concept. One problem that I ran into is that xgettext(1) seems\n>     very particular when picking up translation strings. It accepts\n>     this:\n> \n>         gettext \"hello world\"; echo\n\nDoes ‘gettext -s \"hello world\"’ work, too?  (Just curious.)\n\n>     but not this:\n[...]\n> \n>         gettext <<\"END\";\n> hello world\n> END\n> \n>     Maybe there's a way to make it play nice. But I just used a large\n>     multiline string as a workaround.\n\nNot so nice, but it seems that gettext expects a message id as\nan argument (i.e., it will only replace echo and not cat).\n\n>     I don't know what to do about\n>     'die gettext' other than define a 'die_gettext' wrapper function\n>     and use `xgettext --keyword=die_gettext'.\n\nSounds sensible.\n\n> One thing I haven't done is to try to go ahead and make massive\n> changes to the Git source code to make everything translatable.\n\nI am vaguely worried about performance.  Suppose a function does\n\n\tfor (i = 0; i < 1000000; i++)\n\t\tprintf(_(\"Some interesting label: %s\\n\"), foo(i));\n\nWill this compile to the equivalent of\n\n\tconst char *s = _(\"Some interesting label: %s\\n\");\n\tfor (i = 0; i < 1000000; i++)\n\t\tprintf(s, foo(i));\n\nSuppose someone decides to make that change by hand (maybe the\nloop is too large for the compiler to notice the potential\nwinnings).  Then presumably gcc cannot be able to type-check the\nformat any more.  Is there some way around this that avoids\nboth speed regressions and loss of type-safety?\n\nApologies if this was already answered in the earlier discussion.\n\nThanks,\nJonathan\n"},{"id":"142577","messageId":"AANLkTimI5xGiq_GNF_H2bOLECw0NxOiCPsnRqOS39H32@mail.gmail.com","threadId":"23941","inReplyTo":"20100530014607.GA27387@progeny.tock","subject":"Re: [PATCH/RFC 0/5] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T16:04:07Z","receivedAt":"2010-05-30T16:04:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sun, May 30, 2010 at 01:46, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Hi Ævar,\n\nHi, and thanks for taking the time to review this.\n\n> Ævar Arnfjörð Bjarmason wrote:\n>\n>>     I made three strings in git-pull.sh translatable as a proof of\n>>     concept. One problem that I ran into is that xgettext(1) seems\n>>     very particular when picking up translation strings. It accepts\n>>     this:\n>>\n>>         gettext \"hello world\"; echo\n>\n> Does ‘gettext -s \"hello world\"’ work, too?  (Just curious.)\n\nNo, that just makes \"-s\" translatable. Even options that gettext\naccepts don't work either, you have to use eval_gettext \"\\$foo\"\ninstead of gettext -e \"\\$foo\". The xgettext program is quite naïve\nlike that.\n\n>>     but not this:\n> [...]\n>>\n>>         gettext <<\"END\";\n>> hello world\n>> END\n>>\n>>     Maybe there's a way to make it play nice. But I just used a large\n>>     multiline string as a workaround.\n>\n> Not so nice, but it seems that gettext expects a message id as\n> an argument (i.e., it will only replace echo and not cat).\n\nYes. I mailed the maintainer about this. gettext would need to accept\ntext on STDIN and xgettext would need to find the messages for it to\nwork.\n\nIn the meantime we could just use multiline strings. It works for the\ntest suite.\n\n>>     I don't know what to do about\n>>     'die gettext' other than define a 'die_gettext' wrapper function\n>>     and use `xgettext --keyword=die_gettext'.\n>\n> Sounds sensible.\n>\n>> One thing I haven't done is to try to go ahead and make massive\n>> changes to the Git source code to make everything translatable.\n>\n> I am vaguely worried about performance.  Suppose a function does\n>\n>        for (i = 0; i < 1000000; i++)\n>                printf(_(\"Some interesting label: %s\\n\"), foo(i));\n>\n> Will this compile to the equivalent of\n>\n>        const char *s = _(\"Some interesting label: %s\\n\");\n>        for (i = 0; i < 1000000; i++)\n>                printf(s, foo(i));\n>\n> Suppose someone decides to make that change by hand (maybe the\n> loop is too large for the compiler to notice the potential\n> winnings).  Then presumably gcc cannot be able to type-check the\n> format any more.  Is there some way around this that avoids\n> both speed regressions and loss of type-safety?\n\nAny level of indirection is of course going to be slower, there's no\nway around that. I made two test programs to test this out:\n\ntest-in-loop.c:\n\n    #include <stdio.h>\n    #include <stdlib.h>\n    #include <locale.h>\n    #include <libintl.h>\n\n    #define _(s) gettext(s)\n\n    int foo(long int x) {\n        return x * x;\n    }\n\n    int main(void) {\n        const char *podir = \"/usr/local/share/locale\";\n        if(!podir) puts(\"zomg error\");\n        char *ret = bindtextdomain(\"git\", podir);\n        ret = setlocale(LC_MESSAGES, \"\");\n        ret = setlocale(LC_CTYPE, \"\");\n        ret = textdomain(\"git\");\n\n        for (long int i = 0; i < 10000000; i++) {\n            printf(_(\"Some interesting label: %ld\\n\"), foo(i));\n        }\n\n        return 0;\n    }\n\ntest-outside-loop.c:\n\n    #include <stdio.h>\n    #include <stdlib.h>\n    #include <locale.h>\n    #include <libintl.h>\n\n    #define _(s) gettext(s)\n\n    int foo(long int x) {\n        return x * x;\n    }\n\n    int main(void) {\n        const char *podir = \"/usr/local/share/locale\";\n        if(!podir) puts(\"zomg error\");\n        char *ret = bindtextdomain(\"git\", podir);\n        ret = setlocale(LC_MESSAGES, \"\");\n        ret = setlocale(LC_CTYPE, \"\");\n        ret = textdomain(\"git\");\n\n        const char *s = _(\"Some interesting label: %ld\\n\");\n        for (long int i = 0; i < 10000000; i++)\n            printf(s, foo(i));\n\n        return 0;\n    }\n\nNote that I use 10 million iterations, not 1 million like in your\nexample.\n\nHere's how they compile:\n\n    $ gcc -std=c99 -o test-in-loop test-in-loop.c ; gcc -std=c99 -o\ntest-outside-loop test-outside-loop.c\n    test-in-loop.c: In function ‘main’:\n    test-in-loop.c:21: warning: format ‘%ld’ expects type ‘long int’,\nbut argument 2 has type ‘int’\n\nI.e. your concerns are valid. GCC won't catch an invalid format\nspecifier in this case.\n\nAnd even though gettext tries to make cases like these fast\n(http://www.gnu.org/software/hello/manual/gettext/Optimized-gettext.html)\nit's still a lot slower than hardcoded English:\n\n    perl -MBenchmark=:all -MData::Dump=dump -E 'cmpthese(10, {\n         outside => sub { system \"./test-outside-loop >/dev/null\" },\n         inside =>  sub { system \"./test-in-loop >/dev/null\" },\n    });'\n\n            s/iter  inside outside\n    inside    13.4      --    -83%\n    outside   2.26    495%      --\n\n> Apologies if this was already answered in the earlier discussion.\n\nWhat you can do (and this was covered) is to use msgfmt to check that\nno translations use different format specifiers. But hopefully cases\nwhere you have messages like these in tight loops and the message\nlookup itself is a significant contributor to the program time will be\nso rare as to not be an issue.\n"},{"id":"142586","messageId":"1275252857-21593-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 0/6] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:11Z","receivedAt":"2010-05-30T20:54:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Here's version 2 of the patch series begun by Jeff Epler to make Git\noptionally translatable with GNU gettext.\n\nDue to an error of mine only the cover letter of the previous series\nhad \"PATCH/RFC\" in the subject line. That's rectified in this series.\n\nAside from making sure the test suite always runs under LC_ALL=C,\nsanity tests for the translations, \"how to translate\" documentation,\nand the Perl Makefile issue noted below, this series is pretty much\nready for inclusion in my opinion. Perl support was the last missing\npiece for translating all of the core C+Shell+Perl code.\n\nNew stuff:\n\n  * Perl scripts are now translatable through the Gettext\n    facility. Like the shellscript facility I added this has a\n    graceful fallback if the prerequisite libraries aren't installed.\n\n    I'm using the libintl-perl library which provides\n    Locale::Messages. I could also have used liblocale-gettext-perl\n    which provides Locale::gettext. Debian seems to prefer the latter,\n    but the former is recomended by GNU. The new Git::Gettext library\n    could probably be modified to try both.\n\n    It works 100% for me. Aside from this bit:\n    \n    \t# TODO: How do I make the sed replacements in the top level\n    \t# Makefile reach me here?\n    \t#our $TEXTDOMAINDIR = q|@@LOCALEDIR@@|;\n    \tour $TEXTDOMAINDIR = q</usr/local/share/locale>;\n\n    I couldn't figure out how to make the sed substitution the core\n    /Makefile does for e.g. @@GIT_VERSION@@ work for the hybrid\n    Makefile / perl.mak setup in perl/.\n\n    Suggestions from contributors more familiar with Git's build\n    system welcome.\n\n  * Another thing to note regarding Perl. We have some Perl code\n    that's obviously intended to work with perls as old as 5.6. It\n    would be preferable to translation support if the minimum were\n    bumped to 5.8. Here's why:\n\n        $ perl -e 'printf \"%2\\$s the %1\\$s has\\n\", (\"Clone War\", \"Begun\")'\n        Begun the Clone War has\n\n    Perl 5.6's printf doesn't support that printf syntax, which means\n    that translators would have to make do with the word order of the\n    English messages.\n\n    I haven't seen any documentation about Perl coding guidelines or\n    Perl versions that we aim to support in Documentation/, so I don't\n    know if 5.6 is supposed to be supported or whether the support is\n    just incidental.\n\n    Note that this 5.8 could only be a requirement if the user was\n    using a translation with positional printf formats. Users\n    interested in running the English-only version could still do so\n    on 5.6.\n\n  * Updated is.po. It now contains example translations for C, Shell\n    and Perl programs as a proof of concept.\n\n  * Rewrote the commit message of the shell script support commit to\n    use use the gettext: prefix.\n    \nJeff Epler (1):\n  Add infrastructure for translating Git with gettext\n\nÆvar Arnfjörð Bjarmason (5):\n  gitignore: Ignore files generated by gettext\n  Makefile: Remove Gettext files on make clean\n  gettext: Add a Gettext interface for shell scripts\n  gettext: Add a Gettext interface for Perl\n  gettext: Add a skeleton po/is.po\n\n .gitignore          |    1 +\n Makefile            |   37 +++++++-\n gettext.c           |   17 +++\n gettext.h           |   15 +++\n git-pull.sh         |   15 ++--\n git-send-email.perl |    3 +-\n git-sh-setup.sh     |   33 ++++++\n git.c               |    3 +\n perl/Git/Gettext.pm |   83 +++++++++++++++\n perl/Makefile.PL    |    5 +-\n po/.gitignore       |    1 +\n po/is.po            |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++\n wt-status.c         |  129 ++++++++++++------------\n 13 files changed, 550 insertions(+), 74 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 perl/Git/Gettext.pm\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n"},{"id":"142585","messageId":"1275252857-21593-2-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 1/6] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:12Z","receivedAt":"2010-05-30T20:54:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Jeff Epler <jepler@unpythonic.net>\n\nChange the build process to use GNU's libintl if it's available. If\nnot we define our own skeleton replacement functions which degrade\ngracefully to English.\n\nSigned-off-by: Jeff Epler <jepler@unpythonic.net>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile    |   26 ++++++++++++\n gettext.c   |   17 ++++++++\n gettext.h   |   15 +++++++\n git.c       |    3 +\n wt-status.c |  129 ++++++++++++++++++++++++++++++-----------------------------\n 5 files changed, 126 insertions(+), 64 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n\ndiff --git a/Makefile b/Makefile\nindex d5d6565..7989121 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -297,6 +297,8 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n PTHREAD_LIBS = -lpthread\n+XGETTEXT = xgettext\n+MSGFMT = msgfmt\n \n export TCL_PATH TCLTK_PATH\n \n@@ -523,6 +525,7 @@ LIB_H += userdiff.h\n LIB_H += utf8.h\n LIB_H += xdiff-interface.h\n LIB_H += xdiff/xdiff.h\n+LIB_H += gettext.h\n \n LIB_OBJS += abspath.o\n LIB_OBJS += advice.o\n@@ -564,6 +567,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gettext.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\n@@ -1386,6 +1390,12 @@ ifdef USE_NED_ALLOCATOR\n        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n+ifdef NO_GETTEXT\n+\tCOMPAT_CFLAGS += -DNO_GETTEXT\n+else\n+\tLIBINTL = -lintl\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1415,6 +1425,7 @@ ifndef V\n \tQUIET_BUILT_IN = @echo '   ' BUILTIN $@;\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_SUBDIR0  = +@subdir=\n \tQUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \\\n \t\t\t $(MAKE) $(PRINT_DIR) -C $$subdir\n@@ -1442,6 +1453,7 @@ gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n@@ -1868,6 +1880,17 @@ cscope:\n \t$(RM) cscope*\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n+pot:\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+all:: $(MOFILES)\n+share/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t@mkdir -p $(dir $@)\n+\t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n+\n ### Detect prefix changes\n TRACK_CFLAGS = $(subst ','\\'',$(ALL_CFLAGS)):\\\n              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n@@ -1980,6 +2003,9 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n+\t(cd share && tar cf - locale) | \\\n+\t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\ndiff --git a/gettext.c b/gettext.c\nnew file mode 100644\nindex 0000000..aadce19\n--- /dev/null\n+++ b/gettext.c\n@@ -0,0 +1,17 @@\n+#ifdef NO_GETTEXT\n+void git_setup_gettext() {}\n+#else\n+#include \"exec_cmd.h\"\n+#include <libintl.h>\n+#include <stdlib.h>\n+\n+void git_setup_gettext() {\n+    const char *podir = system_path(\"share/locale\");\n+    if(!podir) return;\n+    char *ret = bindtextdomain(\"git\", podir);\n+    free((void*)podir);\n+    ret = setlocale(LC_MESSAGES, \"\");\n+    ret = setlocale(LC_CTYPE, \"\");\n+    ret = textdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nnew file mode 100644\nindex 0000000..8b221b4\n--- /dev/null\n+++ b/gettext.h\n@@ -0,0 +1,15 @@\n+#ifndef GETTEXT_H\n+#define GETTEXT_H\n+\n+void git_setup_gettext();\n+\n+#ifdef NO_GETTEXT\n+#define _(s) (s)\n+#define N_(s) (s)\n+#else\n+#include <libintl.h>\n+#define _(s) gettext(s)\n+#define N_(s) (s)\n+#endif\n+\n+#endif\ndiff --git a/git.c b/git.c\nindex 99f0363..d749eab 100644\n--- a/git.c\n+++ b/git.c\n@@ -3,6 +3,7 @@\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"run-command.h\"\n+#include \"gettext.h\"\n \n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\\n\"\n@@ -490,6 +491,8 @@ int main(int argc, const char **argv)\n \tif (!cmd)\n \t\tcmd = \"git-help\";\n \n+\tgit_setup_gettext();\n+\n \t/*\n \t * \"git-xxxx\" is the same as \"git xxxx\", but we obviously:\n \t *\ndiff --git a/wt-status.c b/wt-status.c\nindex 14e0acc..70b4293 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"run-command.h\"\n #include \"remote.h\"\n+#include \"gettext.h\"\n \n static char default_wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL, /* WT_STATUS_HEADER */\n@@ -49,33 +50,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Unmerged paths:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t;\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changes to be committed:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_dirty_header(struct wt_status *s,\n@@ -84,17 +85,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changed but not updated:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changed but not updated:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (!has_deleted)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to update what will be committed)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add <file>...\\\" to update what will be committed)\"));\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n \tif (has_dirty_submodules)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (commit or discard the untracked or modified content in submodules)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_other_header(struct wt_status *s,\n@@ -102,16 +103,16 @@ static void wt_status_print_other_header(struct wt_status *s,\n \t\t\t\t\t const char *how)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n-\tcolor_fprintf_ln(s->fp, c, \"# %s files:\", what);\n+\tcolor_fprintf_ln(s->fp, c, _(\"# %s files:\"), what);\n \tif (!advice_status_hints)\n \t\treturn;\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\", how);\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_trailer(struct wt_status *s)\n {\n-\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n }\n \n #define quote_path quote_path_relative\n@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,\n \tconst char *c = color(WT_STATUS_UNMERGED, s);\n \tstruct wt_status_change_data *d = it->util;\n \tstruct strbuf onebuf = STRBUF_INIT;\n-\tconst char *one, *how = \"bug\";\n+\tconst char *one, *how = _(\"bug\");\n \n \tone = quote_path(it->string, -1, &onebuf, s->prefix);\n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (d->stagemask) {\n-\tcase 1: how = \"both deleted:\"; break;\n-\tcase 2: how = \"added by us:\"; break;\n-\tcase 3: how = \"deleted by them:\"; break;\n-\tcase 4: how = \"added by them:\"; break;\n-\tcase 5: how = \"deleted by us:\"; break;\n-\tcase 6: how = \"both added:\"; break;\n-\tcase 7: how = \"both modified:\"; break;\n+\tcase 1: how = _(\"both deleted:\"); break;\n+\tcase 2: how = _(\"added by us:\"); break;\n+\tcase 3: how = _(\"deleted by them:\"); break;\n+\tcase 4: how = _(\"added by them:\"); break;\n+\tcase 5: how = _(\"deleted by us:\"); break;\n+\tcase 6: how = _(\"both added:\"); break;\n+\tcase 7: how = _(\"both modified:\"); break;\n \t}\n-\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n+\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n \tstrbuf_release(&onebuf);\n }\n \n@@ -161,13 +162,13 @@ static void wt_status_print_change_data(struct wt_status *s,\n \t\tbreak;\n \tcase WT_STATUS_CHANGED:\n \t\tif (d->new_submodule_commits || d->dirty_submodule) {\n-\t\t\tstrbuf_addstr(&extra, \" (\");\n+\t\t\tstrbuf_addstr(&extra, _(\" (\"));\n \t\t\tif (d->new_submodule_commits)\n-\t\t\t\tstrbuf_addf(&extra, \"new commits, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"new commits, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n-\t\t\t\tstrbuf_addf(&extra, \"modified content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"modified content, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n-\t\t\t\tstrbuf_addf(&extra, \"untracked content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"untracked content, \"));\n \t\t\tstrbuf_setlen(&extra, extra.len - 2);\n \t\t\tstrbuf_addch(&extra, ')');\n \t\t}\n@@ -178,40 +179,40 @@ static void wt_status_print_change_data(struct wt_status *s,\n \tone = quote_path(one_name, -1, &onebuf, s->prefix);\n \ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"new file:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"copied:     %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"deleted:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"modified:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"renamed:    %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"typechange: %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unknown:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unmerged:   %s\"), one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", status);\n+\t\tdie(_(\"bug: unhandled diff status %c\"), status);\n \t}\n \tif (extra.len) {\n-\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"), extra.buf);\n \t\tstrbuf_release(&extra);\n \t}\n-\tfprintf(s->fp, \"\\n\");\n+\tfprintf(s->fp, _(\"\\n\"));\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)\n \tconst char *branch_color = color(WT_STATUS_HEADER, s);\n \n \tif (s->branch) {\n-\t\tconst char *on_what = \"On branch \";\n+\t\tconst char *on_what = _(\"On branch \");\n \t\tconst char *branch_name = s->branch;\n \t\tif (!prefixcmp(branch_name, \"refs/heads/\"))\n \t\t\tbranch_name += 11;\n \t\telse if (!strcmp(branch_name, \"HEAD\")) {\n \t\t\tbranch_name = \"\";\n \t\t\tbranch_color = color(WT_STATUS_NOBRANCH, s);\n-\t\t\ton_what = \"Not currently on any branch.\";\n+\t\t\ton_what = _(\"Not currently on any branch.\");\n \t\t}\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"# \");\n \t\tcolor_fprintf_ln(s->fp, branch_color, \"%s%s\", on_what, branch_name);\n@@ -634,9 +635,9 @@ void wt_status_print(struct wt_status *s)\n \t}\n \n \tif (s->is_initial) {\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"# Initial commit\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n \t}\n \n \twt_status_print_updated(s);\n@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_submodule_summary(s, 1);  /* unstaged */\n \t}\n \tif (s->show_untracked_files) {\n-\t\twt_status_print_other(s, &s->untracked, \"Untracked\", \"add\");\n+\t\twt_status_print_other(s, &s->untracked, _(\"Untracked\"), _(\"add\"));\n \t\tif (s->show_ignored_files)\n-\t\t\twt_status_print_other(s, &s->ignored, \"Ignored\", \"add -f\");\n+\t\t\twt_status_print_other(s, &s->ignored, _(\"Ignored\"), _(\"add -f\"));\n \t} else if (s->commitable)\n-\t\tfprintf(s->fp, \"# Untracked files not listed%s\\n\",\n+\t\tfprintf(s->fp, _(\"# Untracked files not listed%s\\n\"),\n \t\t\tadvice_status_hints\n-\t\t\t? \" (use -u option to show untracked files)\" : \"\");\n+\t\t\t? _(\" (use -u option to show untracked files)\") : \"\");\n \n \tif (s->verbose)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tfprintf(s->fp, \"# No changes\\n\");\n+\t\t\tfprintf(s->fp, _(\"# No changes\\n\"));\n \t\telse if (s->nowarn)\n \t\t\t; /* nothing */\n \t\telse if (s->workdir_dirty)\n-\t\t\tprintf(\"no changes added to commit%s\\n\",\n+\t\t\tprintf(_(\"no changes added to commit%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\") : \"\");\n \t\telse if (s->untracked.nr)\n-\t\t\tprintf(\"nothing added to commit but untracked files present%s\\n\",\n+\t\t\tprintf(_(\"nothing added to commit but untracked files present%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (s->is_initial)\n \t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (create/copy files and use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (create/copy files and use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (!s->show_untracked_files)\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (use -u to show untracked files)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (use -u to show untracked files)\") : \"\");\n \t\telse\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (working directory clean)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (working directory clean)\") : \"\");\n \t}\n }\n \n-- \n1.7.1.248.gcd6d1\n"},{"id":"142591","messageId":"1275252857-21593-3-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 2/6] gitignore: Ignore files generated by gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:13Z","receivedAt":"2010-05-30T20:54:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"  - Ignore po/git.pot which is autogenerated by a manual run of the\n    Makefile. We're only interested in tracking the po/*.po files.\n\n  - Ignore the /share/ directory. It's created during installation and\n    contains gettext-related files to be installed.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore    |    1 +\n po/.gitignore |    1 +\n 2 files changed, 2 insertions(+), 0 deletions(-)\n create mode 100644 po/.gitignore\n\ndiff --git a/.gitignore b/.gitignore\nindex 14e2b6b..d22c0e5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -204,3 +204,4 @@\n *.pdb\n /Debug/\n /Release/\n+/share/\ndiff --git a/po/.gitignore b/po/.gitignore\nnew file mode 100644\nindex 0000000..221000e\n--- /dev/null\n+++ b/po/.gitignore\n@@ -0,0 +1 @@\n+/*.pot\n-- \n1.7.1.248.gcd6d1\n"},{"id":"142590","messageId":"1275252857-21593-4-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 3/6] Makefile: Remove Gettext files on make clean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:14Z","receivedAt":"2010-05-30T20:54:14Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the automatically generated po/git.pot and share/\nfiles. They're created by the gettext installation process.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 7989121..4de0627 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2153,6 +2153,10 @@ ifndef NO_TCLTK\n \t$(MAKE) -C git-gui clean\n endif\n \t$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS\n+ifndef NO_GETTEXT\n+\t$(RM) po/git.pot\n+\t$(RM) -r share/\n+endif\n \n .PHONY: all install clean strip\n .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell\n-- \n1.7.1.248.gcd6d1\n"},{"id":"142589","messageId":"1275252857-21593-5-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 4/6] gettext: Add a Gettext interface for shell scripts","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:15Z","receivedAt":"2010-05-30T20:54:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use GNU's gettext.sh in git-sh-setup if it's available, otherwise\nfallback on our own custom functions.\n\nA couple of strings in git-pull.sh are now translatable as a proof of\nconcept, including a multiline string.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile        |    7 +++++--\n git-pull.sh     |   15 ++++++++-------\n git-sh-setup.sh |   33 +++++++++++++++++++++++++++++++++\n 3 files changed, 46 insertions(+), 9 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 4de0627..dce2faa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -272,6 +272,7 @@ mandir = share/man\n infodir = share/info\n gitexecdir = libexec/git-core\n sharedir = $(prefix)/share\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ifeq ($(prefix),/usr)\n@@ -285,7 +286,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir\n+export prefix bindir sharedir localedir sysconfdir\n \n CC = gcc\n AR = ar\n@@ -1455,6 +1456,7 @@ htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n+LOCALEDIR_SQ = $(subst ','\\'',$(localedir))\n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n PYTHON_PATH_SQ = $(subst ','\\'',$(PYTHON_PATH))\n@@ -1548,6 +1550,7 @@ $(RM) $@ $@+ && \\\n sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n+    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \\\n     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \\\n     -e $(BROKEN_PATH_FIX) \\\n     $@.sh >$@+\n@@ -1881,7 +1884,7 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 1a4729f..22a6da2 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -121,8 +121,8 @@ error_on_no_merge_candidates () {\n \tdo\n \t\tcase \"$opt\" in\n \t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"Fetching tags only, you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n+\t\t\tgettext \"Fetching tags only, you probably meant:\"; echo\n+\t\t\tgettext \"  git fetch --tags\"; echo\n \t\t\texit 1\n \t\tesac\n \tdone\n@@ -154,11 +154,12 @@ error_on_no_merge_candidates () {\n \t\techo \"a branch. Because this is not the default configured remote\"\n \t\techo \"for your current branch, you must specify a branch on the command line.\"\n \telif [ -z \"$curr_branch\" ]; then\n-\t\techo \"You are not currently on a branch, so I cannot use any\"\n-\t\techo \"'branch.<branchname>.merge' in your configuration file.\"\n-\t\techo \"Please specify which remote branch you want to use on the command\"\n-\t\techo \"line and try again (e.g. 'git pull <repository> <refspec>').\"\n-\t\techo \"See git-pull(1) for details.\"\n+        gettext \"You are not currently on a branch, so I cannot use any\n+'branch.<branchname>.merge' in your configuration file.\n+Please specify which remote branch you want to use on the command\n+line and try again (e.g. 'git pull <repository> <refspec>').\n+See git-pull(1) for details.\";\n+        echo\n \telif [ -z \"$upstream\" ]; then\n \t\techo \"You asked me to pull without telling me which branch you\"\n \t\techo \"want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in\"\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex 6131670..c8010f2 100644\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -211,3 +211,36 @@ case $(uname -s) in\n \t}\n \t;;\n esac\n+\n+# Try to use libintl's gettext.sh, or fall back to English if we\n+# can't.\n+. gettext.sh\n+if test $? -ne 0\n+then\n+    TEXTDOMAIN=git\n+    export TEXDTOMAIN\n+    TEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+    export TEXTDOMAINDIR\n+else\n+    # Since GNU gettext.sh isn't available we'll have to define our\n+    # own dummy functions.\n+\n+    # This code adapted from NessusClient-1.0.2's nessusclient-mkcert\n+    # by Michel Arboi <arboi@alussinan.org>. The original code is\n+    # under the GPLv2.\n+\n+    # Not everyone has echo -n\n+    case $(echo -n) in\n+        \\-n)    Xn=   ; Xc='\\c' ;;\n+        *)      Xn=-n ; Xc=\n+    esac\n+\n+    gettext () {\n+        echo $Xn \"$1\" $Xc\n+    }\n+\n+    eval_gettext () {\n+        eval_gettext_var=\"echo $1\"\n+        echo $Xn `eval $eval_gettext_var` $Xc\n+    }\n+fi\n-- \n1.7.1.248.gcd6d1\n"},{"id":"142587","messageId":"1275252857-21593-6-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 5/6] gettext: Add a Gettext interface for Perl","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:16Z","receivedAt":"2010-05-30T20:54:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make Git's gettext messages available to Perl programs through\nLocale::Messages. Gracefully fall back to English on systems that\ndon't contain the module.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile            |    4 ++-\n git-send-email.perl |    3 +-\n perl/Git/Gettext.pm |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Makefile.PL    |    5 ++-\n 4 files changed, 92 insertions(+), 3 deletions(-)\n create mode 100644 perl/Git/Gettext.pm\n\ndiff --git a/Makefile b/Makefile\nindex dce2faa..2101713 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1884,7 +1884,9 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n+\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 111c981..a36718e 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -26,6 +26,7 @@ use Term::ANSIColor;\n use File::Temp qw/ tempdir tempfile /;\n use Error qw(:try);\n use Git;\n+use Git::Gettext qw< :all >;\n \n Getopt::Long::Configure qw/ pass_through /;\n \n@@ -674,7 +675,7 @@ if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n \t$sender = ask(\"Who should the emails appear to be from? [$sender] \",\n \t              default => $sender);\n-\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n+\tprintf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n \t$prompting++;\n }\n \ndiff --git a/perl/Git/Gettext.pm b/perl/Git/Gettext.pm\nnew file mode 100644\nindex 0000000..f434783\n--- /dev/null\n+++ b/perl/Git/Gettext.pm\n@@ -0,0 +1,83 @@\n+package Git::Gettext;\n+use strict;\n+use warnings;\n+use Exporter;\n+use base 'Exporter';\n+\n+our $VERSION = '0.01';\n+\n+our @EXPORT;\n+our @EXPORT_OK = qw< gettext >;\n+our %EXPORT_TAGS;\n+@{ $EXPORT_TAGS{'all'} } = @EXPORT_OK;\n+\n+sub __bootstrap_locale_messages {\n+\tour $TEXTDOMAIN = 'git';\n+\n+\t# TODO: How do I make the sed replacements in the top level\n+\t# Makefile reach me here?\n+\t#our $TEXTDOMAINDIR = q|@@LOCALEDIR@@|;\n+\tour $TEXTDOMAINDIR = q</usr/local/share/locale>;\n+\n+\trequire POSIX;\n+\tPOSIX->import(qw< setlocale >);\n+\t# Non-core prerequisite module\n+\trequire Locale::Messages;\n+\tLocale::Messages->import(qw< :locale_h :libintl_h >);\n+\n+\tsetlocale(LC_MESSAGES(), '');\n+\tsetlocale(LC_CTYPE(), '');\n+\ttextdomain($TEXTDOMAIN);\n+\tbindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n+\n+\treturn;\n+}\n+\n+BEGIN\n+{\n+\tlocal ($@, $!);\n+\teval { __bootstrap_locale_messages() };\n+\tif ($@) {\n+\t\t# Oh noes, no Locale::Messages here\n+\t\t*gettext = sub ($) { $_[0] };\n+\t}\n+}\n+\n+1;\n+\n+__END__\n+\n+=head1 NAME\n+\n+Git::Gettext - Perl interface to Git's Gettext localizations\n+\n+=head1 DESCRIPTION\n+\n+Git's internal interface to Gettext via L<Locale::Messages>. If\n+L<Locale::Messages> can't be loaded (it's not a core module) we\n+provide stub passthrough fallbacks.\n+\n+=head1 FUNCTIONS\n+\n+=head2 gettext($)\n+\n+L<Locale::Messages>'s gettext function if all goes well, otherwise our\n+passthrough fallback function.\n+\n+=head1 EXPORTS\n+\n+Exports are done via L<Exporter>. Invididual functions can be\n+exporter, or all of them via the C<:all> export tag.\n+\n+=head1 AUTHOR\n+\n+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+=head1 LICENSE AND COPYRIGHT\n+\n+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+This program is free software, you can redistribute it and/or modify\n+it under the same terms as Perl itself.\n+\n+=cut\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nindex 0b9deca..702ec7c 100644\n--- a/perl/Makefile.PL\n+++ b/perl/Makefile.PL\n@@ -16,7 +16,10 @@ endif\n MAKE_FRAG\n }\n \n-my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n+my %pm = (\n+\t'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n+\t'Git/Gettext.pm' => '$(INST_LIBDIR)/Git/Gettext.pm',\n+);\n \n # We come with our own bundled Error.pm. It's not in the set of default\n # Perl modules so install it if it's not available on the system yet.\n-- \n1.7.1.248.gcd6d1\n"},{"id":"142588","messageId":"1275252857-21593-7-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v2 6/6] gettext: Add a skeleton po/is.po","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-30T20:54:17Z","receivedAt":"2010-05-30T20:54:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This example is.po file translates a little bit of C, Shell and Perl\nas an example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n po/is.po |  282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 282 insertions(+), 0 deletions(-)\n create mode 100644 po/is.po\n\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..b716e23\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,282 @@\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2010-05-30 19:24+0000\\n\"\n+\"PO-Revision-Date: 2010-05-30 19:31+0000\\n\"\n+\"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n+\"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"X-Poedit-Language: English\\n\"\n+\"X-Poedit-SourceCharset: utf-8\\n\"\n+\n+#: wt-status.c:53\n+msgid \"# Unmerged paths:\"\n+msgstr \"\"\n+\n+#: wt-status.c:59 wt-status.c:76\n+#, c-format\n+msgid \"#   (use \\\"git reset %s <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:61 wt-status.c:78\n+msgid \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:62\n+msgid \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"\n+msgstr \"\"\n+\n+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110\n+#: wt-status.c:115 wt-status.c:638 wt-status.c:640\n+msgid \"#\"\n+msgstr \"\"\n+\n+#: wt-status.c:70\n+msgid \"# Changes to be committed:\"\n+msgstr \"\"\n+\n+#: wt-status.c:88\n+msgid \"# Changed but not updated:\"\n+msgstr \"\"\n+\n+#: wt-status.c:92\n+msgid \"#   (use \\\"git add <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:94\n+msgid \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:95\n+msgid \"\"\n+\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working \"\n+\"directory)\"\n+msgstr \"\"\n+\n+#: wt-status.c:97\n+msgid \"#   (commit or discard the untracked or modified content in submodules)\"\n+msgstr \"\"\n+\n+#: wt-status.c:106\n+#, c-format\n+msgid \"# %s files:\"\n+msgstr \"\"\n+\n+#: wt-status.c:109\n+#, c-format\n+msgid \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:126\n+msgid \"bug\"\n+msgstr \"\"\n+\n+#: wt-status.c:129 wt-status.c:182\n+msgid \"#\\t\"\n+msgstr \"\"\n+\n+#: wt-status.c:131\n+msgid \"both deleted:\"\n+msgstr \"\"\n+\n+#: wt-status.c:132\n+msgid \"added by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:133\n+msgid \"deleted by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:134\n+msgid \"added by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:135\n+msgid \"deleted by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:136\n+msgid \"both added:\"\n+msgstr \"\"\n+\n+#: wt-status.c:137\n+msgid \"both modified:\"\n+msgstr \"\"\n+\n+#: wt-status.c:139\n+#, c-format\n+msgid \"%-20s%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:165\n+msgid \" (\"\n+msgstr \"\"\n+\n+#: wt-status.c:167\n+msgid \"new commits, \"\n+msgstr \"\"\n+\n+#: wt-status.c:169\n+msgid \"modified content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:171\n+msgid \"untracked content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:185\n+#, c-format\n+msgid \"new file:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:188\n+#, c-format\n+msgid \"copied:     %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:191\n+#, c-format\n+msgid \"deleted:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:194\n+#, c-format\n+msgid \"modified:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:197\n+#, c-format\n+msgid \"renamed:    %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:200\n+#, c-format\n+msgid \"typechange: %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:203\n+#, c-format\n+msgid \"unknown:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:206\n+#, c-format\n+msgid \"unmerged:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:209\n+#, c-format\n+msgid \"bug: unhandled diff status %c\"\n+msgstr \"\"\n+\n+#: wt-status.c:212\n+#, c-format\n+msgid \"%s\"\n+msgstr \"\"\n+\n+#: wt-status.c:215\n+#, c-format\n+msgid \"\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:622\n+msgid \"On branch \"\n+msgstr \"Á greininni \"\n+\n+#: wt-status.c:629\n+msgid \"Not currently on any branch.\"\n+msgstr \"Ekki á neinni grein.\"\n+\n+#: wt-status.c:639\n+msgid \"# Initial commit\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"Untracked\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"add\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"Ignored\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"add -f\"\n+msgstr \"\"\n+\n+#: wt-status.c:655\n+#, c-format\n+msgid \"# Untracked files not listed%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:657\n+msgid \" (use -u option to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:663\n+#, c-format\n+msgid \"# No changes\\n\"\n+msgstr \"# Engar breytingar\\n\"\n+\n+#: wt-status.c:667\n+#, c-format\n+msgid \"no changes added to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:669\n+msgid \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\"\n+msgstr \"\"\n+\n+#: wt-status.c:671\n+#, c-format\n+msgid \"nothing added to commit but untracked files present%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:673\n+msgid \" (use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:676\n+msgid \" (create/copy files and use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:678 wt-status.c:681\n+#, c-format\n+msgid \"nothing to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:679\n+msgid \" (use -u to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:682\n+msgid \" (working directory clean)\"\n+msgstr \"\"\n+\n+#: git-pull.sh:124\n+msgid \"Fetching tags only, you probably meant:\"\n+msgstr \"\"\n+\n+#: git-pull.sh:125\n+msgid \"  git fetch --tags\"\n+msgstr \"\"\n+\n+#: git-pull.sh:157\n+msgid \"\"\n+\"You are not currently on a branch, so I cannot use any\\n\"\n+\"'branch.<branchname>.merge' in your configuration file.\\n\"\n+\"Please specify which remote branch you want to use on the command\\n\"\n+\"line and try again (e.g. 'git pull <repository> <refspec>').\\n\"\n+\"See git-pull(1) for details.\"\n+msgstr \"\"\n+\n+#: git-send-email.perl:678\n+#, perl-format\n+msgid \"Emails will be sent from: %s\\n\"\n+msgstr \"Póstarnir verða sendir frá: %s\\n\"\n-- \n1.7.1.248.gcd6d1\n"},{"id":"142592","messageId":"20100530212912.GA422@progeny.tock","threadId":"23941","inReplyTo":"1275252857-21593-7-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v2 6/6] gettext: Add a skeleton po/is.po","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-05-30T21:29:12Z","receivedAt":"2010-05-30T21:29:12Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi Ævar,\n\nÆvar Arnfjörð Bjarmason wrote:\n\n> +#: wt-status.c:53\n> +msgid \"# Unmerged paths:\"\n> +msgstr \"\"\n\nOn projects that use gettext, merging these line number changes can\nbe a royal pain.  In effect, the .po files are mixing semantically\nmeaningful text and automatically generated cruft.\n\nSo my ignorant questions:\n\n . does gettext use the #: comments for anything important?\n . can they be suppressed when generating the .po file?\n . can they be easily re-added if some translation front-end needs\n   them?\n\n> +#: git-pull.sh:124\n> +msgid \"Fetching tags only, you probably meant:\"\n> +msgstr \"\"\n\nI noticed there are no printf formats among the shell scripting\nexamples.  Would we have to roll our own, like this?\n\n  gettext 'You asked me to pull without telling me which branch you\nwant to OP_TYPE OP_PREP, and 'branch.CURR_BRANCH.merge' in\nyour configuration file does not tell me, either. Please\ntry again (e.g., 'git pull <repository> <refspec>').\nSee git-pull(1) for details.\n' |\n  sed \"\n\ts/OP_TYPE/$op_type/g\n\ts/OP_PREP/$op_prep/g\n\ts/CURR_BRANCH/$curr_branch/g\n  \"\n\nJonathan\n"},{"id":"142593","messageId":"20100530213932.GA477@progeny.tock","threadId":"23941","inReplyTo":"20100530212912.GA422@progeny.tock","subject":"Re: [PATCH/RFC v2 6/6] gettext: Add a skeleton po/is.po","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-05-30T21:39:32Z","receivedAt":"2010-05-30T21:39:32Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n>   gettext 'You asked me to pull without telling me which branch you\n> want to OP_TYPE OP_PREP, and 'branch.CURR_BRANCH.merge' in\n> your configuration file does not tell me, either. Please\n> try again (e.g., 'git pull <repository> <refspec>').\n> See git-pull(1) for details.\n> ' |\n>   sed \"\n> \ts/OP_TYPE/$op_type/g\n> \ts/OP_PREP/$op_prep/g\n> \ts/CURR_BRANCH/$curr_branch/g\n>   \"\n\nApparently this is what \"gettext -e\"/eval_gettext is for.  Sorry for the\nnoise.\n\nJonathan\n"},{"id":"142594","messageId":"20100530222347.GB477@progeny.tock","threadId":"23941","inReplyTo":"AANLkTimI5xGiq_GNF_H2bOLECw0NxOiCPsnRqOS39H32@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Add internationalization support to Git","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-05-30T22:23:48Z","receivedAt":"2010-05-30T22:23:48Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ævar Arnfjörð Bjarmason wrote:\n\n> And even though gettext tries to make cases like these fast\n> (http://www.gnu.org/software/hello/manual/gettext/Optimized-gettext.html)\n> it's still a lot slower than hardcoded English:\n> \n>     perl -MBenchmark=:all -MData::Dump=dump -E 'cmpthese(10, {\n>          outside => sub { system \"./test-outside-loop >/dev/null\" },\n>          inside =>  sub { system \"./test-in-loop >/dev/null\" },\n>     });'\n> \n>             s/iter  inside outside\n>     inside    13.4      --    -83%\n>     outside   2.26    495%      --\n\nGiven:\n\n-- 8< --\n#include <stdio.h>\n#include <stdlib.h>\n#include <locale.h>\n#include <libintl.h>\n#include \"gettext.h\"\n\nint foo(long int x) {\n\treturn x * x;\n}\n\nint main(void) {\n\tconst char *podir = \"/usr/local/share/locale\";\n\tlong int i;\n\n\tbindtextdomain(\"git\", podir);\n\tsetlocale(LC_MESSAGES, \"\");\n\tsetlocale(LC_CTYPE, \"\");\n\ttextdomain(\"git\");\n\n\tfor (i = 0; i < 1000000; i++)\n\t\tprintf(_(\"Some interesting label: %ld\\n\"), foo(i));\n\n\treturn 0;\n}\n-- >8 --\n\nNo message catalog is installed here, and I compile with gcc-4.5 -Wall -W -O2.\nThe results are similar.\n\nA: the standard way.  gettext.h contains \"#define _(s) gettext(s)\" or\n| static inline char *_(const char *s) __attribute__((__format_arg(1)__))\n| {\n|\treturn gettext(s);\n| }\n\n 6.74user 0.02system 0:06.78elapsed 99%CPU (0avgtext+0avgdata 2304maxresident)k\n 0inputs+0outputs (0major+182minor)pagefaults 0swaps\n\n (about 7 seconds.)\n\nB: noop.  gettext.h contains \"#define _(s) s\"\n\n 1.35user 0.01system 0:01.37elapsed 99%CPU (0avgtext+0avgdata 2192maxresident)k\n 0inputs+0outputs (0major+172minor)pagefaults 0swaps\n\n (about 1.5 seconds.)\n\nIt would seem that __attribute__((__pure__)) should let the compiler give\nus the best of both worlds, but no luck.  Even __attribute__((__const__))\nis ignored; the compiler inlines the body of _() before it has a chance\nto notice.\n\nWe can fool the compiler into paying attention by making it not\ninlinable: if gettext.h contains\n\n| extern char *_(const char *s) __attribute__((__format_arg__(1), __const__));\n\nand a separate gettext.c contains\n\n| #include <libintl.h>\n| #include \"gettext.h\"\n| char *_(const char *s) { return gettext(s); }\n\nwe get the performance of B again:\n\n 1.36user 0.01system 0:01.38elapsed 98%CPU (0avgtext+0avgdata 2304maxresident)k\n 0inputs+0outputs (0major+180minor)pagefaults 0swaps\n\nThis amounts to lying to the compiler, since it is possible for the string\npointed to by a single address s to differ between calls to _.  The __pure__\nattribute would be more honest, but for reasons I don’t understand it\nsuppresses the optimization.\n\nMoral of the story: at least in simple cases, we can keep the performance\nand the typechecking.  Phew.\n\nHTH,\nJonathan\n"},{"id":"142608","messageId":"AANLkTinDqGaqlTJs91vB8giQGo6GfEmCdX3wpNX7lMCR@mail.gmail.com","threadId":"23941","inReplyTo":"20100530222347.GB477@progeny.tock","subject":"Re: [PATCH/RFC 0/5] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-31T12:17:11Z","receivedAt":"2010-05-31T12:17:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sun, May 30, 2010 at 22:23, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> [...]\n> It would seem that __attribute__((__pure__)) should let the compiler give\n> us the best of both worlds, but no luck.  Even __attribute__((__const__))\n> is ignored; the compiler inlines the body of _() before it has a chance\n> to notice.\n>\n> We can fool the compiler into paying attention by making it not\n> inlinable: if gettext.h contains\n>\n> | extern char *_(const char *s) __attribute__((__format_arg__(1), __const__));\n>\n> and a separate gettext.c contains\n>\n> | #include <libintl.h>\n> | #include \"gettext.h\"\n> | char *_(const char *s) { return gettext(s); }\n>\n> we get the performance of B again:\n>\n>  1.36user 0.01system 0:01.38elapsed 98%CPU (0avgtext+0avgdata 2304maxresident)k\n>  0inputs+0outputs (0major+180minor)pagefaults 0swaps\n>\n> This amounts to lying to the compiler, since it is possible for the string\n> pointed to by a single address s to differ between calls to _.  The __pure__\n> attribute would be more honest, but for reasons I don’t understand it\n> suppresses the optimization.\n>\n> Moral of the story: at least in simple cases, we can keep the performance\n> and the typechecking.  Phew.\n\nAwesome, how portable is this? If it's just GCC I guess it can just be\nwrapped in #ifdef __GNUC__.\n\nThanks for investingating this.\n"},{"id":"142612","messageId":"AANLkTimutYPEcaCALfO1fDOZcxkrRMN5Axj8eYJGuvcE@mail.gmail.com","threadId":"23941","inReplyTo":"20100530212912.GA422@progeny.tock","subject":"Re: [PATCH/RFC v2 6/6] gettext: Add a skeleton po/is.po","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-05-31T14:17:24Z","receivedAt":"2010-05-31T14:17:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sun, May 30, 2010 at 21:29, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Hi Ęvar,\n>\n> Ęvar Arnfjörš Bjarmason wrote:\n>\n>> +#: wt-status.c:53\n>> +msgid \"# Unmerged paths:\"\n>> +msgstr \"\"\n>\n> On projects that use gettext, merging these line number changes can\n> be a royal pain.  In effect, the .po files are mixing semantically\n> meaningful text and automatically generated cruft.\n>\n> So my ignorant questions:\n>\n>  . does gettext use the #: comments for anything important?\n>  . can they be suppressed when generating the .po file?\n>  . can they be easily re-added if some translation front-end needs\n>   them?\n\nLet me answer that more generally.\n\nUsually when people first see the Gettext format they go \"ew!\". The\nthing is that it's really meant as a format for mixed human and\nprogrammatic editing. Almost everyone editing PO files doesn't do so\npurely with a simple non-PO aware text editor.\n\nPO editors use these comments to allow you to jump to the source\ndefinition to see the message in context. E.g. Emacs's po-mode allows\nyou to do this, and Launchpad displays the file & line number (but\nlast I checked they didn't have an embedded viewer).\n\nA merge of two PO files that doesn't use msgmerge(1) is going to be\npainful. There are some things that it'll throw out and regenerate\n(e.g. automated comments, those matching /^#\\S/), and it might move\nmessages around to match their new position in the respective source\nfiles. Thus a merge that might be hard with a simple git merge might\nbe very easy with a msgmerge-based merge.\n\nNow, we could filter out all these comments (and e.g. context\ncomments) before checking these files in. But that would cause a lot\nof tools like Launchpad and PO editors to behave in unexpected\nways. The Gettext utilities themselves also seem to have no support\nfor initializing/emitting these sort of slim files.\n\nI don't know what the answer is, but this is all something to\nconsider. I'm new to the Gettext format myself, but I've come to like\nthe automatic editing the tools do, especially the automaticy fuzzy\ntagging.\n"},{"id":"142710","messageId":"m3iq62r8jn.fsf@localhost.localdomain","threadId":"23941","inReplyTo":"1275252857-21593-6-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v2 5/6] gettext: Add a Gettext interface for Perl","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-06-01T17:00:18Z","receivedAt":"2010-06-01T17:00:18Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Make Git's gettext messages available to Perl programs through\n> Locale::Messages. Gracefully fall back to English on systems that\n> don't contain the module.\n\nThis is I think a very good idea, both providing wrapper with fallback\nto untranslated messages (and encapsulating translation), and using the\nLocale::Messages module from libintl-perl library.  The \"On the state of\ni18n in Perl\" (http://rassie.org/archives/247) blog post from 26 April\n2009 provides nice counterpoint to Locale::Maketext::TPJ13 / The Perl\nJournal #13 article[1] from 1999... especially because using gettext is\nnatural for translating git command output and GUI, because git uses it\nalready for Tcl/Tk (gitk and git-gui), and it is natural solution for\ncode in C, which slightly less than half of git code.\n\nWell, we could use Locale::Maketext::Gettext, but it is not in Perl\ncore either, and as http://rassie.org/archives/247 says its '*.po'\nfiles are less natural.  The gettext documentation (gettext.info) also\nrecommends libintl-perl, or to be more exact Locale::TextDomain from\nit.\n\n[1] http://search.cpan.org/perldoc?Locale::Maketext::TPJ13\n    http://interglacial.com/~sburke/tpj/as_html/tpj13.html\n\n\nThe question is why not use Locale::TextDomain, the high-level Perl-y\nframework, wrapper around Locale::Messages from the same libintl-perl\nlibrary?  The gettext documentation (in gettext.info, chapter \"13.5.18\nPerl\") says:\n\n  Prerequisite\n     `use POSIX;'\n     `use Locale::TextDomain;' (included in the package libintl-perl\n     which is available on the Comprehensive Perl Archive Network CPAN,\n     http://www.cpan.org/).\n\n\nThis would change\n\n -\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n +\tprintf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n\nto either\n\n +\tprint __\"Emails will be sent from: \", $sender, \"\\n\";\n\nor\n\n +\tprintf __(\"Emails will be sent from: %s\\n\"), $sender;\n\nor\n\n +\tprint __x(\"Emails will be sent from: {sender}\\n\",\n +\t          sender => $sender);\n\n\n> \n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Makefile            |    4 ++-\n>  git-send-email.perl |    3 +-\n>  perl/Git/Gettext.pm |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++\n>  perl/Makefile.PL    |    5 ++-\n>  4 files changed, 92 insertions(+), 3 deletions(-)\n>  create mode 100644 perl/Git/Gettext.pm\n> \n> diff --git a/Makefile b/Makefile\n> index dce2faa..2101713 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -1884,7 +1884,9 @@ cscope:\n>  \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n>  \n>  pot:\n> -\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n> +\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n> +\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n\nShouldn't this line be in earlier patch, i.e. in \"gettext: Add a\nGettext interface for shell scripts\"?\n\n> +\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n\nFrom gettext documentation (in gettext.info, chapter \"13.5.18 Perl\"):\n\n  Extractor\n     `xgettext -k__ -k\\$__ -k%__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2\n     -kN__ -k'\n\nIs it equivalent to specifying 'xgettext --language=Perl'?\n\nOf course the above assumes that you are using Locale::TextDomain, or\nat least use the same conventions.\n\n>  \n>  POFILES := $(wildcard po/*.po)\n>  MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index 111c981..a36718e 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -26,6 +26,7 @@ use Term::ANSIColor;\n>  use File::Temp qw/ tempdir tempfile /;\n>  use Error qw(:try);\n>  use Git;\n> +use Git::Gettext qw< :all >;\n\nPlease follow the existing convention, i.e.\n\n  +use Git::Gettext qw(:all);\n\nlike you see in context line for 'use Error'.\n\n\nWell, not that git-send-email.perl is very consistent about this\nissue, see 'use File::Temp qw/ tempdir tempfile /;' versus \n'use Error qw(:try);' but I'd reather you didn't introduce yet\nanother form.\n\n>  \n>  Getopt::Long::Configure qw/ pass_through /;\n>  \n> @@ -674,7 +675,7 @@ if (!defined $sender) {\n>  \t$sender = $repoauthor || $repocommitter || '';\n>  \t$sender = ask(\"Who should the emails appear to be from? [$sender] \",\n>  \t              default => $sender);\n> -\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n> +\tprintf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n\nAs I wrote, this IMHO should be either\n\n  +\tprintf __(\"Emails will be sent from: %s\\n\"), $sender;\n\nor\n\n  +\tprint __x(\"Emails will be sent from: {sender}\\n\", sender => $sender);\n\n(note that parantheses differ in those two examples).\n\n>  \t$prompting++;\n>  }\n>  \n> diff --git a/perl/Git/Gettext.pm b/perl/Git/Gettext.pm\n> new file mode 100644\n> index 0000000..f434783\n> --- /dev/null\n> +++ b/perl/Git/Gettext.pm\n> @@ -0,0 +1,83 @@\n> +package Git::Gettext;\n\nShould this package be named Git::Gettext, or other name would be\nbetter, perhaps Git::I18N (like e.g. Games::Risk have\nGames::Risk::I18N), or Git::Locale, or even Git::Translator?\n\nNot very important.\n\n> +use strict;\n> +use warnings;\n> +use Exporter;\n> +use base 'Exporter';\n\nO.K.\n\nThe alternative would be to use\n\n  +use Exporter qw(import);\n\n> +\n> +our $VERSION = '0.01';\n> +\n> +our @EXPORT;\n> +our @EXPORT_OK = qw< gettext >;\n\nSame comment as above: more common way is to use qw(gettext) not \nqw< gettext >; it is also the notation used in Exporter documentation.\n\n> +our %EXPORT_TAGS;\n> +@{ $EXPORT_TAGS{'all'} } = @EXPORT_OK;\n\nWhy not simply\n\n  +our %EXPORT_TAGS = ('all' => [ @EXPORT_OK ]);\n\nor the reverse\n\n  +our %EXPORT_TAGS = ('all' => [qw(gettext)]);\n  +our @EXPORT_OK   = @{$EXPORT_TAGS{'all'}};\n\nor the reverse using tag utility functions\n\n  +our %EXPORT_TAGS = ('all' => [qw(gettext)]);\n  +Exporter::export_ok_tags('all');\n\n> +\n> +sub __bootstrap_locale_messages {\n> +\tour $TEXTDOMAIN = 'git';\n> +\n> +\t# TODO: How do I make the sed replacements in the top level\n> +\t# Makefile reach me here?\n> +\t#our $TEXTDOMAINDIR = q|@@LOCALEDIR@@|;\n\nIn Perl (well, in gitweb/gitweb.perl) we use '++VAR++' and not\n'@@VAR@@' for placeholders, because '@' is sigil in Perl.  This is not\nimportant in above example, because it is not interpolated string.\n\n\nMake invoked on perl/Makefile, when invoked from main Makefile by\n'$(MAKE) -C perl' (via QUIET_SUBDIR0) passes 'localedir' to submake;\nperl/Makefile should probably have something like\n\n  localedir ?= $(sharedir)/locale\n\nThat is assuming that 'localedir' is added to list of exported\nvariables.\n\n\nBut I am not sure how such substitution should be performed.\n\n> +\tour $TEXTDOMAINDIR = q</usr/local/share/locale>;\n\nWhy q<...> and not simply '...'?\n\n> +\n> +\trequire POSIX;\n> +\tPOSIX->import(qw< setlocale >);\n> +\t# Non-core prerequisite module\n> +\trequire Locale::Messages;\n> +\tLocale::Messages->import(qw< :locale_h :libintl_h >);\n> +\n> +\tsetlocale(LC_MESSAGES(), '');\n> +\tsetlocale(LC_CTYPE(), '');\n> +\ttextdomain($TEXTDOMAIN);\n> +\tbindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n> +\n> +\treturn;\n> +}\n\nThis would probably be a bit simpler with Locale::TextDomain.\n\n> +\n> +BEGIN\n> +{\n> +\tlocal ($@, $!);\n> +\teval { __bootstrap_locale_messages() };\n> +\tif ($@) {\n> +\t\t# Oh noes, no Locale::Messages here\n> +\t\t*gettext = sub ($) { $_[0] };\n\nDo you intended to use subroutine protytype here?  Ah, I see that\nLocale::Messages::gettext has the same prototype...\n\n> +\t}\n> +}\n\nDoes it need to be in BEGIN block?  Probably yes.\n\n> +\n> +1;\n> +\n> +__END__\n> +\n\nIt's nice that you have provided documentation.\n\n> +=head1 NAME\n> +\n> +Git::Gettext - Perl interface to Git's Gettext localizations\n> +\n> +=head1 DESCRIPTION\n> +\n> +Git's internal interface to Gettext via L<Locale::Messages>. If\n> +L<Locale::Messages> can't be loaded (it's not a core module) we\n> +provide stub passthrough fallbacks.\n\nVery good.\n\nIt would probably be better though to use L<Locale::TextDomain>\ninstead of low(er)-level L<Locale::Messages>.\n\n> +\n> +=head1 FUNCTIONS\n> +\n> +=head2 gettext($)\n> +\n> +L<Locale::Messages>'s gettext function if all goes well, otherwise our\n> +passthrough fallback function.\n\nOther packages use _T() function for that, or like Locale::TextDomain\n__() function.\n\n> +\n> +=head1 EXPORTS\n> +\n> +Exports are done via L<Exporter>. Invididual functions can be\n> +exporter, or all of them via the C<:all> export tag.\n\nShouldn't this be described in less technical way in SYNOPSIS and\nDESCRIPTION sections instead?\n\n> +\n> +=head1 AUTHOR\n> +\n> +E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n> +\n> +=head1 LICENSE AND COPYRIGHT\n> +\n> +Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n> +\n> +This program is free software, you can redistribute it and/or modify\n> +it under the same terms as Perl itself.\n\nWhich is dual licensed: GPL + Perl artistic.\n\nWas it intended to use 'same terms as Perl itself' rather than GPLv2\nor GPLv2+?\n\n> +\n> +=cut\n> diff --git a/perl/Makefile.PL b/perl/Makefile.PL\n> index 0b9deca..702ec7c 100644\n> --- a/perl/Makefile.PL\n> +++ b/perl/Makefile.PL\n> @@ -16,7 +16,10 @@ endif\n>  MAKE_FRAG\n>  }\n>  \n> -my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n> +my %pm = (\n> +\t'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n> +\t'Git/Gettext.pm' => '$(INST_LIBDIR)/Git/Gettext.pm',\n> +);\n>  \n>  # We come with our own bundled Error.pm. It's not in the set of default\n>  # Perl modules so install it if it's not available on the system yet.\n> -- \n> 1.7.1.248.gcd6d1\n> \n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"142707","messageId":"m3eigqr8hf.fsf@localhost.localdomain","threadId":"23941","inReplyTo":"1275252857-21593-2-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v2 1/6] Add infrastructure for translating Git with gettext","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-06-01T17:01:34Z","receivedAt":"2010-06-01T17:01:34Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> From: Jeff Epler <jepler@unpythonic.net>\n> \n> Change the build process to use GNU's libintl if it's available. If\n> not we define our own skeleton replacement functions which degrade\n> gracefully to English.\n\nVery nice.\n\n> \n> Signed-off-by: Jeff Epler <jepler@unpythonic.net>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Makefile    |   26 ++++++++++++\n>  gettext.c   |   17 ++++++++\n>  gettext.h   |   15 +++++++\n>  git.c       |    3 +\n>  wt-status.c |  129 ++++++++++++++++++++++++++++++-----------------------------\n>  5 files changed, 126 insertions(+), 64 deletions(-)\n>  create mode 100644 gettext.c\n>  create mode 100644 gettext.h\n\nCould you also provide change to configure.ac, so that ./configure\nwould detect if we have gettext installed or not?  Thanks in advance.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"142720","messageId":"1275415908-24838-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"m3eigqr8hf.fsf@localhost.localdomain","subject":"[PATCH/RCF] autoconf: Check if <libintl.h> exists and set NO_GETTEXT","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T18:11:48Z","receivedAt":"2010-06-01T18:11:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n\nOn Tue, Jun 1, 2010 at 17:01, Jakub Narebski <jnareb@gmail.com> wrote:\n> [...]\n> Could you also provide change to configure.ac, so that ./configure\n> would detect if we have gettext installed or not?  Thanks in advance.\n\nHere's a check that just checks if we have libintl.h similar to the\nexisting checks for libgen.h and other headers.\n\nDo you think this be adequate?\n\n config.mak.in |    1 +\n configure.ac  |    6 ++++++\n 2 files changed, 7 insertions(+), 0 deletions(-)\n\ndiff --git a/config.mak.in b/config.mak.in\nindex 0d4b64d..a15f3c1 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@\n NO_EXPAT=@NO_EXPAT@\n NO_LIBGEN_H=@NO_LIBGEN_H@\n HAVE_PATHS_H=@HAVE_PATHS_H@\n+NO_GETTEXT=@NO_GETTEXT@\n NEEDS_LIBICONV=@NEEDS_LIBICONV@\n NEEDS_SOCKET=@NEEDS_SOCKET@\n NEEDS_RESOLV=@NEEDS_RESOLV@\ndiff --git a/configure.ac b/configure.ac\nindex 71038fc..7bebfd8 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],\n [HAVE_PATHS_H=])\n AC_SUBST(HAVE_PATHS_H)\n #\n+# Define NO_GETTEXT if you don't have libintl.h\n+AC_CHECK_HEADER([libintl.h],\n+[NO_GETTEXT=],\n+[NO_GETTEXT=YesPlease])\n+AC_SUBST(NO_GETTEXT)\n+#\n # Define NO_STRCASESTR if you don't have strcasestr.\n GIT_CHECK_FUNC(strcasestr,\n [NO_STRCASESTR=],\n-- \n1.7.1.243.g01eae\n"},{"id":"142721","messageId":"AANLkTilLWZA6OrXhF28qCao2svpZWZiEwb5nVhXUTB9i@mail.gmail.com","threadId":"23941","inReplyTo":"m3iq62r8jn.fsf@localhost.localdomain","subject":"Re: [PATCH/RFC v2 5/6] gettext: Add a Gettext interface for Perl","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T19:06:08Z","receivedAt":"2010-06-01T19:06:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Jun 1, 2010 at 17:00, Jakub Narebski <jnareb@gmail.com> wrote:\n>\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Make Git's gettext messages available to Perl programs through\n>> Locale::Messages. Gracefully fall back to English on systems that\n>> don't contain the module.\n>\n> This is I think a very good idea, both providing wrapper with fallback\n> to untranslated messages (and encapsulating translation), and using the\n> Locale::Messages module from libintl-perl library.  The \"On the state of\n> i18n in Perl\" (http://rassie.org/archives/247) blog post from 26 April\n> 2009 provides nice counterpoint to Locale::Maketext::TPJ13 / The Perl\n> Journal #13 article[1] from 1999... especially because using gettext is\n> natural for translating git command output and GUI, because git uses it\n> already for Tcl/Tk (gitk and git-gui), and it is natural solution for\n> code in C, which slightly less than half of git code.\n>\n> Well, we could use Locale::Maketext::Gettext, but it is not in Perl\n> core either, and as http://rassie.org/archives/247 says its '*.po'\n> files are less natural.  The gettext documentation (gettext.info) also\n> recommends libintl-perl, or to be more exact Locale::TextDomain from\n> it.\n>\n> [1] http://search.cpan.org/perldoc?Locale::Maketext::TPJ13\n>    http://interglacial.com/~sburke/tpj/as_html/tpj13.html\n\nLocale::Maketext is a less complete and non-standard alternative as\nthe above blogs note. I think the main reason it's used in favor of\nGettext in many Perl projects is that it can be compiled stand-alone\nfrom the CPAN, i.e. it doesn't depend on libintl.\n\nThat's comfortable when CPAN is your main distribution channel, but\nGit's main distribution channel is via OS packages, which can\ntrivially introduce a gettext dependency (for which they doubtless\nalready have a package).\n\nLocale::Maketext has a Gettext emulation layer, but using it would be\na potential source of bugs (no emulation is perfect).\n\nThat being said the way I wrote Git::Gexttext means any alterante\nimplementation or emulation layer can be seemlessly added later on. We\ncould use (or write) something for Perl, C or Shell that completely\nbypasses libintl for systems that don't have a gettext C library.\n\n> The question is why not use Locale::TextDomain, the high-level Perl-y\n> framework, wrapper around Locale::Messages from the same libintl-perl\n> library?  The gettext documentation (in gettext.info, chapter \"13.5.18\n> Perl\") says:\n>\n>  Prerequisite\n>     `use POSIX;'\n>     `use Locale::TextDomain;' (included in the package libintl-perl\n>     which is available on the Comprehensive Perl Archive Network CPAN,\n>     http://www.cpan.org/).\n>\n>\n> This would change\n>\n>  -      print \"Emails will be sent from: \", $sender, \"\\n\";\n>  +      printf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n>\n> to either\n>\n>  +      print __\"Emails will be sent from: \", $sender, \"\\n\";\n>\n> or\n>\n>  +      printf __(\"Emails will be sent from: %s\\n\"), $sender;\n>\n> or\n>\n>  +      print __x(\"Emails will be sent from: {sender}\\n\",\n>  +                sender => $sender);\n\nI didn't use Locale::TextDomain because it exports a fatter interface\nby default, and I'm not sure at this point what subset of it it would\nmake sense to support.\n\nThis is the default Locale::TexdDomain interface:\n\n   @EXPORT = qw (__ __x __n __nx __xn __p __px __np __npx $__ %__\n                 N__ N__n N__p N__np);\n\nMy Git::Gettext only exports a single gettext() function now. I think\nit's better at this point to have a really small interface and decide\nlater if we'd like to expand it, preferably in a way that'll work\nconsistently across C, Perl and Shell programs.\n\nWe might want to improve plural support, add msgctxt etc. later. But\nfor an initial implementation I'd rather have something simple &\nstupid.\n\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  Makefile            |    4 ++-\n>>  git-send-email.perl |    3 +-\n>>  perl/Git/Gettext.pm |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++\n>>  perl/Makefile.PL    |    5 ++-\n>>  4 files changed, 92 insertions(+), 3 deletions(-)\n>>  create mode 100644 perl/Git/Gettext.pm\n>>\n>> diff --git a/Makefile b/Makefile\n>> index dce2faa..2101713 100644\n>> --- a/Makefile\n>> +++ b/Makefile\n>> @@ -1884,7 +1884,9 @@ cscope:\n>>       $(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n>>\n>>  pot:\n>> -     $(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n>> +     $(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n>> +     $(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n>\n> Shouldn't this line be in earlier patch, i.e. in \"gettext: Add a\n> Gettext interface for shell scripts\"?\n\nIt needed to be split up into seperate line in the Perl commit because ...\n\n>> +     $(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n>\n> From gettext documentation (in gettext.info, chapter \"13.5.18 Perl\"):\n>\n>  Extractor\n>     `xgettext -k__ -k\\$__ -k%__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2\n>     -kN__ -k'\n>\n> Is it equivalent to specifying 'xgettext --language=Perl'?\n\nI'm doing --language=Perl because gettext doesn't recognize .perl as a\nvalid Perl extension. It only knows about `pl', `PL', `pm', `cgi'. (As\nan aside, I haven't found why Git chose to use the quaint .perl\nextension).\n\nBut yeah, using --language=Perl is overshooting it with regards to\nkeyword extraction. From \"5.1 Invoking the `xgettext' Program\":\n\n     To disable the default keyword specifications, the option `-k' or\n     `--keyword' or `--keyword=', without a KEYWORDSPEC, can be used.\n\nI'll check if I can supply --keyword to all the XGETTEXT invocations.\n\n> Of course the above assumes that you are using Locale::TextDomain, or\n> at least use the same conventions.\n>\n>>\n>>  POFILES := $(wildcard po/*.po)\n>>  MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n>> diff --git a/git-send-email.perl b/git-send-email.perl\n>> index 111c981..a36718e 100755\n>> --- a/git-send-email.perl\n>> +++ b/git-send-email.perl\n>> @@ -26,6 +26,7 @@ use Term::ANSIColor;\n>>  use File::Temp qw/ tempdir tempfile /;\n>>  use Error qw(:try);\n>>  use Git;\n>> +use Git::Gettext qw< :all >;\n>\n> Please follow the existing convention, i.e.\n>\n>  +use Git::Gettext qw(:all);\n>\n> like you see in context line for 'use Error'.\n>\n>\n> Well, not that git-send-email.perl is very consistent about this\n> issue, see 'use File::Temp qw/ tempdir tempfile /;' versus\n> 'use Error qw(:try);' but I'd reather you didn't introduce yet\n> another form.\n\nOK. I'll change that. I usually just pick whatever Perl quote\ndelimiters that happen to, literally, be close at hand at the time :)\n\n>>  Getopt::Long::Configure qw/ pass_through /;\n>>\n>> @@ -674,7 +675,7 @@ if (!defined $sender) {\n>>       $sender = $repoauthor || $repocommitter || '';\n>>       $sender = ask(\"Who should the emails appear to be from? [$sender] \",\n>>                     default => $sender);\n>> -     print \"Emails will be sent from: \", $sender, \"\\n\";\n>> +     printf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n>\n> As I wrote, this IMHO should be either\n>\n>  +     printf __(\"Emails will be sent from: %s\\n\"), $sender;\n>\n> or\n>\n>  +     print __x(\"Emails will be sent from: {sender}\\n\", sender => $sender);\n>\n> (note that parantheses differ in those two examples).\n\nI'd prefer the former argument expansion form (i.e. %s, not\n{$sender}), just so translators don't have to deal with two different\nargument forms.\n\nAs for __ or gettext I don't mind. I just picked the former on a whim\nto match the Shell version. Maybe I should just change C|Perl|Shell to\nuse _?\n\nAnd we can use _, __ is just used to disambiguate it from the _\nfilehandle, and Perl's pretty good at disambiguating that already:\n\n    $ perl -E 'sub _ ($) { scalar reverse $_[0] }; say _(\"moo\"); stat\n\"/etc/hosts\"; say ((stat(_))[7])'\n    oom\n    168\n\n>>       $prompting++;\n>>  }\n>>\n>> diff --git a/perl/Git/Gettext.pm b/perl/Git/Gettext.pm\n>> new file mode 100644\n>> index 0000000..f434783\n>> --- /dev/null\n>> +++ b/perl/Git/Gettext.pm\n>> @@ -0,0 +1,83 @@\n>> +package Git::Gettext;\n>\n> Should this package be named Git::Gettext, or other name would be\n> better, perhaps Git::I18N (like e.g. Games::Risk have\n> Games::Risk::I18N), or Git::Locale, or even Git::Translator?\n>\n> Not very important.\n\nI really have no opinion on that, but it does seem like a lot of Perl\npackages on CPAN use the ::I18N suffix.\n\n>> +use strict;\n>> +use warnings;\n>> +use Exporter;\n>> +use base 'Exporter';\n>\n> O.K.\n>\n> The alternative would be to use\n>\n>  +use Exporter qw(import);\n\nNot if we want to maintain 5.6 support. The `use Exporter \"import\"'\nform was only introduced in 5.8. I use it everywhere where I don't\nhave to care about 5.6 support (which is everywhere but Git).\n\n>> +\n>> +our $VERSION = '0.01';\n>> +\n>> +our @EXPORT;\n>> +our @EXPORT_OK = qw< gettext >;\n>\n> Same comment as above: more common way is to use qw(gettext) not\n> qw< gettext >; it is also the notation used in Exporter documentation.\n\nWill do.\n\n>> +our %EXPORT_TAGS;\n>> +@{ $EXPORT_TAGS{'all'} } = @EXPORT_OK;\n>\n> Why not simply\n>\n>  +our %EXPORT_TAGS = ('all' => [ @EXPORT_OK ]);\n>\n> or the reverse\n>\n>  +our %EXPORT_TAGS = ('all' => [qw(gettext)]);\n>  +our @EXPORT_OK   = @{$EXPORT_TAGS{'all'}};\n>\n> or the reverse using tag utility functions\n>\n>  +our %EXPORT_TAGS = ('all' => [qw(gettext)]);\n>  +Exporter::export_ok_tags('all');\n\nJust because it some old code of mine I had around that I copied\nfrom. I could rewrite it to a nicer form.\n\nActually I was considering changing it to just have @EXPORT and\nnothing else. You're going to use gettext if you use the medule\nanyway, so we might as well just import them all everywhere we use\nGettext in Perl.\n\n>> +\n>> +sub __bootstrap_locale_messages {\n>> +     our $TEXTDOMAIN = 'git';\n>> +\n>> +     # TODO: How do I make the sed replacements in the top level\n>> +     # Makefile reach me here?\n>> +     #our $TEXTDOMAINDIR = q|@@LOCALEDIR@@|;\n>\n> In Perl (well, in gitweb/gitweb.perl) we use '++VAR++' and not\n> '@@VAR@@' for placeholders, because '@' is sigil in Perl.  This is not\n> important in above example, because it is not interpolated string.\n\nI'll change it to follow that convention.\n\n> Make invoked on perl/Makefile, when invoked from main Makefile by\n> '$(MAKE) -C perl' (via QUIET_SUBDIR0) passes 'localedir' to submake;\n> perl/Makefile should probably have something like\n>\n>  localedir ?= $(sharedir)/locale\n>\n> That is assuming that 'localedir' is added to list of exported\n> variables.\n>\n> But I am not sure how such substitution should be performed.\n\nI'll try to get something like that to work. Actually the main problem\nseemed to be that it had a hybrid handwritten Makefile and one made by\nEU::MM.\n\n>> +     our $TEXTDOMAINDIR = q</usr/local/share/locale>;\n>\n> Why q<...> and not simply '...'?\n\nSame reason I use qw<>, that is no particular reason other than it\nbeing easier to type on my keyboard. I'll just change it to ''.\n\n>> +     require POSIX;\n>> +     POSIX->import(qw< setlocale >);\n>> +     # Non-core prerequisite module\n>> +     require Locale::Messages;\n>> +     Locale::Messages->import(qw< :locale_h :libintl_h >);\n>> +\n>> +     setlocale(LC_MESSAGES(), '');\n>> +     setlocale(LC_CTYPE(), '');\n>> +     textdomain($TEXTDOMAIN);\n>> +     bindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n>> +\n>> +     return;\n>> +}\n>\n> This would probably be a bit simpler with Locale::TextDomain.\n>\n>> +\n>> +BEGIN\n>> +{\n>> +     local ($@, $!);\n>> +     eval { __bootstrap_locale_messages() };\n>> +     if ($@) {\n>> +             # Oh noes, no Locale::Messages here\n>> +             *gettext = sub ($) { $_[0] };\n>\n> Do you intended to use subroutine protytype here?  Ah, I see that\n> Locale::Messages::gettext has the same prototype...\n\nYeah, otherwise the fallback would have different semantics.\n\n>> +     }\n>> +}\n>\n> Does it need to be in BEGIN block?  Probably yes.\n\nI'm pretty sure it needs to all be at BEGIN time. I recall that\ndeclaring prototypes at runtime was an error in some older versions,\nbut it works now:\n\n    $ perl -E '*meh = sub ($) { \"foo\" }; say prototype \"meh\"'\n    $\n\nAnyway since it's code that's being use'd it's going to always be at\nBEGIN time anyway. I just wanted to be explicit.\n\n>> +\n>> +1;\n>> +\n>> +__END__\n>> +\n>\n> It's nice that you have provided documentation.\n>\n>> +=head1 NAME\n>> +\n>> +Git::Gettext - Perl interface to Git's Gettext localizations\n>> +\n>> +=head1 DESCRIPTION\n>> +\n>> +Git's internal interface to Gettext via L<Locale::Messages>. If\n>> +L<Locale::Messages> can't be loaded (it's not a core module) we\n>> +provide stub passthrough fallbacks.\n>\n> Very good.\n>\n> It would probably be better though to use L<Locale::TextDomain>\n> instead of low(er)-level L<Locale::Messages>.\n>\n>> +\n>> +=head1 FUNCTIONS\n>> +\n>> +=head2 gettext($)\n>> +\n>> +L<Locale::Messages>'s gettext function if all goes well, otherwise our\n>> +passthrough fallback function.\n>\n> Other packages use _T() function for that, or like Locale::TextDomain\n> __() function.\n>\n>> +\n>> +=head1 EXPORTS\n>> +\n>> +Exports are done via L<Exporter>. Invididual functions can be\n>> +exporter, or all of them via the C<:all> export tag.\n>\n> Shouldn't this be described in less technical way in SYNOPSIS and\n> DESCRIPTION sections instead?\n\nYeah, maybe. But there's a convention for `=head1 EXPORTS' in perl\ncore / CPAN. So that's what I added at a whim.\n\n>> +\n>> +=head1 AUTHOR\n>> +\n>> +E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n>> +\n>> +=head1 LICENSE AND COPYRIGHT\n>> +\n>> +Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n>> +\n>> +This program is free software, you can redistribute it and/or modify\n>> +it under the same terms as Perl itself.\n>\n> Which is dual licensed: GPL + Perl artistic.\n>\n> Was it intended to use 'same terms as Perl itself' rather than GPLv2\n> or GPLv2+?\n\nIt's the permissive boilerplate I auto-insert for Perl code. I'll just\nremove it. The COPYING file at the top level will suffice.\n\n>> +\n>> +=cut\n>> diff --git a/perl/Makefile.PL b/perl/Makefile.PL\n>> index 0b9deca..702ec7c 100644\n>> --- a/perl/Makefile.PL\n>> +++ b/perl/Makefile.PL\n>> @@ -16,7 +16,10 @@ endif\n>>  MAKE_FRAG\n>>  }\n>>\n>> -my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n>> +my %pm = (\n>> +     'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n>> +     'Git/Gettext.pm' => '$(INST_LIBDIR)/Git/Gettext.pm',\n>> +);\n>>\n>>  # We come with our own bundled Error.pm. It's not in the set of default\n>>  # Perl modules so install it if it's not available on the system yet.\n>> --\n>> 1.7.1.248.gcd6d1\n>>\n"},{"id":"142727","messageId":"201006012322.24899.jnareb@gmail.com","threadId":"23941","inReplyTo":"1275415908-24838-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RCF] autoconf: Check if <libintl.h> exists and set NO_GETTEXT","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-06-01T21:22:23Z","receivedAt":"2010-06-01T21:22:23Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Tue, Jun 1, 2010, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, Jun 1, 2010 at 17:01, Jakub Narebski <jnareb@gmail.com> wrote:\n> > [...]\n> > Could you also provide change to configure.ac, so that ./configure\n> > would detect if we have gettext installed or not?  Thanks in advance.\n> \n> Here's a check that just checks if we have libintl.h similar to the\n> existing checks for libgen.h and other headers.\n> \n> Do you think this be adequate?\n\nI'm not sure.  If NO_GETTEXT is used only to protect '#include <libintl.h>'\nit might be enough.\n\n> \n>  config.mak.in |    1 +\n>  configure.ac  |    6 ++++++\n>  2 files changed, 7 insertions(+), 0 deletions(-)\n> \n> diff --git a/config.mak.in b/config.mak.in\n> index 0d4b64d..a15f3c1 100644\n> --- a/config.mak.in\n> +++ b/config.mak.in\n> @@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@\n>  NO_EXPAT=@NO_EXPAT@\n>  NO_LIBGEN_H=@NO_LIBGEN_H@\n>  HAVE_PATHS_H=@HAVE_PATHS_H@\n> +NO_GETTEXT=@NO_GETTEXT@\n>  NEEDS_LIBICONV=@NEEDS_LIBICONV@\n>  NEEDS_SOCKET=@NEEDS_SOCKET@\n>  NEEDS_RESOLV=@NEEDS_RESOLV@\n\nO.K.\n\n> diff --git a/configure.ac b/configure.ac\n> index 71038fc..7bebfd8 100644\n> --- a/configure.ac\n> +++ b/configure.ac\n> @@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],\n>  [HAVE_PATHS_H=])\n>  AC_SUBST(HAVE_PATHS_H)\n>  #\n> +# Define NO_GETTEXT if you don't have libintl.h\n> +AC_CHECK_HEADER([libintl.h],\n> +[NO_GETTEXT=],\n> +[NO_GETTEXT=YesPlease])\n> +AC_SUBST(NO_GETTEXT)\n> +#\n>  # Define NO_STRCASESTR if you don't have strcasestr.\n>  GIT_CHECK_FUNC(strcasestr,\n>  [NO_STRCASESTR=],\n\nThe getext documentation says that `gettext.m4' defines AM_GNU_GETTEXT\nmacro that tests for the presence of GNU gettext function family.\n\nThe complication is that `gettext.m4' might not exist, and then\nAM_GNU_GETTEXT would be not defined.  So if we are to use\nAM_GNU_GETTEXT, we should I guess protect it with m4_ifdef():\n\n  m4_ifdef([AM_GNU_GETTEXT], [AM_GNU_GETTEXT([external])])\n\nor something like that.  And of course we need to work around the fact\nthat AM_GNU_GETTEXT sets USE_NLS to either 'yes' or 'no' instead of\nsetting setting NO_GETTEXT to either non-empty or empty value.\n\nOr we can do something similar to what we do for NEEDS_LIBICINV /\nNO_ICONV, namely make ./configure compile simple test program using\ngettext.\n\nCc-ed Ben Walton and David M. Syzdek: perhaps they can help with this\nissue.\n-- \nJakub Narebski\nPoland\n"},{"id":"142734","messageId":"1275435597-4017-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 0/7] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:50Z","receivedAt":"2010-06-01T23:39:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Here's version 3 of the patch series begun by Jeff Epler to make Git\noptionally translatable with GNU gettext.\n\nThis version contains a lot of fixes to issues pointe out by Jakub\nNarebski, and other misc.\n\nSince the last RFC:\n\n  * Squashed some infrastructure patches into the initial commit.\n\n  * Added basic sanity testing for the Gettext support\n\n  * .mo files aren't installed on `make install` time if NO_GETTEXT\n    was specified during the build.\n\n    In C gettext support isn't compiled in. But this happens\n    implicitly in Shell/Perl because the locale files won't be there\n    on the system.\n\n  * NO_GETTEXT is now set correctly depending on whether libintl.h\n    exists when autoconf is used to build Git. Whether this is the\n    best approach to gettext detection with autoconf is being\n    discussed in the \"[PATCH/RCF] autoconf: Check if <libintl.h>\n    exists and set NO_GETTEX\" thread.\n\n  * The localedir is now passed to the Perl code via Makefile\n    trickery. It's no longer hardcoded to /usr/local/share/locale\n\n  * Add `--keyword=` to all xgettext invocations. This way we make\n    sure that only our gettext functions are extracted, not the\n    defaults xgettext.\n\n  * Git::Gettext is now called Git::I18N\n\n  * Remove LICENSE from I18N.pm. It was a boilerplate that shouldn't\n    have been there.\n\n  * Use qw() not qw< > in Perl code.\n\n  * Changed the interface to Git::I18N. Now it exports all its\n    functions by default. If something's using the module it's going\n    to want to import everything anyway. This makes the issue of '@{\n    $EXPORT_TAGS{'all'} }' being ugly syntax moot since it isn't used\n    anymore.\n\n    Users can still import selectively by specifying arguments to\n    import().\n\n  * The GIT_TEXTDOMAINDIR environment variable can be set to override\n    where the C/Perl/Shell locale files are found. This is intended to\n    be set by the test suite.\n\n  * The boolean test for whether gettext.sh was successfully loaded\n    was inverted (oops!)\n\nThings that haven't changed:\n\n  Jakub pointed out some things that I might want to change that I\n  didn't yet. Mostly because I didn't have time yet.\n\n  * Git::I18N still uses Locale::Messages, not Locale::TextDomain.\n\n    I'm still not convinced that the low-level Locale::Messages\n    interface isn't a better fit for us. But I didn't get\n    Locale::TextDomain working at all today so I'm still using\n    Locale::Messages.\n\n  * Perl still uses gettext($), not __($) (see above).\n\n  * use Exporter 'import': Subclassing Exporter instead since we\n    apparently need Perl 5.6 compatibility.\n\nJeff Epler (1):\n  Add infrastructure for translating Git with gettext\n\nÆvar Arnfjörð Bjarmason (6):\n  gettext: Add a Gettext interface for shell scripts\n  gettext: Add a Gettext interface for Perl\n  Makefile: Don't install Gettext .mo files if NO_GETTEXT\n  Makefile: Override --keyword= for all languages\n  gettext: Basic sanity tests for Git's Gettext support\n  gettext: Add a skeleton po/is.po\n\n .gitignore          |    1 +\n Makefile            |   43 ++++++++-\n config.mak.in       |    1 +\n configure.ac        |    6 +\n gettext.c           |   25 +++++\n gettext.h           |   13 +++\n git-pull.sh         |   15 ++--\n git-send-email.perl |    3 +-\n git-sh-setup.sh     |   33 ++++++\n git.c               |    3 +\n perl/Git/I18N.pm    |   73 +++++++++++++\n perl/Makefile       |    3 +-\n perl/Makefile.PL    |   14 +++-\n po/.gitignore       |    1 +\n po/is.po            |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t0200-gettext.sh  |   28 +++++\n wt-status.c         |  129 ++++++++++++------------\n 17 files changed, 597 insertions(+), 76 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 perl/Git/I18N.pm\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n create mode 100755 t/t0200-gettext.sh\n"},{"id":"142735","messageId":"1275435597-4017-2-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 1/7] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:51Z","receivedAt":"2010-06-01T23:39:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Jeff Epler <jepler@unpythonic.net>\n\nChange the build process to use GNU's libintl if it's available. If\nnot we define our own skeleton replacement functions which degrade\ngracefully to English.\n\nGettext .mo files will be installed and looked for in\n$(prefix)/share/locale. GIT_LOCALEDIR can also be set to override\nthat, this variable is only intended for testing Git itself.\n\nSigned-off-by: Jeff Epler <jepler@unpythonic.net>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore    |    1 +\n Makefile      |   30 +++++++++++++\n config.mak.in |    1 +\n configure.ac  |    6 +++\n gettext.c     |   25 +++++++++++\n gettext.h     |   13 ++++++\n git.c         |    3 +\n po/.gitignore |    1 +\n wt-status.c   |  129 +++++++++++++++++++++++++++++----------------------------\n 9 files changed, 145 insertions(+), 64 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 po/.gitignore\n\ndiff --git a/.gitignore b/.gitignore\nindex 14e2b6b..d22c0e5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -204,3 +204,4 @@\n *.pdb\n /Debug/\n /Release/\n+/share/\ndiff --git a/Makefile b/Makefile\nindex d5d6565..4de0627 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -297,6 +297,8 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n PTHREAD_LIBS = -lpthread\n+XGETTEXT = xgettext\n+MSGFMT = msgfmt\n \n export TCL_PATH TCLTK_PATH\n \n@@ -523,6 +525,7 @@ LIB_H += userdiff.h\n LIB_H += utf8.h\n LIB_H += xdiff-interface.h\n LIB_H += xdiff/xdiff.h\n+LIB_H += gettext.h\n \n LIB_OBJS += abspath.o\n LIB_OBJS += advice.o\n@@ -564,6 +567,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gettext.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\n@@ -1386,6 +1390,12 @@ ifdef USE_NED_ALLOCATOR\n        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n+ifdef NO_GETTEXT\n+\tCOMPAT_CFLAGS += -DNO_GETTEXT\n+else\n+\tLIBINTL = -lintl\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1415,6 +1425,7 @@ ifndef V\n \tQUIET_BUILT_IN = @echo '   ' BUILTIN $@;\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_SUBDIR0  = +@subdir=\n \tQUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \\\n \t\t\t $(MAKE) $(PRINT_DIR) -C $$subdir\n@@ -1442,6 +1453,7 @@ gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n@@ -1868,6 +1880,17 @@ cscope:\n \t$(RM) cscope*\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n+pot:\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+all:: $(MOFILES)\n+share/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t@mkdir -p $(dir $@)\n+\t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n+\n ### Detect prefix changes\n TRACK_CFLAGS = $(subst ','\\'',$(ALL_CFLAGS)):\\\n              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n@@ -1980,6 +2003,9 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n+\t(cd share && tar cf - locale) | \\\n+\t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n@@ -2127,6 +2153,10 @@ ifndef NO_TCLTK\n \t$(MAKE) -C git-gui clean\n endif\n \t$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS\n+ifndef NO_GETTEXT\n+\t$(RM) po/git.pot\n+\t$(RM) -r share/\n+endif\n \n .PHONY: all install clean strip\n .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell\ndiff --git a/config.mak.in b/config.mak.in\nindex 0d4b64d..a15f3c1 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@\n NO_EXPAT=@NO_EXPAT@\n NO_LIBGEN_H=@NO_LIBGEN_H@\n HAVE_PATHS_H=@HAVE_PATHS_H@\n+NO_GETTEXT=@NO_GETTEXT@\n NEEDS_LIBICONV=@NEEDS_LIBICONV@\n NEEDS_SOCKET=@NEEDS_SOCKET@\n NEEDS_RESOLV=@NEEDS_RESOLV@\ndiff --git a/configure.ac b/configure.ac\nindex 71038fc..7bebfd8 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],\n [HAVE_PATHS_H=])\n AC_SUBST(HAVE_PATHS_H)\n #\n+# Define NO_GETTEXT if you don't have libintl.h\n+AC_CHECK_HEADER([libintl.h],\n+[NO_GETTEXT=],\n+[NO_GETTEXT=YesPlease])\n+AC_SUBST(NO_GETTEXT)\n+#\n # Define NO_STRCASESTR if you don't have strcasestr.\n GIT_CHECK_FUNC(strcasestr,\n [NO_STRCASESTR=],\ndiff --git a/gettext.c b/gettext.c\nnew file mode 100644\nindex 0000000..c67e5ca\n--- /dev/null\n+++ b/gettext.c\n@@ -0,0 +1,25 @@\n+#ifdef NO_GETTEXT\n+void git_setup_gettext(void) {}\n+#else\n+#include \"exec_cmd.h\"\n+#include <libintl.h>\n+#include <stdlib.h>\n+\n+void git_setup_gettext(void) {\n+\tchar *podir;\n+    char *envdir = getenv(\"GIT_TEXTDOMAINDIR\");\n+\n+\tif (envdir) {\n+\t\t(void)bindtextdomain(\"git\", envdir);\n+\t} else {\n+\t\tpodir = (char *)system_path(\"share/locale\");\n+\t\tif (!podir) return;\n+\t\t(void)bindtextdomain(\"git\", podir);\n+\t\tfree(podir);\n+\t}\n+\n+\t(void)setlocale(LC_MESSAGES, \"\");\n+\t(void)setlocale(LC_CTYPE, \"\");\n+\t(void)textdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nnew file mode 100644\nindex 0000000..a99da6a\n--- /dev/null\n+++ b/gettext.h\n@@ -0,0 +1,13 @@\n+#ifndef GETTEXT_H\n+#define GETTEXT_H\n+\n+void git_setup_gettext(void);\n+\n+#ifdef NO_GETTEXT\n+#define _(s) (s)\n+#else\n+#include <libintl.h>\n+#define _(s) gettext(s)\n+#endif\n+\n+#endif\ndiff --git a/git.c b/git.c\nindex 99f0363..d749eab 100644\n--- a/git.c\n+++ b/git.c\n@@ -3,6 +3,7 @@\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"run-command.h\"\n+#include \"gettext.h\"\n \n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\\n\"\n@@ -490,6 +491,8 @@ int main(int argc, const char **argv)\n \tif (!cmd)\n \t\tcmd = \"git-help\";\n \n+\tgit_setup_gettext();\n+\n \t/*\n \t * \"git-xxxx\" is the same as \"git xxxx\", but we obviously:\n \t *\ndiff --git a/po/.gitignore b/po/.gitignore\nnew file mode 100644\nindex 0000000..221000e\n--- /dev/null\n+++ b/po/.gitignore\n@@ -0,0 +1 @@\n+/*.pot\ndiff --git a/wt-status.c b/wt-status.c\nindex 14e0acc..70b4293 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"run-command.h\"\n #include \"remote.h\"\n+#include \"gettext.h\"\n \n static char default_wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL, /* WT_STATUS_HEADER */\n@@ -49,33 +50,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Unmerged paths:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t;\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changes to be committed:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_dirty_header(struct wt_status *s,\n@@ -84,17 +85,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changed but not updated:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changed but not updated:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (!has_deleted)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to update what will be committed)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add <file>...\\\" to update what will be committed)\"));\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n \tif (has_dirty_submodules)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (commit or discard the untracked or modified content in submodules)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_other_header(struct wt_status *s,\n@@ -102,16 +103,16 @@ static void wt_status_print_other_header(struct wt_status *s,\n \t\t\t\t\t const char *how)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n-\tcolor_fprintf_ln(s->fp, c, \"# %s files:\", what);\n+\tcolor_fprintf_ln(s->fp, c, _(\"# %s files:\"), what);\n \tif (!advice_status_hints)\n \t\treturn;\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\", how);\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_trailer(struct wt_status *s)\n {\n-\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n }\n \n #define quote_path quote_path_relative\n@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,\n \tconst char *c = color(WT_STATUS_UNMERGED, s);\n \tstruct wt_status_change_data *d = it->util;\n \tstruct strbuf onebuf = STRBUF_INIT;\n-\tconst char *one, *how = \"bug\";\n+\tconst char *one, *how = _(\"bug\");\n \n \tone = quote_path(it->string, -1, &onebuf, s->prefix);\n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (d->stagemask) {\n-\tcase 1: how = \"both deleted:\"; break;\n-\tcase 2: how = \"added by us:\"; break;\n-\tcase 3: how = \"deleted by them:\"; break;\n-\tcase 4: how = \"added by them:\"; break;\n-\tcase 5: how = \"deleted by us:\"; break;\n-\tcase 6: how = \"both added:\"; break;\n-\tcase 7: how = \"both modified:\"; break;\n+\tcase 1: how = _(\"both deleted:\"); break;\n+\tcase 2: how = _(\"added by us:\"); break;\n+\tcase 3: how = _(\"deleted by them:\"); break;\n+\tcase 4: how = _(\"added by them:\"); break;\n+\tcase 5: how = _(\"deleted by us:\"); break;\n+\tcase 6: how = _(\"both added:\"); break;\n+\tcase 7: how = _(\"both modified:\"); break;\n \t}\n-\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n+\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n \tstrbuf_release(&onebuf);\n }\n \n@@ -161,13 +162,13 @@ static void wt_status_print_change_data(struct wt_status *s,\n \t\tbreak;\n \tcase WT_STATUS_CHANGED:\n \t\tif (d->new_submodule_commits || d->dirty_submodule) {\n-\t\t\tstrbuf_addstr(&extra, \" (\");\n+\t\t\tstrbuf_addstr(&extra, _(\" (\"));\n \t\t\tif (d->new_submodule_commits)\n-\t\t\t\tstrbuf_addf(&extra, \"new commits, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"new commits, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n-\t\t\t\tstrbuf_addf(&extra, \"modified content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"modified content, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n-\t\t\t\tstrbuf_addf(&extra, \"untracked content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"untracked content, \"));\n \t\t\tstrbuf_setlen(&extra, extra.len - 2);\n \t\t\tstrbuf_addch(&extra, ')');\n \t\t}\n@@ -178,40 +179,40 @@ static void wt_status_print_change_data(struct wt_status *s,\n \tone = quote_path(one_name, -1, &onebuf, s->prefix);\n \ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"new file:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"copied:     %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"deleted:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"modified:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"renamed:    %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"typechange: %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unknown:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unmerged:   %s\"), one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", status);\n+\t\tdie(_(\"bug: unhandled diff status %c\"), status);\n \t}\n \tif (extra.len) {\n-\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"), extra.buf);\n \t\tstrbuf_release(&extra);\n \t}\n-\tfprintf(s->fp, \"\\n\");\n+\tfprintf(s->fp, _(\"\\n\"));\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)\n \tconst char *branch_color = color(WT_STATUS_HEADER, s);\n \n \tif (s->branch) {\n-\t\tconst char *on_what = \"On branch \";\n+\t\tconst char *on_what = _(\"On branch \");\n \t\tconst char *branch_name = s->branch;\n \t\tif (!prefixcmp(branch_name, \"refs/heads/\"))\n \t\t\tbranch_name += 11;\n \t\telse if (!strcmp(branch_name, \"HEAD\")) {\n \t\t\tbranch_name = \"\";\n \t\t\tbranch_color = color(WT_STATUS_NOBRANCH, s);\n-\t\t\ton_what = \"Not currently on any branch.\";\n+\t\t\ton_what = _(\"Not currently on any branch.\");\n \t\t}\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"# \");\n \t\tcolor_fprintf_ln(s->fp, branch_color, \"%s%s\", on_what, branch_name);\n@@ -634,9 +635,9 @@ void wt_status_print(struct wt_status *s)\n \t}\n \n \tif (s->is_initial) {\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"# Initial commit\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n \t}\n \n \twt_status_print_updated(s);\n@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_submodule_summary(s, 1);  /* unstaged */\n \t}\n \tif (s->show_untracked_files) {\n-\t\twt_status_print_other(s, &s->untracked, \"Untracked\", \"add\");\n+\t\twt_status_print_other(s, &s->untracked, _(\"Untracked\"), _(\"add\"));\n \t\tif (s->show_ignored_files)\n-\t\t\twt_status_print_other(s, &s->ignored, \"Ignored\", \"add -f\");\n+\t\t\twt_status_print_other(s, &s->ignored, _(\"Ignored\"), _(\"add -f\"));\n \t} else if (s->commitable)\n-\t\tfprintf(s->fp, \"# Untracked files not listed%s\\n\",\n+\t\tfprintf(s->fp, _(\"# Untracked files not listed%s\\n\"),\n \t\t\tadvice_status_hints\n-\t\t\t? \" (use -u option to show untracked files)\" : \"\");\n+\t\t\t? _(\" (use -u option to show untracked files)\") : \"\");\n \n \tif (s->verbose)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tfprintf(s->fp, \"# No changes\\n\");\n+\t\t\tfprintf(s->fp, _(\"# No changes\\n\"));\n \t\telse if (s->nowarn)\n \t\t\t; /* nothing */\n \t\telse if (s->workdir_dirty)\n-\t\t\tprintf(\"no changes added to commit%s\\n\",\n+\t\t\tprintf(_(\"no changes added to commit%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\") : \"\");\n \t\telse if (s->untracked.nr)\n-\t\t\tprintf(\"nothing added to commit but untracked files present%s\\n\",\n+\t\t\tprintf(_(\"nothing added to commit but untracked files present%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (s->is_initial)\n \t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (create/copy files and use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (create/copy files and use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (!s->show_untracked_files)\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (use -u to show untracked files)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (use -u to show untracked files)\") : \"\");\n \t\telse\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (working directory clean)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (working directory clean)\") : \"\");\n \t}\n }\n \n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142733","messageId":"1275435597-4017-3-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 2/7] gettext: Add a Gettext interface for shell scripts","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:52Z","receivedAt":"2010-06-01T23:39:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use GNU's gettext.sh in git-sh-setup if it's available, otherwise\nfallback on our own custom functions.\n\nA couple of strings in git-pull.sh are now translatable as a proof of\nconcept, including a multiline string.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile        |    7 +++++--\n git-pull.sh     |   15 ++++++++-------\n git-sh-setup.sh |   33 +++++++++++++++++++++++++++++++++\n 3 files changed, 46 insertions(+), 9 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 4de0627..dce2faa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -272,6 +272,7 @@ mandir = share/man\n infodir = share/info\n gitexecdir = libexec/git-core\n sharedir = $(prefix)/share\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ifeq ($(prefix),/usr)\n@@ -285,7 +286,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir\n+export prefix bindir sharedir localedir sysconfdir\n \n CC = gcc\n AR = ar\n@@ -1455,6 +1456,7 @@ htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n+LOCALEDIR_SQ = $(subst ','\\'',$(localedir))\n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n PYTHON_PATH_SQ = $(subst ','\\'',$(PYTHON_PATH))\n@@ -1548,6 +1550,7 @@ $(RM) $@ $@+ && \\\n sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n+    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \\\n     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \\\n     -e $(BROKEN_PATH_FIX) \\\n     $@.sh >$@+\n@@ -1881,7 +1884,7 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 1a4729f..22a6da2 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -121,8 +121,8 @@ error_on_no_merge_candidates () {\n \tdo\n \t\tcase \"$opt\" in\n \t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"Fetching tags only, you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n+\t\t\tgettext \"Fetching tags only, you probably meant:\"; echo\n+\t\t\tgettext \"  git fetch --tags\"; echo\n \t\t\texit 1\n \t\tesac\n \tdone\n@@ -154,11 +154,12 @@ error_on_no_merge_candidates () {\n \t\techo \"a branch. Because this is not the default configured remote\"\n \t\techo \"for your current branch, you must specify a branch on the command line.\"\n \telif [ -z \"$curr_branch\" ]; then\n-\t\techo \"You are not currently on a branch, so I cannot use any\"\n-\t\techo \"'branch.<branchname>.merge' in your configuration file.\"\n-\t\techo \"Please specify which remote branch you want to use on the command\"\n-\t\techo \"line and try again (e.g. 'git pull <repository> <refspec>').\"\n-\t\techo \"See git-pull(1) for details.\"\n+        gettext \"You are not currently on a branch, so I cannot use any\n+'branch.<branchname>.merge' in your configuration file.\n+Please specify which remote branch you want to use on the command\n+line and try again (e.g. 'git pull <repository> <refspec>').\n+See git-pull(1) for details.\";\n+        echo\n \telif [ -z \"$upstream\" ]; then\n \t\techo \"You asked me to pull without telling me which branch you\"\n \t\techo \"want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in\"\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex 6131670..d67901c 100644\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -211,3 +211,36 @@ case $(uname -s) in\n \t}\n \t;;\n esac\n+\n+# Try to use libintl's gettext.sh, or fall back to English if we\n+# can't.\n+. gettext.sh\n+if test $? -eq 0\n+then\n+    TEXTDOMAIN=git\n+    export TEXDTOMAIN\n+    TEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+    export TEXTDOMAINDIR\n+else\n+    # Since GNU gettext.sh isn't available we'll have to define our\n+    # own dummy functions.\n+\n+    # This code adapted from NessusClient-1.0.2's nessusclient-mkcert\n+    # by Michel Arboi <arboi@alussinan.org>. The original code is\n+    # under the GPLv2.\n+\n+    # Not everyone has echo -n\n+    case $(echo -n) in\n+        \\-n)    Xn=   ; Xc='\\c' ;;\n+        *)      Xn=-n ; Xc=\n+    esac\n+\n+    gettext () {\n+        echo $Xn \"$1\" $Xc\n+    }\n+\n+    eval_gettext () {\n+        eval_gettext_var=\"echo $1\"\n+        echo $Xn `eval $eval_gettext_var` $Xc\n+    }\n+fi\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142736","messageId":"1275435597-4017-4-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 3/7] gettext: Add a Gettext interface for Perl","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:53Z","receivedAt":"2010-06-01T23:39:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make Git's gettext messages available to Perl programs through\nLocale::Messages. Gracefully fall back to English on systems that\ndon't contain the module.\n\nThis contains some makefile hacks to pass localedir to\nperl/Makefile. Which in turn passes it to perl.mak, which'll use it to\nsearch/replace occurances of ++LOCALEDIR++ in .pm files.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile            |    6 +++-\n git-send-email.perl |    3 +-\n perl/Git/I18N.pm    |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Makefile       |    3 +-\n perl/Makefile.PL    |   14 +++++++++-\n 5 files changed, 94 insertions(+), 5 deletions(-)\n create mode 100644 perl/Git/I18N.pm\n\ndiff --git a/Makefile b/Makefile\nindex dce2faa..3f0e305 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1505,7 +1505,7 @@ ifndef NO_TCLTK\n \t$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all\n endif\n ifndef NO_PERL\n-\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all\n+\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all\n endif\n ifndef NO_PYTHON\n \t$(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all\n@@ -1884,7 +1884,9 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n+\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 111c981..b9288af 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -26,6 +26,7 @@ use Term::ANSIColor;\n use File::Temp qw/ tempdir tempfile /;\n use Error qw(:try);\n use Git;\n+use Git::I18N;\n \n Getopt::Long::Configure qw/ pass_through /;\n \n@@ -674,7 +675,7 @@ if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n \t$sender = ask(\"Who should the emails appear to be from? [$sender] \",\n \t              default => $sender);\n-\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n+\tprintf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n \t$prompting++;\n }\n \ndiff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\nnew file mode 100644\nindex 0000000..568fd3d\n--- /dev/null\n+++ b/perl/Git/I18N.pm\n@@ -0,0 +1,73 @@\n+package Git::I18N;\n+use strict;\n+use warnings;\n+use Exporter;\n+use base 'Exporter';\n+\n+our $VERSION = '0.01';\n+\n+our @EXPORT = qw(gettext);\n+our @EXPORT_OK = @EXPORT;\n+\n+sub __bootstrap_locale_messages {\n+\tour $TEXTDOMAIN = 'git';\n+\tour $TEXTDOMAINDIR = '++LOCALEDIR++';\n+\n+\trequire POSIX;\n+\tPOSIX->import(qw(setlocale));\n+\t# Non-core prerequisite module\n+\trequire Locale::Messages;\n+\tLocale::Messages->import(qw(:locale_h :libintl_h));\n+\n+\tsetlocale(LC_MESSAGES(), '');\n+\tsetlocale(LC_CTYPE(), '');\n+\ttextdomain($TEXTDOMAIN);\n+\tbindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n+\n+\treturn;\n+}\n+\n+BEGIN\n+{\n+\tlocal ($@, $!);\n+\teval { __bootstrap_locale_messages() };\n+\tif ($@) {\n+\t\t# Oh noes, no Locale::Messages here\n+\t\t*gettext = sub ($) { $_[0] };\n+\t}\n+}\n+\n+1;\n+\n+__END__\n+\n+=head1 NAME\n+\n+Git::I18N - Perl interface to Git's Gettext localizations\n+\n+=head1 SYNOPSIS\n+\n+\tuse Git::I18N;\n+\n+\tprint gettext(\"Welcome to Git!\\n\");\n+\n+\tprintf gettext(\"The following error occured: %s\\n\"), $error;\n+\n+=head1 DESCRIPTION\n+\n+Git's internal interface to Gettext via L<Locale::Messages>. If\n+L<Locale::Messages> can't be loaded (it's not a core module) we\n+provide stub passthrough fallbacks.\n+\n+=head1 FUNCTIONS\n+\n+=head2 gettext($)\n+\n+L<Locale::Messages>'s gettext function if all goes well, otherwise our\n+passthrough fallback function.\n+\n+=head1 AUTHOR\n+\n+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+=cut\ndiff --git a/perl/Makefile b/perl/Makefile\nindex 4ab21d6..4e624ff 100644\n--- a/perl/Makefile\n+++ b/perl/Makefile\n@@ -5,6 +5,7 @@ makfile:=perl.mak\n \n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+localedir_SQ = $(subst ','\\'',$(localedir))\n \n ifndef V\n \tQUIET = @\n@@ -38,7 +39,7 @@ $(makfile): ../GIT-CFLAGS Makefile\n \techo '\techo $(instdir_SQ)' >> $@\n else\n $(makfile): Makefile.PL ../GIT-CFLAGS\n-\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)'\n+\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)' --localedir='$(localedir_SQ)'\n endif\n \n # this is just added comfort for calling make directly in perl dir\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nindex 0b9deca..456d45b 100644\n--- a/perl/Makefile.PL\n+++ b/perl/Makefile.PL\n@@ -1,4 +1,12 @@\n+use strict;\n+use warnings;\n use ExtUtils::MakeMaker;\n+use Getopt::Long;\n+\n+# Sanity: die at first unknown option\n+Getopt::Long::Configure qw/ pass_through /;\n+\n+GetOptions(\"localedir=s\" => \\my $localedir);\n \n sub MY::postamble {\n \treturn <<'MAKE_FRAG';\n@@ -16,7 +24,10 @@ endif\n MAKE_FRAG\n }\n \n-my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n+my %pm = (\n+\t'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n+\t'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',\n+);\n \n # We come with our own bundled Error.pm. It's not in the set of default\n # Perl modules so install it if it's not available on the system yet.\n@@ -33,6 +44,7 @@ WriteMakefile(\n \tNAME            => 'Git',\n \tVERSION_FROM    => 'Git.pm',\n \tPM\t\t=> \\%pm,\n+\tPM_FILTER\t=> qq[\\$(PERL) -pe \"s<\\\\Q++LOCALEDIR++\\\\E><$localedir>\"],\n \tMAKEFILE\t=> 'perl.mak',\n \tINSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'\n );\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142739","messageId":"1275435597-4017-5-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 4/7] Makefile: Don't install Gettext .mo files if NO_GETTEXT","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:54Z","receivedAt":"2010-06-01T23:39:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the Makefile not to build/install .mo files as part of the\ndefault target if NO_GETTEXT=1 is given.\n\nThis was both redundant, and meant that the Perl and Shell programs\nwould use the Gettext strings, since they don't use the\ngit_setup_gettext() function in gettext.c, which is compiled to a stub\nif NO_GETTEXT=1 is set.\n\nReported-by: Jakub Narebski <jnareb@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 3f0e305..40eb1a2 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1891,7 +1891,9 @@ pot:\n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+ifndef NO_GETTEXT\n all:: $(MOFILES)\n+endif\n share/locale/%/LC_MESSAGES/git.mo: po/%.po\n \t@mkdir -p $(dir $@)\n \t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n@@ -2008,9 +2010,11 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+ifndef NO_GETTEXT\n \t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n \t(cd share && tar cf - locale) | \\\n \t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n+endif\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142738","messageId":"1275435597-4017-6-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 5/7] Makefile: Override --keyword= for all languages","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:55Z","receivedAt":"2010-06-01T23:39:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"By default xgettext will supply a default list of keywords depending\non the --language parameter. Disable this in favor of supplying a list\nof keywords manually.\n\nThis reduced the surface area for potential bugs.\n---\n Makefile |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 40eb1a2..62b8279 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1884,9 +1884,9 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n-\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n-\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n+\t$(XGETTEXT) --keyword= --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n+\t$(XGETTEXT) --join-existing --keyword= --keyword=gettext --output=po/git.pot --language=Shell $(SCRIPT_SH)\n+\t$(XGETTEXT) --join-existing --keyword= --keyword=gettext --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142737","messageId":"1275435597-4017-7-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 6/7] gettext: Basic sanity tests for Git's Gettext support","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:56Z","receivedAt":"2010-06-01T23:39:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"---\n t/t0200-gettext.sh |   28 ++++++++++++++++++++++++++++\n 1 files changed, 28 insertions(+), 0 deletions(-)\n create mode 100755 t/t0200-gettext.sh\n\ndiff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh\nnew file mode 100755\nindex 0000000..a8f9edd\n--- /dev/null\n+++ b/t/t0200-gettext.sh\n@@ -0,0 +1,28 @@\n+#!/bin/sh\n+\n+test_description='Gettext support for Git'\n+. ./test-lib.sh\n+. ../../git-sh-setup\n+\n+test_expect_success 'sanity: $TEXTDOMAIN is git' '\n+\ttest $TEXTDOMAIN = \"git\"\n+'\n+\n+test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n+\ttest -d $TEXTDOMAINDIR \n+'\n+\n+test_expect_success 'sanity: Icelandic locale was compiled' '\n+    test -f $TEXTDOMAINDIR/is/LC_MESSAGES/git.mo\n+'\n+\n+test_expect_success 'sanity: gettext(unknown) is passed through' '\n+    gettext \"\" > expect &&\n+    > actual &&\n+    test_cmp expect actual &&\n+    printf \"This is not a translation string\"  > expect\n+\tgettext \"This is not a translation string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_done\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142740","messageId":"1275435597-4017-8-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"1275173125-21010-1-git-send-email-avarab@gmail.com","subject":"[PATCH/RFC v3 7/7] gettext: Add a skeleton po/is.po","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-01T23:39:57Z","receivedAt":"2010-06-01T23:39:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This example is.po file translates a little bit of C, Shell and Perl\nas an example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n po/is.po |  282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 282 insertions(+), 0 deletions(-)\n create mode 100644 po/is.po\n\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..aa1923e\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,282 @@\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2010-05-30 19:24+0000\\n\"\n+\"PO-Revision-Date: 2010-06-01 22:15+0000\\n\"\n+\"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n+\"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"X-Poedit-Language: English\\n\"\n+\"X-Poedit-SourceCharset: utf-8\\n\"\n+\n+#: wt-status.c:53\n+msgid \"# Unmerged paths:\"\n+msgstr \"\"\n+\n+#: wt-status.c:59 wt-status.c:76\n+#, c-format\n+msgid \"#   (use \\\"git reset %s <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:61 wt-status.c:78\n+msgid \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:62\n+msgid \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"\n+msgstr \"\"\n+\n+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110\n+#: wt-status.c:115 wt-status.c:638 wt-status.c:640\n+msgid \"#\"\n+msgstr \"\"\n+\n+#: wt-status.c:70\n+msgid \"# Changes to be committed:\"\n+msgstr \"\"\n+\n+#: wt-status.c:88\n+msgid \"# Changed but not updated:\"\n+msgstr \"\"\n+\n+#: wt-status.c:92\n+msgid \"#   (use \\\"git add <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:94\n+msgid \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:95\n+msgid \"\"\n+\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working \"\n+\"directory)\"\n+msgstr \"\"\n+\n+#: wt-status.c:97\n+msgid \"#   (commit or discard the untracked or modified content in submodules)\"\n+msgstr \"\"\n+\n+#: wt-status.c:106\n+#, c-format\n+msgid \"# %s files:\"\n+msgstr \"\"\n+\n+#: wt-status.c:109\n+#, c-format\n+msgid \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:126\n+msgid \"bug\"\n+msgstr \"\"\n+\n+#: wt-status.c:129 wt-status.c:182\n+msgid \"#\\t\"\n+msgstr \"\"\n+\n+#: wt-status.c:131\n+msgid \"both deleted:\"\n+msgstr \"\"\n+\n+#: wt-status.c:132\n+msgid \"added by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:133\n+msgid \"deleted by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:134\n+msgid \"added by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:135\n+msgid \"deleted by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:136\n+msgid \"both added:\"\n+msgstr \"\"\n+\n+#: wt-status.c:137\n+msgid \"both modified:\"\n+msgstr \"\"\n+\n+#: wt-status.c:139\n+#, c-format\n+msgid \"%-20s%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:165\n+msgid \" (\"\n+msgstr \"\"\n+\n+#: wt-status.c:167\n+msgid \"new commits, \"\n+msgstr \"\"\n+\n+#: wt-status.c:169\n+msgid \"modified content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:171\n+msgid \"untracked content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:185\n+#, c-format\n+msgid \"new file:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:188\n+#, c-format\n+msgid \"copied:     %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:191\n+#, c-format\n+msgid \"deleted:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:194\n+#, c-format\n+msgid \"modified:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:197\n+#, c-format\n+msgid \"renamed:    %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:200\n+#, c-format\n+msgid \"typechange: %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:203\n+#, c-format\n+msgid \"unknown:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:206\n+#, c-format\n+msgid \"unmerged:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:209\n+#, c-format\n+msgid \"bug: unhandled diff status %c\"\n+msgstr \"\"\n+\n+#: wt-status.c:212\n+#, c-format\n+msgid \"%s\"\n+msgstr \"\"\n+\n+#: wt-status.c:215\n+#, c-format\n+msgid \"\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:622\n+msgid \"On branch \"\n+msgstr \"Á greininni \"\n+\n+#: wt-status.c:629\n+msgid \"Not currently on any branch.\"\n+msgstr \"Ekki á neinni grein.\"\n+\n+#: wt-status.c:639\n+msgid \"# Initial commit\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"Untracked\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"add\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"Ignored\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"add -f\"\n+msgstr \"\"\n+\n+#: wt-status.c:655\n+#, c-format\n+msgid \"# Untracked files not listed%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:657\n+msgid \" (use -u option to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:663\n+#, c-format\n+msgid \"# No changes\\n\"\n+msgstr \"# Engar breytingar\\n\"\n+\n+#: wt-status.c:667\n+#, c-format\n+msgid \"no changes added to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:669\n+msgid \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\"\n+msgstr \"\"\n+\n+#: wt-status.c:671\n+#, c-format\n+msgid \"nothing added to commit but untracked files present%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:673\n+msgid \" (use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:676\n+msgid \" (create/copy files and use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:678 wt-status.c:681\n+#, c-format\n+msgid \"nothing to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:679\n+msgid \" (use -u to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:682\n+msgid \" (working directory clean)\"\n+msgstr \"\"\n+\n+#: git-pull.sh:124\n+msgid \"Fetching tags only, you probably meant:\"\n+msgstr \"Næ aðeins í tögg, þú áttir líkast til við:\"\n+\n+#: git-pull.sh:125\n+msgid \"  git fetch --tags\"\n+msgstr \"\"\n+\n+#: git-pull.sh:157\n+msgid \"\"\n+\"You are not currently on a branch, so I cannot use any\\n\"\n+\"'branch.<branchname>.merge' in your configuration file.\\n\"\n+\"Please specify which remote branch you want to use on the command\\n\"\n+\"line and try again (e.g. 'git pull <repository> <refspec>').\\n\"\n+\"See git-pull(1) for details.\"\n+msgstr \"\"\n+\n+#: git-send-email.perl:678\n+#, perl-format\n+msgid \"Emails will be sent from: %s\\n\"\n+msgstr \"Póstarnir verða sendir frá: %s\\n\"\n-- \n1.7.1.248.gb7713.dirty\n"},{"id":"142741","messageId":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","threadId":"23941","inReplyTo":"1275435597-4017-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 0/7] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T00:11:06Z","receivedAt":"2010-06-02T00:11:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Jun 1, 2010 at 23:39, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Here's version 3 of the patch series begun by Jeff Epler to make Git\n> optionally translatable with GNU gettext.\n>\n> This version contains a lot of fixes to issues pointe out by Jakub\n> Narebski, and other misc.\n> [...]\n>  * The GIT_TEXTDOMAINDIR environment variable can be set to override\n>    where the C/Perl/Shell locale files are found. This is intended to\n>    be set by the test suite.\n\nI made a silly error in my rebases and rewrote this commit out of my\ntree. Instead of sending new commits here's the `git diff -w` below:\n\n    diff --git a/git-sh-setup.sh b/git-sh-setup.sh\n    index d67901c..379c9a1 100644\n    --- a/git-sh-setup.sh\n    +++ b/git-sh-setup.sh\n    @@ -219,7 +219,12 @@ if test $? -eq 0\n     then\n         TEXTDOMAIN=git\n         export TEXDTOMAIN\n    +\tif [ -z \"$GIT_TEXTDOMAINDIR\" ]\n    +\tthen\n         TEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n    +\telse\n    +\t\tTEXTDOMAINDIR=$GIT_TEXTDOMAINDIR\n    +\tfi\n         export TEXTDOMAINDIR\n     else\n         # Since GNU gettext.sh isn't available we'll have to define our\n    diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\n    index 568fd3d..e19d99b 100644\n    --- a/perl/Git/I18N.pm\n    +++ b/perl/Git/I18N.pm\n    @@ -11,7 +11,7 @@ our @EXPORT_OK = @EXPORT;\n\n     sub __bootstrap_locale_messages {\n     \tour $TEXTDOMAIN = 'git';\n    -\tour $TEXTDOMAINDIR = '++LOCALEDIR++';\n    +\tour $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++';\n\n     \trequire POSIX;\n     \tPOSIX->import(qw(setlocale));\n    diff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh\n    index a8f9edd..7c2a4cb 100755\n    --- a/t/t0200-gettext.sh\n    +++ b/t/t0200-gettext.sh\n    @@ -1,5 +1,7 @@\n     #!/bin/sh\n\n    +export GIT_TEXTDOMAINDIR=`pwd`/../share/locale\n    +\n     test_description='Gettext support for Git'\n     . ./test-lib.sh\n     . ../../git-sh-setup\n    @@ -9,7 +11,8 @@ test_expect_success 'sanity: $TEXTDOMAIN is git' '\n     '\n\n     test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n    -\ttest -d $TEXTDOMAINDIR\n    +\ttest -d $TEXTDOMAINDIR &&\n    +\ttest $TEXTDOMAINDIR = $GIT_TEXTDOMAINDIR\n     '\n\n     test_expect_success 'sanity: Icelandic locale was compiled' '\n\nAlong with another silly error:\n\n    diff --git a/git-sh-setup.sh b/git-sh-setup.sh\n    index 379c9a1..da8c47f 100644\n    --- a/git-sh-setup.sh\n    +++ b/git-sh-setup.sh\n    @@ -218,7 +218,7 @@ esac\n     if test $? -eq 0\n     then\n         TEXTDOMAIN=git\n    -       export TEXDTOMAIN\n    +       export TEXTDOMAIN\n            if [ -z \"$GIT_TEXTDOMAINDIR\" ]\n            then\n                    TEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n\n\nThese fixes will be included (along with any other fixes) in my next\nseries. Which'll be submitted after soliciting more RFC\ncomments. Sorry everyone.\n"},{"id":"142749","messageId":"1275440764-26153-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 0/7] Add internationalization support to Git","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:05:57Z","receivedAt":"2010-06-02T01:05:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Here's version 4 of the patch series begun by Jeff Epler to make Git\noptionally translatable with GNU gettext.\n\nIt's like the version 4 I submitted an ~hour ago, sans the annoying\nerrors I made and lots of tests:\n\nChanges from v3 to v4:\n\n  * Fix typos and removal of GIT_TEXTDOMAINDIR that I rewrote out with\n    some rebase mistakes.\n\n  * Add meaningful testing. The C, Shell and Perl wrappers are now\n    tested as part of a new t/t0200-gettext.sh test file. Put under\n    the t/t0* namespace because it's a core feature, and using a new\n    t02 prefix because there'll probably be a lot of Gettext tests\n    down the line.\n\nChanges from v2 to v3:\n\n  * Squashed some infrastructure patches into the initial commit.\n\n  * Added basic sanity testing for the Gettext support\n\n  * .mo files aren't installed on `make install` time if NO_GETTEXT\n    was specified during the build.\n\n    In C gettext support isn't compiled in. But this happens\n    implicitly in Shell/Perl because the locale files won't be there\n    on the system.\n\n  * NO_GETTEXT is now set correctly depending on whether libintl.h\n    exists when autoconf is used to build Git. Whether this is the\n    best approach to gettext detection with autoconf is being\n    discussed in the \"[PATCH/RCF] autoconf: Check if <libintl.h>\n    exists and set NO_GETTEX\" thread.\n\n  * The localedir is now passed to the Perl code via Makefile\n    trickery. It's no longer hardcoded to /usr/local/share/locale\n\n  * Add `--keyword=` to all xgettext invocations. This way we make\n    sure that only our gettext functions are extracted, not the\n    defaults xgettext.\n\n  * Git::Gettext is now called Git::I18N\n\n  * Remove LICENSE from I18N.pm. It was a boilerplate that shouldn't\n    have been there.\n\n  * Use qw() not qw< > in Perl code.\n\n  * Changed the interface to Git::I18N. Now it exports all its\n    functions by default. If something's using the module it's going\n    to want to import everything anyway. This makes the issue of '@{\n    $EXPORT_TAGS{'all'} }' being ugly syntax moot since it isn't used\n    anymore.\n\n    Users can still import selectively by specifying arguments to\n    import().\n\n  * The GIT_TEXTDOMAINDIR environment variable can be set to override\n    where the C/Perl/Shell locale files are found. This is intended to\n    be set by the test suite.\n\n  * The boolean test for whether gettext.sh was successfully loaded\n    was inverted (oops!)\n\nThings that haven't changed:\n\n  Jakub pointed out some things that I might want to change that I\n  didn't yet. Mostly because I didn't have time yet.\n\n  * Git::I18N still uses Locale::Messages, not Locale::TextDomain.\n\n    I'm still not convinced that the low-level Locale::Messages\n    interface isn't a better fit for us. But I didn't get\n    Locale::TextDomain working at all today so I'm still using\n    Locale::Messages.\n\n  * Perl still uses gettext($), not __($) (see above).\n\n  * use Exporter 'import': Subclassing Exporter instead since we\n    apparently need Perl 5.6 compatibility.\n\nJeff Epler (1):\n  Add infrastructure for translating Git with gettext\n\nÆvar Arnfjörð Bjarmason (6):\n  gettext: Add a Gettext interface for shell scripts\n  gettext: Add a Gettext interface for Perl\n  Makefile: Don't install Gettext .mo files if NO_GETTEXT\n  Makefile: Override --keyword= for all languages\n  gettext: Sanity tests for Git's Gettext support\n  gettext: Add a skeleton po/is.po\n\n .gitignore          |    1 +\n Makefile            |   43 ++++++++-\n config.mak.in       |    1 +\n configure.ac        |    6 +\n gettext.c           |   25 +++++\n gettext.h           |   13 +++\n git-pull.sh         |   15 ++--\n git-send-email.perl |    3 +-\n git-sh-setup.sh     |   38 +++++++\n git.c               |    3 +\n perl/Git/I18N.pm    |   73 +++++++++++++\n perl/Makefile       |    3 +-\n perl/Makefile.PL    |   14 +++-\n po/.gitignore       |    1 +\n po/is.po            |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t0200-gettext.sh  |   73 +++++++++++++\n wt-status.c         |  129 ++++++++++++------------\n 17 files changed, 647 insertions(+), 76 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 perl/Git/I18N.pm\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n create mode 100755 t/t0200-gettext.sh\n"},{"id":"142748","messageId":"1275440764-26153-2-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:05:58Z","receivedAt":"2010-06-02T01:05:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Jeff Epler <jepler@unpythonic.net>\n\nChange the build process to use GNU's libintl if it's available. If\nnot we define our own skeleton replacement functions which degrade\ngracefully to English.\n\nGettext .mo files will be installed and looked for in\n$(prefix)/share/locale. GIT_LOCALEDIR can also be set to override\nthat, this variable is only intended for testing Git itself.\n\nSigned-off-by: Jeff Epler <jepler@unpythonic.net>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore    |    1 +\n Makefile      |   30 +++++++++++++\n config.mak.in |    1 +\n configure.ac  |    6 +++\n gettext.c     |   25 +++++++++++\n gettext.h     |   13 ++++++\n git.c         |    3 +\n po/.gitignore |    1 +\n wt-status.c   |  129 +++++++++++++++++++++++++++++----------------------------\n 9 files changed, 145 insertions(+), 64 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 po/.gitignore\n\ndiff --git a/.gitignore b/.gitignore\nindex 14e2b6b..d22c0e5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -204,3 +204,4 @@\n *.pdb\n /Debug/\n /Release/\n+/share/\ndiff --git a/Makefile b/Makefile\nindex d5d6565..4de0627 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -297,6 +297,8 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n PTHREAD_LIBS = -lpthread\n+XGETTEXT = xgettext\n+MSGFMT = msgfmt\n \n export TCL_PATH TCLTK_PATH\n \n@@ -523,6 +525,7 @@ LIB_H += userdiff.h\n LIB_H += utf8.h\n LIB_H += xdiff-interface.h\n LIB_H += xdiff/xdiff.h\n+LIB_H += gettext.h\n \n LIB_OBJS += abspath.o\n LIB_OBJS += advice.o\n@@ -564,6 +567,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gettext.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\n@@ -1386,6 +1390,12 @@ ifdef USE_NED_ALLOCATOR\n        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n+ifdef NO_GETTEXT\n+\tCOMPAT_CFLAGS += -DNO_GETTEXT\n+else\n+\tLIBINTL = -lintl\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1415,6 +1425,7 @@ ifndef V\n \tQUIET_BUILT_IN = @echo '   ' BUILTIN $@;\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_SUBDIR0  = +@subdir=\n \tQUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \\\n \t\t\t $(MAKE) $(PRINT_DIR) -C $$subdir\n@@ -1442,6 +1453,7 @@ gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n@@ -1868,6 +1880,17 @@ cscope:\n \t$(RM) cscope*\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n+pot:\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+all:: $(MOFILES)\n+share/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t@mkdir -p $(dir $@)\n+\t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n+\n ### Detect prefix changes\n TRACK_CFLAGS = $(subst ','\\'',$(ALL_CFLAGS)):\\\n              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n@@ -1980,6 +2003,9 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n+\t(cd share && tar cf - locale) | \\\n+\t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n@@ -2127,6 +2153,10 @@ ifndef NO_TCLTK\n \t$(MAKE) -C git-gui clean\n endif\n \t$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS\n+ifndef NO_GETTEXT\n+\t$(RM) po/git.pot\n+\t$(RM) -r share/\n+endif\n \n .PHONY: all install clean strip\n .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell\ndiff --git a/config.mak.in b/config.mak.in\nindex 0d4b64d..a15f3c1 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@\n NO_EXPAT=@NO_EXPAT@\n NO_LIBGEN_H=@NO_LIBGEN_H@\n HAVE_PATHS_H=@HAVE_PATHS_H@\n+NO_GETTEXT=@NO_GETTEXT@\n NEEDS_LIBICONV=@NEEDS_LIBICONV@\n NEEDS_SOCKET=@NEEDS_SOCKET@\n NEEDS_RESOLV=@NEEDS_RESOLV@\ndiff --git a/configure.ac b/configure.ac\nindex 71038fc..7bebfd8 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],\n [HAVE_PATHS_H=])\n AC_SUBST(HAVE_PATHS_H)\n #\n+# Define NO_GETTEXT if you don't have libintl.h\n+AC_CHECK_HEADER([libintl.h],\n+[NO_GETTEXT=],\n+[NO_GETTEXT=YesPlease])\n+AC_SUBST(NO_GETTEXT)\n+#\n # Define NO_STRCASESTR if you don't have strcasestr.\n GIT_CHECK_FUNC(strcasestr,\n [NO_STRCASESTR=],\ndiff --git a/gettext.c b/gettext.c\nnew file mode 100644\nindex 0000000..22cdcc1\n--- /dev/null\n+++ b/gettext.c\n@@ -0,0 +1,25 @@\n+#ifdef NO_GETTEXT\n+void git_setup_gettext(void) {}\n+#else\n+#include \"exec_cmd.h\"\n+#include <libintl.h>\n+#include <stdlib.h>\n+\n+void git_setup_gettext(void) {\n+\tchar *podir;\n+\tchar *envdir = getenv(\"GIT_TEXTDOMAINDIR\");\n+\n+\tif (envdir) {\n+\t\t(void)bindtextdomain(\"git\", envdir);\n+\t} else {\n+\t\tpodir = (char *)system_path(\"share/locale\");\n+\t\tif (!podir) return;\n+\t\t(void)bindtextdomain(\"git\", podir);\n+\t\tfree(podir);\n+\t}\n+\n+\t(void)setlocale(LC_MESSAGES, \"\");\n+\t(void)setlocale(LC_CTYPE, \"\");\n+\t(void)textdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nnew file mode 100644\nindex 0000000..a99da6a\n--- /dev/null\n+++ b/gettext.h\n@@ -0,0 +1,13 @@\n+#ifndef GETTEXT_H\n+#define GETTEXT_H\n+\n+void git_setup_gettext(void);\n+\n+#ifdef NO_GETTEXT\n+#define _(s) (s)\n+#else\n+#include <libintl.h>\n+#define _(s) gettext(s)\n+#endif\n+\n+#endif\ndiff --git a/git.c b/git.c\nindex 99f0363..d749eab 100644\n--- a/git.c\n+++ b/git.c\n@@ -3,6 +3,7 @@\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"run-command.h\"\n+#include \"gettext.h\"\n \n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\\n\"\n@@ -490,6 +491,8 @@ int main(int argc, const char **argv)\n \tif (!cmd)\n \t\tcmd = \"git-help\";\n \n+\tgit_setup_gettext();\n+\n \t/*\n \t * \"git-xxxx\" is the same as \"git xxxx\", but we obviously:\n \t *\ndiff --git a/po/.gitignore b/po/.gitignore\nnew file mode 100644\nindex 0000000..221000e\n--- /dev/null\n+++ b/po/.gitignore\n@@ -0,0 +1 @@\n+/*.pot\ndiff --git a/wt-status.c b/wt-status.c\nindex 14e0acc..70b4293 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"run-command.h\"\n #include \"remote.h\"\n+#include \"gettext.h\"\n \n static char default_wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL, /* WT_STATUS_HEADER */\n@@ -49,33 +50,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Unmerged paths:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t;\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changes to be committed:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_dirty_header(struct wt_status *s,\n@@ -84,17 +85,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changed but not updated:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changed but not updated:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (!has_deleted)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to update what will be committed)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add <file>...\\\" to update what will be committed)\"));\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n \tif (has_dirty_submodules)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (commit or discard the untracked or modified content in submodules)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_other_header(struct wt_status *s,\n@@ -102,16 +103,16 @@ static void wt_status_print_other_header(struct wt_status *s,\n \t\t\t\t\t const char *how)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n-\tcolor_fprintf_ln(s->fp, c, \"# %s files:\", what);\n+\tcolor_fprintf_ln(s->fp, c, _(\"# %s files:\"), what);\n \tif (!advice_status_hints)\n \t\treturn;\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\", how);\n-\tcolor_fprintf_ln(s->fp, c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n+\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n }\n \n static void wt_status_print_trailer(struct wt_status *s)\n {\n-\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n }\n \n #define quote_path quote_path_relative\n@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,\n \tconst char *c = color(WT_STATUS_UNMERGED, s);\n \tstruct wt_status_change_data *d = it->util;\n \tstruct strbuf onebuf = STRBUF_INIT;\n-\tconst char *one, *how = \"bug\";\n+\tconst char *one, *how = _(\"bug\");\n \n \tone = quote_path(it->string, -1, &onebuf, s->prefix);\n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (d->stagemask) {\n-\tcase 1: how = \"both deleted:\"; break;\n-\tcase 2: how = \"added by us:\"; break;\n-\tcase 3: how = \"deleted by them:\"; break;\n-\tcase 4: how = \"added by them:\"; break;\n-\tcase 5: how = \"deleted by us:\"; break;\n-\tcase 6: how = \"both added:\"; break;\n-\tcase 7: how = \"both modified:\"; break;\n+\tcase 1: how = _(\"both deleted:\"); break;\n+\tcase 2: how = _(\"added by us:\"); break;\n+\tcase 3: how = _(\"deleted by them:\"); break;\n+\tcase 4: how = _(\"added by them:\"); break;\n+\tcase 5: how = _(\"deleted by us:\"); break;\n+\tcase 6: how = _(\"both added:\"); break;\n+\tcase 7: how = _(\"both modified:\"); break;\n \t}\n-\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n+\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n \tstrbuf_release(&onebuf);\n }\n \n@@ -161,13 +162,13 @@ static void wt_status_print_change_data(struct wt_status *s,\n \t\tbreak;\n \tcase WT_STATUS_CHANGED:\n \t\tif (d->new_submodule_commits || d->dirty_submodule) {\n-\t\t\tstrbuf_addstr(&extra, \" (\");\n+\t\t\tstrbuf_addstr(&extra, _(\" (\"));\n \t\t\tif (d->new_submodule_commits)\n-\t\t\t\tstrbuf_addf(&extra, \"new commits, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"new commits, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n-\t\t\t\tstrbuf_addf(&extra, \"modified content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"modified content, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n-\t\t\t\tstrbuf_addf(&extra, \"untracked content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"untracked content, \"));\n \t\t\tstrbuf_setlen(&extra, extra.len - 2);\n \t\t\tstrbuf_addch(&extra, ')');\n \t\t}\n@@ -178,40 +179,40 @@ static void wt_status_print_change_data(struct wt_status *s,\n \tone = quote_path(one_name, -1, &onebuf, s->prefix);\n \ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"new file:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"copied:     %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"deleted:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"modified:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"renamed:    %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"typechange: %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unknown:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unmerged:   %s\"), one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", status);\n+\t\tdie(_(\"bug: unhandled diff status %c\"), status);\n \t}\n \tif (extra.len) {\n-\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"), extra.buf);\n \t\tstrbuf_release(&extra);\n \t}\n-\tfprintf(s->fp, \"\\n\");\n+\tfprintf(s->fp, _(\"\\n\"));\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)\n \tconst char *branch_color = color(WT_STATUS_HEADER, s);\n \n \tif (s->branch) {\n-\t\tconst char *on_what = \"On branch \";\n+\t\tconst char *on_what = _(\"On branch \");\n \t\tconst char *branch_name = s->branch;\n \t\tif (!prefixcmp(branch_name, \"refs/heads/\"))\n \t\t\tbranch_name += 11;\n \t\telse if (!strcmp(branch_name, \"HEAD\")) {\n \t\t\tbranch_name = \"\";\n \t\t\tbranch_color = color(WT_STATUS_NOBRANCH, s);\n-\t\t\ton_what = \"Not currently on any branch.\";\n+\t\t\ton_what = _(\"Not currently on any branch.\");\n \t\t}\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"# \");\n \t\tcolor_fprintf_ln(s->fp, branch_color, \"%s%s\", on_what, branch_name);\n@@ -634,9 +635,9 @@ void wt_status_print(struct wt_status *s)\n \t}\n \n \tif (s->is_initial) {\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"# Initial commit\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n \t}\n \n \twt_status_print_updated(s);\n@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_submodule_summary(s, 1);  /* unstaged */\n \t}\n \tif (s->show_untracked_files) {\n-\t\twt_status_print_other(s, &s->untracked, \"Untracked\", \"add\");\n+\t\twt_status_print_other(s, &s->untracked, _(\"Untracked\"), _(\"add\"));\n \t\tif (s->show_ignored_files)\n-\t\t\twt_status_print_other(s, &s->ignored, \"Ignored\", \"add -f\");\n+\t\t\twt_status_print_other(s, &s->ignored, _(\"Ignored\"), _(\"add -f\"));\n \t} else if (s->commitable)\n-\t\tfprintf(s->fp, \"# Untracked files not listed%s\\n\",\n+\t\tfprintf(s->fp, _(\"# Untracked files not listed%s\\n\"),\n \t\t\tadvice_status_hints\n-\t\t\t? \" (use -u option to show untracked files)\" : \"\");\n+\t\t\t? _(\" (use -u option to show untracked files)\") : \"\");\n \n \tif (s->verbose)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tfprintf(s->fp, \"# No changes\\n\");\n+\t\t\tfprintf(s->fp, _(\"# No changes\\n\"));\n \t\telse if (s->nowarn)\n \t\t\t; /* nothing */\n \t\telse if (s->workdir_dirty)\n-\t\t\tprintf(\"no changes added to commit%s\\n\",\n+\t\t\tprintf(_(\"no changes added to commit%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\") : \"\");\n \t\telse if (s->untracked.nr)\n-\t\t\tprintf(\"nothing added to commit but untracked files present%s\\n\",\n+\t\t\tprintf(_(\"nothing added to commit but untracked files present%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (s->is_initial)\n \t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (create/copy files and use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (create/copy files and use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (!s->show_untracked_files)\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (use -u to show untracked files)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (use -u to show untracked files)\") : \"\");\n \t\telse\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (working directory clean)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (working directory clean)\") : \"\");\n \t}\n }\n \n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142754","messageId":"1275440764-26153-3-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 2/7] gettext: Add a Gettext interface for shell scripts","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:05:59Z","receivedAt":"2010-06-02T01:05:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use GNU's gettext.sh in git-sh-setup if it's available, otherwise\nfallback on our own custom functions.\n\nA couple of strings in git-pull.sh are now translatable as a proof of\nconcept, including a multiline string.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile        |    7 +++++--\n git-pull.sh     |   15 ++++++++-------\n git-sh-setup.sh |   38 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 51 insertions(+), 9 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 4de0627..dce2faa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -272,6 +272,7 @@ mandir = share/man\n infodir = share/info\n gitexecdir = libexec/git-core\n sharedir = $(prefix)/share\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ifeq ($(prefix),/usr)\n@@ -285,7 +286,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir\n+export prefix bindir sharedir localedir sysconfdir\n \n CC = gcc\n AR = ar\n@@ -1455,6 +1456,7 @@ htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n+LOCALEDIR_SQ = $(subst ','\\'',$(localedir))\n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n PYTHON_PATH_SQ = $(subst ','\\'',$(PYTHON_PATH))\n@@ -1548,6 +1550,7 @@ $(RM) $@ $@+ && \\\n sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n+    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \\\n     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \\\n     -e $(BROKEN_PATH_FIX) \\\n     $@.sh >$@+\n@@ -1881,7 +1884,7 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c)\n+\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 1a4729f..22a6da2 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -121,8 +121,8 @@ error_on_no_merge_candidates () {\n \tdo\n \t\tcase \"$opt\" in\n \t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"Fetching tags only, you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n+\t\t\tgettext \"Fetching tags only, you probably meant:\"; echo\n+\t\t\tgettext \"  git fetch --tags\"; echo\n \t\t\texit 1\n \t\tesac\n \tdone\n@@ -154,11 +154,12 @@ error_on_no_merge_candidates () {\n \t\techo \"a branch. Because this is not the default configured remote\"\n \t\techo \"for your current branch, you must specify a branch on the command line.\"\n \telif [ -z \"$curr_branch\" ]; then\n-\t\techo \"You are not currently on a branch, so I cannot use any\"\n-\t\techo \"'branch.<branchname>.merge' in your configuration file.\"\n-\t\techo \"Please specify which remote branch you want to use on the command\"\n-\t\techo \"line and try again (e.g. 'git pull <repository> <refspec>').\"\n-\t\techo \"See git-pull(1) for details.\"\n+        gettext \"You are not currently on a branch, so I cannot use any\n+'branch.<branchname>.merge' in your configuration file.\n+Please specify which remote branch you want to use on the command\n+line and try again (e.g. 'git pull <repository> <refspec>').\n+See git-pull(1) for details.\";\n+        echo\n \telif [ -z \"$upstream\" ]; then\n \t\techo \"You asked me to pull without telling me which branch you\"\n \t\techo \"want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in\"\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex 6131670..53cfc42 100644\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -211,3 +211,41 @@ case $(uname -s) in\n \t}\n \t;;\n esac\n+\n+# Try to use libintl's gettext.sh, or fall back to English if we\n+# can't.\n+. gettext.sh\n+if test $? -eq 0\n+then\n+\tTEXTDOMAIN=git\n+\texport TEXTDOMAIN\n+\tif [ -z \"$GIT_TEXTDOMAINDIR\" ]\n+\tthen\n+\t\tTEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+\telse\n+\t\tTEXTDOMAINDIR=$GIT_TEXTDOMAINDIR\n+\tfi\n+\texport TEXTDOMAINDIR\n+else\n+\t# Since GNU gettext.sh isn't available we'll have to define our\n+\t# own dummy functions.\n+\n+\t# This code adapted from NessusClient-1.0.2's nessusclient-mkcert\n+\t# by Michel Arboi <arboi@alussinan.org>. The original code is\n+\t# under the GPLv2.\n+\n+\t# Not everyone has echo -n\n+\tcase $(echo -n) in\n+\t\t\\-n)\tXn=\t  ; Xc='\\c' ;;\n+\t\t*)\t\tXn=-n ; Xc=\n+\tesac\n+\n+\tgettext () {\n+\t\techo $Xn \"$1\" $Xc\n+\t}\n+\n+\teval_gettext () {\n+\t\teval_gettext_var=\"echo $1\"\n+\t\techo $Xn `eval $eval_gettext_var` $Xc\n+\t}\n+fi\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142751","messageId":"1275440764-26153-4-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 3/7] gettext: Add a Gettext interface for Perl","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:06:00Z","receivedAt":"2010-06-02T01:06:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make Git's gettext messages available to Perl programs through\nLocale::Messages. Gracefully fall back to English on systems that\ndon't contain the module.\n\nThis contains some makefile hacks to pass localedir to\nperl/Makefile. Which in turn passes it to perl.mak, which'll use it to\nsearch/replace occurances of ++LOCALEDIR++ in .pm files.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile            |    6 +++-\n git-send-email.perl |    3 +-\n perl/Git/I18N.pm    |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Makefile       |    3 +-\n perl/Makefile.PL    |   14 +++++++++-\n 5 files changed, 94 insertions(+), 5 deletions(-)\n create mode 100644 perl/Git/I18N.pm\n\ndiff --git a/Makefile b/Makefile\nindex dce2faa..3f0e305 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1505,7 +1505,7 @@ ifndef NO_TCLTK\n \t$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all\n endif\n ifndef NO_PERL\n-\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all\n+\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all\n endif\n ifndef NO_PYTHON\n \t$(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all\n@@ -1884,7 +1884,9 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n+\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n+\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 111c981..b9288af 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -26,6 +26,7 @@ use Term::ANSIColor;\n use File::Temp qw/ tempdir tempfile /;\n use Error qw(:try);\n use Git;\n+use Git::I18N;\n \n Getopt::Long::Configure qw/ pass_through /;\n \n@@ -674,7 +675,7 @@ if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n \t$sender = ask(\"Who should the emails appear to be from? [$sender] \",\n \t              default => $sender);\n-\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n+\tprintf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n \t$prompting++;\n }\n \ndiff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\nnew file mode 100644\nindex 0000000..e19d99b\n--- /dev/null\n+++ b/perl/Git/I18N.pm\n@@ -0,0 +1,73 @@\n+package Git::I18N;\n+use strict;\n+use warnings;\n+use Exporter;\n+use base 'Exporter';\n+\n+our $VERSION = '0.01';\n+\n+our @EXPORT = qw(gettext);\n+our @EXPORT_OK = @EXPORT;\n+\n+sub __bootstrap_locale_messages {\n+\tour $TEXTDOMAIN = 'git';\n+\tour $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++';\n+\n+\trequire POSIX;\n+\tPOSIX->import(qw(setlocale));\n+\t# Non-core prerequisite module\n+\trequire Locale::Messages;\n+\tLocale::Messages->import(qw(:locale_h :libintl_h));\n+\n+\tsetlocale(LC_MESSAGES(), '');\n+\tsetlocale(LC_CTYPE(), '');\n+\ttextdomain($TEXTDOMAIN);\n+\tbindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n+\n+\treturn;\n+}\n+\n+BEGIN\n+{\n+\tlocal ($@, $!);\n+\teval { __bootstrap_locale_messages() };\n+\tif ($@) {\n+\t\t# Oh noes, no Locale::Messages here\n+\t\t*gettext = sub ($) { $_[0] };\n+\t}\n+}\n+\n+1;\n+\n+__END__\n+\n+=head1 NAME\n+\n+Git::I18N - Perl interface to Git's Gettext localizations\n+\n+=head1 SYNOPSIS\n+\n+\tuse Git::I18N;\n+\n+\tprint gettext(\"Welcome to Git!\\n\");\n+\n+\tprintf gettext(\"The following error occured: %s\\n\"), $error;\n+\n+=head1 DESCRIPTION\n+\n+Git's internal interface to Gettext via L<Locale::Messages>. If\n+L<Locale::Messages> can't be loaded (it's not a core module) we\n+provide stub passthrough fallbacks.\n+\n+=head1 FUNCTIONS\n+\n+=head2 gettext($)\n+\n+L<Locale::Messages>'s gettext function if all goes well, otherwise our\n+passthrough fallback function.\n+\n+=head1 AUTHOR\n+\n+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+=cut\ndiff --git a/perl/Makefile b/perl/Makefile\nindex 4ab21d6..4e624ff 100644\n--- a/perl/Makefile\n+++ b/perl/Makefile\n@@ -5,6 +5,7 @@ makfile:=perl.mak\n \n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+localedir_SQ = $(subst ','\\'',$(localedir))\n \n ifndef V\n \tQUIET = @\n@@ -38,7 +39,7 @@ $(makfile): ../GIT-CFLAGS Makefile\n \techo '\techo $(instdir_SQ)' >> $@\n else\n $(makfile): Makefile.PL ../GIT-CFLAGS\n-\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)'\n+\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)' --localedir='$(localedir_SQ)'\n endif\n \n # this is just added comfort for calling make directly in perl dir\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nindex 0b9deca..456d45b 100644\n--- a/perl/Makefile.PL\n+++ b/perl/Makefile.PL\n@@ -1,4 +1,12 @@\n+use strict;\n+use warnings;\n use ExtUtils::MakeMaker;\n+use Getopt::Long;\n+\n+# Sanity: die at first unknown option\n+Getopt::Long::Configure qw/ pass_through /;\n+\n+GetOptions(\"localedir=s\" => \\my $localedir);\n \n sub MY::postamble {\n \treturn <<'MAKE_FRAG';\n@@ -16,7 +24,10 @@ endif\n MAKE_FRAG\n }\n \n-my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n+my %pm = (\n+\t'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n+\t'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',\n+);\n \n # We come with our own bundled Error.pm. It's not in the set of default\n # Perl modules so install it if it's not available on the system yet.\n@@ -33,6 +44,7 @@ WriteMakefile(\n \tNAME            => 'Git',\n \tVERSION_FROM    => 'Git.pm',\n \tPM\t\t=> \\%pm,\n+\tPM_FILTER\t=> qq[\\$(PERL) -pe \"s<\\\\Q++LOCALEDIR++\\\\E><$localedir>\"],\n \tMAKEFILE\t=> 'perl.mak',\n \tINSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'\n );\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142750","messageId":"1275440764-26153-5-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 4/7] Makefile: Don't install Gettext .mo files if NO_GETTEXT","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:06:01Z","receivedAt":"2010-06-02T01:06:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the Makefile not to build/install .mo files as part of the\ndefault target if NO_GETTEXT=1 is given.\n\nThis was both redundant, and meant that the Perl and Shell programs\nwould use the Gettext strings, since they don't use the\ngit_setup_gettext() function in gettext.c, which is compiled to a stub\nif NO_GETTEXT=1 is set.\n\nReported-by: Jakub Narebski <jnareb@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 3f0e305..40eb1a2 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1891,7 +1891,9 @@ pot:\n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+ifndef NO_GETTEXT\n all:: $(MOFILES)\n+endif\n share/locale/%/LC_MESSAGES/git.mo: po/%.po\n \t@mkdir -p $(dir $@)\n \t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n@@ -2008,9 +2010,11 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+ifndef NO_GETTEXT\n \t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n \t(cd share && tar cf - locale) | \\\n \t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n+endif\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142752","messageId":"1275440764-26153-6-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 5/7] Makefile: Override --keyword= for all languages","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:06:02Z","receivedAt":"2010-06-02T01:06:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"By default xgettext will supply a default list of keywords depending\non the --language parameter. Disable this in favor of supplying a list\nof keywords manually.\n\nThis reduced the surface area for potential bugs.\n---\n Makefile |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 40eb1a2..62b8279 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1884,9 +1884,9 @@ cscope:\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n pot:\n-\t$(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n-\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n-\t$(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n+\t$(XGETTEXT) --keyword= --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n+\t$(XGETTEXT) --join-existing --keyword= --keyword=gettext --output=po/git.pot --language=Shell $(SCRIPT_SH)\n+\t$(XGETTEXT) --join-existing --keyword= --keyword=gettext --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n \n POFILES := $(wildcard po/*.po)\n MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142753","messageId":"1275440764-26153-7-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 6/7] gettext: Sanity tests for Git's Gettext support","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:06:03Z","receivedAt":"2010-06-02T01:06:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"These tests check if Git's C, Shell and Perl wrappers for Gettext are\nworking.\n---\n t/t0200-gettext.sh |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 73 insertions(+), 0 deletions(-)\n create mode 100755 t/t0200-gettext.sh\n\ndiff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh\nnew file mode 100755\nindex 0000000..ff2f9f9\n--- /dev/null\n+++ b/t/t0200-gettext.sh\n@@ -0,0 +1,73 @@\n+#!/bin/sh\n+D=`pwd`\n+export GIT_TEXTDOMAINDIR=$D/../share/locale\n+\n+test_description='Gettext support for Git'\n+. ./test-lib.sh\n+. ../../git-sh-setup\n+\n+test_expect_success 'sanity: $TEXTDOMAIN is git' '\n+    test $TEXTDOMAIN = \"git\"\n+'\n+\n+test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n+    test -d $TEXTDOMAINDIR &&\n+    test $TEXTDOMAINDIR = $GIT_TEXTDOMAINDIR\n+'\n+\n+test_expect_success 'sanity: Icelandic locale was compiled' '\n+    test -f $TEXTDOMAINDIR/is/LC_MESSAGES/git.mo\n+'\n+\n+test_expect_success 'sanity: gettext(\"\") metadata is OK' '\n+    LC_ALL=is_IS.UTF-8 gettext \"\" > expect &&\n+    grep \"Project-Id-Version: Git\" expect &&\n+    grep \"Git Mailing List <git@vger.kernel.org>\" expect &&\n+    grep \"Content-Type: text/plain; charset=UTF-8\" expect &&\n+    grep \"Content-Transfer-Encoding: 8bit\" expect\n+'\n+\n+test_expect_success 'sanity: gettext(unknown) is passed through' '\n+    printf \"This is not a translation string\"  > expect\n+    gettext \"This is not a translation string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'sanity: C program git-status reads our message catalog ' '\n+    > foo &&\n+    test_commit foo \"a message\"\n+    git checkout -b topic/gettext-testing &&\n+    git status | grep topic/gettext-testing > expect\n+    echo \"# On branch topic/gettext-testing\" > actual\n+    test_cmp expect actual &&\n+    LC_ALL=is_IS.UTF-8 git status | grep topic/gettext-testing > expect\n+    echo \"# Ã greininni topic/gettext-testing\" > actual\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'sanity: Perl program Git::I18N reads our message catalog ' '\n+    echo \"On branch \" > expect &&\n+    perl -I\"$D/../perl\" -MGit::I18N -le \"print gettext(q[On branch ])\" > actual &&\n+    test_cmp expect actual &&\n+\n+    echo \"Ã greininni \" > expect &&\n+    LC_ALL=is_IS.UTF-8 perl -I\"$D/../perl\" -MGit::I18N -le \"print gettext(q[On branch ])\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'Setup another Git repository for testing' '\n+    mkdir parent &&\n+    (cd parent && git init &&\n+     echo one >file && git add file &&\n+     git commit -m one)\n+'\n+\n+test_expect_success 'sanity: Shell program git-pull reads our message catalog' '\n+    cd parent &&\n+    (git pull --tags \"../\" >out 2>err || :) &&\n+    grep \"Fetching tags only\" err &&\n+    (LC_ALL=is_IS.UTF-8 git pull --tags \"../\" >out 2>err || :) &&\n+    grep \"NÃ¦ aÃ°eins Ã­\" err \n+'\n+\n+test_done\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142755","messageId":"1275440764-26153-8-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v4 7/7] gettext: Add a skeleton po/is.po","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T01:06:04Z","receivedAt":"2010-06-02T01:06:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This example is.po file translates a little bit of C, Shell and Perl\nas an example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n po/is.po |  282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 282 insertions(+), 0 deletions(-)\n create mode 100644 po/is.po\n\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..aa1923e\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,282 @@\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2010-05-30 19:24+0000\\n\"\n+\"PO-Revision-Date: 2010-06-01 22:15+0000\\n\"\n+\"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n+\"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"X-Poedit-Language: English\\n\"\n+\"X-Poedit-SourceCharset: utf-8\\n\"\n+\n+#: wt-status.c:53\n+msgid \"# Unmerged paths:\"\n+msgstr \"\"\n+\n+#: wt-status.c:59 wt-status.c:76\n+#, c-format\n+msgid \"#   (use \\\"git reset %s <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:61 wt-status.c:78\n+msgid \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"\n+msgstr \"\"\n+\n+#: wt-status.c:62\n+msgid \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"\n+msgstr \"\"\n+\n+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110\n+#: wt-status.c:115 wt-status.c:638 wt-status.c:640\n+msgid \"#\"\n+msgstr \"\"\n+\n+#: wt-status.c:70\n+msgid \"# Changes to be committed:\"\n+msgstr \"\"\n+\n+#: wt-status.c:88\n+msgid \"# Changed but not updated:\"\n+msgstr \"\"\n+\n+#: wt-status.c:92\n+msgid \"#   (use \\\"git add <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:94\n+msgid \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:95\n+msgid \"\"\n+\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working \"\n+\"directory)\"\n+msgstr \"\"\n+\n+#: wt-status.c:97\n+msgid \"#   (commit or discard the untracked or modified content in submodules)\"\n+msgstr \"\"\n+\n+#: wt-status.c:106\n+#, c-format\n+msgid \"# %s files:\"\n+msgstr \"\"\n+\n+#: wt-status.c:109\n+#, c-format\n+msgid \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"\n+msgstr \"\"\n+\n+#: wt-status.c:126\n+msgid \"bug\"\n+msgstr \"\"\n+\n+#: wt-status.c:129 wt-status.c:182\n+msgid \"#\\t\"\n+msgstr \"\"\n+\n+#: wt-status.c:131\n+msgid \"both deleted:\"\n+msgstr \"\"\n+\n+#: wt-status.c:132\n+msgid \"added by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:133\n+msgid \"deleted by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:134\n+msgid \"added by them:\"\n+msgstr \"\"\n+\n+#: wt-status.c:135\n+msgid \"deleted by us:\"\n+msgstr \"\"\n+\n+#: wt-status.c:136\n+msgid \"both added:\"\n+msgstr \"\"\n+\n+#: wt-status.c:137\n+msgid \"both modified:\"\n+msgstr \"\"\n+\n+#: wt-status.c:139\n+#, c-format\n+msgid \"%-20s%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:165\n+msgid \" (\"\n+msgstr \"\"\n+\n+#: wt-status.c:167\n+msgid \"new commits, \"\n+msgstr \"\"\n+\n+#: wt-status.c:169\n+msgid \"modified content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:171\n+msgid \"untracked content, \"\n+msgstr \"\"\n+\n+#: wt-status.c:185\n+#, c-format\n+msgid \"new file:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:188\n+#, c-format\n+msgid \"copied:     %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:191\n+#, c-format\n+msgid \"deleted:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:194\n+#, c-format\n+msgid \"modified:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:197\n+#, c-format\n+msgid \"renamed:    %s -> %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:200\n+#, c-format\n+msgid \"typechange: %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:203\n+#, c-format\n+msgid \"unknown:    %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:206\n+#, c-format\n+msgid \"unmerged:   %s\"\n+msgstr \"\"\n+\n+#: wt-status.c:209\n+#, c-format\n+msgid \"bug: unhandled diff status %c\"\n+msgstr \"\"\n+\n+#: wt-status.c:212\n+#, c-format\n+msgid \"%s\"\n+msgstr \"\"\n+\n+#: wt-status.c:215\n+#, c-format\n+msgid \"\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:622\n+msgid \"On branch \"\n+msgstr \"Á greininni \"\n+\n+#: wt-status.c:629\n+msgid \"Not currently on any branch.\"\n+msgstr \"Ekki á neinni grein.\"\n+\n+#: wt-status.c:639\n+msgid \"# Initial commit\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"Untracked\"\n+msgstr \"\"\n+\n+#: wt-status.c:651\n+msgid \"add\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"Ignored\"\n+msgstr \"\"\n+\n+#: wt-status.c:653\n+msgid \"add -f\"\n+msgstr \"\"\n+\n+#: wt-status.c:655\n+#, c-format\n+msgid \"# Untracked files not listed%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:657\n+msgid \" (use -u option to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:663\n+#, c-format\n+msgid \"# No changes\\n\"\n+msgstr \"# Engar breytingar\\n\"\n+\n+#: wt-status.c:667\n+#, c-format\n+msgid \"no changes added to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:669\n+msgid \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\"\n+msgstr \"\"\n+\n+#: wt-status.c:671\n+#, c-format\n+msgid \"nothing added to commit but untracked files present%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:673\n+msgid \" (use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:676\n+msgid \" (create/copy files and use \\\"git add\\\" to track)\"\n+msgstr \"\"\n+\n+#: wt-status.c:678 wt-status.c:681\n+#, c-format\n+msgid \"nothing to commit%s\\n\"\n+msgstr \"\"\n+\n+#: wt-status.c:679\n+msgid \" (use -u to show untracked files)\"\n+msgstr \"\"\n+\n+#: wt-status.c:682\n+msgid \" (working directory clean)\"\n+msgstr \"\"\n+\n+#: git-pull.sh:124\n+msgid \"Fetching tags only, you probably meant:\"\n+msgstr \"Næ aðeins í tögg, þú áttir líkast til við:\"\n+\n+#: git-pull.sh:125\n+msgid \"  git fetch --tags\"\n+msgstr \"\"\n+\n+#: git-pull.sh:157\n+msgid \"\"\n+\"You are not currently on a branch, so I cannot use any\\n\"\n+\"'branch.<branchname>.merge' in your configuration file.\\n\"\n+\"Please specify which remote branch you want to use on the command\\n\"\n+\"line and try again (e.g. 'git pull <repository> <refspec>').\\n\"\n+\"See git-pull(1) for details.\"\n+msgstr \"\"\n+\n+#: git-send-email.perl:678\n+#, perl-format\n+msgid \"Emails will be sent from: %s\\n\"\n+msgstr \"Póstarnir verða sendir frá: %s\\n\"\n-- \n1.7.1.251.gec7f5.dirty\n"},{"id":"142786","messageId":"4C05FAEF.2040205@viscovery.net","threadId":"23941","inReplyTo":"1275435597-4017-3-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 2/7] gettext: Add a Gettext interface for shell scripts","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-06-02T06:32:15Z","receivedAt":"2010-06-02T06:32:15Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"[When you resend the series in such a manner that you collect a Cc list\nmanually, please do *not* include me. I'm not interested in this series.]\n\nAm 6/2/2010 1:39, schrieb Ævar Arnfjörð Bjarmason:\n> +    # Not everyone has echo -n\n> +    case $(echo -n) in\n> +        \\-n)    Xn=   ; Xc='\\c' ;;\n> +        *)      Xn=-n ; Xc=\n> +    esac\n\nDon't use 'echo'; use 'printf %s'.\n\n> +\n> +    gettext () {\n> +        echo $Xn \"$1\" $Xc\n> +    }\n> +\n> +    eval_gettext () {\n> +        eval_gettext_var=\"echo $1\"\n> +        echo $Xn `eval $eval_gettext_var` $Xc\n> +    }\n\n-- Hannes\n"},{"id":"142787","messageId":"4C05FB0F.1060107@viscovery.net","threadId":"23941","inReplyTo":"1275435597-4017-7-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 6/7] gettext: Basic sanity tests for Git's Gettext support","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-06-02T06:32:47Z","receivedAt":"2010-06-02T06:32:47Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"[When you resend the series in such a manner that you collect a Cc list\nmanually, please do *not* include me. I'm not interested in this series.]\n\nAm 6/2/2010 1:39, schrieb Ævar Arnfjörð Bjarmason:\n> +test_expect_success 'sanity: $TEXTDOMAIN is git' '\n> +\ttest $TEXTDOMAIN = \"git\"\n> +'\n> +\n> +test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n> +\ttest -d $TEXTDOMAINDIR \n> +'\n> +\n> +test_expect_success 'sanity: Icelandic locale was compiled' '\n> +    test -f $TEXTDOMAINDIR/is/LC_MESSAGES/git.mo\n> +'\n\n3 times: put \"$foo\" in double-quotes.\n\n> +test_expect_success 'sanity: gettext(unknown) is passed through' '\n> +    gettext \"\" > expect &&\n> +    > actual &&\n> +    test_cmp expect actual &&\n> +    printf \"This is not a translation string\"  > expect\n> +\tgettext \"This is not a translation string\" > actual &&\n\nStrange indentation and you break the && chain.\n\n-- Hannes\n"},{"id":"142788","messageId":"4C05FB18.7010200@viscovery.net","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"Re: [PATCH/RFC v3 0/7] Add internationalization support to Git","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-06-02T06:32:56Z","receivedAt":"2010-06-02T06:32:56Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 6/2/2010 2:11, schrieb Ævar Arnfjörð Bjarmason:\n>     +export GIT_TEXTDOMAINDIR=`pwd`/../share/locale\n\nThis works only in some shells for two reasons:\n\n- 'export foo=bar' syntax is not understood everywhere;\n\n- if it is understood, then some shells still split the expansion in\n'export foo=`pwd`' at white-space.\n\nUse 'foo=bar; export foo', like you did elsewhere.\n\n>      test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n>     -\ttest -d $TEXTDOMAINDIR\n>     +\ttest -d $TEXTDOMAINDIR &&\n>     +\ttest $TEXTDOMAINDIR = $GIT_TEXTDOMAINDIR\n\nDouble-quotes, double-quotes!\n\n-- Hannes\n"},{"id":"142798","messageId":"AANLkTim-z6JYmyvl5QWycPV9orsUu8qLg2ZVFP6ZeVLC@mail.gmail.com","threadId":"23941","inReplyTo":"4C05FAEF.2040205@viscovery.net","subject":"Re: [PATCH/RFC v3 2/7] gettext: Add a Gettext interface for shell scripts","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T08:53:39Z","receivedAt":"2010-06-02T08:53:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Wed, Jun 2, 2010 at 06:32, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> [When you resend the series in such a manner that you collect a Cc list\n> manually, please do *not* include me. I'm not interested in this series.]\n>\n> Am 6/2/2010 1:39, schrieb Ævar Arnfjörð Bjarmason:\n>> +    # Not everyone has echo -n\n>> +    case $(echo -n) in\n>> +        \\-n)    Xn=   ; Xc='\\c' ;;\n>> +        *)      Xn=-n ; Xc=\n>> +    esac\n>\n> Don't use 'echo'; use 'printf %s'.\n\nI didn't write this code (as the comment says) but I /thought/ that\nthe whole point of it was to autodetect if echo -n worked, and if so\nuse it because it'd be faster than printf \"%s\", otherwise use some\nevil foo\\n\\c hack.\n\nThat hack doesn't work on bash ('\\c' produces a space), maybe it\ndoesn't work anywhere. Do you have a shell that doesn't support echo\n-n? What does it output there?\n\nI wouldn't be surprised if it did need to be changed to printf\n\"%s\". I'm just curious where it broke and how.\n"},{"id":"142799","messageId":"alpine.DEB.2.00.1006021006590.23247@ds9.cixit.se","threadId":"23941","inReplyTo":"1275440764-26153-2-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2010-06-02T09:12:29Z","receivedAt":"2010-06-02T09:12:29Z","isPatch":true,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Ævar Arnfjörð Bjarmason:\n\n> +\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n\nThis is a multi-line string, and should be translated as such.\n\nThe trailing \"#\" should either be part of the translated multi-line string, \nor be added explicitely, and untranslated, at the end.\n\n> +\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n\nDetermine how to handle the trailing \"#\" as above.\n\n> +\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n\nMulti-line.\n\n> +\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n\nTrailing \"#\".\n\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n> +\tcolor_fprintf_ln(s->fp, c, _(\"#\"));\n\nDitto.\n\n> +\tcase 1: how = _(\"both deleted:\"); break;\n> +\tcase 2: how = _(\"added by us:\"); break;\n> +\tcase 3: how = _(\"deleted by them:\"); break;\n> +\tcase 4: how = _(\"added by them:\"); break;\n> +\tcase 5: how = _(\"deleted by us:\"); break;\n> +\tcase 6: how = _(\"both added:\"); break;\n> +\tcase 7: how = _(\"both modified:\"); break;\n> \t}\n> -\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n> +\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n\ndoes color_fprintf() gracefully handle cutting text for multi-byte \nencodings, and text width? Otherwise I can see this bite us for all \nnon-ASCII locales in general (if long translated are needed), and \nfor CJK locales in particular (for variable character widths).\n\n> -\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n> +\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"), extra.buf);\n\nShould not be in _()\n\n> -\tfprintf(s->fp, \"\\n\");\n> +\tfprintf(s->fp, _(\"\\n\"));\n\nDitto.\n\n> +\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n> +\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n> +\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\"));\n\nEither a multi-line string, or untranslate the \"#\"s.\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"142800","messageId":"AANLkTilClUTkrpnMhBTlcBZC-r2OemT4m22bDnc6fRPy@mail.gmail.com","threadId":"23941","inReplyTo":"alpine.DEB.2.00.1006021006590.23247@ds9.cixit.se","subject":"Re: [PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T09:29:27Z","receivedAt":"2010-06-02T09:29:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Wed, Jun 2, 2010 at 09:12, Peter Krefting <peter@softwolves.pp.se> wrote:\n> Ævar Arnfjörð Bjarmason:\n>\n>> +               color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached\n>> <file>...\\\" to unstage)\"));\n>> +       color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as\n>> appropriate to mark resolution)\"));\n>> +       color_fprintf_ln(s->fp, c, _(\"#\"));\n>\n> This is a multi-line string, and should be translated as such.\n>\n> The trailing \"#\" should either be part of the translated multi-line string,\n> or be added explicitely, and untranslated, at the end.\n>\n>> +               color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached\n>> <file>...\\\" to unstage)\"));\n>> +       color_fprintf_ln(s->fp, c, _(\"#\"));\n>\n> Determine how to handle the trailing \"#\" as above.\n>\n>> +               color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm\n>> <file>...\\\" to update what will be committed)\"));\n>> +       color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout --\n>> <file>...\\\" to discard changes in working directory)\"));\n>\n> Multi-line.\n>\n>> +               color_fprintf_ln(s->fp, c, _(\"#   (commit or discard the\n>> untracked or modified content in submodules)\"));\n>> +       color_fprintf_ln(s->fp, c, _(\"#\"));\n>\n> Trailing \"#\".\n>\n>> +       color_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to\n>> include in what will be committed)\"), how);\n>> +       color_fprintf_ln(s->fp, c, _(\"#\"));\n>\n> Ditto.\n>\n>> +       case 1: how = _(\"both deleted:\"); break;\n>> +       case 2: how = _(\"added by us:\"); break;\n>> +       case 3: how = _(\"deleted by them:\"); break;\n>> +       case 4: how = _(\"added by them:\"); break;\n>> +       case 5: how = _(\"deleted by us:\"); break;\n>> +       case 6: how = _(\"both added:\"); break;\n>> +       case 7: how = _(\"both modified:\"); break;\n>>        }\n>> -       color_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n>> +       color_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n>\n> does color_fprintf() gracefully handle cutting text for multi-byte\n> encodings, and text width? Otherwise I can see this bite us for all\n> non-ASCII locales in general (if long translated are needed), and for CJK\n> locales in particular (for variable character widths).\n>\n>> -               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\",\n>> extra.buf);\n>> +               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"%s\"),\n>> extra.buf);\n>\n> Should not be in _()\n>\n>> -       fprintf(s->fp, \"\\n\");\n>> +       fprintf(s->fp, _(\"\\n\"));\n>\n> Ditto.\n>\n>> +               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),\n>> _(\"#\"));\n>> +               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"#\n>> Initial commit\"));\n>> +               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),\n>> _(\"#\"));\n>\n> Either a multi-line string, or untranslate the \"#\"s.\n\nAll of the points you raised are correct. This is a bad way to do\nthings.\n\nIt was added in Jeff in his original WIP patch as an example of\ntranslation being possible, but I should just remove it. It's not\nready to go in for the reasons you cited.\n\nI'll just remove the wt-status.c chunk out of the patch completely in\nthe next submission, and instead translate a few select strings in\nsome C program well.\n\nMaking things like wt-status.c translatable is going to be hard to do\nproperly. It uses a lot of lego (sticking strings incrementally\ntogether), and due to the coloring of output this'll be particularly\nhard to convert.\n\n(Also, for reference, here's a general guide on how to translate C\nprograms well):\n\n    http://gnu.april.org/software/automake/manual/gettext/Preparing-Strings.html\n"},{"id":"142802","messageId":"4C0626A8.50105@viscovery.net","threadId":"23941","inReplyTo":"AANLkTim-z6JYmyvl5QWycPV9orsUu8qLg2ZVFP6ZeVLC@mail.gmail.com","subject":"Re: [PATCH/RFC v3 2/7] gettext: Add a Gettext interface for shell scripts","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-06-02T09:38:48Z","receivedAt":"2010-06-02T09:38:48Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 6/2/2010 10:53, schrieb Ævar Arnfjörð Bjarmason:\n> That hack doesn't work on bash ('\\c' produces a space), maybe it\n> doesn't work anywhere. Do you have a shell that doesn't support echo\n> -n? What does it output there?\n\nIt's not just echo -n. You are dealing with text that is outside your\ncontrol. There are implementations of echo that interpret backslash in the\ntext (like \\t, \\n etc.). You are risking that they are treated as escape\ncharacters rather than printed as-are.\n\n> I wouldn't be surprised if it did need to be changed to printf\n> \"%s\". I'm just curious where it broke and how.\n\nActually, I don't know where -n does not work.\n\n-- Hannes\n"},{"id":"142808","messageId":"alpine.DEB.2.00.1006021109010.23247@ds9.cixit.se","threadId":"23941","inReplyTo":"AANLkTilClUTkrpnMhBTlcBZC-r2OemT4m22bDnc6fRPy@mail.gmail.com","subject":"Re: [PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2010-06-02T10:11:51Z","receivedAt":"2010-06-02T10:11:51Z","isPatch":true,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Ævar Arnfjörð Bjarmason:\n\n> Making things like wt-status.c translatable is going to be hard to do \n> properly. It uses a lot of lego (sticking strings incrementally together),\n\nHowever, preparing them for translation is probably going to make them \nbetter anyway, as this kind of string building is incredibly brittle, even \nfor English strings.\n\nYou also have to look out for pluralisation issues, fortunately Gettext does \nhave support for the various types of plural forms that are used, so it \nshould be possible. The problem is just identifying where they are needed.\n\n> and due to the coloring of output this'll be particularly hard to convert.\n\nIs the colouring based on knowing the contents of the actual text, or is it \nenough to know the markers? I admit not having looked at the colouring code \nat all...\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"142810","messageId":"AANLkTinzZUaFBzNHzxBA94ECeUKdejVGqSQF1TUtOrrk@mail.gmail.com","threadId":"23941","inReplyTo":"alpine.DEB.2.00.1006021109010.23247@ds9.cixit.se","subject":"Re: [PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T10:56:05Z","receivedAt":"2010-06-02T10:56:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Wed, Jun 2, 2010 at 10:11, Peter Krefting <peter@softwolves.pp.se> wrote:\n> Ævar Arnfjörð Bjarmason:\n>\n>> Making things like wt-status.c translatable is going to be hard to do\n>> properly. It uses a lot of lego (sticking strings incrementally together),\n>\n> However, preparing them for translation is probably going to make them\n> better anyway, as this kind of string building is incredibly brittle, even\n> for English strings.\n\nYeah, but they aren't better as they are now. Personally I'd rather\nincrementally add translation support correctly than do an incomplete\njob of it and wait for the complaints (and subsequent fixes) to come\nin.\n\nBut maybe that's counter-productive. Just making the English strings\ntranslatable as-is is still going to make most of Git translatable,\nand it isn't going to be that bad for languages like German and\nFrench.\n\nMaybe worse is better :)\n\n> You also have to look out for pluralisation issues, fortunately Gettext does\n> have support for the various types of plural forms that are used, so it\n> should be possible. The problem is just identifying where they are needed.\n\nYeah. I'm going to support pluralisation (and maybe msgctxt) across\nthe C-Perl-Shell stack when there's a need for it. I haven't found any\nmessage in Git yet that requires it, but then again I haven't looked\nhard either.\n\nIt would be useful to have an example of a message that could use\npluralization, even better examples in all of C, Perl and Shell.\n\n>> and due to the coloring of output this'll be particularly hard to convert.\n>\n> Is the colouring based on knowing the contents of the actual text, or is it\n> enough to know the markers? I admit not having looked at the colouring code\n> at all...\n\nThere's nothing wrong with coloring in particular, it's just that due\nto the nature of the current implementation code that does coloring\nends up being a bad offender in the \"assemble the strings a few bytes\nat a time with strcat()\" department.\n\nThat can be fixed, it just takes a bit of time and tedium.\n"},{"id":"142813","messageId":"alpine.DEB.2.00.1006021224170.4751@ds9.cixit.se","threadId":"23941","inReplyTo":"AANLkTinzZUaFBzNHzxBA94ECeUKdejVGqSQF1TUtOrrk@mail.gmail.com","subject":"Re: [PATCH/RFC v4 1/7] Add infrastructure for translating Git with gettext","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2010-06-02T11:31:17Z","receivedAt":"2010-06-02T11:31:17Z","isPatch":true,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Ævar Arnfjörð Bjarmason:\n\n> But maybe that's counter-productive. Just making the English strings \n> translatable as-is is still going to make most of Git translatable, and it \n> isn't going to be that bad for languages like German and French.\n\nI think this is the best approach. Without actually making *everything* \navailable for translation it is impossible to weed out the problems. Some of \nthe easier \"hack\" strings (plural word%s, sentence %s%s building, etc) can \nbe fixed during conversion, the rest can be done later as complai^Wcomments \ncome in.\n\n> It would be useful to have an example of a message that could use \n> pluralization, even better examples in all of C, Perl and Shell.\n\nThere is the \"Your branch is ahead of...\" messages, they were introduced in \ncommit b0030db331141bedfaf02f34a83f18712c0ae011, and are currently using a \n\"commit%s\" form, where the %s either maps to an empty string or \"s\". Should \nbe fairly trivial to fix. I think there are other examples as well, but \nthat's the first one I came to think of. :-)\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"142815","messageId":"201006021347.51960.jnareb@gmail.com","threadId":"23941","inReplyTo":"AANLkTilLWZA6OrXhF28qCao2svpZWZiEwb5nVhXUTB9i@mail.gmail.com","subject":"Re: [PATCH/RFC v2 5/6] gettext: Add a Gettext interface for Perl","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-06-02T11:47:50Z","receivedAt":"2010-06-02T11:47:50Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Tue, 1 June 2010, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, Jun 1, 2010 at 17:00, Jakub Narebski <jnareb@gmail.com> wrote:\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> Make Git's gettext messages available to Perl programs through\n>>> Locale::Messages. [...]\n>>\n>> This is I think a very good idea [...] using the\n>> Locale::Messages module from libintl-perl library.  The \"On the state of\n>> i18n in Perl\" (http://rassie.org/archives/247) blog post from 26 April\n>> 2009 provides nice counterpoint to Locale::Maketext::TPJ13 / The Perl\n>> Journal #13 article[1] from 1999... especially because using gettext is\n>> natural for translating git command output and GUI, because git uses it\n>> already for Tcl/Tk (gitk and git-gui), and it is natural solution for\n>> code in C, which slightly less than half of git code.\n>>\n>> Well, we could use Locale::Maketext::Gettext, but it is not in Perl\n>> core either, and as http://rassie.org/archives/247 says its '*.po'\n>> files are less natural.  The gettext documentation (gettext.info) also\n>> recommends libintl-perl, or to be more exact Locale::TextDomain from\n>> it.\n>>\n>> [1] http://search.cpan.org/perldoc?Locale::Maketext::TPJ13\n>>     http://interglacial.com/~sburke/tpj/as_html/tpj13.html\n> \n> Locale::Maketext is a less complete and non-standard alternative as\n> the above blogs note. I think the main reason it's used in favor of\n> Gettext in many Perl projects is that it can be compiled stand-alone\n> from the CPAN, i.e. it doesn't depend on libintl.\n\nThat, and the fact that some Perl projects / modules on CPAN started\nusing Locale::Maketext before gettext acquired functionality for\nhandling plural forms like ngettext.  The mentioned article from\nThe Perl Journal #13 might have also mislead module authors...\n\nOn the other hand libintl-perl distribution contains pure-Perl gettext\nemulation module: Locale::gettext_pp.\n\n> \n> That's comfortable when CPAN is your main distribution channel, but\n> Git's main distribution channel is via OS packages, which can\n> trivially introduce a gettext dependency (for which they doubtless\n> already have a package).\n\nWe need gettext for C, for shell, and for Tcl/Tk anyway.\n\nBTW. some projects keep copy of libintl / gettext library in 'intl/'\nsubdirectory, to be used if it is not present in the target system.\nPerl has 'inc/' and 'use inc::latest' (unfortunately in core only\nsince 5.011002, i.e. 5.12 in practice) to keep private copy of modules\nto be used / installed if they are not present in system.\n\n> \n> Locale::Maketext has a Gettext emulation layer, but using it would be\n> a potential source of bugs (no emulation is perfect).\n\nOTOH see Locale::gettext_pp from libintl-perl (the distribution\ncontaining Locale::Messages and Locale::TextDomain modules).\n\n> \n> That being said the way I wrote Git::Gexttext means any alterante\n> implementation or emulation layer can be seemlessly added later on. We\n> could use (or write) something for Perl, C or Shell that completely\n> bypasses libintl for systems that don't have a gettext C library.\n\nRight.\n\nBesides I think that the base gettext (no plural forms etc.) is the\nsame (would produce the same *.po files) for Locale::Maketext::Gettext\nand for Locale::Messages / Locale::TextDomain.\n\n> \n>> The question is why not use Locale::TextDomain, the high-level Perl-y\n>> framework, wrapper around Locale::Messages from the same libintl-perl\n>> library?  The gettext documentation (in gettext.info, chapter \"13.5.18\n>> Perl\") says:\n>>\n>>  Prerequisite\n>>     `use POSIX;'\n>>     `use Locale::TextDomain;' (included in the package libintl-perl\n>>     which is available on the Comprehensive Perl Archive Network CPAN,\n>>     http://www.cpan.org/).\n>>\n>>\n>> This would change\n>>\n>>  -      print \"Emails will be sent from: \", $sender, \"\\n\";\n>>  +      printf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n>>\n>> to either\n>>\n>>  +      print __\"Emails will be sent from: \", $sender, \"\\n\";\n>>\n>> or\n>>\n>>  +      printf __(\"Emails will be sent from: %s\\n\"), $sender;\n>>\n>> or\n>>\n>>  +      print __x(\"Emails will be sent from: {sender}\\n\",\n>>  +                sender => $sender);\n> \n> I didn't use Locale::TextDomain because it exports a fatter interface\n> by default, and I'm not sure at this point what subset of it it would\n> make sense to support.\n> \n> This is the default Locale::TextDomain interface:\n> \n>    @EXPORT = qw (__ __x __n __nx __xn __p __px __np __npx $__ %__\n>                  N__ N__n N__p N__np);\n> \n> My Git::Gettext only exports a single gettext() function now. I think\n> it's better at this point to have a really small interface and decide\n> later if we'd like to expand it, preferably in a way that'll work\n> consistently across C, Perl and Shell programs.\n\nThat is not, I think, the problem.  You don't need to re-export _all_\nof Locale::TextDomain interface (or create and export stubs for all\nabove functions and variables).\n\n> \n> We might want to improve plural support, add msgctxt etc. later. But\n> for an initial implementation I'd rather have something simple &\n> stupid.\n\nThat's understandable.\n\nBTW. I wonder if git currently has anywhere mesage that depends on\nplural form, or does it always use plural / multiform, like for\nexample '1 files changed' from \"git diff --summary\"...\n\n> \n>>> Signed-off-by: ?var Arnfjör? Bjarmason <avarab@gmail.com>\n>>> ---\n>>>  Makefile            |    4 ++-\n>>>  git-send-email.perl |    3 +-\n>>>  perl/Git/Gettext.pm |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++\n>>>  perl/Makefile.PL    |    5 ++-\n>>>  4 files changed, 92 insertions(+), 3 deletions(-)\n>>>  create mode 100644 perl/Git/Gettext.pm\n>>>\n>>> diff --git a/Makefile b/Makefile\n>>> index dce2faa..2101713 100644\n>>> --- a/Makefile\n>>> +++ b/Makefile\n>>> @@ -1884,7 +1884,9 @@ cscope:\n>>>       $(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n>>>\n>>>  pot:\n>>> -     $(XGETTEXT) -k_ -o po/git.pot $(C_OBJ:o=c) $(SCRIPT_SH)\n>>> +     $(XGETTEXT) --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c)\n>>> +     $(XGETTEXT) --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH)\n>>\n>> Shouldn't this line be in earlier patch, i.e. in \"gettext: Add a\n>> Gettext interface for shell scripts\"?\n> \n> It needed to be split up into seperate line in the Perl commit because ...\n> \n>>> +     $(XGETTEXT) --join-existing --output=po/git.pot --language=Perl $(SCRIPT_PERL)\n>>\n>> From gettext documentation (in gettext.info, chapter \"13.5.18 Perl\"):\n>>\n>>  Extractor\n>>     `xgettext -k__ -k\\$__ -k%__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2\n>>     -kN__ -k'\n>>\n>> Is it equivalent to specifying 'xgettext --language=Perl'?\n> \n> I'm doing --language=Perl because gettext doesn't recognize .perl as a\n> valid Perl extension. It only knows about `pl', `PL', `pm', `cgi'.\n\nAll right.\n\n> (As an aside, I haven't found why Git chose to use the quaint .perl\n> extension).\n> \n> But yeah, using --language=Perl is overshooting it with regards to\n> keyword extraction. From \"5.1 Invoking the `xgettext' Program\":\n> \n>      To disable the default keyword specifications, the option `-k' or\n>      `--keyword' or `--keyword=', without a KEYWORDSPEC, can be used.\n> \n> I'll check if I can supply --keyword to all the XGETTEXT invocations.\n> \n>> Of course the above assumes that you are using Locale::TextDomain, or\n>> at least use the same conventions.\n\nIn my opinion we should use the common convention for the programming\nlanguage, like described in chapter 15 \"Other Programming Languages\"\nin gettext manual: \n  http://www.gnu.org/software/gettext/manual/gettext.html#Programming-Languages\n\n * C:      _(\"msg\")\n * Perl:   __\"msg\"\n * shell:  $(gettext \"abc\")\n * Tcl/Tk: [_ \"msg\"]\n * Python: _('msg')\n\nOn the other hand the only currently traslated part of git, namely\ngitk and git-gui, both of which are written in Tcl/Tk, do not use\nrecommended gettext shorthand, i.e. [_ \"msg\"], but the gettext\nfunction directly, i.e. [mc \"msg\"] (in the imported form, and not\n[::msgcat::mc \"msg\"]).  I guess this is caused by the fact that\nshorthand is not that shorter here...\n\n>>>  Getopt::Long::Configure qw/ pass_through /;\n>>>\n>>> @@ -674,7 +675,7 @@ if (!defined $sender) {\n>>>       $sender = $repoauthor || $repocommitter || '';\n>>>       $sender = ask(\"Who should the emails appear to be from? [$sender] \",\n>>>                     default => $sender);\n>>> -     print \"Emails will be sent from: \", $sender, \"\\n\";\n>>> +     printf gettext(\"Emails will be sent from: %s\\n\"), $sender;\n>>\n>> As I wrote, this IMHO should be either\n>>\n>>  +     printf __(\"Emails will be sent from: %s\\n\"), $sender;\n>>\n>> or\n>>\n>>  +     print __x(\"Emails will be sent from: {sender}\\n\", sender => $sender);\n>>\n>> (note that parantheses differ in those two examples).\n> \n> I'd prefer the former argument expansion form (i.e. %s, not\n> {$sender}), just so translators don't have to deal with two different\n> argument forms.\n\nWell, in this case this does not matter (much), because we have only\nsingle placeholder.\n\nThe Locale::TextDomain manpage says that the reason behind __x() is\ntwofold.  First, you would need context to know what placeholder means\nin\n\n  printf __\"This is the %s %s.\\n\", $color, $thing;\n\nas you would have only\n\n  msgid \"This is the %s %s.\\n\"\n\nin the PO file.  Second, formatting with position (to change order of\nparameters) is possible with 'printf' only for Perl 5.8.0 or never:\n\n  printf __(\"This is the %1\\$s %2\\$s.\\n\"), $color, $thing;\n\nSo that's the reason for introducing\n\n  print __x(\"This is the {color} {thing}.\\n\",\n            color => $color, thing => $thing);\n\n> As for __ or gettext I don't mind. I just picked the former on a whim\n> to match the Shell version. Maybe I should just change C|Perl|Shell to\n> use _?\n> \n> And we can use _, __ is just used to disambiguate it from the _\n> filehandle, and Perl's pretty good at disambiguating that already:\n> \n>     $ perl -E 'sub _ ($) { scalar reverse $_[0] }; say _(\"moo\"); stat\n> \"/etc/hosts\"; say ((stat(_))[7])'\n>     oom\n>     168\n\nLocale::TextDomain::FAQ says:\n\n Q. Why does Locale::TextDomain use a double underscore? I am used to\n    a single underscore from C or other languages.\n\n A. Function names that consist of exactly one non-alphanumerical\n    character make the function automatically global in Perl. Besides,\n    in Perl 6 the concatenation operator will be the underscore\n    instead of the dot.\n\n    [jn: actually the string concatenation operator in Perl 6 is '~',\n     according to http://perlgeek.de/en/article/5-to-6#post_11: \n     \"Perl 5 to 6\" Lesson 11 - Changes to Perl 5 Operators]\n\n\nAlthough 'gettext-tools/examples/hello-perl/hello-1.pl.in' from\ngettext sources\n  http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/examples/hello-perl/hello-1.pl.in\n(hello-1 uses Locale::Messages, hello-2 uses Locale::TextDomain)\nuses _(\"msg\") shortcut:\n\n  sub _ ($) { &gettext; }\n\nHmmm...\n\n>>> diff --git a/perl/Git/Gettext.pm b/perl/Git/Gettext.pm\n>>> new file mode 100644\n>>> index 0000000..f434783\n>>> --- /dev/null\n>>> +++ b/perl/Git/Gettext.pm\n>>> @@ -0,0 +1,83 @@\n>>> +package Git::Gettext;\n>>\n>> Should this package be named Git::Gettext, or other name would be\n>> better, perhaps Git::I18N (like e.g. Games::Risk have\n>> Games::Risk::I18N), or Git::Locale, or even Git::Translator?\n>>\n>> Not very important.\n> \n> I really have no opinion on that, but it does seem like a lot of Perl\n> packages on CPAN use the ::I18N suffix.\n\nAlso using Git::I18N allows us to change the backend from gettext to\nsomething other (like Locale::Maketext lexicon, or something yet\nanother).\n\n>>> +use strict;\n>>> +use warnings;\n>>> +use Exporter;\n>>> +use base 'Exporter';\n>>\n>> O.K.\n>>\n>> The alternative would be to use\n>>\n>>  +use Exporter qw(import);\n> \n> Not if we want to maintain 5.6 support. The `use Exporter \"import\"'\n> form was only introduced in 5.8. I use it everywhere where I don't\n> have to care about 5.6 support (which is everywhere but Git).\n\nOh, all right.  Thanks for explanation.\n\n>>> +our %EXPORT_TAGS;\n>>> +@{ $EXPORT_TAGS{'all'} } = @EXPORT_OK;\n>>\n>> Why not simply\n>>\n>>  +our %EXPORT_TAGS = ('all' => [ @EXPORT_OK ]);\n[...]\n> \n> Just because it some old code of mine I had around that I copied\n> from. I could rewrite it to a nicer form.\n> \n> Actually I was considering changing it to just have @EXPORT and\n> nothing else. You're going to use gettext if you use the module\n> anyway, so we might as well just import them all everywhere we use\n> Gettext in Perl.\n\nRight, if we use Git::Gettext / Git::I18N it means that we want to do\nmessage traslation, so we would need to import subroutines anyway.\n\n>>> +\n>>> +sub __bootstrap_locale_messages {\n>>> +     our $TEXTDOMAIN = 'git';\n>>> +\n>>> +     # TODO: How do I make the sed replacements in the top level\n>>> +     # Makefile reach me here?\n>>> +     #our $TEXTDOMAINDIR = q|@@LOCALEDIR@@|;\n[...]\n>> Make invoked on perl/Makefile, when invoked from main Makefile by\n>> '$(MAKE) -C perl' (via QUIET_SUBDIR0) passes 'localedir' to submake;\n>> perl/Makefile should probably have something like\n>>\n>>  localedir ?= $(sharedir)/locale\n>>\n>> That is assuming that 'localedir' is added to list of exported\n>> variables.\n>>\n>> But I am not sure how such substitution should be performed.\n> \n> I'll try to get something like that to work. Actually the main problem\n> seemed to be that it had a hybrid handwritten Makefile and one made by\n> EU::MM.\n\nThe problem with EU::MM is that while ExtUtils::MakeMaker was first\nreleased as a core module with Perl 5, git requires for generated\nmakefile (well, perl.mak included by perl/Makefile) to be compatibile\nwith DESTDIR mechanism.  This requires ExtUtils::MakeMaker version 6.11+,\nwhich was released with perl 5.006002 (Perl v5.6.2).\n\nHmmm... perhaps we can bump requirement from Perl 5.6 to Perl 5.6.2\nand get rid of hybrid handwritten Makefile?\n\nOtherwise you would have to either duplicate EU::MM work in\nhandwritten Makefile, or somehow make perl/Makefile to do\ntransformation before perl/perl.mak generated by EU::MM starts\nworking...\n\n>>> +\n>>> +BEGIN\n>>> +{\n>>> +     local ($@, $!);\n>>> +     eval { __bootstrap_locale_messages() };\n>>> +     if ($@) {\n>>> +             # Oh noes, no Locale::Messages here\n>>> +             *gettext = sub ($) { $_[0] };\n>>> +     }\n>>> +}\n>>\n>> Does it need to be in BEGIN block?  Probably yes.\n> \n> I'm pretty sure it needs to all be at BEGIN time. I recall that\n> declaring prototypes at runtime was an error in some older versions,\n> but it works now:\n> \n>     $ perl -E '*meh = sub ($) { \"foo\" }; say prototype \"meh\"'\n>     $\n> \n> Anyway since it's code that's being use'd it's going to always be at\n> BEGIN time anyway. I just wanted to be explicit.\n\nAll right, probably better to be safe.\n\n>>> +=head1 EXPORTS\n>>> +\n>>> +Exports are done via L<Exporter>. Invididual functions can be\n>>> +exporter, or all of them via the C<:all> export tag.\n>>\n>> Shouldn't this be described in less technical way in SYNOPSIS and\n>> DESCRIPTION sections instead?\n> \n> Yeah, maybe. But there's a convention for `=head1 EXPORTS' in perl\n> core / CPAN. So that's what I added at a whim.\n\nHmmm... I don't recall seeing EXPORTS section often in manpages for\nPerl modules, at least not for the ones I use...\n\n\nBTW. I tried to find Perl module / Perl program that uses\nLocale::TextDomain for l10n, but provides passthrough fallback if it\nis not installed... but haven't find any.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"142839","messageId":"1275517993-23093-1-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v5 0/2] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T22:33:11Z","receivedAt":"2010-06-02T22:33:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This is version 5 of the patch series to make Git optionally\ntranslatable with GNU gettext.\n\nI split and squashed the whole thing down into just two patches. The\nfirst commit adds all the needed core infrastructure, and the second\ncommit contains an initial stab at starting translation for the core\ntools, along with some tests that could be added as a result.\n\nThe changes this time around are:\n\n  * Testing testing & more testing. Including testing for xgettext\n    message extraction, that .po files are generated correctly etc.\n\n  * There's now a git-sh-i18n library for the shell, so gettext.sh\n    isn't loaded as part of git-sh-setup.\n\n  * Shell portability fixes suggested by Johannes Sixt\n\n  * Other misc suggestions and fixes Jakub Narebski, Peter Krefting,\n    and Jonathan Nieder pointed out were incorporated.\n\n  * I did not change over to Locale::TextDomain for Perl. I wrote a\n    version of Git::I18N in it and found that it was more trouble than\n    it was worth\n\nI think (this time around, really) that this series is ready for\ninclusion unless some issue is raised that I've missed. But to play\ndevil's advocate this is what might prevent it from being included.\n\n  * gettext is on by default. I think that's a feature, but Git won't\n    build by default on e.g. Solaris unless the packager adds\n    NO_GETTEXT=YesPlease to the make arguments. Of course if they use\n    ./configure it'll detect if libintl.h exists and act\n    appropriately.\n\n    I think gettext on by default is a feature, it's equivalent to\n    what we do for our other /*/po/ stuff. But pending discussion of\n    this I haven't updated e.g. INSTALL. Comments welcome.\n\n  * There isn't documentation on how to use this from a developer and\n    maintainer standpoint. And there's no docs for translators.\n\n    Where would the developer/maintainer docs belong? But for most of\n    the things such a documentation would include I think other\n    existing resources would do fine, e.g. the GNU gettext manual.\n\nÆvar Arnfjörð Bjarmason (2):\n  Add infrastructure for translating Git with gettext\n  Add initial C, Shell and Perl gettext translations\n\n .gitignore                         |    2 +\n Makefile                           |   44 ++++++++++-\n config.mak.in                      |    1 +\n configure.ac                       |    6 ++\n gettext.c                          |   25 ++++++\n gettext.h                          |   13 +++\n git-pull.sh                        |   16 ++--\n git-send-email.perl                |    3 +-\n git-sh-i18n.sh                     |   33 ++++++++\n git.c                              |    3 +\n perl/Git/I18N.pm                   |   77 +++++++++++++++++++\n perl/Makefile                      |    3 +-\n perl/Makefile.PL                   |   14 +++-\n po/.gitignore                      |    1 +\n po/is.po                           |   71 +++++++++++++++++\n t/t0200-gettext.sh                 |  146 ++++++++++++++++++++++++++++++++++++\n t/t0200-gettext/test.c             |   10 +++\n t/t0200-gettext/test.perl          |   11 +++\n t/t0200-gettext/test.sh            |   14 ++++\n t/t0201-gettext-shell-fallbacks.sh |   40 ++++++++++\n t/test-lib.sh                      |    1 +\n wt-status.c                        |  107 +++++++++++++-------------\n 22 files changed, 576 insertions(+), 65 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 git-sh-i18n.sh\n create mode 100644 perl/Git/I18N.pm\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n create mode 100755 t/t0200-gettext.sh\n create mode 100644 t/t0200-gettext/test.c\n create mode 100644 t/t0200-gettext/test.perl\n create mode 100644 t/t0200-gettext/test.sh\n create mode 100755 t/t0201-gettext-shell-fallbacks.sh\n"},{"id":"142840","messageId":"1275517993-23093-2-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v5 1/2] Add infrastructure for translating Git with gettext","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T22:33:12Z","receivedAt":"2010-06-02T22:33:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"All of the interface messages in Git core are currently hardcoded in\nEnglish. Change that by optionally enabling translation of the core C,\nShell and Perl programs via GNU gettext. If you set the appropriate\nLC_* variables Git will speak your language, provided that someone has\nsubmitted a translation.\n\nIf gettext isn't available, or if Git is compiled with\nNO_GETTEXT=YesPlease, then Git fall back on its previous behavior of\nonly speaking English.\n\nWith NO_GETTEXT=YesPlease gettext support will be #defined away for C\nprograms. For Shell and Perl programs we rely on the git message\ncatalog not being avalalable. That's a reasonable assumption since the\n*.po files won't be installed on the system during make install.\n\nThe gettext wrappers that are provided in the patch are only the bare\nminimum required to begin translation work. In particular I haven't\nadded wrappers for the gettext functions that enable plural support,\nor those that provide message context (msgctxt). Those can be added\nlater. The intent is to start with a small subset and see what we need\nlater, not to start with something that's unnecessarily large right\naway.\n\nImplementation and usage notes:\n\n * General:\n\n   Gettext .mo files will be installed and looked for in the standard\n   $(prefix)/share/locale path. GIT_TEXTDOMAINDIR can also be set to\n   override that. But this is only intended to be used to test Git\n   itself.\n\n * Perl:\n\n   Perl code that wants to be localized should use the new Git::I18n\n   module. It imports a __ function into the caller's package by\n   default.\n\n   Instead of using the high level Locale::TextDomain interface I've\n   opted to use the low-level (equivalent to the C interface)\n   Locale::Messages module, which Locale::TextDomain itself uses.\n\n   Locale::TextDomain does a lot of redundant work we don't need, and\n   some of it would potentially introduce bugs. It tries to set the\n   $TEXTDOMAIN based on package of the caller, and has its own\n   hardcoded paths where it'll search for messages.\n\n   I found it easier just to completely avoid it rather than try to\n   circumvent its behavior. In any case, this is an issue wholly\n   internal Git::I18N. Its guts can be changed later if that's deemed\n   necessary.\n\n * Shell:\n\n   Shell code that wants to be localized should use the new\n   git-sh-i18n library. It's just a wrapper for the system's\n   gettext.sh.\n\n   If gettext.sh isn't available we'll fall back on a dumb\n   printf(1)-powered fall-through wrapper.\n\n   I originally tried to detect if the system supported `echo -n' but\n   I found this to be a waste of time. My benchmarks on Linux, Solaris\n   and FreeBSD reveal that printf(1) is fast enough, especially since\n   we aren't calling gettext() from within any tight loops.\n\nThis patch is based on work by Jeff Epler <jepler@unpythonic.net> who\ndid the initial Makefile / C work, and a lot of comments from the Git\nmailing list.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore                         |    2 +\n Makefile                           |   44 ++++++++++++++-\n config.mak.in                      |    1 +\n configure.ac                       |    6 ++\n gettext.c                          |   25 +++++++++\n gettext.h                          |   13 +++++\n git-sh-i18n.sh                     |   33 +++++++++++\n git.c                              |    3 +\n perl/Git/I18N.pm                   |   77 ++++++++++++++++++++++++++\n perl/Makefile                      |    3 +-\n perl/Makefile.PL                   |   14 +++++-\n po/.gitignore                      |    1 +\n po/is.po                           |   48 ++++++++++++++++\n t/t0200-gettext.sh                 |  104 ++++++++++++++++++++++++++++++++++++\n t/t0200-gettext/test.c             |   11 ++++\n t/t0200-gettext/test.perl          |   11 ++++\n t/t0200-gettext/test.sh            |   14 +++++\n t/t0201-gettext-shell-fallbacks.sh |   40 ++++++++++++++\n t/test-lib.sh                      |    1 +\n 19 files changed, 447 insertions(+), 4 deletions(-)\n create mode 100644 gettext.c\n create mode 100644 gettext.h\n create mode 100644 git-sh-i18n.sh\n create mode 100644 perl/Git/I18N.pm\n create mode 100644 po/.gitignore\n create mode 100644 po/is.po\n create mode 100755 t/t0200-gettext.sh\n create mode 100644 t/t0200-gettext/test.c\n create mode 100644 t/t0200-gettext/test.perl\n create mode 100644 t/t0200-gettext/test.sh\n create mode 100755 t/t0201-gettext-shell-fallbacks.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 14e2b6b..6c2b193 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -125,6 +125,7 @@\n /git-rm\n /git-send-email\n /git-send-pack\n+/git-sh-i18n\n /git-sh-setup\n /git-shell\n /git-shortlog\n@@ -204,3 +205,4 @@\n *.pdb\n /Debug/\n /Release/\n+/share/\ndiff --git a/Makefile b/Makefile\nindex d5d6565..32f5e52 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -272,6 +272,7 @@ mandir = share/man\n infodir = share/info\n gitexecdir = libexec/git-core\n sharedir = $(prefix)/share\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ifeq ($(prefix),/usr)\n@@ -285,7 +286,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir\n+export prefix bindir sharedir sysconfdir localedir\n \n CC = gcc\n AR = ar\n@@ -297,6 +298,8 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n PTHREAD_LIBS = -lpthread\n+XGETTEXT = xgettext\n+MSGFMT = msgfmt\n \n export TCL_PATH TCLTK_PATH\n \n@@ -358,6 +361,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-sh-setup\n+SCRIPT_LIB += git-sh-i18n\n \n SCRIPT_PERL += git-add--interactive.perl\n SCRIPT_PERL += git-difftool.perl\n@@ -523,6 +527,7 @@ LIB_H += userdiff.h\n LIB_H += utf8.h\n LIB_H += xdiff-interface.h\n LIB_H += xdiff/xdiff.h\n+LIB_H += gettext.h\n \n LIB_OBJS += abspath.o\n LIB_OBJS += advice.o\n@@ -564,6 +569,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gettext.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\n@@ -1386,6 +1392,12 @@ ifdef USE_NED_ALLOCATOR\n        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n+ifdef NO_GETTEXT\n+\tCOMPAT_CFLAGS += -DNO_GETTEXT\n+else\n+\tLIBINTL = -lintl\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1415,6 +1427,7 @@ ifndef V\n \tQUIET_BUILT_IN = @echo '   ' BUILTIN $@;\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_SUBDIR0  = +@subdir=\n \tQUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \\\n \t\t\t $(MAKE) $(PRINT_DIR) -C $$subdir\n@@ -1442,7 +1455,9 @@ gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+sharedir_SQ = $(subst ','\\'',$(sharedir))\n \n+LOCALEDIR_SQ = $(subst ','\\'',$(localedir))\n SHELL_PATH_SQ = $(subst ','\\'',$(SHELL_PATH))\n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n PYTHON_PATH_SQ = $(subst ','\\'',$(PYTHON_PATH))\n@@ -1491,7 +1506,7 @@ ifndef NO_TCLTK\n \t$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all\n endif\n ifndef NO_PERL\n-\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all\n+\t$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all\n endif\n ifndef NO_PYTHON\n \t$(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all\n@@ -1536,6 +1551,7 @@ $(RM) $@ $@+ && \\\n sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n+    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \\\n     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \\\n     -e $(BROKEN_PATH_FIX) \\\n     $@.sh >$@+\n@@ -1868,6 +1884,21 @@ cscope:\n \t$(RM) cscope*\n \t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n \n+pot:\n+\t$(XGETTEXT) --add-comments --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c) t/t0200-gettext/test.c\n+\t$(XGETTEXT) --add-comments --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH) t/t0200-gettext/test.sh\n+\t$(XGETTEXT) --add-comments --join-existing --keyword=__ --output=po/git.pot --language=Perl $(SCRIPT_PERL) t/t0200-gettext/test.perl\n+\n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))\n+ifndef NO_GETTEXT\n+all:: $(MOFILES)\n+endif\n+share/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t@mkdir -p $(dir $@)\n+\t$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<\n+\n ### Detect prefix changes\n TRACK_CFLAGS = $(subst ','\\'',$(ALL_CFLAGS)):\\\n              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n@@ -1980,6 +2011,11 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \t$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'\n+ifndef NO_GETTEXT\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'\n+\t(cd share && tar cf - locale) | \\\n+\t\t(cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)\n+endif\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n@@ -2127,6 +2163,10 @@ ifndef NO_TCLTK\n \t$(MAKE) -C git-gui clean\n endif\n \t$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS\n+ifndef NO_GETTEXT\n+\t$(RM) po/git.pot\n+\t$(RM) -r share/\n+endif\n \n .PHONY: all install clean strip\n .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell\ndiff --git a/config.mak.in b/config.mak.in\nindex 0d4b64d..a15f3c1 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@\n NO_EXPAT=@NO_EXPAT@\n NO_LIBGEN_H=@NO_LIBGEN_H@\n HAVE_PATHS_H=@HAVE_PATHS_H@\n+NO_GETTEXT=@NO_GETTEXT@\n NEEDS_LIBICONV=@NEEDS_LIBICONV@\n NEEDS_SOCKET=@NEEDS_SOCKET@\n NEEDS_RESOLV=@NEEDS_RESOLV@\ndiff --git a/configure.ac b/configure.ac\nindex 71038fc..7bebfd8 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],\n [HAVE_PATHS_H=])\n AC_SUBST(HAVE_PATHS_H)\n #\n+# Define NO_GETTEXT if you don't have libintl.h\n+AC_CHECK_HEADER([libintl.h],\n+[NO_GETTEXT=],\n+[NO_GETTEXT=YesPlease])\n+AC_SUBST(NO_GETTEXT)\n+#\n # Define NO_STRCASESTR if you don't have strcasestr.\n GIT_CHECK_FUNC(strcasestr,\n [NO_STRCASESTR=],\ndiff --git a/gettext.c b/gettext.c\nnew file mode 100644\nindex 0000000..22cdcc1\n--- /dev/null\n+++ b/gettext.c\n@@ -0,0 +1,25 @@\n+#ifdef NO_GETTEXT\n+void git_setup_gettext(void) {}\n+#else\n+#include \"exec_cmd.h\"\n+#include <libintl.h>\n+#include <stdlib.h>\n+\n+void git_setup_gettext(void) {\n+\tchar *podir;\n+\tchar *envdir = getenv(\"GIT_TEXTDOMAINDIR\");\n+\n+\tif (envdir) {\n+\t\t(void)bindtextdomain(\"git\", envdir);\n+\t} else {\n+\t\tpodir = (char *)system_path(\"share/locale\");\n+\t\tif (!podir) return;\n+\t\t(void)bindtextdomain(\"git\", podir);\n+\t\tfree(podir);\n+\t}\n+\n+\t(void)setlocale(LC_MESSAGES, \"\");\n+\t(void)setlocale(LC_CTYPE, \"\");\n+\t(void)textdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nnew file mode 100644\nindex 0000000..a99da6a\n--- /dev/null\n+++ b/gettext.h\n@@ -0,0 +1,13 @@\n+#ifndef GETTEXT_H\n+#define GETTEXT_H\n+\n+void git_setup_gettext(void);\n+\n+#ifdef NO_GETTEXT\n+#define _(s) (s)\n+#else\n+#include <libintl.h>\n+#define _(s) gettext(s)\n+#endif\n+\n+#endif\ndiff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\nnew file mode 100644\nindex 0000000..ae1d5cd\n--- /dev/null\n+++ b/git-sh-i18n.sh\n@@ -0,0 +1,33 @@\n+#!/bin/sh\n+#\n+# This is what Git uses internally to bootstrap its gettext\n+# shellscript interface.\n+\n+# Try to use libintl's gettext.sh, or fall back to English if we\n+# can't.\n+. gettext.sh\n+\n+if test $? -eq 0 && test -z \"$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\"\n+then\n+\tTEXTDOMAIN=git\n+\texport TEXTDOMAIN\n+\tif [ -z \"$GIT_TEXTDOMAINDIR\" ]\n+\tthen\n+\t\tTEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+\telse\n+\t\tTEXTDOMAINDIR=\"$GIT_TEXTDOMAINDIR\"\n+\tfi\n+\texport TEXTDOMAINDIR\n+else\n+\t# Since gettext.sh isn't available we'll have to define our own\n+\t# dummy pass-through functions.\n+\n+\tgettext () {\n+\t\tprintf \"%s\" \"$1\"\n+\t}\n+\n+\teval_gettext () {\n+\t\tgettext_eval=\"printf '%s' \\\"$1\\\"\"\n+\t\tprintf \"%s\" \"`eval \\\"$gettext_eval\\\"`\"\n+\t}\n+fi\ndiff --git a/git.c b/git.c\nindex 99f0363..d749eab 100644\n--- a/git.c\n+++ b/git.c\n@@ -3,6 +3,7 @@\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"run-command.h\"\n+#include \"gettext.h\"\n \n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\\n\"\n@@ -490,6 +491,8 @@ int main(int argc, const char **argv)\n \tif (!cmd)\n \t\tcmd = \"git-help\";\n \n+\tgit_setup_gettext();\n+\n \t/*\n \t * \"git-xxxx\" is the same as \"git xxxx\", but we obviously:\n \t *\ndiff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\nnew file mode 100644\nindex 0000000..cabdcec\n--- /dev/null\n+++ b/perl/Git/I18N.pm\n@@ -0,0 +1,77 @@\n+package Git::I18N;\n+use strict;\n+use warnings;\n+use Exporter;\n+use base 'Exporter';\n+\n+our $VERSION = '0.01';\n+\n+our @EXPORT = qw(__);\n+our @EXPORT_OK = @EXPORT;\n+\n+sub __ ($);\n+\n+sub __bootstrap_locale_messages {\n+\tour $TEXTDOMAIN = 'git';\n+\tour $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++';\n+\n+\trequire POSIX;\n+\tPOSIX->import(qw(setlocale));\n+\t# Non-core prerequisite module\n+\trequire Locale::Messages;\n+\tLocale::Messages->import(qw(:locale_h :libintl_h));\n+\n+\tsetlocale(LC_MESSAGES(), '');\n+\tsetlocale(LC_CTYPE(), '');\n+\ttextdomain($TEXTDOMAIN);\n+\tbindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);\n+\n+\treturn;\n+}\n+\n+BEGIN\n+{\n+\tlocal ($@, $!);\n+\teval { __bootstrap_locale_messages() };\n+\tif ($@) {\n+\t\t# Oh noes, no Locale::Messages here\n+\t\t*__\t = sub ($) { $_[0] };\n+\t} else {\n+\t\t*__\t = sub ($) { goto &Locale::Messages::gettext };\n+\t}\n+}\n+\n+1;\n+\n+__END__\n+\n+=head1 NAME\n+\n+Git::I18N - Perl interface to Git's Gettext localizations\n+\n+=head1 SYNOPSIS\n+\n+\tuse Git::I18N;\n+\n+\tprint __(\"Welcome to Git!\\n\");\n+\n+\tprintf __(\"The following error occured: %s\\n\"), $error;\n+\n+=head1 DESCRIPTION\n+\n+Git's internal interface to Gettext via L<Locale::Messages>. If\n+L<Locale::Messages> can't be loaded (it's not a core module) we\n+provide stub passthrough fallbacks.\n+\n+=head1 FUNCTIONS\n+\n+=head2 __($)\n+\n+L<Locale::Messages>'s gettext function if all goes well, otherwise our\n+passthrough fallback function.\n+\n+=head1 AUTHOR\n+\n+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+=cut\ndiff --git a/perl/Makefile b/perl/Makefile\nindex 4ab21d6..4e624ff 100644\n--- a/perl/Makefile\n+++ b/perl/Makefile\n@@ -5,6 +5,7 @@ makfile:=perl.mak\n \n PERL_PATH_SQ = $(subst ','\\'',$(PERL_PATH))\n prefix_SQ = $(subst ','\\'',$(prefix))\n+localedir_SQ = $(subst ','\\'',$(localedir))\n \n ifndef V\n \tQUIET = @\n@@ -38,7 +39,7 @@ $(makfile): ../GIT-CFLAGS Makefile\n \techo '\techo $(instdir_SQ)' >> $@\n else\n $(makfile): Makefile.PL ../GIT-CFLAGS\n-\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)'\n+\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)' --localedir='$(localedir_SQ)'\n endif\n \n # this is just added comfort for calling make directly in perl dir\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nindex 0b9deca..456d45b 100644\n--- a/perl/Makefile.PL\n+++ b/perl/Makefile.PL\n@@ -1,4 +1,12 @@\n+use strict;\n+use warnings;\n use ExtUtils::MakeMaker;\n+use Getopt::Long;\n+\n+# Sanity: die at first unknown option\n+Getopt::Long::Configure qw/ pass_through /;\n+\n+GetOptions(\"localedir=s\" => \\my $localedir);\n \n sub MY::postamble {\n \treturn <<'MAKE_FRAG';\n@@ -16,7 +24,10 @@ endif\n MAKE_FRAG\n }\n \n-my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');\n+my %pm = (\n+\t'Git.pm' => '$(INST_LIBDIR)/Git.pm',\n+\t'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',\n+);\n \n # We come with our own bundled Error.pm. It's not in the set of default\n # Perl modules so install it if it's not available on the system yet.\n@@ -33,6 +44,7 @@ WriteMakefile(\n \tNAME            => 'Git',\n \tVERSION_FROM    => 'Git.pm',\n \tPM\t\t=> \\%pm,\n+\tPM_FILTER\t=> qq[\\$(PERL) -pe \"s<\\\\Q++LOCALEDIR++\\\\E><$localedir>\"],\n \tMAKEFILE\t=> 'perl.mak',\n \tINSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'\n );\ndiff --git a/po/.gitignore b/po/.gitignore\nnew file mode 100644\nindex 0000000..221000e\n--- /dev/null\n+++ b/po/.gitignore\n@@ -0,0 +1 @@\n+/*.pot\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..ac4317b\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,48 @@\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2010-06-02 17:35+0000\\n\"\n+\"PO-Revision-Date: 2010-06-02 16:01+0000\\n\"\n+\"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n+\"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"X-Poedit-Language: English\\n\"\n+\"X-Poedit-SourceCharset: utf-8\\n\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.c:6\n+msgid \"TEST: A C test string\"\n+msgstr \"TILRAUN: C tilraunastrengur\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.c:9\n+#, c-format\n+msgid \"TEST: A C test string %s\"\n+msgstr \"TILRAUN: C tilraunastrengur %s\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.sh:8\n+msgid \"TEST: A Shell test string\"\n+msgstr \"TILRAUN: Skeljartilraunastrengur\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.sh:11\n+#, sh-format\n+msgid \"TEST: A Shell test $variable\"\n+msgstr \"TILRAUN: Skeljartilraunastrengur með breytunni $variable\"\n+\n+#. This is a phony Perl program that's only here to test xgettext\n+#. message extraction\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.perl:5\n+msgid \"TEST: A Perl test string\"\n+msgstr \"TILRAUN: Perl tilraunastrengur\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200-gettext/test.perl:8\n+#, perl-format\n+msgid \"TEST: A Perl test variable %s\"\n+msgstr \"TILRAUN: Perl tilraunastrengur með breytunni %s\"\ndiff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh\nnew file mode 100755\nindex 0000000..7b01ce4\n--- /dev/null\n+++ b/t/t0200-gettext.sh\n@@ -0,0 +1,104 @@\n+#!/bin/sh\n+D=`pwd`\n+GIT_TEXTDOMAINDIR=\"$D/../share/locale\"\n+GIT_POROOT=\"$D/../po\"\n+export GIT_TEXTDOMAINDIR GIT_POROOT\n+\n+test_description='Gettext support for Git'\n+. ./test-lib.sh\n+. ../../git-sh-i18n\n+\n+test_expect_success 'sanity: $TEXTDOMAIN is git' '\n+    test $TEXTDOMAIN = \"git\"\n+'\n+\n+test_expect_success 'sanity: $TEXTDOMAINDIR exists' '\n+    test -d \"$TEXTDOMAINDIR\" &&\n+    test \"$TEXTDOMAINDIR\" = \"$GIT_TEXTDOMAINDIR\"\n+'\n+\n+test_expect_success 'sanity: Icelandic locale was compiled' '\n+    test -f \"$TEXTDOMAINDIR/is/LC_MESSAGES/git.mo\"\n+'\n+\n+test_expect_success 'sanity: No gettext(\"\") data for fantasy locale' '\n+    LANGUAGE=is LC_ALL=tlh_TLH.UTF-8 gettext \"\" > real-locale &&\n+    test_expect_failure test -s real-locale\n+'\n+\n+test_expect_success 'sanity: Some gettext(\"\") data for real locale' '\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"\" > fantasy-locale &&\n+    test -s fantasy-locale\n+'\n+\n+# TODO: When we have more locales, generalize this to test them\n+# all. Maybe we'll need a dir->locale map for that.\n+test_expect_success 'sanity: gettext(\"\") metadata is OK' '\n+    # Return value may be non-zero\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"\" > zero-expect &&\n+    grep \"Project-Id-Version: Git\" zero-expect &&\n+    grep \"Git Mailing List <git@vger.kernel.org>\" zero-expect &&\n+    grep \"Content-Type: text/plain; charset=UTF-8\" zero-expect &&\n+    grep \"Content-Transfer-Encoding: 8bit\" zero-expect\n+'\n+\n+test_expect_success 'sanity: gettext(unknown) is passed through' '\n+    printf \"This is not a translation string\"  > expect &&\n+    gettext \"This is not a translation string\" > actual &&\n+    eval_gettext \"This is not a translation string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+# xgettext from C\n+test_expect_success 'xgettext: C extraction' '\n+    printf \"TILRAUN: C tilraunastrengur\" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"TEST: A C test string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'xgettext: C extraction with %s' '\n+    printf \"TILRAUN: C tilraunastrengur %%s\" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"TEST: A C test string %s\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+# xgettext from Shell\n+test_expect_success 'xgettext: Shell extraction' '\n+    printf \"TILRAUN: Skeljartilraunastrengur\" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"TEST: A Shell test string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'xgettext: Shell extraction with $variable' '\n+    printf \"TILRAUN: Skeljartilraunastrengur með breytunni a var i able\" > x-expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 variable=\"a var i able\" eval_gettext \"TEST: A Shell test \\$variable\" > x-actual &&\n+    test_cmp x-expect x-actual\n+'\n+\n+# xgettext from Perl\n+test_expect_success 'xgettext: Perl extraction' '\n+    printf \"TILRAUN: Perl tilraunastrengur\" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"TEST: A Perl test string\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'xgettext: Perl extraction with %s' '\n+    printf \"TILRAUN: Perl tilraunastrengur með breytunni %%s\" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext \"TEST: A Perl test variable %s\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'xgettext: Perl _() strings are not extracted' '\n+    > expect &&\n+    grep \"A Perl string xgettext will not get\" $GIT_POROOT/is.po > actual;\n+    test_cmp expect actual\n+'\n+\n+# xgettext extracts comments\n+test_expect_success 'xgettext: Comment extraction with --add-comments' '\n+    grep \"TRANSLATORS: This is a test\" ../t0200-gettext/* | wc -l > expect &&\n+    grep \"TRANSLATORS: This is a test\" $GIT_POROOT/is.po  | wc -l > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_done\ndiff --git a/t/t0200-gettext/test.c b/t/t0200-gettext/test.c\nnew file mode 100644\nindex 0000000..9fa4c23\n--- /dev/null\n+++ b/t/t0200-gettext/test.c\n@@ -0,0 +1,11 @@\n+/* This is a phony C program that's only here to test xgettext message extraction */\n+\n+int main(void)\n+{\n+\t/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tputs(_(\"TEST: A C test string\"));\n+\n+\t/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tprintf(_(\"TEST: A C test string %s\"), \"variable\");\n+}\n+\t\ndiff --git a/t/t0200-gettext/test.perl b/t/t0200-gettext/test.perl\nnew file mode 100644\nindex 0000000..8c50ef0\n--- /dev/null\n+++ b/t/t0200-gettext/test.perl\n@@ -0,0 +1,11 @@\n+# This is a phony Perl program that's only here to test xgettext\n+# message extraction\n+\n+# TRANSLATORS: This is a test. You don't need to translate it.\n+print __(\"TEST: A Perl test string\");\n+\n+# TRANSLATORS: This is a test. You don't need to translate it.\n+printf __(\"TEST: A Perl test variable %s\"), \"moo\";\n+\n+# TRANSLATORS: If you see this, Git has a bug\n+print _\"TEST: A Perl string xgettext will not get\";\ndiff --git a/t/t0200-gettext/test.sh b/t/t0200-gettext/test.sh\nnew file mode 100644\nindex 0000000..022d607\n--- /dev/null\n+++ b/t/t0200-gettext/test.sh\n@@ -0,0 +1,14 @@\n+# This is a phony Shell program that's only here to test xgettext\n+# message extraction\n+\n+# so the above comment won't be folded into the next one by xgettext\n+echo\n+\n+# TRANSLATORS: This is a test. You don't need to translate it.\n+gettext \"TEST: A Shell test string\"\n+\n+# TRANSLATORS: This is a test. You don't need to translate it.\n+eval_gettext \"TEST: A Shell test \\$variable\"\n+\n+# TRANSLATORS: If you see this, Git has a bug\n+_(\"TEST: A Shell string xgettext won't get\")\ndiff --git a/t/t0201-gettext-shell-fallbacks.sh b/t/t0201-gettext-shell-fallbacks.sh\nnew file mode 100755\nindex 0000000..827adb2\n--- /dev/null\n+++ b/t/t0201-gettext-shell-fallbacks.sh\n@@ -0,0 +1,40 @@\n+#!/bin/sh\n+D=`pwd`\n+GIT_TEXTDOMAINDIR=\"$D/../share/locale\"\n+GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease\n+\n+export GIT_TEXTDOMAINDIR GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\n+\n+test_description='Gettext Shell fallbacks'\n+. ./test-lib.sh\n+. ../../git-sh-i18n\n+\n+test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' '\n+\ttest_expect_failure test -z \"$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\"\n+'\n+\n+test_expect_success 'gettext: our gettext() fallback has pass-through semantics' '\n+    printf \"test\" > expect &&\n+    gettext \"test\" > actual &&\n+    test_cmp expect actual &&\n+    printf \"test more words\" > expect &&\n+    gettext \"test more words\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' '\n+    printf \"test\" > expect &&\n+    eval_gettext \"test\" > actual &&\n+    test_cmp expect actual &&\n+    printf \"test more words\" > expect &&\n+    eval_gettext \"test more words\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' '\n+    printf \"test YesPlease\" > expect &&\n+    eval_gettext \"test \\$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_done\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 454880a..cb3c9c5 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -37,6 +37,7 @@ ORIGINAL_TERM=$TERM\n # For repeatability, reset the environment to known value.\n LANG=C\n LC_ALL=C\n+LANGUAGE=C\n PAGER=cat\n TZ=UTC\n TERM=dumb\n-- \n1.7.1.242.g290e3.dirty\n"},{"id":"142841","messageId":"1275517993-23093-3-git-send-email-avarab@gmail.com","threadId":"23941","inReplyTo":"AANLkTimhxqGRPjYz-k5f-LTIk6KajEwUuGJWt-dAKZQT@mail.gmail.com","subject":"[PATCH/RFC v5 2/2] Add initial C, Shell and Perl gettext translations","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-02T22:33:13Z","receivedAt":"2010-06-02T22:33:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the git status, git pull, and git send-email commands to have\nat least one translatable string. Each command uses a different core\nlanguage, so this makes a good example of how C, Shell and Perl\nprograms can be translated using gettext.\n\nSince this introduces translation into the real Git tools more tests\ncan be added to check if they translations actually work for real core\ntools.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-pull.sh            |   16 ++++---\n git-send-email.perl    |    3 +-\n po/is.po               |   27 +++++++++++-\n t/t0200-gettext.sh     |   42 +++++++++++++++++++\n t/t0200-gettext/test.c |    1 -\n wt-status.c            |  107 ++++++++++++++++++++++++------------------------\n 6 files changed, 132 insertions(+), 64 deletions(-)\n\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 1a4729f..0d95722 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -9,6 +9,7 @@ LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEA\n SUBDIRECTORY_OK=Yes\n OPTIONS_SPEC=\n . git-sh-setup\n+. git-sh-i18n\n set_reflog_action \"pull $*\"\n require_work_tree\n cd_to_toplevel\n@@ -121,8 +122,8 @@ error_on_no_merge_candidates () {\n \tdo\n \t\tcase \"$opt\" in\n \t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"Fetching tags only, you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n+\t\t\tgettext \"Fetching tags only, you probably meant:\"; echo\n+\t\t\tgettext \"  git fetch --tags\"; echo\n \t\t\texit 1\n \t\tesac\n \tdone\n@@ -154,11 +155,12 @@ error_on_no_merge_candidates () {\n \t\techo \"a branch. Because this is not the default configured remote\"\n \t\techo \"for your current branch, you must specify a branch on the command line.\"\n \telif [ -z \"$curr_branch\" ]; then\n-\t\techo \"You are not currently on a branch, so I cannot use any\"\n-\t\techo \"'branch.<branchname>.merge' in your configuration file.\"\n-\t\techo \"Please specify which remote branch you want to use on the command\"\n-\t\techo \"line and try again (e.g. 'git pull <repository> <refspec>').\"\n-\t\techo \"See git-pull(1) for details.\"\n+\t\tgettext \"You are not currently on a branch, so I cannot use any\n+'branch.<branchname>.merge' in your configuration file.\n+Please specify which remote branch you want to use on the command\n+line and try again (e.g. 'git pull <repository> <refspec>').\n+See git-pull(1) for details.\";\n+\t\techo\n \telif [ -z \"$upstream\" ]; then\n \t\techo \"You asked me to pull without telling me which branch you\"\n \t\techo \"want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in\"\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 111c981..4977fdf 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -26,6 +26,7 @@ use Term::ANSIColor;\n use File::Temp qw/ tempdir tempfile /;\n use Error qw(:try);\n use Git;\n+use Git::I18N;\n \n Getopt::Long::Configure qw/ pass_through /;\n \n@@ -674,7 +675,7 @@ if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n \t$sender = ask(\"Who should the emails appear to be from? [$sender] \",\n \t              default => $sender);\n-\tprint \"Emails will be sent from: \", $sender, \"\\n\";\n+\tprintf __(\"Emails will be sent from: %s\\n\"), $sender;\n \t$prompting++;\n }\n \ndiff --git a/po/is.po b/po/is.po\nindex ac4317b..72437c3 100644\n--- a/po/is.po\n+++ b/po/is.po\n@@ -2,8 +2,8 @@ msgid \"\"\n msgstr \"\"\n \"Project-Id-Version: Git\\n\"\n \"Report-Msgid-Bugs-To: \\n\"\n-\"POT-Creation-Date: 2010-06-02 17:35+0000\\n\"\n-\"PO-Revision-Date: 2010-06-02 16:01+0000\\n\"\n+\"POT-Creation-Date: 2010-06-02 19:43+0000\\n\"\n+\"PO-Revision-Date: 2010-06-02 19:35+0000\\n\"\n \"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\\n\"\n \"Language-Team: Git Mailing List <git@vger.kernel.org>\\n\"\n \"MIME-Version: 1.0\\n\"\n@@ -12,6 +12,20 @@ msgstr \"\"\n \"X-Poedit-Language: English\\n\"\n \"X-Poedit-SourceCharset: utf-8\\n\"\n \n+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110\n+#: wt-status.c:622\n+msgid \"On branch \"\n+msgstr \"Á greininni \"\n+\n+#: wt-status.c:629\n+msgid \"Not currently on any branch.\"\n+msgstr \"Ekki á neinni grein.\"\n+\n+#: wt-status.c:663\n+#, c-format\n+msgid \"# No changes\\n\"\n+msgstr \"# Engar breytingar\\n\"\n+\n #. TRANSLATORS: This is a test. You don't need to translate it.\n #: t/t0200-gettext/test.c:6\n msgid \"TEST: A C test string\"\n@@ -23,6 +37,10 @@ msgstr \"TILRAUN: C tilraunastrengur\"\n msgid \"TEST: A C test string %s\"\n msgstr \"TILRAUN: C tilraunastrengur %s\"\n \n+#: git-pull.sh:124\n+msgid \"Fetching tags only, you probably meant:\"\n+msgstr \"Næ aðeins í tögg, þú áttir líkast til við:\"\n+\n #. TRANSLATORS: This is a test. You don't need to translate it.\n #: t/t0200-gettext/test.sh:8\n msgid \"TEST: A Shell test string\"\n@@ -34,6 +52,11 @@ msgstr \"TILRAUN: Skeljartilraunastrengur\"\n msgid \"TEST: A Shell test $variable\"\n msgstr \"TILRAUN: Skeljartilraunastrengur með breytunni $variable\"\n \n+#: git-send-email.perl:678\n+#, perl-format\n+msgid \"Emails will be sent from: %s\\n\"\n+msgstr \"Póstarnir verða sendir frá: %s\\n\"\n+\n #. This is a phony Perl program that's only here to test xgettext\n #. message extraction\n #. TRANSLATORS: This is a test. You don't need to translate it.\ndiff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh\nindex 7b01ce4..95f05ec 100755\n--- a/t/t0200-gettext.sh\n+++ b/t/t0200-gettext.sh\n@@ -101,4 +101,46 @@ test_expect_success 'xgettext: Comment extraction with --add-comments' '\n     test_cmp expect actual\n '\n \n+# Actually execute some C, Perl and Shell code that uses Gettext\n+test_expect_success 'C: git-status reads our message catalog ' '\n+    > foo &&\n+    test_commit \"some-file\" &&\n+    git checkout -b topic/gettext-testing &&\n+    LANGUAGE=C LC_ALL=C git status | grep topic/gettext-testing > expect &&\n+    echo \"# On branch topic/gettext-testing\" > actual &&\n+    test_cmp expect actual &&\n+\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 git status | grep topic/gettext-testing > expect &&\n+    echo \"# Á greininni topic/gettext-testing\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'Perl: Git::I18N reads our message catalog ' '\n+    # Bail out if the system doesn not have Locale::Messages\n+    perl -MLocale::Messages -e1 2>/dev/null || return 0\n+\n+    echo \"On branch \" > expect &&\n+    LANGUAGE=C LC_ALL=C perl -I\"$D/../perl\" -MGit::I18N -le \"print __(q[On branch ])\" > actual &&\n+    test_cmp expect actual &&\n+\n+    echo \"Á greininni \" > expect &&\n+    LANGUAGE=is LC_ALL=is_IS.UTF-8 perl -I\"$D/../perl\" -MGit::I18N -le \"print __(q[On branch ])\" > actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'Shell: git-pull reads our message catalog' '\n+    # Repository for testing\n+    mkdir parent &&\n+    (cd parent && git init &&\n+     echo one >file && git add file &&\n+     git commit -m one) &&\n+\n+    # Actual test\n+    (cd parent &&\n+    (LANGUAGE=C LC_ALL=C git pull --tags \"../\" >out 2>err);\n+    grep \"Fetching tags only\" err &&\n+    (LANGUAGE=is LC_ALL=is_IS.UTF-8 git pull --tags ../ >out 2>err || :) &&\n+    grep \"Næ aðeins í\" err)\n+'\n+\n test_done\ndiff --git a/t/t0200-gettext/test.c b/t/t0200-gettext/test.c\nindex 9fa4c23..171bcc6 100644\n--- a/t/t0200-gettext/test.c\n+++ b/t/t0200-gettext/test.c\n@@ -8,4 +8,3 @@ int main(void)\n \t/* TRANSLATORS: This is a test. You don't need to translate it. */\n \tprintf(_(\"TEST: A C test string %s\"), \"variable\");\n }\n-\t\ndiff --git a/wt-status.c b/wt-status.c\nindex 14e0acc..484a866 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"run-command.h\"\n #include \"remote.h\"\n+#include \"gettext.h\"\n \n static char default_wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL, /* WT_STATUS_HEADER */\n@@ -49,16 +50,16 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Unmerged paths:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t;\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" as appropriate to mark resolution)\"));\n \tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n@@ -66,15 +67,15 @@ static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changes to be committed:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (s->in_merge)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git reset %s <file>...\\\" to unstage)\"), s->reference);\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git rm --cached <file>...\\\" to unstage)\"));\n \tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n@@ -84,16 +85,16 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n \n-\tcolor_fprintf_ln(s->fp, c, \"# Changed but not updated:\");\n+\tcolor_fprintf_ln(s->fp, c, _(\"# Changed but not updated:\"));\n \tif (!advice_status_hints)\n \t\treturn;\n \tif (!has_deleted)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to update what will be committed)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add <file>...\\\" to update what will be committed)\"));\n \telse\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\");\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git add/rm <file>...\\\" to update what will be committed)\"));\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git checkout -- <file>...\\\" to discard changes in working directory)\"));\n \tif (has_dirty_submodules)\n-\t\tcolor_fprintf_ln(s->fp, c, \"#   (commit or discard the untracked or modified content in submodules)\");\n+\t\tcolor_fprintf_ln(s->fp, c, _(\"#   (commit or discard the untracked or modified content in submodules)\"));\n \tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n@@ -102,10 +103,10 @@ static void wt_status_print_other_header(struct wt_status *s,\n \t\t\t\t\t const char *how)\n {\n \tconst char *c = color(WT_STATUS_HEADER, s);\n-\tcolor_fprintf_ln(s->fp, c, \"# %s files:\", what);\n+\tcolor_fprintf_ln(s->fp, c, _(\"# %s files:\"), what);\n \tif (!advice_status_hints)\n \t\treturn;\n-\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\", how);\n+\tcolor_fprintf_ln(s->fp, c, _(\"#   (use \\\"git %s <file>...\\\" to include in what will be committed)\"), how);\n \tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,\n \tconst char *c = color(WT_STATUS_UNMERGED, s);\n \tstruct wt_status_change_data *d = it->util;\n \tstruct strbuf onebuf = STRBUF_INIT;\n-\tconst char *one, *how = \"bug\";\n+\tconst char *one, *how = _(\"bug\");\n \n \tone = quote_path(it->string, -1, &onebuf, s->prefix);\n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n \tswitch (d->stagemask) {\n-\tcase 1: how = \"both deleted:\"; break;\n-\tcase 2: how = \"added by us:\"; break;\n-\tcase 3: how = \"deleted by them:\"; break;\n-\tcase 4: how = \"added by them:\"; break;\n-\tcase 5: how = \"deleted by us:\"; break;\n-\tcase 6: how = \"both added:\"; break;\n-\tcase 7: how = \"both modified:\"; break;\n+\tcase 1: how = _(\"both deleted:\"); break;\n+\tcase 2: how = _(\"added by us:\"); break;\n+\tcase 3: how = _(\"deleted by them:\"); break;\n+\tcase 4: how = _(\"added by them:\"); break;\n+\tcase 5: how = _(\"deleted by us:\"); break;\n+\tcase 6: how = _(\"both added:\"); break;\n+\tcase 7: how = _(\"both modified:\"); break;\n \t}\n-\tcolor_fprintf(s->fp, c, \"%-20s%s\\n\", how, one);\n+\tcolor_fprintf(s->fp, c, _(\"%-20s%s\\n\"), how, one);\n \tstrbuf_release(&onebuf);\n }\n \n@@ -163,11 +164,11 @@ static void wt_status_print_change_data(struct wt_status *s,\n \t\tif (d->new_submodule_commits || d->dirty_submodule) {\n \t\t\tstrbuf_addstr(&extra, \" (\");\n \t\t\tif (d->new_submodule_commits)\n-\t\t\t\tstrbuf_addf(&extra, \"new commits, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"new commits, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n-\t\t\t\tstrbuf_addf(&extra, \"modified content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"modified content, \"));\n \t\t\tif (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n-\t\t\t\tstrbuf_addf(&extra, \"untracked content, \");\n+\t\t\t\tstrbuf_addf(&extra, _(\"untracked content, \"));\n \t\t\tstrbuf_setlen(&extra, extra.len - 2);\n \t\t\tstrbuf_addch(&extra, ')');\n \t\t}\n@@ -178,34 +179,34 @@ static void wt_status_print_change_data(struct wt_status *s,\n \tone = quote_path(one_name, -1, &onebuf, s->prefix);\n \ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), _(\"#\\t\"));\n \tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"new file:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"copied:     %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"deleted:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"modified:   %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, _(\"renamed:    %s -> %s\"), one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"typechange: %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unknown:    %s\"), one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, _(\"unmerged:   %s\"), one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", status);\n+\t\tdie(_(\"bug: unhandled diff status %c\"), status);\n \t}\n \tif (extra.len) {\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"%s\", extra.buf);\n@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)\n \tconst char *branch_color = color(WT_STATUS_HEADER, s);\n \n \tif (s->branch) {\n-\t\tconst char *on_what = \"On branch \";\n+\t\tconst char *on_what = _(\"On branch \");\n \t\tconst char *branch_name = s->branch;\n \t\tif (!prefixcmp(branch_name, \"refs/heads/\"))\n \t\t\tbranch_name += 11;\n \t\telse if (!strcmp(branch_name, \"HEAD\")) {\n \t\t\tbranch_name = \"\";\n \t\t\tbranch_color = color(WT_STATUS_NOBRANCH, s);\n-\t\t\ton_what = \"Not currently on any branch.\";\n+\t\t\ton_what = _(\"Not currently on any branch.\");\n \t\t}\n \t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"# \");\n \t\tcolor_fprintf_ln(s->fp, branch_color, \"%s%s\", on_what, branch_name);\n@@ -635,7 +636,7 @@ void wt_status_print(struct wt_status *s)\n \n \tif (s->is_initial) {\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"# Initial commit\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _(\"# Initial commit\"));\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), \"#\");\n \t}\n \n@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_submodule_summary(s, 1);  /* unstaged */\n \t}\n \tif (s->show_untracked_files) {\n-\t\twt_status_print_other(s, &s->untracked, \"Untracked\", \"add\");\n+\t\twt_status_print_other(s, &s->untracked, _(\"Untracked\"), _(\"add\"));\n \t\tif (s->show_ignored_files)\n-\t\t\twt_status_print_other(s, &s->ignored, \"Ignored\", \"add -f\");\n+\t\t\twt_status_print_other(s, &s->ignored, _(\"Ignored\"), _(\"add -f\"));\n \t} else if (s->commitable)\n-\t\tfprintf(s->fp, \"# Untracked files not listed%s\\n\",\n+\t\tfprintf(s->fp, _(\"# Untracked files not listed%s\\n\"),\n \t\t\tadvice_status_hints\n-\t\t\t? \" (use -u option to show untracked files)\" : \"\");\n+\t\t\t? _(\" (use -u option to show untracked files)\") : \"\");\n \n \tif (s->verbose)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tfprintf(s->fp, \"# No changes\\n\");\n+\t\t\tfprintf(s->fp, _(\"# No changes\\n\"));\n \t\telse if (s->nowarn)\n \t\t\t; /* nothing */\n \t\telse if (s->workdir_dirty)\n-\t\t\tprintf(\"no changes added to commit%s\\n\",\n+\t\t\tprintf(_(\"no changes added to commit%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" and/or \\\"git commit -a\\\")\") : \"\");\n \t\telse if (s->untracked.nr)\n-\t\t\tprintf(\"nothing added to commit but untracked files present%s\\n\",\n+\t\t\tprintf(_(\"nothing added to commit but untracked files present%s\\n\"),\n \t\t\t\tadvice_status_hints\n-\t\t\t\t? \" (use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (s->is_initial)\n \t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (create/copy files and use \\\"git add\\\" to track)\" : \"\");\n+\t\t\t\t? _(\" (create/copy files and use \\\"git add\\\" to track)\") : \"\");\n \t\telse if (!s->show_untracked_files)\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (use -u to show untracked files)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (use -u to show untracked files)\") : \"\");\n \t\telse\n-\t\t\tprintf(\"nothing to commit%s\\n\", advice_status_hints\n-\t\t\t\t? \" (working directory clean)\" : \"\");\n+\t\t\tprintf(_(\"nothing to commit%s\\n\"), advice_status_hints\n+\t\t\t\t? _(\" (working directory clean)\") : \"\");\n \t}\n }\n \n-- \n1.7.1.242.g290e3.dirty\n"}]}