test-poisongen does a similar job to gettext poison feature except
that it does it at build time. Gibberish .mo files are generated for
all supported langauges and put in po/build/poison-locale. Target
"poison-locale" is for this.

User can run the test with these .mo files by setting POISON_LOCALE
while running the test suite. User must also set LANG/LC_* correctly
(and the system is supposed to support that locale).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 On Tue, Aug 21, 2012 at 11:37 PM, Junio C Hamano <gits...@pobox.com> wrote:
 > I would say it is not worse than just "annoying"; if the cost will
 > go away, I'd rather see this conversion postponed and is done as
 > part of (and preferrably at the end of) the "poison with a
 > poison-locale" series.

 OK let me redo step one. test-poisongen requires libgettextpo. I'm
 not sure if this library if gnu specific. We may need another flag
 for it instead of NO_GETTEXT. We don't need a fake language code with
 this approach.

 Makefile         |  19 ++++++++
 t/test-lib.sh    |  10 +++-
 test-poisongen.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 wrap-for-bin.sh  |   6 ++-
 4 files changed, 171 insertions(+), 3 deletions(-)
 mode change 100644 => 100755 t/test-lib.sh
 create mode 100644 test-poisongen.c
 mode change 100644 => 100755 wrap-for-bin.sh

diff --git a/Makefile b/Makefile
index 6b0c961..6ea2665 100644
--- a/Makefile
+++ b/Makefile
@@ -496,6 +496,9 @@ TEST_PROGRAMS_NEED_X += test-mergesort
 TEST_PROGRAMS_NEED_X += test-mktemp
 TEST_PROGRAMS_NEED_X += test-parse-options
 TEST_PROGRAMS_NEED_X += test-path-utils
+ifndef NO_GETTEXT
+TEST_PROGRAMS_NEED_X += test-poisongen
+endif
 TEST_PROGRAMS_NEED_X += test-revision-walking
 TEST_PROGRAMS_NEED_X += test-run-command
 TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
@@ -2428,6 +2431,19 @@ endif
 po/build/locale/%/LC_MESSAGES/git.mo: po/%.po
        $(QUIET_MSGFMT)mkdir -p $(dir $@) && $(MSGFMT) -o $@ $<
 
+ifndef NO_GETTEXT
+POISON_MOFILES := $(patsubst 
po/%.po,po/build/poison-locale/%/LC_MESSAGES/git.mo,$(POFILES))
+
+po/build/poison-locale/%.po: po/%.po test-poisongen$X po/git.pot
+       $(QUIET_MSGFMT)mkdir -p $(dir $@) && \
+       ./test-poisongen po/git.pot $@
+
+po/build/poison-locale/%/LC_MESSAGES/git.mo: po/build/poison-locale/%.po
+       $(QUIET_MSGFMT)mkdir -p $(dir $@) && $(MSGFMT) -o $@ $<
+
+poison-locale: $(POISON_MOFILES)
+endif
+
 FIND_SOURCE_FILES = ( git ls-files '*.[hcS]' 2>/dev/null || \
                        $(FIND) . \( -name .git -type d -prune \) \
                                -o \( -name '*.[hcS]' -type f -print \) )
@@ -2564,6 +2580,9 @@ test-svn-fe$X: vcs-svn/lib.a
 
 .PRECIOUS: $(TEST_OBJS)
 
+test-poisongen$X: test-poisongen.o GIT-LDFLAGS $(GITLIBS)
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) 
$(filter %.a,$^) $(LIBS) -lgettextpo
+
 test-%$X: test-%.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) 
$(filter %.a,$^) $(LIBS)
 
diff --git a/t/test-lib.sh b/t/test-lib.sh
old mode 100644
new mode 100755
index bb4f886..d4060e8
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -55,8 +55,10 @@ GIT_BUILD_DIR="$TEST_DIRECTORY"/..
 export PERL_PATH SHELL_PATH
 
 # For repeatability, reset the environment to known value.
-LANG=C
-LC_ALL=C
+if [ -z "$POISON_LOCALE" ]; then
+       LANG=C
+       LC_ALL=C
+fi
 PAGER=cat
 TZ=UTC
 TERM=dumb
@@ -92,6 +94,10 @@ export GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT
 export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 export EDITOR
+if test -n "$POISON_LOCALE"; then
+       GIT_POISON_LOCALE=yes
+       export GIT_POISON_LOCALE
+fi
 
 # Protect ourselves from common misconfiguration to export
 # CDPATH into the environment
diff --git a/test-poisongen.c b/test-poisongen.c
new file mode 100644
index 0000000..5905aa9
--- /dev/null
+++ b/test-poisongen.c
@@ -0,0 +1,139 @@
+#include <gettext-po.h>
+#include "cache.h"
+#include "strbuf.h"
+
+static void xerror(int severity,
+                  po_message_t message,
+                  const char *filename, size_t lineno, size_t column,
+                  int multiline_p, const char *message_text)
+{
+       die("%s:%d:%d %s", filename, lineno, column, message_text);
+}
+
+static void xerror2(int severity,
+                   po_message_t message1,
+                   const char *filename1, size_t lineno1, size_t column1,
+                   int multiline_p1, const char *message_text1,
+                   po_message_t message2,
+                   const char *filename2, size_t lineno2, size_t column2,
+                   int multiline_p2, const char *message_text2)
+{
+       die("%s:%d:%d %s (%s:%d:%d %s)",
+           filename1, lineno1, column1, message_text1,
+           filename2, lineno2, column2, message_text2);
+}
+
+static void translate(const char *msg, struct strbuf *buf)
+{
+       const char *end = msg + strlen(msg);
+       const char *text = "* GETTEXT POISON *";
+       int text_len = strlen(text);
+       int t = 0;
+
+       strbuf_reset(buf);
+       /* preserve \n and printf format specifiers because msgfmt
+          barfs otherwise. */
+       while (msg < end) {
+               /* printf specifiers and shell variables, it's a quite
+                  relax check */
+               if ((*msg == '%' || *msg == '$') && msg+1 < end) {
+                       strbuf_addch(buf, *msg++);
+                       do
+                              strbuf_addch(buf, *msg);
+                       while (msg < end && !isspace(*msg++));
+               } else if (*msg == '\n') {
+                       /* we only need to preserve trailing newlines, doing
+                          more does not really harm */
+                       strbuf_addch(buf, '\n');
+                       msg++;
+               } else {
+                       strbuf_addch(buf, text[t]);
+                       t = (t + 1) % text_len;
+                       msg++;
+               }
+       }
+}
+
+int main(int argc, char **argv)
+{
+       const char *project_header = "Project-Id-Version: ";
+       const char *charset_header = "Content-Type: text/plain; charset=";
+       const char *plural_header = "Plural-Forms: nplurals=";
+       struct po_xerror_handler handler = { xerror, xerror2 };
+       po_file_t src;
+       const char *file = argv[1];
+       po_message_iterator_t iter;
+       po_message_t msg;
+       struct strbuf buf = STRBUF_INIT;
+
+       if (argc != 3)
+               die("usage: test-poisongen <pot file> <poison po file>");
+
+       src = po_file_read(file, &handler);
+       if (src == NULL)
+               die("could not open %s\n", file);
+
+       iter = po_message_iterator(src, "messages");
+       while ((msg = po_next_message(iter)) != NULL) {
+               /* msgid "" is the header, special handling */
+               if (po_message_msgid(msg)[0] == '\0') {
+                       const char *p;
+
+                       /* no fuzzy, msgfmt does not like it */
+                       po_message_set_fuzzy(msg, 0);
+
+                       strbuf_reset(&buf);
+                       strbuf_addstr(&buf, po_message_msgstr(msg));
+
+                       if (!prefixcmp(buf.buf, project_header) &&
+                           !prefixcmp(buf.buf + strlen(project_header),
+                                      "PACKAGE VERSION\n")) {
+                               strbuf_splice(&buf, strlen(project_header),
+                                             strlen("PACKAGE VERSION"),
+                                             "git poison",
+                                             strlen("git poison"));
+                       }
+
+                       /* Content-Type: text/plain; charset=UTF-8 */
+                       if ((p = strstr(buf.buf, charset_header)) != NULL &&
+                           !prefixcmp(p + strlen(charset_header), 
"CHARSET\n")) {
+                               p += strlen(charset_header);
+                               strbuf_splice(&buf, p - buf.buf, 
strlen("CHARSET"),
+                                             "UTF-8", strlen("UTF-8"));
+                       }
+
+                       /* Plural-Forms: nplurals=2; plural=1 */
+                       if ((p = strstr(buf.buf, plural_header)) != NULL &&
+                           !prefixcmp(p + strlen(plural_header), "INTEGER; 
plural=EXPRESSION")) {
+                               int offset;
+                               p += strlen(plural_header);
+                               offset = p - buf.buf;
+                               strbuf_splice(&buf, offset, strlen("INTEGER"), 
"2", 1);
+                               offset += 1;
+                               assert(!prefixcmp(buf.buf + offset, "; 
plural=EXPRESSION"));
+                               offset += strlen("; plural=");
+                               strbuf_splice(&buf, offset, 
strlen("EXPRESSION"), "1", 1);
+                       }
+
+                       po_message_set_msgstr(msg, buf.buf);
+                       continue;
+               }
+               if (po_message_msgid_plural(msg)) {
+                       int index = 0;
+
+                       translate(po_message_msgid(msg), &buf);
+                       po_message_set_msgstr_plural(msg, index++, buf.buf);
+
+                       while (po_message_msgstr_plural(msg, index)) {
+                               translate(po_message_msgid_plural(msg), &buf);
+                               po_message_set_msgstr_plural(msg, index++, 
buf.buf);
+                       }
+               } else {
+                       translate(po_message_msgid(msg), &buf);
+                       po_message_set_msgstr(msg, buf.buf);
+               }
+       }
+
+       po_file_write(src, argv[2], &handler);
+       return 0;
+}
diff --git a/wrap-for-bin.sh b/wrap-for-bin.sh
old mode 100644
new mode 100755
index 53a8dd0..99bc816
--- a/wrap-for-bin.sh
+++ b/wrap-for-bin.sh
@@ -15,7 +15,11 @@ else
        export GIT_TEMPLATE_DIR
 fi
 GITPERLLIB='@@BUILD_DIR@@/perl/blib/lib'
-GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'
+if test -n "$GIT_POISON_LOCALE"; then
+       GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/poison-locale'
+else
+       GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'
+fi
 PATH='@@BUILD_DIR@@/bin-wrappers:'"$PATH"
 export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
 
-- 
1.7.12.rc2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to