* [PATCH/RFC v6 0/2] Add infrastructure for translating Git with gettext
@ 2010-06-03 21:10 Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 1/2] " Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 2/2] Add initial C, Shell and Perl gettext translations Ævar Arnfjörð Bjarmason
0 siblings, 2 replies; 3+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2010-06-03 21:10 UTC (permalink / raw)
To: git; +Cc: Ævar Arnfjörð Bjarmason
This is version 6 of the patch series to make Git optionally
translatable with GNU gettext.
I had some time on the train so I polished it up since v5. Changes
since then:
* Add a blurb to INSTALL about GNU libintl being a default
requirement for building Git.
* There's now a Test::More test for Git::I18N. That module now has
complete test coverage.
* git-sh-i18n.sh now has source code comments how to use it, and
pointer to the GNU gettext manual for more.
* Eliminate the use of a wrapper function in the Perl library in
favor of a symbol table alias.
* I tested the new Perl code I wrote on perl 5.6.2, it works.
* The tests now run successfully when Git isn't built with Perl
support, or when the system doesn't support the locales we're
trying to test.
* Improve the new tests by using variables defined in test-lib.sh to
find out where the git root/po dir is instead of my own
replacements.
* Make the tests easier to read by reducing redundancy and using
e.g. "test_expect_failure grep" instead of calling test_cmp on the
results of two grep invocations.
* Add new xgettext translator comment extraction tests.
* Moved t/t0200-gettext/* tests to t/t0200/*. This follows the
convention of other tests that have their own subdirs in t/.
* Add a small (one-line) copyright notice to git-sh-i18n.sh and
Git::I18N.
Here's the difference between v5 and v6 in git diff --stat -M format:
INSTALL | 8 ++
Makefile | 6 +-
git-sh-i18n.sh | 18 +++-
perl/Git/I18N.pm | 28 ++++--
po/is.po | 2 -
t/t0200-gettext.sh | 52 ++++------
t/{t0200-gettext => t0200}/test.c | 0
t/{t0200-gettext => t0200}/test.perl | 3 +
t/{t0200-gettext => t0200}/test.sh | 0
...ell-fallbacks.sh => t0201-gettext-fallbacks.sh} | 12 ++-
t/t0202-gettext-perl.sh | 20 ++++
t/t0202/test.pl | 104 ++++++++++++++++++++
12 files changed, 203 insertions(+), 50 deletions(-)
Ævar Arnfjörð Bjarmason (2):
Add infrastructure for translating Git with gettext
Add initial C, Shell and Perl gettext translations
.gitignore | 2 +
INSTALL | 8 +++
Makefile | 44 +++++++++++++-
config.mak.in | 1 +
configure.ac | 6 ++
gettext.c | 25 ++++++++
gettext.h | 13 ++++
git-pull.sh | 16 +++--
git-send-email.perl | 3 +-
git-sh-i18n.sh | 47 ++++++++++++++
git.c | 3 +
perl/Git/I18N.pm | 91 ++++++++++++++++++++++++++++
perl/Makefile | 3 +-
perl/Makefile.PL | 14 ++++-
po/.gitignore | 1 +
po/is.po | 69 +++++++++++++++++++++
t/t0200-gettext.sh | 136 ++++++++++++++++++++++++++++++++++++++++++
t/t0200/test.c | 10 +++
t/t0200/test.perl | 14 ++++
t/t0200/test.sh | 14 ++++
t/t0201-gettext-fallbacks.sh | 42 +++++++++++++
t/t0202-gettext-perl.sh | 20 ++++++
t/t0202/test.pl | 104 ++++++++++++++++++++++++++++++++
t/test-lib.sh | 1 +
wt-status.c | 107 +++++++++++++++++----------------
25 files changed, 729 insertions(+), 65 deletions(-)
create mode 100644 gettext.c
create mode 100644 gettext.h
create mode 100644 git-sh-i18n.sh
create mode 100644 perl/Git/I18N.pm
create mode 100644 po/.gitignore
create mode 100644 po/is.po
create mode 100755 t/t0200-gettext.sh
create mode 100644 t/t0200/test.c
create mode 100644 t/t0200/test.perl
create mode 100644 t/t0200/test.sh
create mode 100755 t/t0201-gettext-fallbacks.sh
create mode 100755 t/t0202-gettext-perl.sh
create mode 100644 t/t0202/test.pl
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH/RFC v6 1/2] Add infrastructure for translating Git with gettext
2010-06-03 21:10 [PATCH/RFC v6 0/2] Add infrastructure for translating Git with gettext Ævar Arnfjörð Bjarmason
@ 2010-06-03 21:10 ` Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 2/2] Add initial C, Shell and Perl gettext translations Ævar Arnfjörð Bjarmason
1 sibling, 0 replies; 3+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2010-06-03 21:10 UTC (permalink / raw)
To: git; +Cc: Ævar Arnfjörð Bjarmason
All of the interface messages in Git core are currently hardcoded in
English. Change that by optionally enabling translation of the core C,
Shell and Perl programs via GNU gettext. If you set the appropriate
LC_* variables Git will speak your language, provided that someone has
submitted a translation.
If gettext isn't available, or if Git is compiled with
NO_GETTEXT=YesPlease, then Git fall back on its previous behavior of
only speaking English.
With NO_GETTEXT=YesPlease gettext support will be #defined away for C
programs. For Shell and Perl programs we rely on the git message
catalog not being avalalable. That's a reasonable assumption since the
*.po files won't be installed on the system during make install.
The gettext wrappers that are provided in the patch are only the bare
minimum required to begin translation work. In particular I haven't
added wrappers for the gettext functions that enable plural support,
or those that provide message context (msgctxt). Those can be added
later. The intent is to start with a small subset and see what we need
later, not to start with something that's unnecessarily large right
away.
Implementation and usage notes:
* General:
Gettext .mo files will be installed and looked for in the standard
$(prefix)/share/locale path. GIT_TEXTDOMAINDIR can also be set to
override that. But this is only intended to be used to test Git
itself.
* Perl:
Perl code that wants to be localized should use the new Git::I18n
module. It imports a __ function into the caller's package by
default.
Instead of using the high level Locale::TextDomain interface I've
opted to use the low-level (equivalent to the C interface)
Locale::Messages module, which Locale::TextDomain itself uses.
Locale::TextDomain does a lot of redundant work we don't need, and
some of it would potentially introduce bugs. It tries to set the
$TEXTDOMAIN based on package of the caller, and has its own
hardcoded paths where it'll search for messages.
I found it easier just to completely avoid it rather than try to
circumvent its behavior. In any case, this is an issue wholly
internal Git::I18N. Its guts can be changed later if that's deemed
necessary.
* Shell:
Shell code that wants to be localized should use the new
git-sh-i18n library. It's just a wrapper for the system's
gettext.sh.
If gettext.sh isn't available we'll fall back on a dumb
printf(1)-powered fall-through wrapper.
I originally tried to detect if the system supported `echo -n' but
I found this to be a waste of time. My benchmarks on Linux, Solaris
and FreeBSD reveal that printf(1) is fast enough, especially since
we aren't calling gettext() from within any tight loops.
This patch is based on work by Jeff Epler <jepler@unpythonic.net> who
did the initial Makefile / C work, and a lot of comments from the Git
mailing list.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
.gitignore | 2 +
INSTALL | 8 +++
Makefile | 44 +++++++++++++-
config.mak.in | 1 +
configure.ac | 6 ++
gettext.c | 25 ++++++++
gettext.h | 13 ++++
git-sh-i18n.sh | 47 ++++++++++++++
git.c | 3 +
perl/Git/I18N.pm | 91 ++++++++++++++++++++++++++++
perl/Makefile | 3 +-
perl/Makefile.PL | 14 ++++-
po/.gitignore | 1 +
po/is.po | 46 ++++++++++++++
t/t0200-gettext.sh | 136 ++++++++++++++++++++++++++++++++++++++++++
t/t0200/test.c | 11 ++++
t/t0200/test.perl | 14 ++++
t/t0200/test.sh | 14 ++++
t/t0201-gettext-fallbacks.sh | 42 +++++++++++++
t/t0202-gettext-perl.sh | 20 ++++++
t/t0202/test.pl | 104 ++++++++++++++++++++++++++++++++
t/test-lib.sh | 1 +
22 files changed, 642 insertions(+), 4 deletions(-)
create mode 100644 gettext.c
create mode 100644 gettext.h
create mode 100644 git-sh-i18n.sh
create mode 100644 perl/Git/I18N.pm
create mode 100644 po/.gitignore
create mode 100644 po/is.po
create mode 100755 t/t0200-gettext.sh
create mode 100644 t/t0200/test.c
create mode 100644 t/t0200/test.perl
create mode 100644 t/t0200/test.sh
create mode 100755 t/t0201-gettext-fallbacks.sh
create mode 100755 t/t0202-gettext-perl.sh
create mode 100644 t/t0202/test.pl
diff --git a/.gitignore b/.gitignore
index 14e2b6b..6c2b193 100644
--- a/.gitignore
+++ b/.gitignore
@@ -125,6 +125,7 @@
/git-rm
/git-send-email
/git-send-pack
+/git-sh-i18n
/git-sh-setup
/git-shell
/git-shortlog
@@ -204,3 +205,4 @@
*.pdb
/Debug/
/Release/
+/share/
diff --git a/INSTALL b/INSTALL
index 61086ab..f30d5bd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -93,6 +93,14 @@ Issues of note:
history graphically, and in git-gui. If you don't want gitk or
git-gui, you can use NO_TCLTK.
+ - The GNU "libintl" library is used by default for localizing
+ Git. It needs a gettext.h on the system for C code, gettext.sh
+ for shell scripts, and libintl-perl for Perl programs.
+
+ Set NO_GETTEXT to disable localization support and make Git only
+ use English. Under autoconf the configure script will do this
+ automatically if it can't find libintl on the system.
+
- Some platform specific issues are dealt with Makefile rules,
but depending on your specific installation, you may not
have all the libraries/tools needed, or you may have
diff --git a/Makefile b/Makefile
index d5d6565..5169aec 100644
--- a/Makefile
+++ b/Makefile
@@ -272,6 +272,7 @@ mandir = share/man
infodir = share/info
gitexecdir = libexec/git-core
sharedir = $(prefix)/share
+localedir = $(sharedir)/locale
template_dir = share/git-core/templates
htmldir = share/doc/git-doc
ifeq ($(prefix),/usr)
@@ -285,7 +286,7 @@ lib = lib
# DESTDIR=
pathsep = :
-export prefix bindir sharedir sysconfdir
+export prefix bindir sharedir sysconfdir localedir
CC = gcc
AR = ar
@@ -297,6 +298,8 @@ RPMBUILD = rpmbuild
TCL_PATH = tclsh
TCLTK_PATH = wish
PTHREAD_LIBS = -lpthread
+XGETTEXT = xgettext
+MSGFMT = msgfmt
export TCL_PATH TCLTK_PATH
@@ -358,6 +361,7 @@ SCRIPT_SH += git-web--browse.sh
SCRIPT_LIB += git-mergetool--lib
SCRIPT_LIB += git-parse-remote
SCRIPT_LIB += git-sh-setup
+SCRIPT_LIB += git-sh-i18n
SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-difftool.perl
@@ -523,6 +527,7 @@ LIB_H += userdiff.h
LIB_H += utf8.h
LIB_H += xdiff-interface.h
LIB_H += xdiff/xdiff.h
+LIB_H += gettext.h
LIB_OBJS += abspath.o
LIB_OBJS += advice.o
@@ -564,6 +569,7 @@ LIB_OBJS += entry.o
LIB_OBJS += environment.o
LIB_OBJS += exec_cmd.o
LIB_OBJS += fsck.o
+LIB_OBJS += gettext.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
LIB_OBJS += hash.o
@@ -1386,6 +1392,12 @@ ifdef USE_NED_ALLOCATOR
COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
endif
+ifdef NO_GETTEXT
+ COMPAT_CFLAGS += -DNO_GETTEXT
+else
+ LIBINTL = -lintl
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
@@ -1415,6 +1427,7 @@ ifndef V
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
QUIET_GEN = @echo ' ' GEN $@;
QUIET_LNCP = @echo ' ' LN/CP $@;
+ QUIET_MSGFMT = @echo ' ' MSGFMT $@;
QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir
@@ -1442,7 +1455,9 @@ gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_SQ = $(subst ','\'',$(htmldir))
prefix_SQ = $(subst ','\'',$(prefix))
+sharedir_SQ = $(subst ','\'',$(sharedir))
+LOCALEDIR_SQ = $(subst ','\'',$(localedir))
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
@@ -1491,7 +1506,7 @@ ifndef NO_TCLTK
$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
endif
ifndef NO_PERL
- $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
+ $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all
endif
ifndef NO_PYTHON
$(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
@@ -1536,6 +1551,7 @@ $(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+ -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-e $(BROKEN_PATH_FIX) \
$@.sh >$@+
@@ -1868,6 +1884,21 @@ cscope:
$(RM) cscope*
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
+pot:
+ $(XGETTEXT) --add-comments --keyword=_ --output=po/git.pot --language=C $(C_OBJ:o=c) t/t0200/test.c
+ $(XGETTEXT) --add-comments --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH) t/t0200/test.sh
+ $(XGETTEXT) --add-comments --join-existing --keyword=__ --output=po/git.pot --language=Perl $(SCRIPT_PERL) t/t0200/test.perl
+
+POFILES := $(wildcard po/*.po)
+MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))
+MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))
+ifndef NO_GETTEXT
+all:: $(MOFILES)
+endif
+share/locale/%/LC_MESSAGES/git.mo: po/%.po
+ @mkdir -p $(dir $@)
+ $(QUIET_MSGFMT)$(MSGFMT) -o $@ $<
+
### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
@@ -1980,6 +2011,11 @@ install: all
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
+ifndef NO_GETTEXT
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'
+ (cd share && tar cf - locale) | \
+ (cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)
+endif
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
ifndef NO_PERL
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
@@ -2127,6 +2163,10 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
+ifndef NO_GETTEXT
+ $(RM) po/git.pot
+ $(RM) -r share/
+endif
.PHONY: all install clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/config.mak.in b/config.mak.in
index 0d4b64d..a15f3c1 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -32,6 +32,7 @@ NO_CURL=@NO_CURL@
NO_EXPAT=@NO_EXPAT@
NO_LIBGEN_H=@NO_LIBGEN_H@
HAVE_PATHS_H=@HAVE_PATHS_H@
+NO_GETTEXT=@NO_GETTEXT@
NEEDS_LIBICONV=@NEEDS_LIBICONV@
NEEDS_SOCKET=@NEEDS_SOCKET@
NEEDS_RESOLV=@NEEDS_RESOLV@
diff --git a/configure.ac b/configure.ac
index 71038fc..7bebfd8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -730,6 +730,12 @@ AC_CHECK_HEADER([paths.h],
[HAVE_PATHS_H=])
AC_SUBST(HAVE_PATHS_H)
#
+# Define NO_GETTEXT if you don't have libintl.h
+AC_CHECK_HEADER([libintl.h],
+[NO_GETTEXT=],
+[NO_GETTEXT=YesPlease])
+AC_SUBST(NO_GETTEXT)
+#
# Define NO_STRCASESTR if you don't have strcasestr.
GIT_CHECK_FUNC(strcasestr,
[NO_STRCASESTR=],
diff --git a/gettext.c b/gettext.c
new file mode 100644
index 0000000..22cdcc1
--- /dev/null
+++ b/gettext.c
@@ -0,0 +1,25 @@
+#ifdef NO_GETTEXT
+void git_setup_gettext(void) {}
+#else
+#include "exec_cmd.h"
+#include <libintl.h>
+#include <stdlib.h>
+
+void git_setup_gettext(void) {
+ char *podir;
+ char *envdir = getenv("GIT_TEXTDOMAINDIR");
+
+ if (envdir) {
+ (void)bindtextdomain("git", envdir);
+ } else {
+ podir = (char *)system_path("share/locale");
+ if (!podir) return;
+ (void)bindtextdomain("git", podir);
+ free(podir);
+ }
+
+ (void)setlocale(LC_MESSAGES, "");
+ (void)setlocale(LC_CTYPE, "");
+ (void)textdomain("git");
+}
+#endif
diff --git a/gettext.h b/gettext.h
new file mode 100644
index 0000000..a99da6a
--- /dev/null
+++ b/gettext.h
@@ -0,0 +1,13 @@
+#ifndef GETTEXT_H
+#define GETTEXT_H
+
+void git_setup_gettext(void);
+
+#ifdef NO_GETTEXT
+#define _(s) (s)
+#else
+#include <libintl.h>
+#define _(s) gettext(s)
+#endif
+
+#endif
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
new file mode 100644
index 0000000..d4963e9
--- /dev/null
+++ b/git-sh-i18n.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Ævar Arnfjörð Bjarmason
+#
+# This is Git's interface to gettext.sh. Use it right after
+# git-sh-setup as:
+#
+# . git-sh-setup
+# . git-sh-i18n
+#
+# # For constant interface messages:
+# gettext "A message for the user"; echo
+#
+# # To interpolate variables:
+# details="oh noes"
+# eval_gettext "An error occured: \$details"; echo
+#
+# See "info '(gettext)sh'" for the full manual.
+
+# Try to use libintl's gettext.sh, or fall back to English if we
+# can't.
+. gettext.sh
+
+if test $? -eq 0 && test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
+then
+ TEXTDOMAIN=git
+ export TEXTDOMAIN
+ if [ -z "$GIT_TEXTDOMAINDIR" ]
+ then
+ TEXTDOMAINDIR="@@LOCALEDIR@@"
+ else
+ TEXTDOMAINDIR="$GIT_TEXTDOMAINDIR"
+ fi
+ export TEXTDOMAINDIR
+else
+ # Since gettext.sh isn't available we'll have to define our own
+ # dummy pass-through functions.
+
+ gettext () {
+ printf "%s" "$1"
+ }
+
+ eval_gettext () {
+ gettext_eval="printf '%s' \"$1\""
+ printf "%s" "`eval \"$gettext_eval\"`"
+ }
+fi
diff --git a/git.c b/git.c
index 99f0363..d749eab 100644
--- a/git.c
+++ b/git.c
@@ -3,6 +3,7 @@
#include "cache.h"
#include "quote.h"
#include "run-command.h"
+#include "gettext.h"
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
@@ -490,6 +491,8 @@ int main(int argc, const char **argv)
if (!cmd)
cmd = "git-help";
+ git_setup_gettext();
+
/*
* "git-xxxx" is the same as "git xxxx", but we obviously:
*
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
new file mode 100644
index 0000000..5918d68
--- /dev/null
+++ b/perl/Git/I18N.pm
@@ -0,0 +1,91 @@
+package Git::I18N;
+use 5.006002;
+use strict;
+use warnings;
+use Exporter;
+use base 'Exporter';
+
+our $VERSION = '0.01';
+
+our @EXPORT = qw(__);
+our @EXPORT_OK = @EXPORT;
+
+sub __bootstrap_locale_messages {
+ our $TEXTDOMAIN = 'git';
+ our $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++';
+
+ require POSIX;
+ POSIX->import(qw(setlocale));
+ # Non-core prerequisite module
+ require Locale::Messages;
+ Locale::Messages->import(qw(:locale_h :libintl_h));
+
+ setlocale(LC_MESSAGES(), '');
+ setlocale(LC_CTYPE(), '');
+ textdomain($TEXTDOMAIN);
+ bindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR);
+
+ return;
+}
+
+BEGIN
+{
+ # Used by our test script to see if it should test fallbacks or
+ # not.
+ our $__HAS_LIBRARY = 1;
+
+ local $@;
+ eval { __bootstrap_locale_messages() };
+ if ($@) {
+ # Tell test.pl that we couldn't load the gettext library.
+ $Git::I18N::__HAS_LIBRARY = 0;
+
+ # Just a fall-through no-op
+ *__ = sub ($) { $_[0] };
+ } else {
+ *__ = \&Locale::Messages::gettext;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Git::I18N - Perl interface to Git's Gettext localizations
+
+=head1 SYNOPSIS
+
+ use Git::I18N;
+
+ print __("Welcome to Git!\n");
+
+ printf __("The following error occured: %s\n"), $error;
+
+=head1 DESCRIPTION
+
+Git's internal Perl interface to gettext via L<Locale::Messages>. If
+L<Locale::Messages> can't be loaded (it's not a core module) we
+provide stub passthrough fallbacks.
+
+This is a distilled interface to gettext, see C<info '(gettext)Perl'>
+for the full interface. This module implements only a small part of
+it.
+
+=head1 FUNCTIONS
+
+=head2 __($)
+
+L<Locale::Messages>'s gettext function if all goes well, otherwise our
+passthrough fallback function.
+
+=head1 AUTHOR
+
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>
+
+=head1 COPYRIGHT
+
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avarab@gmail.com>
+
+=cut
diff --git a/perl/Makefile b/perl/Makefile
index 4ab21d6..4e624ff 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -5,6 +5,7 @@ makfile:=perl.mak
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
prefix_SQ = $(subst ','\'',$(prefix))
+localedir_SQ = $(subst ','\'',$(localedir))
ifndef V
QUIET = @
@@ -38,7 +39,7 @@ $(makfile): ../GIT-CFLAGS Makefile
echo ' echo $(instdir_SQ)' >> $@
else
$(makfile): Makefile.PL ../GIT-CFLAGS
- $(PERL_PATH) $< PREFIX='$(prefix_SQ)'
+ $(PERL_PATH) $< PREFIX='$(prefix_SQ)' --localedir='$(localedir_SQ)'
endif
# this is just added comfort for calling make directly in perl dir
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index 0b9deca..456d45b 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -1,4 +1,12 @@
+use strict;
+use warnings;
use ExtUtils::MakeMaker;
+use Getopt::Long;
+
+# Sanity: die at first unknown option
+Getopt::Long::Configure qw/ pass_through /;
+
+GetOptions("localedir=s" => \my $localedir);
sub MY::postamble {
return <<'MAKE_FRAG';
@@ -16,7 +24,10 @@ endif
MAKE_FRAG
}
-my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');
+my %pm = (
+ 'Git.pm' => '$(INST_LIBDIR)/Git.pm',
+ 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',
+);
# We come with our own bundled Error.pm. It's not in the set of default
# Perl modules so install it if it's not available on the system yet.
@@ -33,6 +44,7 @@ WriteMakefile(
NAME => 'Git',
VERSION_FROM => 'Git.pm',
PM => \%pm,
+ PM_FILTER => qq[\$(PERL) -pe "s<\\Q++LOCALEDIR++\\E><$localedir>"],
MAKEFILE => 'perl.mak',
INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'
);
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000..221000e
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1 @@
+/*.pot
diff --git a/po/is.po b/po/is.po
new file mode 100644
index 0000000..1b35738
--- /dev/null
+++ b/po/is.po
@@ -0,0 +1,46 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 17:35+0000\n"
+"PO-Revision-Date: 2010-06-02 16:01+0000\n"
+"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"
+"Language-Team: Git Mailing List <git@vger.kernel.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: English\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.c:6
+msgid "TEST: A C test string"
+msgstr "TILRAUN: C tilraunastrengur"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.c:9
+#, c-format
+msgid "TEST: A C test string %s"
+msgstr "TILRAUN: C tilraunastrengur %s"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.sh:8
+msgid "TEST: A Shell test string"
+msgstr "TILRAUN: Skeljartilraunastrengur"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.sh:11
+#, sh-format
+msgid "TEST: A Shell test $variable"
+msgstr "TILRAUN: Skeljartilraunastrengur með breytunni $variable"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.perl:5
+msgid "TEST: A Perl test string"
+msgstr "TILRAUN: Perl tilraunastrengur"
+
+#. TRANSLATORS: This is a test. You don't need to translate it.
+#: t/t0200-gettext/test.perl:8
+#, perl-format
+msgid "TEST: A Perl test variable %s"
+msgstr "TILRAUN: Perl tilraunastrengur með breytunni %s"
diff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh
new file mode 100755
index 0000000..7eba5dd
--- /dev/null
+++ b/t/t0200-gettext.sh
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+test_description='Gettext support for Git'
+
+. ./test-lib.sh
+
+GIT_TEXTDOMAINDIR="$GIT_EXEC_PATH/share/locale"
+GIT_PO_PATH="$GIT_EXEC_PATH/po"
+export GIT_TEXTDOMAINDIR GIT_PO_PATH
+
+. "$GIT_EXEC_PATH"/git-sh-i18n
+
+test_expect_success 'sanity: $TEXTDOMAIN is git' '
+ test $TEXTDOMAIN = "git"
+'
+
+test_expect_success 'sanity: $TEXTDOMAINDIR exists' '
+ test -d "$TEXTDOMAINDIR" &&
+ test "$TEXTDOMAINDIR" = "$GIT_TEXTDOMAINDIR"
+'
+
+test_expect_success 'sanity: Icelandic locale was compiled' '
+ test -f "$TEXTDOMAINDIR/is/LC_MESSAGES/git.mo"
+'
+
+test_expect_success 'sanity: No gettext("") data for fantasy locale' '
+ LANGUAGE=is LC_ALL=tlh_TLH.UTF-8 gettext "" > real-locale &&
+ test_expect_failure test -s real-locale
+'
+
+test_expect_success 'sanity: Some gettext("") data for real locale' '
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "" > fantasy-locale &&
+ test -s fantasy-locale
+'
+
+# TODO: When we have more locales, generalize this to test them
+# all. Maybe we'll need a dir->locale map for that.
+test_expect_success 'sanity: gettext("") metadata is OK' '
+ # Return value may be non-zero
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "" > zero-expect &&
+ grep "Project-Id-Version: Git" zero-expect &&
+ grep "Git Mailing List <git@vger.kernel.org>" zero-expect &&
+ grep "Content-Type: text/plain; charset=UTF-8" zero-expect &&
+ grep "Content-Transfer-Encoding: 8bit" zero-expect
+'
+
+test_expect_success 'sanity: gettext(unknown) is passed through' '
+ printf "This is not a translation string" > expect &&
+ gettext "This is not a translation string" > actual &&
+ eval_gettext "This is not a translation string" > actual &&
+ test_cmp expect actual
+'
+
+# xgettext from C
+test_expect_success 'xgettext: C extraction' '
+ printf "TILRAUN: C tilraunastrengur" > expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "TEST: A C test string" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'xgettext: C extraction with %s' '
+ printf "TILRAUN: C tilraunastrengur %%s" > expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "TEST: A C test string %s" > actual &&
+ test_cmp expect actual
+'
+
+# xgettext from Shell
+test_expect_success 'xgettext: Shell extraction' '
+ printf "TILRAUN: Skeljartilraunastrengur" > expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "TEST: A Shell test string" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'xgettext: Shell extraction with $variable' '
+ printf "TILRAUN: Skeljartilraunastrengur með breytunni a var i able" > x-expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 variable="a var i able" eval_gettext "TEST: A Shell test \$variable" > x-actual &&
+ test_cmp x-expect x-actual
+'
+
+# xgettext from Perl
+test_expect_success 'xgettext: Perl extraction' '
+ printf "TILRAUN: Perl tilraunastrengur" > expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "TEST: A Perl test string" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'xgettext: Perl extraction with %s' '
+ printf "TILRAUN: Perl tilraunastrengur með breytunni %%s" > expect &&
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 gettext "TEST: A Perl test variable %s" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'xgettext: Perl _() strings are not extracted' '
+ test_expect_failure grep "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po
+'
+
+test_expect_success 'xgettext: Comment extraction with --add-comments' '
+ grep "TRANSLATORS: This is a test" "$TEST_DIRECTORY"/t0200/* | wc -l > expect &&
+ grep "TRANSLATORS: This is a test" "$GIT_PO_PATH"/is.po | wc -l > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'xgettext: Comment extraction with --add-comments stops at statements' '
+ test_expect_failure grep "This is a phony" "$GIT_PO_PATH"/is.po &&
+ test_expect_failure grep "the above comment" "$GIT_PO_PATH"/is.po
+'
+
+# Actually execute some C and Shell code that uses Gettext
+test_expect_success 'C: git-status reads our message catalog ' '
+ test_commit "some-file" &&
+ git checkout -b test/gettext &&
+ LANGUAGE=C LC_ALL=C git status | grep test/gettext > expect &&
+ echo "# On branch test/gettext" > actual &&
+ test_cmp expect actual &&
+
+ LANGUAGE=is LC_ALL=is_IS.UTF-8 git status | grep test/gettext > expect &&
+ echo "# Á greininni test/gettext" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'Shell: git-pull reads our message catalog' '
+ # Repository for testing
+ mkdir parent &&
+ (cd parent && git init &&
+ echo one >file && git add file &&
+ git commit -m one) &&
+
+ # Actual test
+ (cd parent &&
+ (LANGUAGE=C LC_ALL=C git pull --tags "../" >out 2>err);
+ grep "Fetching tags only" err &&
+ (LANGUAGE=is LC_ALL=is_IS.UTF-8 git pull --tags ../ >out 2>err || :) &&
+ grep "Næ aðeins í" err)
+'
+
+test_done
diff --git a/t/t0200/test.c b/t/t0200/test.c
new file mode 100644
index 0000000..9fa4c23
--- /dev/null
+++ b/t/t0200/test.c
@@ -0,0 +1,11 @@
+/* This is a phony C program that's only here to test xgettext message extraction */
+
+int main(void)
+{
+ /* TRANSLATORS: This is a test. You don't need to translate it. */
+ puts(_("TEST: A C test string"));
+
+ /* TRANSLATORS: This is a test. You don't need to translate it. */
+ printf(_("TEST: A C test string %s"), "variable");
+}
+
diff --git a/t/t0200/test.perl b/t/t0200/test.perl
new file mode 100644
index 0000000..36fba34
--- /dev/null
+++ b/t/t0200/test.perl
@@ -0,0 +1,14 @@
+# This is a phony Perl program that's only here to test xgettext
+# message extraction
+
+# so the above comment won't be folded into the next one by xgettext
+1;
+
+# TRANSLATORS: This is a test. You don't need to translate it.
+print __("TEST: A Perl test string");
+
+# TRANSLATORS: This is a test. You don't need to translate it.
+printf __("TEST: A Perl test variable %s"), "moo";
+
+# TRANSLATORS: If you see this, Git has a bug
+print _"TEST: A Perl string xgettext will not get";
diff --git a/t/t0200/test.sh b/t/t0200/test.sh
new file mode 100644
index 0000000..022d607
--- /dev/null
+++ b/t/t0200/test.sh
@@ -0,0 +1,14 @@
+# This is a phony Shell program that's only here to test xgettext
+# message extraction
+
+# so the above comment won't be folded into the next one by xgettext
+echo
+
+# TRANSLATORS: This is a test. You don't need to translate it.
+gettext "TEST: A Shell test string"
+
+# TRANSLATORS: This is a test. You don't need to translate it.
+eval_gettext "TEST: A Shell test \$variable"
+
+# TRANSLATORS: If you see this, Git has a bug
+_("TEST: A Shell string xgettext won't get")
diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh
new file mode 100755
index 0000000..b4bc1df
--- /dev/null
+++ b/t/t0201-gettext-fallbacks.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='Gettext Shell fallbacks'
+
+. ./test-lib.sh
+
+GIT_TEXTDOMAINDIR="$GIT_EXEC_PATH/share/locale"
+GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease
+
+export GIT_TEXTDOMAINDIR GIT_INTERNAL_GETTEXT_TEST_FALLBACKS
+
+. "$GIT_EXEC_PATH"/git-sh-i18n
+
+test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' '
+ test_expect_failure test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
+'
+
+test_expect_success 'gettext: our gettext() fallback has pass-through semantics' '
+ printf "test" > expect &&
+ gettext "test" > actual &&
+ test_cmp expect actual &&
+ printf "test more words" > expect &&
+ gettext "test more words" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' '
+ printf "test" > expect &&
+ eval_gettext "test" > actual &&
+ test_cmp expect actual &&
+ printf "test more words" > expect &&
+ eval_gettext "test more words" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' '
+ printf "test YesPlease" > expect &&
+ eval_gettext "test \$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" > actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh
new file mode 100755
index 0000000..9b075b1
--- /dev/null
+++ b/t/t0202-gettext-perl.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='Perl gettext interface (Git::I18N)'
+. ./test-lib.sh
+
+if ! test_have_prereq PERL; then
+ say 'skipping perl interface tests, perl not available'
+ test_done
+fi
+
+"$PERL_PATH" -MTest::More -e 0 2>/dev/null || {
+ say "Perl Test::More unavailable, skipping test"
+ test_done
+}
+
+test_external_without_stderr \
+ 'Perl Git::I18N API' \
+ "$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl
+
+test_done
diff --git a/t/t0202/test.pl b/t/t0202/test.pl
new file mode 100644
index 0000000..4e9a0dc
--- /dev/null
+++ b/t/t0202/test.pl
@@ -0,0 +1,104 @@
+#!/usr/bin/perl
+use 5.006002;
+use lib (split(/:/, $ENV{GITPERLLIB}));
+use warnings;
+use strict;
+use Test::More tests => 9;
+use Git::I18N;
+use POSIX qw(:locale_h);
+
+my $has_gettext_library = $Git::I18N::__HAS_LIBRARY;
+
+ok(1, "Testing Git::I18N version $Git::I18N::VERSION with " .
+ ($has_gettext_library
+ ? "Locale::Messages version $Locale::Messages::VERSION"
+ : "NO Perl gettext library"));
+ok(1, "Git::I18N is located at $INC{'Git/I18N.pm'}");
+
+ok($Git::I18N::VERSION, 'sanity: Git::I18N defines a $VERSION');
+{
+ my $exports = @Git::I18N::EXPORT;
+ ok($exports, "sanity: Git::I18N has $exports export(s)");
+}
+is_deeply(\@Git::I18N::EXPORT, \@Git::I18N::EXPORT_OK, "sanity: Git::I18N exports everything by default");
+
+# prototypes
+{
+ # Add prototypes here when modifying the public interface to add
+ # more gettext wrapper functions.
+ my %prototypes = (qw(
+ __ $
+ ));
+ while (my ($sub, $proto) = each %prototypes) {
+ is(prototype(\&{"Git::I18N::$sub"}), $proto, "sanity: $sub has a $proto prototype");
+ }
+}
+
+# Test basic passthrough in the C locale
+{
+ local $ENV{LANGUAGE} = 'C';
+ local $ENV{LC_ALL} = 'C';
+ local $ENV{LANG} = 'C';
+
+ my ($got, $expect) = (('TEST: A Perl test string') x 2);
+
+ is(__($got), $expect, "Passing a string through __() in the C locale works");
+}
+
+# Test a basic message on different locales
+SKIP: {
+ unless ($ENV{TEST_GIT_I18N_EXHAUSTIVE}) {
+ # Can't reliably test __() with a non-C locales because the
+ # required locales may not be installed on the system.
+ #
+ # We test for these anyway as part of the shell
+ # tests. Skipping these here will eliminate failures on odd
+ # platforms with incomplete locale data.
+
+ skip "Set TEST_GIT_I18N_EXHAUSTIVE=1 to enable exhaustive Git::I18N locale tests", 2;
+ }
+
+ my $test = sub {
+ my ($got, $expect, $msg, $locale) = @_;
+ # Maybe this system doesn't have the locale we're trying to
+ # test.
+ my $locale_ok = setlocale(LC_ALL, $locale);
+ is(__($got), $expect, "$msg a gettext library + <$locale> locale <$got> turns into <$expect>");
+ };
+
+ my $env_C = sub {
+ $ENV{LANGUAGE} = 'C';
+ $ENV{LC_ALL} = 'C';
+ };
+
+ my $env_is = sub {
+ $ENV{LANGUAGE} = 'is';
+ $ENV{LC_ALL} = 'is_IS.UTF-8';
+ };
+
+ # Translation's the same as the original
+ my ($got, $expect) = (('TEST: A Perl test string') x 2);
+
+ if ($has_gettext_library) {
+ {
+ local %ENV; $env_C->();
+ $test->($got, $expect, "With", 'C');
+ }
+
+ {
+ my ($got, $expect) = ($got, 'TILRAUN: Perl tilraunastrengur');
+ local %ENV; $env_is->();
+ $test->($got, $expect, "With", 'is_IS.UTF-8');
+ }
+ } else {
+ {
+ local %ENV; $env_C->();
+ $test->($got, $expect, "Without", 'C');
+ }
+
+ {
+ local %ENV; $env_is->();
+ $test->($got, $expect, "Without", 'is');
+ }
+ }
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 454880a..cb3c9c5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -37,6 +37,7 @@ ORIGINAL_TERM=$TERM
# For repeatability, reset the environment to known value.
LANG=C
LC_ALL=C
+LANGUAGE=C
PAGER=cat
TZ=UTC
TERM=dumb
--
1.7.1.242.g64631
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH/RFC v6 2/2] Add initial C, Shell and Perl gettext translations
2010-06-03 21:10 [PATCH/RFC v6 0/2] Add infrastructure for translating Git with gettext Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 1/2] " Ævar Arnfjörð Bjarmason
@ 2010-06-03 21:10 ` Ævar Arnfjörð Bjarmason
1 sibling, 0 replies; 3+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2010-06-03 21:10 UTC (permalink / raw)
To: git; +Cc: Ævar Arnfjörð Bjarmason
Change the git status, git pull, and git send-email commands to have
at least one translatable string. Each command uses a different core
language, so this makes a good example of how C, Shell and Perl
programs can be translated using gettext.
Since this introduces translation into the real Git tools more tests
can be added to check if they translations actually work for real core
tools.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-pull.sh | 16 ++++---
git-send-email.perl | 3 +-
po/is.po | 27 ++++++++++++-
t/t0200/test.c | 1 -
wt-status.c | 107 ++++++++++++++++++++++++++-------------------------
5 files changed, 90 insertions(+), 64 deletions(-)
diff --git a/git-pull.sh b/git-pull.sh
index 1a4729f..0d95722 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -9,6 +9,7 @@ LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEA
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
. git-sh-setup
+. git-sh-i18n
set_reflog_action "pull $*"
require_work_tree
cd_to_toplevel
@@ -121,8 +122,8 @@ error_on_no_merge_candidates () {
do
case "$opt" in
-t|--t|--ta|--tag|--tags)
- echo "Fetching tags only, you probably meant:"
- echo " git fetch --tags"
+ gettext "Fetching tags only, you probably meant:"; echo
+ gettext " git fetch --tags"; echo
exit 1
esac
done
@@ -154,11 +155,12 @@ error_on_no_merge_candidates () {
echo "a branch. Because this is not the default configured remote"
echo "for your current branch, you must specify a branch on the command line."
elif [ -z "$curr_branch" ]; then
- echo "You are not currently on a branch, so I cannot use any"
- echo "'branch.<branchname>.merge' in your configuration file."
- echo "Please specify which remote branch you want to use on the command"
- echo "line and try again (e.g. 'git pull <repository> <refspec>')."
- echo "See git-pull(1) for details."
+ gettext "You are not currently on a branch, so I cannot use any
+'branch.<branchname>.merge' in your configuration file.
+Please specify which remote branch you want to use on the command
+line and try again (e.g. 'git pull <repository> <refspec>').
+See git-pull(1) for details.";
+ echo
elif [ -z "$upstream" ]; then
echo "You asked me to pull without telling me which branch you"
echo "want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in"
diff --git a/git-send-email.perl b/git-send-email.perl
index 111c981..4977fdf 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -26,6 +26,7 @@ use Term::ANSIColor;
use File::Temp qw/ tempdir tempfile /;
use Error qw(:try);
use Git;
+use Git::I18N;
Getopt::Long::Configure qw/ pass_through /;
@@ -674,7 +675,7 @@ if (!defined $sender) {
$sender = $repoauthor || $repocommitter || '';
$sender = ask("Who should the emails appear to be from? [$sender] ",
default => $sender);
- print "Emails will be sent from: ", $sender, "\n";
+ printf __("Emails will be sent from: %s\n"), $sender;
$prompting++;
}
diff --git a/po/is.po b/po/is.po
index 1b35738..0c77b90 100644
--- a/po/is.po
+++ b/po/is.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-06-02 17:35+0000\n"
-"PO-Revision-Date: 2010-06-02 16:01+0000\n"
+"POT-Creation-Date: 2010-06-02 19:43+0000\n"
+"PO-Revision-Date: 2010-06-02 19:35+0000\n"
"Last-Translator: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"
"Language-Team: Git Mailing List <git@vger.kernel.org>\n"
"MIME-Version: 1.0\n"
@@ -12,6 +12,20 @@ msgstr ""
"X-Poedit-Language: English\n"
"X-Poedit-SourceCharset: utf-8\n"
+#: wt-status.c:63 wt-status.c:79 wt-status.c:98 wt-status.c:110
+#: wt-status.c:622
+msgid "On branch "
+msgstr "Á greininni "
+
+#: wt-status.c:629
+msgid "Not currently on any branch."
+msgstr "Ekki á neinni grein."
+
+#: wt-status.c:663
+#, c-format
+msgid "# No changes\n"
+msgstr "# Engar breytingar\n"
+
#. TRANSLATORS: This is a test. You don't need to translate it.
#: t/t0200-gettext/test.c:6
msgid "TEST: A C test string"
@@ -23,6 +37,10 @@ msgstr "TILRAUN: C tilraunastrengur"
msgid "TEST: A C test string %s"
msgstr "TILRAUN: C tilraunastrengur %s"
+#: git-pull.sh:124
+msgid "Fetching tags only, you probably meant:"
+msgstr "Næ aðeins í tögg, þú áttir líkast til við:"
+
#. TRANSLATORS: This is a test. You don't need to translate it.
#: t/t0200-gettext/test.sh:8
msgid "TEST: A Shell test string"
@@ -34,6 +52,11 @@ msgstr "TILRAUN: Skeljartilraunastrengur"
msgid "TEST: A Shell test $variable"
msgstr "TILRAUN: Skeljartilraunastrengur með breytunni $variable"
+#: git-send-email.perl:678
+#, perl-format
+msgid "Emails will be sent from: %s\n"
+msgstr "Póstarnir verða sendir frá: %s\n"
+
#. TRANSLATORS: This is a test. You don't need to translate it.
#: t/t0200-gettext/test.perl:5
msgid "TEST: A Perl test string"
diff --git a/t/t0200/test.c b/t/t0200/test.c
index 9fa4c23..171bcc6 100644
--- a/t/t0200/test.c
+++ b/t/t0200/test.c
@@ -8,4 +8,3 @@ int main(void)
/* TRANSLATORS: This is a test. You don't need to translate it. */
printf(_("TEST: A C test string %s"), "variable");
}
-
diff --git a/wt-status.c b/wt-status.c
index 14e0acc..484a866 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -9,6 +9,7 @@
#include "quote.h"
#include "run-command.h"
#include "remote.h"
+#include "gettext.h"
static char default_wt_status_colors[][COLOR_MAXLEN] = {
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -49,16 +50,16 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+ color_fprintf_ln(s->fp, c, _("# Unmerged paths:"));
if (!advice_status_hints)
return;
if (s->in_merge)
;
else if (!s->is_initial)
- color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
+ color_fprintf_ln(s->fp, c, _("# (use \"git reset %s <file>...\" to unstage)"), s->reference);
else
- color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
- color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" as appropriate to mark resolution)");
+ color_fprintf_ln(s->fp, c, _("# (use \"git rm --cached <file>...\" to unstage)"));
+ color_fprintf_ln(s->fp, c, _("# (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
color_fprintf_ln(s->fp, c, "#");
}
@@ -66,15 +67,15 @@ static void wt_status_print_cached_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Changes to be committed:");
+ color_fprintf_ln(s->fp, c, _("# Changes to be committed:"));
if (!advice_status_hints)
return;
if (s->in_merge)
; /* NEEDSWORK: use "git reset --unresolve"??? */
else if (!s->is_initial)
- color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
+ color_fprintf_ln(s->fp, c, _("# (use \"git reset %s <file>...\" to unstage)"), s->reference);
else
- color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
+ color_fprintf_ln(s->fp, c, _("# (use \"git rm --cached <file>...\" to unstage)"));
color_fprintf_ln(s->fp, c, "#");
}
@@ -84,16 +85,16 @@ static void wt_status_print_dirty_header(struct wt_status *s,
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Changed but not updated:");
+ color_fprintf_ln(s->fp, c, _("# Changed but not updated:"));
if (!advice_status_hints)
return;
if (!has_deleted)
- color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)");
+ color_fprintf_ln(s->fp, c, _("# (use \"git add <file>...\" to update what will be committed)"));
else
- color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)");
- color_fprintf_ln(s->fp, c, "# (use \"git checkout -- <file>...\" to discard changes in working directory)");
+ color_fprintf_ln(s->fp, c, _("# (use \"git add/rm <file>...\" to update what will be committed)"));
+ color_fprintf_ln(s->fp, c, _("# (use \"git checkout -- <file>...\" to discard changes in working directory)"));
if (has_dirty_submodules)
- color_fprintf_ln(s->fp, c, "# (commit or discard the untracked or modified content in submodules)");
+ color_fprintf_ln(s->fp, c, _("# (commit or discard the untracked or modified content in submodules)"));
color_fprintf_ln(s->fp, c, "#");
}
@@ -102,10 +103,10 @@ static void wt_status_print_other_header(struct wt_status *s,
const char *how)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# %s files:", what);
+ color_fprintf_ln(s->fp, c, _("# %s files:"), what);
if (!advice_status_hints)
return;
- color_fprintf_ln(s->fp, c, "# (use \"git %s <file>...\" to include in what will be committed)", how);
+ color_fprintf_ln(s->fp, c, _("# (use \"git %s <file>...\" to include in what will be committed)"), how);
color_fprintf_ln(s->fp, c, "#");
}
@@ -122,20 +123,20 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
const char *c = color(WT_STATUS_UNMERGED, s);
struct wt_status_change_data *d = it->util;
struct strbuf onebuf = STRBUF_INIT;
- const char *one, *how = "bug";
+ const char *one, *how = _("bug");
one = quote_path(it->string, -1, &onebuf, s->prefix);
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
switch (d->stagemask) {
- case 1: how = "both deleted:"; break;
- case 2: how = "added by us:"; break;
- case 3: how = "deleted by them:"; break;
- case 4: how = "added by them:"; break;
- case 5: how = "deleted by us:"; break;
- case 6: how = "both added:"; break;
- case 7: how = "both modified:"; break;
+ case 1: how = _("both deleted:"); break;
+ case 2: how = _("added by us:"); break;
+ case 3: how = _("deleted by them:"); break;
+ case 4: how = _("added by them:"); break;
+ case 5: how = _("deleted by us:"); break;
+ case 6: how = _("both added:"); break;
+ case 7: how = _("both modified:"); break;
}
- color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+ color_fprintf(s->fp, c, _("%-20s%s\n"), how, one);
strbuf_release(&onebuf);
}
@@ -163,11 +164,11 @@ static void wt_status_print_change_data(struct wt_status *s,
if (d->new_submodule_commits || d->dirty_submodule) {
strbuf_addstr(&extra, " (");
if (d->new_submodule_commits)
- strbuf_addf(&extra, "new commits, ");
+ strbuf_addf(&extra, _("new commits, "));
if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
- strbuf_addf(&extra, "modified content, ");
+ strbuf_addf(&extra, _("modified content, "));
if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
- strbuf_addf(&extra, "untracked content, ");
+ strbuf_addf(&extra, _("untracked content, "));
strbuf_setlen(&extra, extra.len - 2);
strbuf_addch(&extra, ')');
}
@@ -178,34 +179,34 @@ static void wt_status_print_change_data(struct wt_status *s,
one = quote_path(one_name, -1, &onebuf, s->prefix);
two = quote_path(two_name, -1, &twobuf, s->prefix);
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+ color_fprintf(s->fp, color(WT_STATUS_HEADER, s), _("#\t"));
switch (status) {
case DIFF_STATUS_ADDED:
- color_fprintf(s->fp, c, "new file: %s", one);
+ color_fprintf(s->fp, c, _("new file: %s"), one);
break;
case DIFF_STATUS_COPIED:
- color_fprintf(s->fp, c, "copied: %s -> %s", one, two);
+ color_fprintf(s->fp, c, _("copied: %s -> %s"), one, two);
break;
case DIFF_STATUS_DELETED:
- color_fprintf(s->fp, c, "deleted: %s", one);
+ color_fprintf(s->fp, c, _("deleted: %s"), one);
break;
case DIFF_STATUS_MODIFIED:
- color_fprintf(s->fp, c, "modified: %s", one);
+ color_fprintf(s->fp, c, _("modified: %s"), one);
break;
case DIFF_STATUS_RENAMED:
- color_fprintf(s->fp, c, "renamed: %s -> %s", one, two);
+ color_fprintf(s->fp, c, _("renamed: %s -> %s"), one, two);
break;
case DIFF_STATUS_TYPE_CHANGED:
- color_fprintf(s->fp, c, "typechange: %s", one);
+ color_fprintf(s->fp, c, _("typechange: %s"), one);
break;
case DIFF_STATUS_UNKNOWN:
- color_fprintf(s->fp, c, "unknown: %s", one);
+ color_fprintf(s->fp, c, _("unknown: %s"), one);
break;
case DIFF_STATUS_UNMERGED:
- color_fprintf(s->fp, c, "unmerged: %s", one);
+ color_fprintf(s->fp, c, _("unmerged: %s"), one);
break;
default:
- die("bug: unhandled diff status %c", status);
+ die(_("bug: unhandled diff status %c"), status);
}
if (extra.len) {
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf);
@@ -618,14 +619,14 @@ void wt_status_print(struct wt_status *s)
const char *branch_color = color(WT_STATUS_HEADER, s);
if (s->branch) {
- const char *on_what = "On branch ";
+ const char *on_what = _("On branch ");
const char *branch_name = s->branch;
if (!prefixcmp(branch_name, "refs/heads/"))
branch_name += 11;
else if (!strcmp(branch_name, "HEAD")) {
branch_name = "";
branch_color = color(WT_STATUS_NOBRANCH, s);
- on_what = "Not currently on any branch.";
+ on_what = _("Not currently on any branch.");
}
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
@@ -635,7 +636,7 @@ void wt_status_print(struct wt_status *s)
if (s->is_initial) {
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
+ color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), _("# Initial commit"));
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
}
@@ -647,38 +648,38 @@ void wt_status_print(struct wt_status *s)
wt_status_print_submodule_summary(s, 1); /* unstaged */
}
if (s->show_untracked_files) {
- wt_status_print_other(s, &s->untracked, "Untracked", "add");
+ wt_status_print_other(s, &s->untracked, _("Untracked"), _("add"));
if (s->show_ignored_files)
- wt_status_print_other(s, &s->ignored, "Ignored", "add -f");
+ wt_status_print_other(s, &s->ignored, _("Ignored"), _("add -f"));
} else if (s->commitable)
- fprintf(s->fp, "# Untracked files not listed%s\n",
+ fprintf(s->fp, _("# Untracked files not listed%s\n"),
advice_status_hints
- ? " (use -u option to show untracked files)" : "");
+ ? _(" (use -u option to show untracked files)") : "");
if (s->verbose)
wt_status_print_verbose(s);
if (!s->commitable) {
if (s->amend)
- fprintf(s->fp, "# No changes\n");
+ fprintf(s->fp, _("# No changes\n"));
else if (s->nowarn)
; /* nothing */
else if (s->workdir_dirty)
- printf("no changes added to commit%s\n",
+ printf(_("no changes added to commit%s\n"),
advice_status_hints
- ? " (use \"git add\" and/or \"git commit -a\")" : "");
+ ? _(" (use \"git add\" and/or \"git commit -a\")") : "");
else if (s->untracked.nr)
- printf("nothing added to commit but untracked files present%s\n",
+ printf(_("nothing added to commit but untracked files present%s\n"),
advice_status_hints
- ? " (use \"git add\" to track)" : "");
+ ? _(" (use \"git add\" to track)") : "");
else if (s->is_initial)
printf("nothing to commit%s\n", advice_status_hints
- ? " (create/copy files and use \"git add\" to track)" : "");
+ ? _(" (create/copy files and use \"git add\" to track)") : "");
else if (!s->show_untracked_files)
- printf("nothing to commit%s\n", advice_status_hints
- ? " (use -u to show untracked files)" : "");
+ printf(_("nothing to commit%s\n"), advice_status_hints
+ ? _(" (use -u to show untracked files)") : "");
else
- printf("nothing to commit%s\n", advice_status_hints
- ? " (working directory clean)" : "");
+ printf(_("nothing to commit%s\n"), advice_status_hints
+ ? _(" (working directory clean)") : "");
}
}
--
1.7.1.242.g64631
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2010-06-03 21:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-03 21:10 [PATCH/RFC v6 0/2] Add infrastructure for translating Git with gettext Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 1/2] " Ævar Arnfjörð Bjarmason
2010-06-03 21:10 ` [PATCH/RFC v6 2/2] Add initial C, Shell and Perl gettext translations Ævar Arnfjörð Bjarmason
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).