From 93ac323c113731e82689e2cbd80ce674dae9a9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1igo=20Mart=C3=ADnez?= Date: Mon, 5 Jun 2017 16:46:36 +0200 Subject: [PATCH 2/3] Added support for plugin file generation with msgfmt. * gettext-tools/doc/msgfmt.texi: Filled information regarding plugin options. * gettext-tools/src/msgfmt.c: Added support for plugin file output. * tests/Makefile.am: Added msgfmt-plugin-1 file. * tests/msgfmt-plugin-1: A new test for plugin files based on Desktop test. --- gettext-tools/doc/msgfmt.texi | 56 ++++++++++++++ gettext-tools/src/msgfmt.c | 144 +++++++++++++++++++++++++++++++++--- gettext-tools/tests/Makefile.am | 1 + gettext-tools/tests/msgfmt-plugin-1 | 82 ++++++++++++++++++++ 4 files changed, 271 insertions(+), 12 deletions(-) create mode 100755 gettext-tools/tests/msgfmt-plugin-1 diff --git a/gettext-tools/doc/msgfmt.texi b/gettext-tools/doc/msgfmt.texi index 90350cb05..5cbf6be7c 100644 --- a/gettext-tools/doc/msgfmt.texi +++ b/gettext-tools/doc/msgfmt.texi @@ -70,6 +70,11 @@ Desktop Entry mode: generate a @file{.desktop} file. @cindex XML mode, and @code{msgfmt} program XML mode: generate an XML file. address@hidden --plugin address@hidden address@hidden, @code{msgfmt} option} address@hidden Plugin mode, and @code{msgfmt} program +Plugin mode: generate a @file{.plugin} file. + @end table @subsection Output file location @@ -272,6 +277,57 @@ variable. For either operation modes, the @samp{-o} and @samp{--template} options are mandatory. address@hidden Plugin mode operations + address@hidden @samp address@hidden address@hidden address@hidden address@hidden, @code{msgfmt} option} +Specify a .plugin file used as a template. + address@hidden address@hidden address@hidden address@hidden address@hidden address@hidden, @code{msgfmt} option} address@hidden address@hidden, @code{msgfmt} option} +Specify @var{keywordspec} as an additional keyword to be looked for. +Without a @var{keywordspec}, the option means to not use default keywords. + address@hidden -l @var{locale} address@hidden address@hidden address@hidden address@hidden, @code{msgfmt} option} address@hidden address@hidden, @code{msgfmt} option} +Specify the locale name, either a language specification of the form @var{ll} +or a combined language and country specification of the form @var{ll_CC}. + address@hidden -d @var{directory} address@hidden address@hidden, @code{msgfmt} option} +Specify the directory where PO files are read. The directory must +contain the @samp{LINGUAS} file. + address@hidden table + +To generate a @samp{.plugin} file for a single locale, you can use it +as follows. + address@hidden +msgfmt --plugin address@hidden address@hidden \ + -o @var{file} @var{filename}.po @dots{} address@hidden example + +msgfmt provides a special "bulk" operation mode to process multiple address@hidden files at a time. + address@hidden +msgfmt --plugin address@hidden -d @var{directory} -o @var{file} address@hidden example + +msgfmt first reads the @samp{LINGUAS} file under @var{directory}, and +then processes all @samp{.po} files listed there. You can also limit +the locales to a subset, through the @samp{LINGUAS} environment +variable. + +For either operation modes, the @samp{-o} and @samp{--template} +options are mandatory. + @subsection Input file syntax @table @samp diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c index 940121d44..274b058a8 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -125,6 +125,14 @@ static const char *xml_base_directory; static const char *xml_language; static its_rule_list_ty *xml_its_rules; +/* Plugin mode output file specification. */ +static bool plugin_mode; +static const char *plugin_locale_name; +static const char *plugin_template_name; +static const char *plugin_base_directory; +static hash_table plugin_keywords; +static bool plugin_default_keywords = true; + /* We may have more than one input file. Domains with same names in different files have to merged. So we need a list of tables for each output file. */ @@ -199,6 +207,7 @@ static const struct option long_options[] = { "locale", required_argument, NULL, 'l' }, { "no-hash", no_argument, NULL, CHAR_MAX + 6 }, { "output-file", required_argument, NULL, 'o' }, + { "plugin", no_argument, NULL, CHAR_MAX + 17 }, { "properties-input", no_argument, NULL, 'P' }, { "qt", no_argument, NULL, CHAR_MAX + 9 }, { "resource", required_argument, NULL, 'r' }, @@ -303,6 +312,7 @@ main (int argc, char *argv[]) tcl_base_directory = optarg; desktop_base_directory = optarg; xml_base_directory = optarg; + plugin_base_directory = optarg; break; case 'D': dir_list_append (optarg); @@ -318,7 +328,10 @@ main (int argc, char *argv[]) break; case 'k': if (optarg == NULL) - desktop_default_keywords = false; + { + desktop_default_keywords = false; + plugin_default_keywords = false; + } else { if (desktop_keywords.table == NULL) @@ -328,6 +341,14 @@ main (int argc, char *argv[]) } desktop_add_keyword (&desktop_keywords, optarg, false); + + if (plugin_keywords.table == NULL) + { + hash_init (&plugin_keywords, 100); + plugin_default_keywords = false; + } + + desktop_add_keyword (&plugin_keywords, optarg, false); } break; case 'l': @@ -336,6 +357,7 @@ main (int argc, char *argv[]) tcl_locale_name = optarg; desktop_locale_name = optarg; xml_locale_name = optarg; + plugin_locale_name = optarg; break; case 'L': xml_language = optarg; @@ -432,6 +454,10 @@ main (int argc, char *argv[]) case CHAR_MAX + 16: /* --template=TEMPLATE */ desktop_template_name = optarg; xml_template_name = optarg; + plugin_template_name = optarg; + break; + case CHAR_MAX + 17: /* --plugin */ + plugin_mode = true; break; default: usage (EXIT_FAILURE); @@ -460,18 +486,29 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Test whether we have a .po file name as argument. */ if (optind >= argc && !(desktop_mode && desktop_base_directory) - && !(xml_mode && xml_base_directory)) + && !(xml_mode && xml_base_directory) + && !(plugin_mode && plugin_base_directory)) { error (EXIT_SUCCESS, 0, _("no input file given")); usage (EXIT_FAILURE); } if (optind < argc && ((desktop_mode && desktop_base_directory) - || (xml_mode && xml_base_directory))) + || (xml_mode && xml_base_directory) + || (plugin_mode && plugin_base_directory))) { + static const char *mode; + + if (desktop_mode) + mode = "--desktop"; + else if (xml_mode) + mode = "--xml"; + else + mode = "--plugin"; + error (EXIT_SUCCESS, 0, _("no input file should be given if %s and %s are specified"), - desktop_mode ? "--desktop" : "--xml", "-d"); + mode, "-d"); usage (EXIT_FAILURE); } @@ -484,10 +521,11 @@ There is NO WARRANTY, to the extent permitted by law.\n\ | (tcl_mode ? 8 : 0) | (qt_mode ? 16 : 0) | (desktop_mode ? 32 : 0) - | (xml_mode ? 64 : 0); + | (xml_mode ? 64 : 0) + | (plugin_mode ? 128 : 0); static const char *mode_options[] = { "--java", "--csharp", "--csharp-resources", "--tcl", "--qt", - "--desktop", "--xml" }; + "--desktop", "--xml", "--plugin" }; /* More than one bit set? */ if (modes & (modes - 1)) { @@ -621,6 +659,34 @@ There is NO WARRANTY, to the extent permitted by law.\n\ usage (EXIT_FAILURE); } } + else if (plugin_mode) + { + if (plugin_template_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"--template template\" specification"), + "--plugin"); + usage (EXIT_FAILURE); + } + if (output_file_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"-o file\" specification"), + "--plugin"); + usage (EXIT_FAILURE); + } + if (plugin_base_directory != NULL && plugin_locale_name != NULL) + error (EXIT_FAILURE, 0, + _("%s and %s are mutually exclusive in %s"), + "-d", "-l", "--plugin"); + if (plugin_base_directory == NULL && plugin_locale_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"-l locale\" specification"), + "--plugin"); + usage (EXIT_FAILURE); + } + } else { if (java_resource_name != NULL) @@ -725,6 +791,27 @@ There is NO WARRANTY, to the extent permitted by law.\n\ exit (exit_status); } + if (plugin_mode && plugin_default_keywords) + { + if (plugin_keywords.table == NULL) + hash_init (&plugin_keywords, 100); + desktop_add_keyword (&plugin_keywords, "Name", false); + desktop_add_keyword (&plugin_keywords, "Description", false); + } + + /* Bulk processing mode for .plugin files. + Process all .po files in plugin_base_directory. */ + if (plugin_mode && plugin_base_directory) + { + exit_status = msgfmt_desktop_bulk (plugin_base_directory, + plugin_template_name, + &plugin_keywords, + output_file_name); + if (plugin_keywords.table != NULL) + hash_destroy (&plugin_keywords); + exit (exit_status); + } + /* The -o option determines the name of the domain and therefore the output file. */ if (output_file_name != NULL) @@ -839,6 +926,18 @@ There is NO WARRANTY, to the extent permitted by law.\n\ domain->file_name)) exit_status = EXIT_FAILURE; } + else if (plugin_mode) + { + if (msgdomain_write_desktop (domain->mlp, canon_encoding, + plugin_locale_name, + plugin_template_name, + &plugin_keywords, + domain->file_name)) + exit_status = EXIT_FAILURE; + + if (plugin_keywords.table != NULL) + hash_destroy (&plugin_keywords); + } else { if (msgdomain_write_mo (domain->mlp, domain->domain_name, @@ -946,6 +1045,8 @@ Operation mode:\n")); --desktop Desktop Entry mode: generate a .desktop file\n")); printf (_("\ --xml XML mode: generate XML file\n")); + printf (_("\ + --plugin Plugin mode: generate a .plugin file\n")); printf ("\n"); printf (_("\ Output file location:\n")); @@ -1028,6 +1129,23 @@ The -l, -o, and --template options are mandatory. If -D is specified, input\n\ files are read from the directory instead of the command line arguments.\n")); printf ("\n"); printf (_("\ +Plugin mode options:\n")); + printf (_("\ + -l, --locale=LOCALE locale name, either language or language_COUNTRY\n")); + printf (_("\ + -o, --output-file=FILE write output to specified file\n")); + printf (_("\ + --template=TEMPLATE a .desktop file used as a template\n")); + printf (_("\ + -d DIRECTORY base directory of .po files\n")); + printf (_("\ + -kWORD, --keyword=WORD look for WORD as an additional keyword\n\ + -k, --keyword do not to use default keywords\n")); + printf (_("\ +The -l, -o, and --template options are mandatory. If -D is specified, input\n\ +files are read from the directory instead of the command line arguments.\n")); + printf ("\n"); + printf (_("\ Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); @@ -1215,7 +1333,8 @@ msgfmt_set_domain (default_catalog_reader_ty *this, char *name) /* If no output file was given, we change it with each 'domain' directive. */ if (!java_mode && !csharp_mode && !csharp_resources_mode && !tcl_mode - && !qt_mode && !desktop_mode && !xml_mode && output_file_name == NULL) + && !qt_mode && !desktop_mode && !xml_mode && plugin_mode + && output_file_name == NULL) { size_t correct; @@ -1638,10 +1757,11 @@ msgfmt_operand_list_add_from_directory (msgfmt_operand_list_ty *operands, return retval; } -/* Helper function to support 'bulk' operation mode of --desktop. - This reads all .po files in DIRECTORY and merges them into a - .desktop file FILE_NAME. Currently it does not support some - options available in 'iterative' mode, such as --statistics. */ +/* Helper function to support 'bulk' operation mode of --desktop + and --plugin. This reads all .po files in DIRECTORY and merges + them into a .desktop or .plugin file FILE_NAME. Currently it + does not support some options available in 'iterative' mode, + such as --statistics. */ static int msgfmt_desktop_bulk (const char *directory, const char *template_file_name, @@ -1661,7 +1781,7 @@ msgfmt_desktop_bulk (const char *directory, return 1; } - /* Write the messages into .desktop file. */ + /* Write the messages into .desktop or .plugin file. */ status = msgdomain_write_desktop_bulk (&operands, template_file_name, keywords, diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index f50509a6a..3a9c2fa36 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -51,6 +51,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ msgfmt-qt-1 msgfmt-qt-2 \ msgfmt-desktop-1 msgfmt-desktop-2 \ msgfmt-xml-1 msgfmt-xml-2 \ + msgfmt-plugin-1 \ msggrep-1 msggrep-2 msggrep-3 msggrep-4 msggrep-5 msggrep-6 msggrep-7 \ msggrep-8 msggrep-9 msggrep-10 msggrep-11 \ msginit-1 msginit-2 msginit-3 msginit-4 \ diff --git a/gettext-tools/tests/msgfmt-plugin-1 b/gettext-tools/tests/msgfmt-plugin-1 new file mode 100755 index 000000000..4b4221203 --- /dev/null +++ b/gettext-tools/tests/msgfmt-plugin-1 @@ -0,0 +1,82 @@ +#! /bin/sh +. "${srcdir=.}/init.sh"; path_prepend_ . ../src + +# Test iterative mode of msgfmt --plugin. + +cat <<\EOF > mf.plugin +[Plugin] +Module=helloworld +Depends=foo;bar;baz +Loader=C +Name =Foo +Description[foo]=Already translated description +Description= \sThis is a \nmultiline description; for testing +EOF + +cat <<\EOF > fr.po +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-05 18:00+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: mf.plugin:7 +msgid "Foo" +msgstr "" +"French\n" +"foo" + +#: mf.plugin:9 +msgid "" +" This is a \n" +"multiline description; for testing" +msgstr "" +"French \n" +"description" +EOF + +cat <<\EOF > mf.plugin.ok +[Plugin] +Module=helloworld +Depends=foo;bar;baz +Loader=C +Name[fr]=French\nfoo +Name=Foo +Description[foo]=Already translated description +Description[fr]=French \ndescription +Description=\sThis is a \nmultiline description; for testing +EOF + +# Sanity checks for contradicting options. + +${MSGFMT} --plugin --template=mf.plugin -l fr fr.po \ + >/dev/null 2>/dev/null \ + && Exit 1 + +${MSGFMG} --plugin --template=mf.plugin fr.po -o mf.plugin.out \ + >/dev/null 2>/dev/null \ + && Exit 1 + +# Proceed to the .plugin file generation. + +${MSGFMT} --plugin --template=mf.plugin -l fr fr.po -o mf.plugin.out \ + || Exit 1 + +: ${DIFF=diff} +${DIFF} mf.plugin.ok mf.plugin.out +result=$? + +exit $result -- 2.11.0