{"thread":{"id":"29091","subject":"request for re-review of i18n-enable patch","startedAt":"2011-12-06T04:54:18Z","lastAt":"2011-12-06T04:54:18Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"180337","messageId":"7vd3c2i9l1.fsf@alter.siamese.dyndns.org","threadId":"29091","inReplyTo":null,"subject":"request for re-review of i18n-enable patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-12-06T04:54:18Z","receivedAt":"2011-12-06T04:54:18Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I am resending this (after squashing a mini-fix from Ramsay) to solicit\nanother round of review, hoping that people can catch any potential glitch\nbefore we merge this to 'next'.\n\nThanks.\n\n-- >8 --\nFrom: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSubject: [PATCH] i18n: add infrastructure for translating Git with gettext\n\nChange the skeleton implementation of i18n in Git to one that can show\nlocalized strings to users for our C, Shell and Perl programs using\neither GNU libintl or the Solaris gettext implementation.\n\nThis new internationalization support is enabled by default. If\ngettext isn't available, or if Git is compiled with\nNO_GETTEXT=YesPlease, Git falls back on its current behavior of\nshowing interface messages in English. When using the autoconf script\nwe'll auto-detect if the gettext libraries are installed and act\nappropriately.\n\nThis change is somewhat large because as well as adding a C, Shell and\nPerl i18n interface we're adding a lot of tests for them, and for\nthose tests to work we need a skeleton PO file to actually test\ntranslations. A minimal Icelandic translation is included for this\npurpose. Icelandic includes multi-byte characters which makes it easy\nto test various edge cases, and it's a language I happen to\nunderstand.\n\nThe rest of the commit message goes into detail about various\nsub-parts of this commit.\n\n= Installation\n\nGettext .mo files will be installed and looked for in the standard\n$(prefix)/share/locale path. GIT_TEXTDOMAINDIR can also be set to\noverride that, but that's only intended to be used to test Git itself.\n\n= Perl\n\nPerl code that's to be localized should use the new Git::I18n\nmodule. It imports a __ function into the caller's package by default.\n\nInstead of using the high level Locale::TextDomain interface I've\nopted to use the low-level (equivalent to the C interface)\nLocale::Messages module, which Locale::TextDomain itself uses.\n\nLocale::TextDomain does a lot of redundant work we don't need, and\nsome of it would potentially introduce bugs. It tries to set the\n$TEXTDOMAIN based on package of the caller, and has its own\nhardcoded paths where it'll search for messages.\n\nI found it easier just to completely avoid it rather than try to\ncircumvent its behavior. In any case, this is an issue wholly\ninternal Git::I18N. Its guts can be changed later if that's deemed\nnecessary.\n\nSee <AANLkTilYD_NyIZMyj9dHtVk-ylVBfvyxpCC7982LWnVd@mail.gmail.com> for\na further elaboration on this topic.\n\n= Shell\n\nShell code that's to be localized should use the git-sh-i18n\nlibrary. It's basically just a wrapper for the system's gettext.sh.\n\nIf gettext.sh isn't available we'll fall back on gettext(1) if it's\navailable. The latter is available without the former on Solaris,\nwhich has its own non-GNU gettext implementation. We also need to\nemulate eval_gettext() there.\n\nIf neither are present we'll use a dumb printf(1) fall-through\nwrapper.\n\n= About libcharset.h and langinfo.h\n\nWe use libcharset to query the character set of the current locale if\nit's available. I.e. we'll use it instead of nl_langinfo if\nHAVE_LIBCHARSET_H is set.\n\nThe GNU gettext manual recommends using langinfo.h's\nnl_langinfo(CODESET) to acquire the current character set, but on\nsystems that have libcharset.h's locale_charset() using the latter is\neither saner, or the only option on those systems.\n\nGNU and Solaris have a nl_langinfo(CODESET), FreeBSD can use either,\nbut MinGW and some others need to use libcharset.h's locale_charset()\ninstead.\n\n=Credits\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, including Jonathan Nieder, Jakub Narebski, Johannes\nSixt, Erik Faye-Lund, Peter Krefting, Junio C Hamano, Thomas Rast and\nothers.\n\n[jc: squashed a small Makefile fix from Ramsay]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/CodingGuidelines      |    7 +\n INSTALL                             |   12 ++\n Makefile                            |   81 ++++++++++++-\n config.mak.in                       |    3 +\n configure.ac                        |   19 +++\n daemon.c                            |    2 +\n fast-import.c                       |    2 +\n gettext.c                           |  117 ++++++++++++++++++\n gettext.h                           |   25 ++++-\n git-sh-i18n.sh                      |  100 +++++++++++-----\n git.c                               |    2 +\n http-backend.c                      |    2 +\n http-fetch.c                        |    2 +\n http-push.c                         |    2 +\n imap-send.c                         |    2 +\n perl/Git/I18N.pm                    |   89 ++++++++++++++\n perl/Makefile                       |    3 +-\n perl/Makefile.PL                    |   14 ++-\n po/.gitignore                       |    1 +\n po/README                           |  229 +++++++++++++++++++++++++++++++++++\n po/is.po                            |   93 ++++++++++++++\n shell.c                             |    2 +\n show-index.c                        |    2 +\n t/lib-gettext.sh                    |   55 +++++++++\n t/t0200-gettext-basic.sh            |  108 ++++++++++++++++\n t/t0200/test.c                      |   23 ++++\n t/t0200/test.perl                   |   14 ++\n t/t0200/test.sh                     |   14 ++\n t/t0201-gettext-fallbacks.sh        |   20 +++-\n t/t0202-gettext-perl.sh             |   27 ++++\n t/t0202/test.pl                     |  110 +++++++++++++++++\n t/t0203-gettext-setlocale-sanity.sh |   26 ++++\n t/t0204-gettext-reencode-sanity.sh  |   78 ++++++++++++\n t/t0205-gettext-poison.sh           |   36 ++++++\n t/test-lib.sh                       |    3 +\n upload-pack.c                       |    2 +\n wrap-for-bin.sh                     |    3 +-\n 37 files changed, 1291 insertions(+), 39 deletions(-)\n create mode 100644 perl/Git/I18N.pm\n create mode 100644 po/README\n create mode 100644 po/is.po\n create mode 100644 t/lib-gettext.sh\n create mode 100755 t/t0200-gettext-basic.sh\n create mode 100644 t/t0200/test.c\n create mode 100644 t/t0200/test.perl\n create mode 100644 t/t0200/test.sh\n create mode 100755 t/t0202-gettext-perl.sh\n create mode 100644 t/t0202/test.pl\n create mode 100755 t/t0203-gettext-setlocale-sanity.sh\n create mode 100755 t/t0204-gettext-reencode-sanity.sh\n create mode 100755 t/t0205-gettext-poison.sh\n\ndiff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines\nindex fe1c1e5..4830086 100644\n--- a/Documentation/CodingGuidelines\n+++ b/Documentation/CodingGuidelines\n@@ -81,6 +81,10 @@ For shell scripts specifically (not exhaustive):\n      are ERE elements not BRE (note that \\? and \\+ are not even part\n      of BRE -- making them accessible from BRE is a GNU extension).\n \n+ - Use Git's gettext wrappers in git-sh-i18n to make the user\n+   interface translatable. See \"Marking strings for translation\" in\n+   po/README.\n+\n For C programs:\n \n  - We use tabs to indent, and interpret tabs as taking up to\n@@ -144,6 +148,9 @@ For C programs:\n  - When we pass <string, length> pair to functions, we should try to\n    pass them in that order.\n \n+ - Use Git's gettext wrappers to make the user interface\n+   translatable. See \"Marking strings for translation\" in po/README.\n+\n Writing Documentation:\n \n  Every user-visible change should be reflected in the documentation.\ndiff --git a/INSTALL b/INSTALL\nindex bf0d97e..8120641 100644\n--- a/INSTALL\n+++ b/INSTALL\n@@ -106,6 +106,18 @@ Issues of note:\n \t  history graphically, and in git-gui.  If you don't want gitk or\n \t  git-gui, you can use NO_TCLTK.\n \n+\t- A gettext library is used by default for localizing Git. The\n+\t  primary target is GNU libintl, but the Solaris gettext\n+\t  implementation also works.\n+\n+\t  We need a gettext.h on the system for C code, gettext.sh (or\n+\t  Solaris gettext(1)) for shell scripts, and libintl-perl for Perl\n+\t  programs.\n+\n+\t  Set NO_GETTEXT to disable localization support and make Git only\n+\t  use English. Under autoconf the configure script will do this\n+\t  automatically if it can't find libintl on the system.\n+\n  - Some platform specific issues are dealt with Makefile rules,\n    but depending on your specific installation, you may not\n    have all the libraries/tools needed, or you may have\ndiff --git a/Makefile b/Makefile\nindex ee34eab..08b9297 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -43,6 +43,22 @@ all::\n # Define EXPATDIR=/foo/bar if your expat header and library files are in\n # /foo/bar/include and /foo/bar/lib directories.\n #\n+# Define NO_GETTEXT if you don't want Git output to be translated.\n+# A translated Git requires GNU libintl or another gettext implementation,\n+# plus libintl-perl at runtime.\n+#\n+# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't\n+# trust the langinfo.h's nl_langinfo(CODESET) function to return the\n+# current character set. GNU and Solaris have a nl_langinfo(CODESET),\n+# FreeBSD can use either, but MinGW and some others need to use\n+# libcharset.h's locale_charset() instead.\n+#\n+# Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't\n+# need -lintl when linking.\n+#\n+# Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt\n+# doesn't support GNU extensions like --check and --statistics\n+#\n # Define HAVE_PATHS_H if you have paths.h and want to use the default PATH\n # it specifies.\n #\n@@ -301,6 +317,7 @@ gitexecdir = libexec/git-core\n mergetoolsdir = $(gitexecdir)/mergetools\n sharedir = $(prefix)/share\n gitwebdir = $(sharedir)/gitweb\n+localedir = $(sharedir)/locale\n template_dir = share/git-core/templates\n htmldir = share/doc/git-doc\n ETC_GITCONFIG = $(sysconfdir)/gitconfig\n@@ -309,7 +326,7 @@ lib = lib\n # DESTDIR=\n pathsep = :\n \n-export prefix bindir sharedir sysconfdir gitwebdir\n+export prefix bindir sharedir sysconfdir gitwebdir localedir\n \n CC = gcc\n AR = ar\n@@ -322,6 +339,7 @@ RPMBUILD = rpmbuild\n TCL_PATH = tclsh\n TCLTK_PATH = wish\n XGETTEXT = xgettext\n+MSGFMT = msgfmt\n PTHREAD_LIBS = -lpthread\n PTHREAD_CFLAGS =\n GCOV = gcov\n@@ -621,6 +639,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@@ -817,12 +836,14 @@ ifeq ($(uname_S),Linux)\n \tNO_STRLCPY = YesPlease\n \tNO_MKSTEMPS = YesPlease\n \tHAVE_PATHS_H = YesPlease\n+\tLIBC_CONTAINS_LIBINTL = YesPlease\n endif\n ifeq ($(uname_S),GNU/kFreeBSD)\n \tNO_STRLCPY = YesPlease\n \tNO_MKSTEMPS = YesPlease\n \tHAVE_PATHS_H = YesPlease\n \tDIR_HAS_BSD_GROUP_SEMANTICS = YesPlease\n+\tLIBC_CONTAINS_LIBINTL = YesPlease\n endif\n ifeq ($(uname_S),UnixWare)\n \tCC = cc\n@@ -889,6 +910,7 @@ ifeq ($(uname_S),SunOS)\n \tNO_MKSTEMPS = YesPlease\n \tNO_REGEX = YesPlease\n \tNO_FNMATCH_CASEFOLD = YesPlease\n+\tNO_MSGFMT_EXTENDED_OPTIONS = YesPlease\n \tifeq ($(uname_R),5.6)\n \t\tSOCKLEN_T = int\n \t\tNO_HSTRERROR = YesPlease\n@@ -1012,6 +1034,7 @@ ifeq ($(uname_S),GNU)\n \tNO_STRLCPY=YesPlease\n \tNO_MKSTEMPS = YesPlease\n \tHAVE_PATHS_H = YesPlease\n+\tLIBC_CONTAINS_LIBINTL = YesPlease\n endif\n ifeq ($(uname_S),IRIX)\n \tNO_SETENV = YesPlease\n@@ -1228,6 +1251,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))\n \tEXTLIBS += /mingw/lib/libz.a\n \tNO_R_TO_GCC_LINKER = YesPlease\n \tINTERNAL_QSORT = YesPlease\n+\tHAVE_LIBCHARSET_H = YesPlease\n else\n \tNO_CURL = YesPlease\n endif\n@@ -1405,6 +1429,11 @@ endif\n ifdef NEEDS_LIBGEN\n \tEXTLIBS += -lgen\n endif\n+ifndef NO_GETTEXT\n+ifndef LIBC_CONTAINS_LIBINTL\n+\tEXTLIBS += -lintl\n+endif\n+endif\n ifdef NEEDS_SOCKET\n \tEXTLIBS += -lsocket\n endif\n@@ -1447,9 +1476,11 @@ ifdef NO_SYMLINK_HEAD\n \tBASIC_CFLAGS += -DNO_SYMLINK_HEAD\n endif\n ifdef GETTEXT_POISON\n-\tLIB_OBJS += gettext.o\n \tBASIC_CFLAGS += -DGETTEXT_POISON\n endif\n+ifdef NO_GETTEXT\n+\tBASIC_CFLAGS += -DNO_GETTEXT\n+endif\n ifdef NO_STRCASESTR\n \tCOMPAT_CFLAGS += -DNO_STRCASESTR\n \tCOMPAT_OBJS += compat/strcasestr.o\n@@ -1612,6 +1643,10 @@ ifdef HAVE_PATHS_H\n \tBASIC_CFLAGS += -DHAVE_PATHS_H\n endif\n \n+ifdef HAVE_LIBCHARSET_H\n+\tBASIC_CFLAGS += -DHAVE_LIBCHARSET_H\n+endif\n+\n ifdef DIR_HAS_BSD_GROUP_SEMANTICS\n \tCOMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS\n endif\n@@ -1632,6 +1667,10 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT\n \texport GIT_TEST_CMP_USE_COPIED_CONTEXT\n endif\n \n+ifndef NO_MSGFMT_EXTENDED_OPTIONS\n+\tMSGFMT += --check --statistics\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK=NoThanks\n endif\n@@ -1662,6 +1701,7 @@ ifndef V\n \tQUIET_GEN      = @echo '   ' GEN $@;\n \tQUIET_LNCP     = @echo '   ' LN/CP $@;\n \tQUIET_XGETTEXT = @echo '   ' XGETTEXT $@;\n+\tQUIET_MSGFMT   = @echo '   ' MSGFMT $@;\n \tQUIET_GCOV     = @echo '   ' GCOV $@;\n \tQUIET_SP       = @echo '   ' SP $<;\n \tQUIET_SUBDIR0  = +@subdir=\n@@ -1688,6 +1728,7 @@ bindir_SQ = $(subst ','\\'',$(bindir))\n bindir_relative_SQ = $(subst ','\\'',$(bindir_relative))\n mandir_SQ = $(subst ','\\'',$(mandir))\n infodir_SQ = $(subst ','\\'',$(infodir))\n+localedir_SQ = $(subst ','\\'',$(localedir))\n gitexecdir_SQ = $(subst ','\\'',$(gitexecdir))\n template_dir_SQ = $(subst ','\\'',$(template_dir))\n htmldir_SQ = $(subst ','\\'',$(htmldir))\n@@ -1743,7 +1784,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@@ -1793,6 +1834,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \\\n     -e 's|@@DIFF@@|$(DIFF_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@@ -2045,6 +2087,9 @@ config.sp config.s config.o: EXTRA_CPPFLAGS = \\\n attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \\\n \t-DETC_GITATTRIBUTES='\"$(ETC_GITATTRIBUTES_SQ)\"'\n \n+gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \\\n+\t-DGIT_LOCALE_PATH='\"$(localedir_SQ)\"'\n+\n http.sp http.s http.o: EXTRA_CPPFLAGS = \\\n \t-DGIT_HTTP_USER_AGENT='\"git/$(GIT_VERSION)\"'\n \n@@ -2118,17 +2163,37 @@ XGETTEXT_FLAGS = \\\n XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n \t--keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell\n+XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl\n LOCALIZED_C := $(C_OBJ:o=c)\n LOCALIZED_SH := $(SCRIPT_SH)\n+LOCALIZED_PERL := $(SCRIPT_PERL)\n+\n+ifdef XGETTEXT_INCLUDE_TESTS\n+LOCALIZED_C += t/t0200/test.c\n+LOCALIZED_SH += t/t0200/test.sh\n+LOCALIZED_PERL += t/t0200/test.perl\n+endif\n \n po/git.pot: $(LOCALIZED_C)\n \t$(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C)\n \t$(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) \\\n \t\t$(LOCALIZED_SH)\n+\t$(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_PERL) \\\n+\t\t$(LOCALIZED_PERL)\n \tmv $@+ $@\n \n pot: po/git.pot\n \n+POFILES := $(wildcard po/*.po)\n+MOFILES := $(patsubst po/%.po,po/build/locale/%/LC_MESSAGES/git.mo,$(POFILES))\n+\n+ifndef NO_GETTEXT\n+all:: $(MOFILES)\n+endif\n+\n+po/build/locale/%/LC_MESSAGES/git.mo: po/%.po\n+\t$(QUIET_MSGFMT)mkdir -p $(dir $@) && $(MSGFMT) -o $@ $<\n+\n FIND_SOURCE_FILES = ( git ls-files '*.[hcS]' 2>/dev/null || \\\n \t\t\t$(FIND) . \\( -name .git -type d -prune \\) \\\n \t\t\t\t-o \\( -name '*.[hcS]' -type f -print \\) )\n@@ -2147,7 +2212,8 @@ cscope:\n \n ### Detect prefix changes\n TRACK_CFLAGS = $(CC):$(subst ','\\'',$(ALL_CFLAGS)):\\\n-             $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)\n+             $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\\\n+             $(localedir_SQ)\n \n GIT-CFLAGS: FORCE\n \t@FLAGS='$(TRACK_CFLAGS)'; \\\n@@ -2184,6 +2250,7 @@ endif\n ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT\n \t@echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@\n endif\n+\t@echo NO_GETTEXT=\\''$(subst ','\\'',$(subst ','\\'',$(NO_GETTEXT)))'\\' >>$@\n \t@echo GETTEXT_POISON=\\''$(subst ','\\'',$(subst ','\\'',$(GETTEXT_POISON)))'\\' >>$@\n \n ### Detect Tck/Tk interpreter path changes\n@@ -2299,6 +2366,11 @@ install: all\n \t$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install\n \t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'\n \t$(INSTALL) -m 644 mergetools/* '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'\n+ifndef NO_GETTEXT\n+\t$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(localedir_SQ)'\n+\t(cd po/build/locale && $(TAR) cf - .) | \\\n+\t(cd '$(DESTDIR_SQ)$(localedir_SQ)' && umask 022 && $(TAR) xof -)\n+endif\n ifndef NO_PERL\n \t$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install\n \t$(MAKE) -C gitweb install\n@@ -2435,6 +2507,7 @@ clean:\n \t$(RM) $(TEST_PROGRAMS)\n \t$(RM) -r bin-wrappers\n \t$(RM) -r $(dep_dirs)\n+\t$(RM) -r po/build/\n \t$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r autom4te.cache\n \t$(RM) config.log config.mak.autogen config.mak.append config.status config.cache\ndiff --git a/config.mak.in b/config.mak.in\nindex ab37101..10698c8 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -35,6 +35,9 @@ NO_CURL=@NO_CURL@\n NO_EXPAT=@NO_EXPAT@\n NO_LIBGEN_H=@NO_LIBGEN_H@\n HAVE_PATHS_H=@HAVE_PATHS_H@\n+HAVE_LIBCHARSET_H=@HAVE_LIBCHARSET_H@\n+NO_GETTEXT=@NO_GETTEXT@\n+LIBC_CONTAINS_LIBINTL=@LIBC_CONTAINS_LIBINTL@\n NEEDS_LIBICONV=@NEEDS_LIBICONV@\n NEEDS_SOCKET=@NEEDS_SOCKET@\n NEEDS_RESOLV=@NEEDS_RESOLV@\ndiff --git a/configure.ac b/configure.ac\nindex 048a1d4..630dbdd 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -636,6 +636,12 @@ AC_CHECK_LIB([c], [basename],\n AC_SUBST(NEEDS_LIBGEN)\n test -n \"$NEEDS_LIBGEN\" && LIBS=\"$LIBS -lgen\"\n \n+AC_CHECK_LIB([c], [gettext],\n+[LIBC_CONTAINS_LIBINTL=YesPlease],\n+[LIBC_CONTAINS_LIBINTL=])\n+AC_SUBST(LIBC_CONTAINS_LIBINTL)\n+test -n \"$LIBC_CONTAINS_LIBINTL\" || LIBS=\"$LIBS -lintl\"\n+\n ## Checks for header files.\n AC_MSG_NOTICE([CHECKS for header files])\n #\n@@ -818,6 +824,19 @@ AC_CHECK_HEADER([paths.h],\n [HAVE_PATHS_H=])\n AC_SUBST(HAVE_PATHS_H)\n #\n+# Define NO_GETTEXT if you don't want Git output to be translated.\n+# A translated Git requires GNU libintl or another gettext implementation\n+AC_CHECK_HEADER([libintl.h],\n+[NO_GETTEXT=],\n+[NO_GETTEXT=YesPlease])\n+AC_SUBST(NO_GETTEXT)\n+#\n+# Define HAVE_LIBCHARSET_H if have libcharset.h\n+AC_CHECK_HEADER([libcharset.h],\n+[HAVE_LIBCHARSET_H=YesPlease],\n+[HAVE_LIBCHARSET_H=])\n+AC_SUBST(HAVE_LIBCHARSET_H)\n+#\n # Define NO_STRCASESTR if you don't have strcasestr.\n GIT_CHECK_FUNC(strcasestr,\n [NO_STRCASESTR=],\ndiff --git a/daemon.c b/daemon.c\nindex fa28300..15ce918 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1099,6 +1099,8 @@ int main(int argc, char **argv)\n \tstruct credentials *cred = NULL;\n \tint i;\n \n+\tgit_setup_gettext();\n+\n \tgit_extract_argv0_path(argv[0]);\n \n \tfor (i = 1; i < argc; i++) {\ndiff --git a/fast-import.c b/fast-import.c\nindex 8d8ea3c..b59e7db 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -3292,6 +3292,8 @@ int main(int argc, const char **argv)\n \n \tgit_extract_argv0_path(argv[0]);\n \n+\tgit_setup_gettext();\n+\n \tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n \t\tusage(fast_import_usage);\n \ndiff --git a/gettext.c b/gettext.c\nindex ae5394a..f75bca7 100644\n--- a/gettext.c\n+++ b/gettext.c\n@@ -5,6 +5,18 @@\n #include \"git-compat-util.h\"\n #include \"gettext.h\"\n \n+#ifndef NO_GETTEXT\n+#\tinclude <locale.h>\n+#\tinclude <libintl.h>\n+#\tifdef HAVE_LIBCHARSET_H\n+#\t\tinclude <libcharset.h>\n+#\telse\n+#\t\tinclude <langinfo.h>\n+#\t\tdefine locale_charset() nl_langinfo(CODESET)\n+#\tendif\n+#endif\n+\n+#ifdef GETTEXT_POISON\n int use_gettext_poison(void)\n {\n \tstatic int poison_requested = -1;\n@@ -12,3 +24,108 @@ int use_gettext_poison(void)\n \t\tpoison_requested = getenv(\"GIT_GETTEXT_POISON\") ? 1 : 0;\n \treturn poison_requested;\n }\n+#endif\n+\n+#ifndef NO_GETTEXT\n+static void init_gettext_charset(const char *domain)\n+{\n+\tconst char *charset;\n+\n+\t/*\n+\t   This trick arranges for messages to be emitted in the user's\n+\t   requested encoding, but avoids setting LC_CTYPE from the\n+\t   environment for the whole program.\n+\n+\t   This primarily done to avoid a bug in vsnprintf in the GNU C\n+\t   Library [1]. which triggered a \"your vsnprintf is broken\" error\n+\t   on Git's own repository when inspecting v0.99.6~1 under a UTF-8\n+\t   locale.\n+\n+\t   That commit contains a ISO-8859-1 encoded author name, which\n+\t   the locale aware vsnprintf(3) won't interpolate in the format\n+\t   argument, due to mismatch between the data encoding and the\n+\t   locale.\n+\n+\t   Even if it wasn't for that bug we wouldn't want to use LC_CTYPE at\n+\t   this point, because it'd require auditing all the code that uses C\n+\t   functions whose semantics are modified by LC_CTYPE.\n+\n+\t   But only setting LC_MESSAGES as we do creates a problem, since\n+\t   we declare the encoding of our PO files[2] the gettext\n+\t   implementation will try to recode it to the user's locale, but\n+\t   without LC_CTYPE it'll emit something like this on 'git init'\n+\t   under the Icelandic locale:\n+\n+\t       Bj? til t?ma Git lind ? /hlagh/.git/\n+\n+\t   Gettext knows about the encoding of our PO file, but we haven't\n+\t   told it about the user's encoding, so all the non-US-ASCII\n+\t   characters get encoded to question marks.\n+\n+\t   But we're in luck! We can set LC_CTYPE from the environment\n+\t   only while we call nl_langinfo and\n+\t   bind_textdomain_codeset. That suffices to tell gettext what\n+\t   encoding it should emit in, so it'll now say:\n+\n+\t       Bjó til tóma Git lind í /hlagh/.git/\n+\n+\t   And the equivalent ISO-8859-1 string will be emitted under a\n+\t   ISO-8859-1 locale.\n+\n+\t   With this change way we get the advantages of setting LC_CTYPE\n+\t   (talk to the user in his language/encoding), without the major\n+\t   drawbacks (changed semantics for C functions we rely on).\n+\n+\t   However foreign functions using other message catalogs that\n+\t   aren't using our neat trick will still have a problem, e.g. if\n+\t   we have to call perror(3):\n+\n+\t   #include <stdio.h>\n+\t   #include <locale.h>\n+\t   #include <errno.h>\n+\n+\t   int main(void)\n+\t   {\n+\t\t   setlocale(LC_MESSAGES, \"\");\n+\t\t   setlocale(LC_CTYPE, \"C\");\n+\t\t   errno = ENODEV;\n+\t\t   perror(\"test\");\n+\t\t   return 0;\n+\t   }\n+\n+\t   Running that will give you a message with question marks:\n+\n+\t   $ LANGUAGE= LANG=de_DE.utf8 ./test\n+\t   test: Kein passendes Ger?t gefunden\n+\n+\t   In the long term we should probably see about getting that\n+\t   vsnprintf bug in glibc fixed, and audit our code so it won't\n+\t   fall apart under a non-C locale.\n+\n+\t   Then we could simply set LC_CTYPE from the environment, which would\n+\t   make things like the external perror(3) messages work.\n+\n+\t   See t/t0203-gettext-setlocale-sanity.sh's \"gettext.c\" tests for\n+\t   regression tests.\n+\n+\t   1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530\n+\t   2. E.g. \"Content-Type: text/plain; charset=UTF-8\\n\" in po/is.po\n+\t*/\n+\tsetlocale(LC_CTYPE, \"\");\n+\tcharset = locale_charset();\n+\tbind_textdomain_codeset(domain, charset);\n+\tsetlocale(LC_CTYPE, \"C\");\n+}\n+\n+void git_setup_gettext(void)\n+{\n+\tconst char *podir = getenv(\"GIT_TEXTDOMAINDIR\");\n+\n+\tif (!podir)\n+\t\tpodir = GIT_LOCALE_PATH;\n+\tbindtextdomain(\"git\", podir);\n+\tsetlocale(LC_MESSAGES, \"\");\n+\tinit_gettext_charset(\"git\");\n+\ttextdomain(\"git\");\n+}\n+#endif\ndiff --git a/gettext.h b/gettext.h\nindex 24d9182..57ba8bb 100644\n--- a/gettext.h\n+++ b/gettext.h\n@@ -13,8 +13,29 @@\n #error \"namespace conflict: '_' or 'Q_' is pre-defined?\"\n #endif\n \n+#ifndef NO_GETTEXT\n+#\tinclude <libintl.h>\n+#else\n+#\tifdef gettext\n+#\t\tundef gettext\n+#\tendif\n+#\tdefine gettext(s) (s)\n+#\tifdef ngettext\n+#\t\tundef ngettext\n+#\tendif\n+#\tdefine ngettext(s, p, n) ((n == 1) ? (s) : (p))\n+#endif\n+\n #define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))\n \n+#ifndef NO_GETTEXT\n+extern void git_setup_gettext(void);\n+#else\n+static inline void git_setup_gettext(void)\n+{\n+}\n+#endif\n+\n #ifdef GETTEXT_POISON\n extern int use_gettext_poison(void);\n #else\n@@ -23,7 +44,7 @@ extern int use_gettext_poison(void);\n \n static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)\n {\n-\treturn use_gettext_poison() ? \"# GETTEXT POISON #\" : msgid;\n+\treturn use_gettext_poison() ? \"# GETTEXT POISON #\" : gettext(msgid);\n }\n \n static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)\n@@ -31,7 +52,7 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n)\n {\n \tif (use_gettext_poison())\n \t\treturn \"# GETTEXT POISON #\";\n-\treturn n == 1 ? msgid : plu;\n+\treturn ngettext(msgid, plu, n);\n }\n \n /* Mark msgid for translation but do not translate it. */\ndiff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\nindex e672366..b4575fb 100644\n--- a/git-sh-i18n.sh\n+++ b/git-sh-i18n.sh\n@@ -2,47 +2,91 @@\n #\n # Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n #\n-# This is a skeleton no-op implementation of gettext for Git. It'll be\n-# replaced by something that uses gettext.sh in a future patch series.\n+# This is Git's interface to gettext.sh. See po/README for usage\n+# instructions.\n+\n+# Export the TEXTDOMAIN* data that we need for Git\n+TEXTDOMAIN=git\n+export TEXTDOMAIN\n+if test -z \"$GIT_TEXTDOMAINDIR\"\n+then\n+\tTEXTDOMAINDIR=\"@@LOCALEDIR@@\"\n+else\n+\tTEXTDOMAINDIR=\"$GIT_TEXTDOMAINDIR\"\n+fi\n+export TEXTDOMAINDIR\n \n if test -z \"$GIT_GETTEXT_POISON\"\n then\n-\tgettext () {\n-\t\tprintf \"%s\" \"$1\"\n-\t}\n+\tif test -z \"$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\" && type gettext.sh >/dev/null 2>&1\n+\tthen\n+\t\t# This is GNU libintl's gettext.sh, we don't need to do anything\n+\t\t# else than setting up the environment and loading gettext.sh\n+\t\tGIT_INTERNAL_GETTEXT_SH_SCHEME=gnu\n+\t\texport GIT_INTERNAL_GETTEXT_SH_SCHEME\n \n-\tgettextln() {\n-\t\tprintf \"%s\\n\" \"$1\"\n-\t}\n+\t\t# Try to use libintl's gettext.sh, or fall back to English if we\n+\t\t# can't.\n+\t\t. gettext.sh\n \n-\teval_gettext () {\n-\t\tprintf \"%s\" \"$1\" | (\n-\t\t\texport PATH $(git sh-i18n--envsubst --variables \"$1\");\n-\t\t\tgit sh-i18n--envsubst \"$1\"\n-\t\t)\n-\t}\n+\telif test -z \"$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\" && test \"$(gettext -h 2>&1)\" = \"-h\"\n+\tthen\n+\t\t# We don't have gettext.sh, but there's a gettext binary in our\n+\t\t# path. This is probably Solaris or something like it which has a\n+\t\t# gettext implementation that isn't GNU libintl.\n+\t\tGIT_INTERNAL_GETTEXT_SH_SCHEME=solaris\n+\t\texport GIT_INTERNAL_GETTEXT_SH_SCHEME\n \n-\teval_gettextln () {\n-\t\tprintf \"%s\\n\" \"$1\" | (\n-\t\t\texport PATH $(git sh-i18n--envsubst --variables \"$1\");\n-\t\t\tgit sh-i18n--envsubst \"$1\"\n-\t\t)\n-\t}\n+\t\t# Solaris has a gettext(1) but no eval_gettext(1)\n+\t\teval_gettext () {\n+\t\t\tgettext \"$1\" | (\n+\t\t\t\texport PATH $(git sh-i18n--envsubst --variables \"$1\");\n+\t\t\t\tgit sh-i18n--envsubst \"$1\"\n+\t\t\t)\n+\t\t}\n+\n+\telse\n+\t\t# Since gettext.sh isn't available we'll have to define our own\n+\t\t# dummy pass-through functions.\n+\n+\t\t# Tell our tests that we don't have the real gettext.sh\n+\t\tGIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n+\t\texport GIT_INTERNAL_GETTEXT_SH_SCHEME\n+\n+\t\tgettext () {\n+\t\t\tprintf \"%s\" \"$1\"\n+\t\t}\n+\n+\t\teval_gettext () {\n+\t\t\tprintf \"%s\" \"$1\" | (\n+\t\t\t\texport PATH $(git sh-i18n--envsubst --variables \"$1\");\n+\t\t\t\tgit sh-i18n--envsubst \"$1\"\n+\t\t\t)\n+\t\t}\n+\tfi\n else\n+\t# Emit garbage under GETTEXT_POISON=YesPlease. Unlike the C tests\n+\t# this relies on an environment variable\n+\n+\tGIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n+\texport GIT_INTERNAL_GETTEXT_SH_SCHEME\n+\n \tgettext () {\n \t\tprintf \"%s\" \"# GETTEXT POISON #\"\n \t}\n \n-\tgettextln () {\n-\t\tprintf \"%s\\n\" \"# GETTEXT POISON #\"\n-\t}\n-\n \teval_gettext () {\n \t\tprintf \"%s\" \"# GETTEXT POISON #\"\n \t}\n-\n-\teval_gettextln () {\n-\t\tprintf \"%s\\n\" \"# GETTEXT POISON #\"\n-\t}\n fi\n \n+# Git-specific wrapper functions\n+gettextln () {\n+\tgettext \"$1\"\n+\techo\n+}\n+\n+eval_gettextln () {\n+\teval_gettext \"$1\"\n+\techo\n+}\ndiff --git a/git.c b/git.c\nindex 8e34903..fa918b5 100644\n--- a/git.c\n+++ b/git.c\n@@ -537,6 +537,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/http-backend.c b/http-backend.c\nindex 59ad7da..869d515 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -545,6 +545,8 @@ int main(int argc, char **argv)\n \tchar *cmd_arg = NULL;\n \tint i;\n \n+\tgit_setup_gettext();\n+\n \tgit_extract_argv0_path(argv[0]);\n \tset_die_routine(die_webcgi);\n \ndiff --git a/http-fetch.c b/http-fetch.c\nindex 69299b7..9719d58 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -22,6 +22,8 @@ int main(int argc, const char **argv)\n \tint get_verbosely = 0;\n \tint get_recover = 0;\n \n+\tgit_setup_gettext();\n+\n \tgit_extract_argv0_path(argv[0]);\n \n \twhile (arg < argc && argv[arg][0] == '-') {\ndiff --git a/http-push.c b/http-push.c\nindex edd553b..f856299 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1748,6 +1748,8 @@ int main(int argc, char **argv)\n \tint new_refs;\n \tstruct ref *ref, *local_refs;\n \n+\tgit_setup_gettext();\n+\n \tgit_extract_argv0_path(argv[0]);\n \n \trepo = xcalloc(sizeof(*repo), 1);\ndiff --git a/imap-send.c b/imap-send.c\nindex e1ad1a4..9fba422 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -1539,6 +1539,8 @@ int main(int argc, char **argv)\n \n \tgit_extract_argv0_path(argv[0]);\n \n+\tgit_setup_gettext();\n+\n \tif (argc != 1)\n \t\tusage(imap_send_usage);\n \ndiff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\nnew file mode 100644\nindex 0000000..07597dc\n--- /dev/null\n+++ b/perl/Git/I18N.pm\n@@ -0,0 +1,89 @@\n+package Git::I18N;\n+use 5.008;\n+use strict;\n+use warnings;\n+use Exporter 'import';\n+\n+our @EXPORT = qw(__);\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+\t# Used by our test script to see if it should test fallbacks or\n+\t# not.\n+\tour $__HAS_LIBRARY = 1;\n+\n+\tlocal $@;\n+\teval {\n+\t\t__bootstrap_locale_messages();\n+\t\t*__ = \\&Locale::Messages::gettext;\n+\t\t1;\n+\t} or do {\n+\t\t# Tell test.pl that we couldn't load the gettext library.\n+\t\t$Git::I18N::__HAS_LIBRARY = 0;\n+\n+\t\t# Just a fall-through no-op\n+\t\t*__ = 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 __(\"Welcome to Git!\\n\");\n+\n+\tprintf __(\"The following error occured: %s\\n\"), $error;\n+\n+=head1 DESCRIPTION\n+\n+Git's internal Perl 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+This is a distilled interface to gettext, see C<info '(gettext)Perl'>\n+for the full interface. This module implements only a small part of\n+it.\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+=head1 COPYRIGHT\n+\n+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>\n+\n+=cut\ndiff --git a/perl/Makefile b/perl/Makefile\nindex a2ffb64..b2977cd 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)' INSTALL_BASE=''\n+\t$(PERL_PATH) $< PREFIX='$(prefix_SQ)' INSTALL_BASE='' --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\nindex a242a86..4caa631 100644\n--- a/po/.gitignore\n+++ b/po/.gitignore\n@@ -1 +1,2 @@\n /git.pot\n+/build\ndiff --git a/po/README b/po/README\nnew file mode 100644\nindex 0000000..10b0ad2\n--- /dev/null\n+++ b/po/README\n@@ -0,0 +1,229 @@\n+Core GIT Translations\n+=====================\n+\n+This directory holds the translations for the core of Git. This\n+document describes how to add to and maintain these translations, and\n+how to mark source strings for translation.\n+\n+\n+Generating a .pot file\n+----------------------\n+\n+The po/git.pot file contains a message catalog extracted from Git's\n+sources. You need to generate it to add new translations with\n+msginit(1), or update existing ones with msgmerge(1).\n+\n+Since the file can be automatically generated it's not checked into\n+git.git. To generate it do, at the top-level:\n+\n+    make pot\n+\n+\n+Initializing a .po file\n+-----------------------\n+\n+To add a new translation first generate git.pot (see above) and then\n+in the po/ directory do:\n+\n+    msginit --locale=XX\n+\n+Where XX is your locale, e.g. \"is\", \"de\" or \"pt_BR\".\n+\n+Then edit the automatically generated copyright info in your new XX.po\n+to be correct, e.g. for Icelandic:\n+\n+    @@ -1,6 +1,6 @@\n+    -# Icelandic translations for PACKAGE package.\n+    -# Copyright (C) 2010 THE PACKAGE'S COPYRIGHT HOLDER\n+    -# This file is distributed under the same license as the PACKAGE package.\n+    +# Icelandic translations for Git.\n+    +# Copyright (C) 2010 Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n+    +# This file is distributed under the same license as the Git package.\n+     # Ævar Arnfjörð Bjarmason <avarab@gmail.com>, 2010.\n+\n+And change references to PACKAGE VERSION in the PO Header Entry to\n+just \"Git\":\n+\n+    perl -pi -e 's/(?<=\"Project-Id-Version: )PACKAGE VERSION/Git/' XX.po\n+\n+\n+Updating a .po file\n+-------------------\n+\n+If there's an existing *.po file for your language but you need to\n+update the translation you first need to generate git.pot (see above)\n+and then in the po/ directory do:\n+\n+    msgmerge --add-location --backup=off -U XX.po git.pot\n+\n+Where XX.po is the file you want to update.\n+\n+Testing your changes\n+--------------------\n+\n+Before you submit your changes go back to the top-level and do:\n+\n+    make\n+\n+On systems with GNU gettext (i.e. not Solaris) this will compile your\n+changed PO file with `msgfmt --check`, the --check option flags many\n+common errors, e.g. missing printf format strings, or translated\n+messages that deviate from the originals in whether they begin/end\n+with a newline or not.\n+\n+\n+Marking strings for translation\n+-------------------------------\n+\n+Before strings can be translated they first have to be marked for\n+translation.\n+\n+Git uses an internationalization interface that wraps the system's\n+gettext library, so most of the advice in your gettext documentation\n+(on GNU systems `info gettext` in a terminal) applies.\n+\n+General advice:\n+\n+ - Don't mark everything for translation, only strings which will be\n+   read by humans (the porcelain interface) should be translated.\n+\n+   The output from Git's plumbing utilities will primarily be read by\n+   programs and would break scripts under non-C locales if it was\n+   translated. Plumbing strings should not be translated, since\n+   they're part of Git's API.\n+\n+ - Adjust the strings so that they're easy to translate. Most of the\n+   advice in `info '(gettext)Preparing Strings'` applies here.\n+\n+ - If something is unclear or ambiguous you can use a \"TRANSLATORS\"\n+   comment to tell the translators what to make of it. These will be\n+   extracted by xgettext(1) and put in the po/*.po files, e.g. from\n+   git-am.sh:\n+\n+       # TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]\n+       # in your translation. The program will only accept English\n+       # input at this point.\n+       gettext \"Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all \"\n+\n+   Or in C, from builtin/revert.c:\n+\n+       /* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n+       die(_(\"%s: Unable to write new index file\"), action_name(opts));\n+\n+We provide wrappers for C, Shell and Perl programs. Here's how they're\n+used:\n+\n+C:\n+\n+ - Include builtin.h at the top, it'll pull in in gettext.h, which\n+   defines the gettext interface. Consult with the list if you need to\n+   use gettext.h directly.\n+\n+ - The C interface is a subset of the normal GNU gettext\n+   interface. We currently export these functions:\n+\n+   - _()\n+\n+    Mark and translate a string. E.g.:\n+\n+        printf(_(\"HEAD is now at %s\"), hex);\n+\n+   - Q_()\n+\n+    Mark and translate a plural string. E.g.:\n+\n+        printf(Q_(\"%d commit\", \"%d commits\", number_of_commits));\n+\n+    This is just a wrapper for the ngettext() function.\n+\n+   - N_()\n+\n+    A no-op pass-through macro for marking strings inside static\n+    initializations, e.g.:\n+\n+        static const char *reset_type_names[] = {\n+            N_(\"mixed\"), N_(\"soft\"), N_(\"hard\"), N_(\"merge\"), N_(\"keep\"), NULL\n+        };\n+\n+    And then, later:\n+\n+        die(_(\"%s reset is not allowed in a bare repository\"),\n+               _(reset_type_names[reset_type]));\n+\n+    Here _() couldn't have statically determined what the translation\n+    string will be, but since it was already marked for translation\n+    with N_() the look-up in the message catalog will succeed.\n+\n+Shell:\n+\n+ - The Git gettext shell interface is just a wrapper for\n+   gettext.sh. Import it right after git-sh-setup like this:\n+\n+       . git-sh-setup\n+       . git-sh-i18n\n+\n+   And then use the gettext or eval_gettext functions:\n+\n+       # For constant interface messages:\n+       gettext \"A message for the user\"; echo\n+\n+       # To interpolate variables:\n+       details=\"oh noes\"\n+       eval_gettext \"An error occured: \\$details\"; echo\n+\n+   In addition we have wrappers for messages that end with a trailing\n+   newline. I.e. you could write the above as:\n+\n+       # For constant interface messages:\n+       gettextln \"A message for the user\"\n+\n+       # To interpolate variables:\n+       details=\"oh noes\"\n+       eval_gettextln \"An error occured: \\$details\"\n+\n+   More documentation about the interface is available in the GNU info\n+   page: `info '(gettext)sh'`. Looking at git-am.sh (the first shell\n+   command to be translated) for examples is also useful:\n+\n+       git log --reverse -p --grep=i18n git-am.sh\n+\n+Perl:\n+\n+ - The Git::I18N module provides a limited subset of the\n+   Locale::Messages functionality, e.g.:\n+\n+       use Git::I18N;\n+       print __(\"Welcome to Git!\\n\");\n+       printf __(\"The following error occured: %s\\n\"), $error;\n+\n+   Run `perldoc perl/Git/I18N.pm` for more info.\n+\n+\n+Testing marked strings\n+----------------------\n+\n+Even if you've correctly marked porcelain strings for translation\n+something in the test suite might still depend on the US English\n+version of the strings, e.g. to grep some error message or other\n+output.\n+\n+To smoke out issues like these Git can be compiled with gettext poison\n+support, at the top-level:\n+\n+    make GETTEXT_POISON=YesPlease\n+\n+That'll give you a git which emits gibberish on every call to\n+gettext. It's obviously not meant to be installed, but you should run\n+the test suite with it:\n+\n+    cd t && prove -j 9 ./t[0-9]*.sh\n+\n+If tests break with it you should inspect them manually and see if\n+what you're translating is sane, i.e. that you're not translating\n+plumbing output.\n+\n+If not you should replace calls to grep with test_i18ngrep, or\n+test_cmp calls with test_i18ncmp. If that's not enough you can skip\n+the whole test by making it depend on the C_LOCALE_OUTPUT\n+prerequisite. See existing test files with this prerequisite for\n+examples.\ndiff --git a/po/is.po b/po/is.po\nnew file mode 100644\nindex 0000000..8692a8b\n--- /dev/null\n+++ b/po/is.po\n@@ -0,0 +1,93 @@\n+# Icelandic translations for Git.\n+# Copyright (C) 2010 Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n+# This file is distributed under the same license as the Git package.\n+# Ævar Arnfjörð Bjarmason <avarab@gmail.com>, 2010.\n+#\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: Git\\n\"\n+\"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\\n\"\n+\"POT-Creation-Date: 2010-09-20 14:44+0000\\n\"\n+\"PO-Revision-Date: 2010-06-05 19:06 +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+\"Language: is\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=UTF-8\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/test.c:5\n+msgid \"See 'git help COMMAND' for more information on a specific command.\"\n+msgstr \"Sjá 'git help SKIPUN' til að sjá hjálp fyrir tiltekna skipun.\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/test.c:10\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/test.c:13\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/test.c:16\n+#, c-format\n+msgid \"TEST: Hello World!\"\n+msgstr \"TILRAUN: Halló Heimur!\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/test.c:19\n+#, c-format\n+msgid \"TEST: Old English Runes\"\n+msgstr \"TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/test.c:22\n+#, c-format\n+msgid \"TEST: ‘single’ and “double” quotes\"\n+msgstr \"TILRAUN: ‚einfaldar‘ og „tvöfaldar“ gæsalappir\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/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/test.sh:11\n+#, sh-format\n+msgid \"TEST: A Shell test $variable\"\n+msgstr \"TILRAUN: Skeljartilraunastrengur með breytunni $variable\"\n+\n+#. TRANSLATORS: This is a test. You don't need to translate it.\n+#: t/t0200/test.perl:8\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/test.perl:11\n+#, perl-format\n+msgid \"TEST: A Perl test variable %s\"\n+msgstr \"TILRAUN: Perl tilraunastrengur með breytunni %s\"\n+\n+#. TRANSLATORS: The first '%s' is either \"Reinitialized\n+#. existing\" or \"Initialized empty\", the second \" shared\" or\n+#. \"\", and the last '%s%s' is the verbatim directory name.\n+#: builtin/init-db.c:355\n+#, c-format\n+msgid \"%s%s Git repository in %s%s\\n\"\n+msgstr \"%s%s Git lind í %s%s\\n\"\n+\n+#: builtin/init-db.c:356\n+msgid \"Reinitialized existing\"\n+msgstr \"Endurgerði\"\n+\n+#: builtin/init-db.c:356\n+msgid \"Initialized empty\"\n+msgstr \"Bjó til tóma\"\n+\n+#: builtin/init-db.c:357\n+msgid \" shared\"\n+msgstr \" sameiginlega\"\ndiff --git a/shell.c b/shell.c\nindex abb8622..84b237f 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -137,6 +137,8 @@ int main(int argc, char **argv)\n \tint devnull_fd;\n \tint count;\n \n+\tgit_setup_gettext();\n+\n \tgit_extract_argv0_path(argv[0]);\n \n \t/*\ndiff --git a/show-index.c b/show-index.c\nindex 63f9da5..5a9eed7 100644\n--- a/show-index.c\n+++ b/show-index.c\n@@ -11,6 +11,8 @@ int main(int argc, char **argv)\n \tunsigned int version;\n \tstatic unsigned int top_index[256];\n \n+\tgit_setup_gettext();\n+\n \tif (argc != 1)\n \t\tusage(show_index_usage);\n \tif (fread(top_index, 2 * 4, 1, stdin) != 1)\ndiff --git a/t/lib-gettext.sh b/t/lib-gettext.sh\nnew file mode 100644\nindex 0000000..0f76f6c\n--- /dev/null\n+++ b/t/lib-gettext.sh\n@@ -0,0 +1,55 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+. ./test-lib.sh\n+\n+GIT_TEXTDOMAINDIR=\"$GIT_BUILD_DIR/po/build/locale\"\n+GIT_PO_PATH=\"$GIT_BUILD_DIR/po\"\n+export GIT_TEXTDOMAINDIR GIT_PO_PATH\n+\n+. \"$GIT_BUILD_DIR\"/git-sh-i18n\n+\n+if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON\n+then\n+\t# is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian\n+\tis_IS_locale=$(locale -a | sed -n '/^is_IS\\.[uU][tT][fF]-*8$/{\n+\t\tp\n+\t\tq\n+\t}')\n+\t# is_IS.ISO8859-1 on Solaris and FreeBSD, is_IS.iso88591 on Debian\n+\tis_IS_iso_locale=$(locale -a | sed -n '/^is_IS\\.[iI][sS][oO]8859-*1$/{\n+\t\tp\n+\t\tq\n+\t}')\n+\n+\t# Export them as an environment variable so the t0202/test.pl Perl\n+\t# test can use it too\n+\texport is_IS_locale is_IS_iso_locale\n+\n+\tif test -n \"$is_IS_locale\" &&\n+\t\ttest $GIT_INTERNAL_GETTEXT_SH_SCHEME != \"fallthrough\"\n+\tthen\n+\t\t# Some of the tests need the reference Icelandic locale\n+\t\ttest_set_prereq GETTEXT_LOCALE\n+\n+\t\t# Exporting for t0202/test.pl\n+\t\tGETTEXT_LOCALE=1\n+\t\texport GETTEXT_LOCALE\n+\t\tsay \"# lib-gettext: Found '$is_IS_locale' as an is_IS UTF-8 locale\"\n+\telse\n+\t\tsay \"# lib-gettext: No is_IS UTF-8 locale available\"\n+\tfi\n+\n+\tif test -n \"$is_IS_iso_locale\" &&\n+\t\ttest $GIT_INTERNAL_GETTEXT_SH_SCHEME != \"fallthrough\"\n+\tthen\n+\t\t# Some of the tests need the reference Icelandic locale\n+\t\ttest_set_prereq GETTEXT_ISO_LOCALE\n+\n+\t\tsay \"# lib-gettext: Found '$is_IS_iso_locale' as an is_IS ISO-8859-1 locale\"\n+\telse\n+\t\tsay \"# lib-gettext: No is_IS ISO-8859-1 locale available\"\n+\tfi\n+fi\ndiff --git a/t/t0200-gettext-basic.sh b/t/t0200-gettext-basic.sh\nnew file mode 100755\nindex 0000000..8853d8a\n--- /dev/null\n+++ b/t/t0200-gettext-basic.sh\n@@ -0,0 +1,108 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+test_description='Gettext support for Git'\n+\n+. ./lib-gettext.sh\n+\n+test_expect_success \"sanity: \\$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)\" '\n+    test -n \"$GIT_INTERNAL_GETTEXT_SH_SCHEME\"\n+'\n+\n+test_expect_success 'sanity: $TEXTDOMAIN is git' '\n+    test $TEXTDOMAIN = \"git\"\n+'\n+\n+test_expect_success 'xgettext sanity: Perl _() strings are not extracted' '\n+    ! grep \"A Perl string xgettext will not get\" \"$GIT_PO_PATH\"/is.po\n+'\n+\n+test_expect_success 'xgettext sanity: Comment extraction with --add-comments' '\n+    grep \"TRANSLATORS: This is a test\" \"$TEST_DIRECTORY\"/t0200/* | wc -l >expect &&\n+    grep \"TRANSLATORS: This is a test\" \"$GIT_PO_PATH\"/is.po  | wc -l >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success 'xgettext sanity: Comment extraction with --add-comments stops at statements' '\n+    ! grep \"This is a phony\" \"$GIT_PO_PATH\"/is.po &&\n+    ! grep \"the above comment\" \"$GIT_PO_PATH\"/is.po\n+'\n+\n+test_expect_success GETTEXT 'sanity: $TEXTDOMAINDIR exists without NO_GETTEXT=YesPlease' '\n+    test -d \"$TEXTDOMAINDIR\" &&\n+    test \"$TEXTDOMAINDIR\" = \"$GIT_TEXTDOMAINDIR\"\n+'\n+\n+test_expect_success GETTEXT 'sanity: Icelandic locale was compiled' '\n+    test -f \"$TEXTDOMAINDIR/is/LC_MESSAGES/git.mo\"\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 GETTEXT_LOCALE 'sanity: gettext(\"\") metadata is OK' '\n+    # Return value may be non-zero\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" 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 GETTEXT_LOCALE '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 GETTEXT_LOCALE 'xgettext: C extraction of _() and N_() strings' '\n+    printf \"TILRAUN: C tilraunastrengur\" >expect &&\n+    printf \"\\n\" >>expect &&\n+    printf \"Sjá '\\''git help SKIPUN'\\'' til að sjá hjálp fyrir tiltekna skipun.\" >>expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: A C test string\" >actual &&\n+    printf \"\\n\" >>actual &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"See '\\''git help COMMAND'\\'' for more information on a specific command.\" >>actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'xgettext: C extraction with %s' '\n+    printf \"TILRAUN: C tilraunastrengur %%s\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: A C test string %s\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+# xgettext from Shell\n+test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction' '\n+    printf \"TILRAUN: Skeljartilraunastrengur\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: A Shell test string\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction with $variable' '\n+    printf \"TILRAUN: Skeljartilraunastrengur með breytunni a var i able\" >x-expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" 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 GETTEXT_LOCALE 'xgettext: Perl extraction' '\n+    printf \"TILRAUN: Perl tilraunastrengur\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: A Perl test string\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'xgettext: Perl extraction with %s' '\n+    printf \"TILRAUN: Perl tilraunastrengur með breytunni %%s\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: A Perl test variable %s\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'sanity: Some gettext(\"\") data for real locale' '\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"\" >real-locale &&\n+    test -s real-locale\n+'\n+\n+test_done\ndiff --git a/t/t0200/test.c b/t/t0200/test.c\nnew file mode 100644\nindex 0000000..584d45c\n--- /dev/null\n+++ b/t/t0200/test.c\n@@ -0,0 +1,23 @@\n+/* This is a phony C program that's only here to test xgettext message extraction */\n+\n+const char help[] =\n+\t/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tN_(\"See 'git help COMMAND' for more information on a specific command.\");\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/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tprintf(_(\"TEST: Hello World!\"));\n+\n+\t/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tprintf(_(\"TEST: Old English Runes\"));\n+\n+\t/* TRANSLATORS: This is a test. You don't need to translate it. */\n+\tprintf(_(\"TEST: ‘single’ and “double” quotes\"));\n+}\ndiff --git a/t/t0200/test.perl b/t/t0200/test.perl\nnew file mode 100644\nindex 0000000..36fba34\n--- /dev/null\n+++ b/t/t0200/test.perl\n@@ -0,0 +1,14 @@\n+# This is a phony Perl 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+1;\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/test.sh b/t/t0200/test.sh\nnew file mode 100644\nindex 0000000..022d607\n--- /dev/null\n+++ b/t/t0200/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-fallbacks.sh b/t/t0201-gettext-fallbacks.sh\nindex 54d98b9..52b1c27 100755\n--- a/t/t0201-gettext-fallbacks.sh\n+++ b/t/t0201-gettext-fallbacks.sh\n@@ -5,8 +5,24 @@\n \n test_description='Gettext Shell fallbacks'\n \n-. ./test-lib.sh\n-. \"$GIT_BUILD_DIR\"/git-sh-i18n\n+GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease\n+export GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\n+\n+. ./lib-gettext.sh\n+\n+test_expect_success \"sanity: \\$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)\" '\n+    test -n \"$GIT_INTERNAL_GETTEXT_SH_SCHEME\"\n+'\n+\n+test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' '\n+    test -n \"$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS\"\n+'\n+\n+test_expect_success C_LOCALE_OUTPUT 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME\" is fallthrough' '\n+    echo fallthrough >expect &&\n+    echo $GIT_INTERNAL_GETTEXT_SH_SCHEME >actual &&\n+    test_cmp expect actual\n+'\n \n test_expect_success 'gettext: our gettext() fallback has pass-through semantics' '\n     printf \"test\" >expect &&\ndiff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh\nnew file mode 100755\nindex 0000000..428ebb0\n--- /dev/null\n+++ b/t/t0202-gettext-perl.sh\n@@ -0,0 +1,27 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+test_description='Perl gettext interface (Git::I18N)'\n+\n+. ./lib-gettext.sh\n+\n+if ! test_have_prereq PERL; then\n+\tskip_all='skipping perl interface tests, perl not available'\n+\ttest_done\n+fi\n+\n+\"$PERL_PATH\" -MTest::More -e 0 2>/dev/null || {\n+\tskip_all=\"Perl Test::More unavailable, skipping test\"\n+\ttest_done\n+}\n+\n+# The external test will outputs its own plan\n+test_external_has_tap=1\n+\n+test_external_without_stderr \\\n+    'Perl Git::I18N API' \\\n+    \"$PERL_PATH\" \"$TEST_DIRECTORY\"/t0202/test.pl\n+\n+test_done\ndiff --git a/t/t0202/test.pl b/t/t0202/test.pl\nnew file mode 100644\nindex 0000000..2c10cb4\n--- /dev/null\n+++ b/t/t0202/test.pl\n@@ -0,0 +1,110 @@\n+#!/usr/bin/perl\n+use 5.008;\n+use lib (split(/:/, $ENV{GITPERLLIB}));\n+use strict;\n+use warnings;\n+use POSIX qw(:locale_h);\n+use Test::More tests => 8;\n+use Git::I18N;\n+\n+my $has_gettext_library = $Git::I18N::__HAS_LIBRARY;\n+\n+ok(1, \"Testing Git::I18N with \" .\n+\t ($has_gettext_library\n+\t  ? (defined $Locale::Messages::VERSION\n+\t\t ? \"Locale::Messages version $Locale::Messages::VERSION\"\n+\t\t # Versions of Locale::Messages before 1.17 didn't have a\n+\t\t # $VERSION variable.\n+\t\t : \"Locale::Messages version <1.17\")\n+\t  : \"NO Perl gettext library\"));\n+ok(1, \"Git::I18N is located at $INC{'Git/I18N.pm'}\");\n+\n+{\n+\tmy $exports = @Git::I18N::EXPORT;\n+\tok($exports, \"sanity: Git::I18N has $exports export(s)\");\n+}\n+is_deeply(\\@Git::I18N::EXPORT, \\@Git::I18N::EXPORT_OK, \"sanity: Git::I18N exports everything by default\");\n+\n+# prototypes\n+{\n+\t# Add prototypes here when modifying the public interface to add\n+\t# more gettext wrapper functions.\n+\tmy %prototypes = (qw(\n+\t\t__\t$\n+\t));\n+\twhile (my ($sub, $proto) = each %prototypes) {\n+\t\tis(prototype(\\&{\"Git::I18N::$sub\"}), $proto, \"sanity: $sub has a $proto prototype\");\n+\t}\n+}\n+\n+# Test basic passthrough in the C locale\n+{\n+\tlocal $ENV{LANGUAGE} = 'C';\n+\tlocal $ENV{LC_ALL}   = 'C';\n+\tlocal $ENV{LANG}     = 'C';\n+\n+\tmy ($got, $expect) = (('TEST: A Perl test string') x 2);\n+\n+\tis(__($got), $expect, \"Passing a string through __() in the C locale works\");\n+}\n+\n+# Test a basic message on different locales\n+SKIP: {\n+\tunless ($ENV{GETTEXT_LOCALE}) {\n+\t\t# Can't reliably test __() with a non-C locales because the\n+\t\t# required locales may not be installed on the system.\n+\t\t#\n+\t\t# We test for these anyway as part of the shell\n+\t\t# tests. Skipping these here will eliminate failures on odd\n+\t\t# platforms with incomplete locale data.\n+\n+\t\tskip \"GETTEXT_LOCALE must be set by lib-gettext.sh for exhaustive Git::I18N tests\", 2;\n+\t}\n+\n+\t# The is_IS UTF-8 locale passed from lib-gettext.sh\n+\tmy $is_IS_locale = $ENV{is_IS_locale};\n+\n+\tmy $test = sub {\n+\t\tmy ($got, $expect, $msg, $locale) = @_;\n+\t\t# Maybe this system doesn't have the locale we're trying to\n+\t\t# test.\n+\t\tmy $locale_ok = setlocale(LC_ALL, $locale);\n+\t\tis(__($got), $expect, \"$msg a gettext library + <$locale> locale <$got> turns into <$expect>\");\n+\t};\n+\n+\tmy $env_C = sub {\n+\t\t$ENV{LANGUAGE} = 'C';\n+\t\t$ENV{LC_ALL}   = 'C';\n+\t};\n+\n+\tmy $env_is = sub {\n+\t\t$ENV{LANGUAGE} = 'is';\n+\t\t$ENV{LC_ALL}   = $is_IS_locale;\n+\t};\n+\n+\t# Translation's the same as the original\n+\tmy ($got, $expect) = (('TEST: A Perl test string') x 2);\n+\n+\tif ($has_gettext_library) {\n+\t\t{\n+\t\t\tlocal %ENV; $env_C->();\n+\t\t\t$test->($got, $expect, \"With\", 'C');\n+\t\t}\n+\n+\t\t{\n+\t\t\tmy ($got, $expect) = ($got, 'TILRAUN: Perl tilraunastrengur');\n+\t\t\tlocal %ENV; $env_is->();\n+\t\t\t$test->($got, $expect, \"With\", $is_IS_locale);\n+\t\t}\n+\t} else {\n+\t\t{\n+\t\t\tlocal %ENV; $env_C->();\n+\t\t\t$test->($got, $expect, \"Without\", 'C');\n+\t\t}\n+\n+\t\t{\n+\t\t\tlocal %ENV; $env_is->();\n+\t\t\t$test->($got, $expect, \"Without\", 'is');\n+\t\t}\n+\t}\n+}\ndiff --git a/t/t0203-gettext-setlocale-sanity.sh b/t/t0203-gettext-setlocale-sanity.sh\nnew file mode 100755\nindex 0000000..a212460\n--- /dev/null\n+++ b/t/t0203-gettext-setlocale-sanity.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+test_description=\"The Git C functions aren't broken by setlocale(3)\"\n+\n+. ./lib-gettext.sh\n+\n+test_expect_success 'git show a ISO-8859-1 commit under C locale' '\n+\t. \"$TEST_DIRECTORY\"/t3901-8859-1.txt &&\n+\ttest_commit \"iso-c-commit\" iso-under-c &&\n+\tgit show >out 2>err &&\n+\t! test -s err &&\n+\tgrep -q \"iso-c-commit\" out\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' '\n+\t. \"$TEST_DIRECTORY\"/t3901-8859-1.txt &&\n+\ttest_commit \"iso-utf8-commit\" iso-under-utf8 &&\n+\tLANGUAGE=is LC_ALL=\"$is_IS_locale\" git show >out 2>err &&\n+\t! test -s err &&\n+\tgrep -q \"iso-utf8-commit\" out\n+'\n+\n+test_done\ndiff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh\nnew file mode 100755\nindex 0000000..189af90\n--- /dev/null\n+++ b/t/t0204-gettext-reencode-sanity.sh\n@@ -0,0 +1,78 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+test_description=\"Gettext reencoding of our *.po/*.mo files works\"\n+\n+. ./lib-gettext.sh\n+\n+\n+test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Icelandic' '\n+    printf \"TILRAUN: Halló Heimur!\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: Hello World!\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Runes' '\n+    printf \"TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: Old English Runes\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Icelandic' '\n+    printf \"TILRAUN: Halló Heimur!\" | iconv -f UTF-8 -t ISO8859-1 >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_iso_locale\" gettext \"TEST: Hello World!\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' '\n+    LANGUAGE=is LC_ALL=\"$is_IS_iso_locale\" gettext \"TEST: Old English Runes\" >runes &&\n+\n+\tif grep \"^TEST: Old English Runes$\" runes\n+\tthen\n+\t\tsay \"Your system can not handle this complexity and returns the string as-is\"\n+\telse\n+\t\t# Both Solaris and GNU libintl will return this stream of\n+\t\t# question marks, so it is s probably portable enough\n+\t\tprintf \"TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????\" >runes-expect &&\n+\t\ttest_cmp runes-expect runes\n+\tfi\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' '\n+    printf \"TILRAUN: ‚einfaldar‘ og „tvöfaldar“ gæsalappir\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" gettext \"TEST: ‘single’ and “double” quotes\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+# How these quotes get transliterated depends on the gettext implementation:\n+#\n+#   Debian:  ,einfaldar' og ,,tvöfaldar\" [GNU libintl]\n+#   FreeBSD: `einfaldar` og \"tvöfaldar\"  [GNU libintl]\n+#   Solaris: ?einfaldar? og ?tvöfaldar?  [Solaris libintl]\n+#\n+# Just make sure the contents are transliterated, and don't use grep -q\n+# so that these differences are emitted under --verbose for curious\n+# eyes.\n+test_expect_success GETTEXT_ISO_LOCALE 'gettext: Fetching a UTF-8 msgid -> ISO-8859-1' '\n+    LANGUAGE=is LC_ALL=\"$is_IS_iso_locale\" gettext \"TEST: ‘single’ and “double” quotes\" >actual &&\n+    grep \"einfaldar\" actual &&\n+    grep \"$(echo tvöfaldar | iconv -f UTF-8 -t ISO8859-1)\" actual\n+'\n+\n+test_expect_success GETTEXT_LOCALE 'gettext.c: git init UTF-8 -> UTF-8' '\n+    printf \"Bjó til tóma Git lind\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_locale\" git init repo >actual &&\n+    test_when_finished \"rm -rf repo\" &&\n+    grep \"^$(cat expect) \" actual\n+'\n+\n+test_expect_success GETTEXT_ISO_LOCALE 'gettext.c: git init UTF-8 -> ISO-8859-1' '\n+    printf \"Bjó til tóma Git lind\" >expect &&\n+    LANGUAGE=is LC_ALL=\"$is_IS_iso_locale\" git init repo >actual &&\n+    test_when_finished \"rm -rf repo\" &&\n+    grep \"^$(cat expect | iconv -f UTF-8 -t ISO8859-1) \" actual\n+'\n+\n+test_done\ndiff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh\nnew file mode 100755\nindex 0000000..2361590\n--- /dev/null\n+++ b/t/t0205-gettext-poison.sh\n@@ -0,0 +1,36 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason\n+#\n+\n+test_description='Gettext Shell poison'\n+\n+. ./lib-gettext.sh\n+\n+test_expect_success GETTEXT_POISON \"sanity: \\$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)\" '\n+    test -n \"$GIT_INTERNAL_GETTEXT_SH_SCHEME\"\n+'\n+\n+test_expect_success GETTEXT_POISON 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME\" is poison' '\n+    test \"$GIT_INTERNAL_GETTEXT_SH_SCHEME\" = \"poison\"\n+'\n+\n+test_expect_success GETTEXT_POISON 'gettext: our gettext() fallback has poison semantics' '\n+    printf \"# GETTEXT POISON #\" >expect &&\n+    gettext \"test\" >actual &&\n+    test_cmp expect actual &&\n+    printf \"# GETTEXT POISON #\" >expect &&\n+    gettext \"test more words\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_expect_success GETTEXT_POISON 'eval_gettext: our eval_gettext() fallback has poison semantics' '\n+    printf \"# GETTEXT POISON #\" >expect &&\n+    eval_gettext \"test\" >actual &&\n+    test_cmp expect actual &&\n+    printf \"# GETTEXT POISON #\" >expect &&\n+    eval_gettext \"test more words\" >actual &&\n+    test_cmp expect actual\n+'\n+\n+test_done\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex bdd9513..9cfabe4 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -44,6 +44,7 @@ export LANG LC_ALL PAGER TERM TZ\n EDITOR=:\n unset VISUAL\n unset EMAIL\n+unset LANGUAGE\n unset $(perl -e '\n \tmy @env = keys %ENV;\n \tmy $ok = join(\"|\", qw(\n@@ -1113,12 +1114,14 @@ esac\n test -z \"$NO_PERL\" && test_set_prereq PERL\n test -z \"$NO_PYTHON\" && test_set_prereq PYTHON\n test -n \"$USE_LIBPCRE\" && test_set_prereq LIBPCRE\n+test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n \n # Can we rely on git's output in the C locale?\n if test -n \"$GETTEXT_POISON\"\n then\n \tGIT_GETTEXT_POISON=YesPlease\n \texport GIT_GETTEXT_POISON\n+\ttest_set_prereq GETTEXT_POISON\n else\n \ttest_set_prereq C_LOCALE_OUTPUT\n fi\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 470cffd..6f36f62 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -784,6 +784,8 @@ int main(int argc, char **argv)\n \tint i;\n \tint strict = 0;\n \n+\tgit_setup_gettext();\n+\n \tpacket_trace_identity(\"upload-pack\");\n \tgit_extract_argv0_path(argv[0]);\n \tread_replace_refs = 0;\ndiff --git a/wrap-for-bin.sh b/wrap-for-bin.sh\nindex 09feb1f..53a8dd0 100644\n--- a/wrap-for-bin.sh\n+++ b/wrap-for-bin.sh\n@@ -15,7 +15,8 @@ else\n \texport GIT_TEMPLATE_DIR\n fi\n GITPERLLIB='@@BUILD_DIR@@/perl/blib/lib'\n+GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'\n PATH='@@BUILD_DIR@@/bin-wrappers:'\"$PATH\"\n-export GIT_EXEC_PATH GITPERLLIB PATH\n+export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR\n \n exec \"${GIT_EXEC_PATH}/@@PROG@@\" \"$@\"\n-- \n1.7.8.145.gd94c5\n"}]}