From 4fcef5686c4807721c5e8536db542293ee8d804e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1igo=20Mart=C3=ADnez?= Date: Tue, 6 Jun 2017 11:43:02 +0200 Subject: [PATCH 1/3] Added support for plugin file string extraction in xgettext. * gettext-tools/doc/xgettext.texi: Filled information regarding plugin options. * gettext-tools/src/Makefile.am: Added x-plugin.c and x-plugin.h files. * gettext-tools/src/x-desktop.c: Removed static keyword for extract methods not using static variables that can be shared. * gettext-tools/src/x-desktop.h: Exposed extract methods and the reader structure to be shared among Desktop Entry like files. * gettext-tools/src/x-plugin.c: Support for plugin files. * gettext-tools/src/x-plugin.h: Exposed extract method for plugin files. * gettext-tools/src/xgettext.c: Added support for plugin backend. * tests/Makefile.am: Added xgettext-plugin-1 file. * tests/xgettext-plugin-1: A new test for plugin files based on Desktop test. --- gettext-tools/doc/xgettext.texi | 7 +- gettext-tools/src/Makefile.am | 4 +- gettext-tools/src/x-desktop.c | 14 +--- gettext-tools/src/x-desktop.h | 19 +++++ gettext-tools/src/x-plugin.c | 150 ++++++++++++++++++++++++++++++++++ gettext-tools/src/x-plugin.h | 47 +++++++++++ gettext-tools/src/xgettext.c | 8 +- gettext-tools/tests/Makefile.am | 1 + gettext-tools/tests/xgettext-plugin-1 | 95 +++++++++++++++++++++ 9 files changed, 328 insertions(+), 17 deletions(-) create mode 100644 gettext-tools/src/x-plugin.c create mode 100644 gettext-tools/src/x-plugin.h create mode 100755 gettext-tools/tests/xgettext-plugin-1 diff --git a/gettext-tools/doc/xgettext.texi b/gettext-tools/doc/xgettext.texi index e2700d9f5..84bcb849d 100644 --- a/gettext-tools/doc/xgettext.texi +++ b/gettext-tools/doc/xgettext.texi @@ -74,7 +74,7 @@ are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, @code{Shell}, @code{Smalltalk}, @code{Java}, @code{JavaProperties}, @code{C#}, @code{awk}, @code{YCP}, @code{Tcl}, @code{Perl}, @code{PHP}, @code{GCC-source}, @code{NXStringTable}, @code{RST}, @code{Glade}, @code{Lua}, @code{JavaScript}, address@hidden, @code{GSettings}, @code{Desktop}. address@hidden, @code{GSettings}, @code{Desktop}, @code{Plugin}. @item -C @itemx --c++ @@ -257,7 +257,7 @@ escaped. This option has an effect with most languages, namely C, C++, ObjectiveC, Shell, Python, Lisp, EmacsLisp, librep, Java, C#, awk, Tcl, Perl, PHP, -GCC-source, Glade, Lua, JavaScript, Vala, GSettings, Desktop. +GCC-source, Glade, Lua, JavaScript, Vala, GSettings, Desktop, Plugin. The default keyword specifications, which are always looked for if not explicitly disabled, are language dependent. They are: @@ -341,6 +341,9 @@ For Vala: @code{_}, @code{Q_}, @code{N_}, @code{NC_}, @code{dgettext:2}, @item For Desktop: @code{Name}, @code{GenericName}, @code{Comment}, @code{Icon}, @code{Keywords}. + address@hidden +For Plugin: @code{Name}, @code{Description}. @end itemize To disable the default keyword specifications, the option @samp{-k} or diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 764afd13a..bf1c7a0df 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -55,7 +55,7 @@ po-time.h plural-table.h lang-table.h format.h filters.h \ xgettext.h x-c.h x-po.h x-sh.h x-python.h x-lisp.h x-elisp.h x-librep.h \ x-scheme.h x-smalltalk.h x-java.h x-properties.h x-csharp.h x-awk.h x-ycp.h \ x-tcl.h x-perl.h x-php.h x-stringtable.h x-rst.h x-glade.h x-lua.h \ -x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h +x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h x-plugin.h EXTRA_DIST += FILES project-id @@ -180,7 +180,7 @@ xgettext_SOURCES += \ x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \ x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \ x-rst.c x-lua.c x-javascript.c x-vala.c \ - x-desktop.c + x-desktop.c x-plugin.c if !WOE32DLL msgattrib_SOURCES = msgattrib.c else diff --git a/gettext-tools/src/x-desktop.c b/gettext-tools/src/x-desktop.c index 3f382ff50..862965f17 100644 --- a/gettext-tools/src/x-desktop.c +++ b/gettext-tools/src/x-desktop.c @@ -92,15 +92,7 @@ init_keywords (void) } } -typedef struct extract_desktop_reader_ty extract_desktop_reader_ty; -struct extract_desktop_reader_ty -{ - DESKTOP_READER_TY - - message_list_ty *mlp; -}; - -static void +void extract_desktop_handle_group (struct desktop_reader_ty *reader, const char *group) { @@ -131,7 +123,7 @@ extract_desktop_handle_pair (struct desktop_reader_ty *reader, savable_comment_reset (); } -static void +void extract_desktop_handle_comment (struct desktop_reader_ty *reader, const char *buffer) { @@ -153,7 +145,7 @@ extract_desktop_handle_comment (struct desktop_reader_ty *reader, } } -static void +void extract_desktop_handle_blank (struct desktop_reader_ty *reader, const char *s) { diff --git a/gettext-tools/src/x-desktop.h b/gettext-tools/src/x-desktop.h index 4a820e5dd..194277855 100644 --- a/gettext-tools/src/x-desktop.h +++ b/gettext-tools/src/x-desktop.h @@ -20,6 +20,7 @@ #include "message.h" #include "xgettext.h" +#include "read-desktop.h" #ifdef __cplusplus @@ -33,6 +34,15 @@ extern "C" { #define SCANNERS_DESKTOP \ { "Desktop", extract_desktop, NULL, NULL, NULL, NULL }, \ +/* Desktop Entry like file reader. */ +typedef struct extract_desktop_reader_ty extract_desktop_reader_ty; +struct extract_desktop_reader_ty +{ + DESKTOP_READER_TY + + message_list_ty *mlp; +}; + /* Scan a Desktop Entry file and add its translatable strings to mdlp. */ extern void extract_desktop (FILE *fp, const char *real_filename, const char *logical_filename, @@ -41,6 +51,15 @@ extern void extract_desktop (FILE *fp, const char *real_filename, extern void x_desktop_keyword (const char *keyword); +/* Handle Group from a Desktop Entry like file. */ +extern void extract_desktop_handle_group (struct desktop_reader_ty *reader, + const char *group); +/* Handle comments from a Desktop Entry like file. */ +extern void extract_desktop_handle_comment (struct desktop_reader_ty *reader, + const char *buffer); +/* Handle blanks from a Desktop Entry like file. */ +extern void extract_desktop_handle_blank (struct desktop_reader_ty *reader, + const char *s); #ifdef __cplusplus } diff --git a/gettext-tools/src/x-plugin.c b/gettext-tools/src/x-plugin.c new file mode 100644 index 000000000..ca92adefb --- /dev/null +++ b/gettext-tools/src/x-plugin.c @@ -0,0 +1,150 @@ +/* xgettext Desktop Entry backend. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + + This file was written by Iñigo Martínez , 2017. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Specification. */ +#include "x-plugin.h" +#include "x-desktop.h" + +#include +#include +#include +#include +#include + +#include "message.h" +#include "xgettext.h" +#include "error.h" +#include "error-progname.h" +#include "xalloc.h" +#include "xvasprintf.h" +#include "hash.h" +#include "gettext.h" +#include "read-desktop.h" +#include "po-charset.h" + +/* ====================== Keyword set customization. ====================== */ + +/* The syntax of libpeas Plugin file is a Desktop Entry variant with a + custom set of keys. It is defined at + https://git.gnome.org/browse/libpeas/tree/libpeas/peas-plugin-info.c + + The syntax of a Desktop Entry file is defined at + http://standards.freedesktop.org/desktop-entry-spec/latest/index.html + + Basically, values with 'localestring' type can be translated. + + The type of a value is determined by looking at the key associated + with it. The list of available keys are listed on: + http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s05.html */ + +static hash_table keywords; +static bool default_keywords = true; + +static void +add_keyword (const char *name, hash_table *keywords, bool is_list) +{ + if (name == NULL) + default_keywords = false; + else + { + if (keywords->table == NULL) + hash_init (keywords, 100); + + desktop_add_keyword (keywords, name, is_list); + } +} + +void +x_plugin_keyword (const char *name) +{ + add_keyword (name, &keywords, false); +} + +static void +init_keywords (void) +{ + if (default_keywords) + { + if (keywords.table == NULL) + hash_init (&keywords, 100); + + desktop_add_keyword (&keywords, "Name", false); + desktop_add_keyword (&keywords, "Description", false); + default_keywords = false; + } +} + +static void +extract_plugin_handle_pair (struct desktop_reader_ty *reader, + lex_pos_ty *key_pos, + const char *key, + const char *locale, + const char *value) +{ + extract_desktop_reader_ty *extract_reader = + (extract_desktop_reader_ty *) reader; + void *keyword_value; + + if (!locale /* Skip already translated entry. */ + && hash_find_entry (&keywords, key, strlen (key), &keyword_value) == 0) + { + bool is_list = (bool) keyword_value; + + remember_a_message (extract_reader->mlp, NULL, + desktop_unescape_string (value, is_list), + null_context, key_pos, + NULL, savable_comment); + } + savable_comment_reset (); +} + +desktop_reader_class_ty extract_plugin_methods = + { + sizeof (extract_desktop_reader_ty), + NULL, + NULL, + extract_desktop_handle_group, + extract_plugin_handle_pair, + extract_desktop_handle_comment, + extract_desktop_handle_blank + }; + +void +extract_plugin (FILE *f, + const char *real_filename, const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp) +{ + desktop_reader_ty *reader = desktop_reader_alloc (&extract_plugin_methods); + extract_desktop_reader_ty *extract_reader = + (extract_desktop_reader_ty *) reader; + + init_keywords (); + xgettext_current_source_encoding = po_charset_utf8; + + extract_reader->mlp = mdlp->item[0]->messages; + + desktop_parse (reader, f, real_filename, logical_filename); + desktop_reader_free (reader); + + reader = NULL; +} diff --git a/gettext-tools/src/x-plugin.h b/gettext-tools/src/x-plugin.h new file mode 100644 index 000000000..548ba3d30 --- /dev/null +++ b/gettext-tools/src/x-plugin.h @@ -0,0 +1,47 @@ +/* xgettext plugin backend. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + Written by Iñigo Martínez , 2017. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include + +#include "message.h" +#include "xgettext.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define EXTENSIONS_PLUGIN \ + { "plugin", "Plugin" }, \ + +#define SCANNERS_PLUGIN \ + { "Plugin", extract_plugin, NULL, NULL, NULL, NULL }, \ + +/* Scan a Plugin file and add its translatable strings to mdlp. */ +extern void extract_plugin (FILE *fp, const char *real_filename, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp); + +extern void x_plugin_keyword (const char *keyword); + + +#ifdef __cplusplus +} +#endif diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index a80ee51ac..5f24dc8ad 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -106,6 +106,7 @@ #include "x-vala.h" #include "x-gsettings.h" #include "x-desktop.h" +#include "x-plugin.h" #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) @@ -487,6 +488,7 @@ main (int argc, char *argv[]) x_javascript_keyword (optarg); x_vala_keyword (optarg); x_desktop_keyword (optarg); + x_plugin_keyword (optarg); if (optarg == NULL) no_default_keywords = true; else @@ -1080,7 +1082,7 @@ Choice of input file language:\n")); EmacsLisp, librep, Scheme, Smalltalk, Java,\n\ JavaProperties, C#, awk, YCP, Tcl, Perl, PHP,\n\ GCC-source, NXStringTable, RST, Glade, Lua,\n\ - JavaScript, Vala, Desktop)\n")); + JavaScript, Vala, Desktop, Plugin)\n")); printf (_("\ -C, --c++ shorthand for --language=C++\n")); printf (_("\ @@ -1130,7 +1132,7 @@ Language specific options:\n")); (only languages C, C++, ObjectiveC, Shell,\n\ Python, Lisp, EmacsLisp, librep, Scheme, Java,\n\ C#, awk, Tcl, Perl, PHP, GCC-source, Glade,\n\ - Lua, JavaScript, Vala, Desktop)\n")); + Lua, JavaScript, Vala, Desktop, Plugin)\n")); printf (_("\ --flag=WORD:ARG:FLAG additional flag for strings inside the argument\n\ number ARG of keyword WORD\n")); @@ -3904,6 +3906,7 @@ language_to_extractor (const char *name) SCANNERS_GSETTINGS SCANNERS_DESKTOP SCANNERS_APPDATA + SCANNERS_PLUGIN /* Here may follow more languages and their scanners: pike, etc... Make sure new scanners honor the --exclude-file option. */ }; @@ -3995,6 +3998,7 @@ extension_to_language (const char *extension) EXTENSIONS_GSETTINGS EXTENSIONS_DESKTOP EXTENSIONS_APPDATA + EXTENSIONS_PLUGIN /* Here may follow more file extensions... */ }; diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index 38b47b922..f50509a6a 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -114,6 +114,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ xgettext-gsettings-1 \ xgettext-desktop-1 \ xgettext-its-1 xgettext-its-2 \ + xgettext-plugin-1 \ format-awk-1 format-awk-2 \ format-boost-1 format-boost-2 \ format-c-1 format-c-2 format-c-3 format-c-4 format-c-5 \ diff --git a/gettext-tools/tests/xgettext-plugin-1 b/gettext-tools/tests/xgettext-plugin-1 new file mode 100755 index 000000000..141488b1b --- /dev/null +++ b/gettext-tools/tests/xgettext-plugin-1 @@ -0,0 +1,95 @@ +#!/bin/sh +. "${srcdir=.}/init.sh"; path_prepend_ . ../src + +# Test of Plugin support. + +: ${XGETTEXT=xgettext} + +cat <<\EOF >err1.plugin +[Plugin] +This is an invalid line +Name =Foo +EOF + +(LANGUAGE= LC_ALL=C ${XGETTEXT} --add-comments -o - err1.plugin 2>&1; exit) | grep "missing '=' after" || Exit 1 + +cat <<\EOF >err2.plugin +[Plugin +EOF + +(LANGUAGE= LC_ALL=C ${XGETTEXT} --add-comments -o - err2.plugin 2>&1; exit) | grep "unterminated group name" || Exit 1 + +cat <<\EOF >err3.plugin +[Plugin] + Not a blank line! +EOF + +(LANGUAGE= LC_ALL=C ${XGETTEXT} --add-comments -o - err3.plugin 2>&1; exit) | grep "invalid non-blank line" || Exit 1 + +cat <<\EOF >err4.plugin +[Plugin]a +EOF + +(LANGUAGE= LC_ALL=C ${XGETTEXT} --add-comments -o - err4.plugin 2>&1; exit) | grep "invalid non-blank character" || Exit 1 + +# gettext 0.19.4 issued an baseless warning of this. +cat <<\EOF >ok4.plugin +[Plugin] +EOF + +(LANGUAGE= LC_ALL=C ${XGETTEXT} --add-comments -o - ok4.plugin 2>&1; exit) | grep "invalid non-blank character" && Exit 1 + +cat <<\EOF > xg.plugin +[Plugin] +Module=helloworld +Loader=C +Name =Foo +# This is a comment for description +# This is a comment for description +Description= \sThis is a \nmultiline\t description; for testing +Description[foo]=Already translated description +Copyright = Copyright (C) 1995-1998, 2000-2016 Free Software Foundation, Inc. +# This is a comment before a blank line + +Website=https://wiki.gnome.org/Projects/Libpeas +EOF + +${XGETTEXT} --add-comments -o - xg.plugin | grep -v 'POT-Creation-Date' > xg-plugin.pot || Exit 1 + +cat <<\EOF > xg-plugin.ok +# 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" +"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=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: xg.plugin:5 +msgid "Foo" +msgstr "" + +#. This is a comment for description +#. This is a comment for description +#: xg.desktop:8 +msgid "" +" This is a \n" +"multiline\t description; for testing" +msgstr "" +EOF + +: ${DIFF=diff} +${DIFF} xg-plugin.ok xg-plugin.pot +result=$? + +exit $result -- 2.11.0