* Glade:: Glade - GNOME user interface description
* GSettings:: GSettings - GNOME user configuration schema
* AppData:: AppData - freedesktop.org application description
-* XML:: XML - Generic XML files
+* Preparing ITS Rules:: Preparing Rules for XML Internationalization
Concluding Remarks
* Glade:: Glade - GNOME user interface description
* GSettings:: GSettings - GNOME user configuration schema
* AppData:: AppData - freedesktop.org application description
-* XML:: XML - Generic XML files
+* Preparing ITS Rules:: Preparing Rules for XML Internationalization
@end menu
@node POT, RST, List of Data Formats, List of Data Formats
@code{xgettext}, @code{intltool-extract}
@end table
-@node AppData, XML, GSettings, List of Data Formats
+@node AppData, Preparing ITS Rules, GSettings, List of Data Formats
@subsection AppData - freedesktop.org application description
@table @asis
@code{xgettext}, @code{intltool-extract}, @code{itstool}
@end table
-@node XML, , AppData, List of Data Formats
-@subsection XML - Generic XML files
-
-@table @asis
-@item RPMs
-
-@item File extension
-@code{xml}, or anything else
-
-@item Extractor
-@code{xgettext}, @code{itstool}
-@end table
-
@menu
-* Preparing ITS Rules:: Preparing Rules for XML Internationalization
@end menu
-@node Preparing ITS Rules, , XML, XML
-@subsubsection Preparing Rules for XML Internationalization
+@node Preparing ITS Rules, , AppData, List of Data Formats
+@subsection Preparing Rules for XML Internationalization
@cindex preparing rules for XML translation
Marking translatable strings in an XML file is done with a separate
categories are: @samp{Translate}, @samp{Localization Note},
@samp{Elements Within Text}, and @samp{Preserve Space}.
-For example, given the following XML document:
+For example, given the following XML document in a file
+@file{messages.xml}:
@example
<?xml version="1.0"?>
</its:rules>
@end example
-@samp{xgettext} uses another file called "locating rule" to associate an
-ITS rule with an XML file. For example, if the above XML file is saved
-as @file{messages.xml} and the corresponding ITS file is saved as
-@file{messages.its}, the locating rule would look like the following.
+@samp{xgettext} needs another file called "locating rule" to associate
+an ITS rule with an XML file. For example, if the above ITS file is
+saved as @file{messages.its}, the locating rule would look like:
@example
<?xml version="1.0"?>
<locatingRules>
- <locatingRule pattern="*.xml">
+ <locatingRule language="Messages" pattern="*.xml">
<documentRule localName="messages" target="messages.its"/>
</locatingRule>
- <locatingRule pattern="*.msg" target="messages.its"/>
+ <locatingRule language="Messages" pattern="*.msg" target="messages.its"/>
</locatingRules>
@end example
which denotes either a literal file name or a wildcard pattern of the
XML file. The @code{locatingRule} element can have child
@code{documentRule} element, which adds checks on the content of the XML
-file. The first rule matches any file with the @file{.xml} file
-extension, but only applies to XML files whose root node is
-@samp{<messages>}.
+file.
+
+The first rule matches any file with the @file{.xml} file extension, but
+it only applies to XML files whose root element is @samp{<messages>}.
The second rule also allows any file with the @file{.msg} file extension
-to be handled with the same ITS rule file.
+to be handled with the same ITS rule file. The optional @code{language}
+attribute of @code{locatingRule} allows @code{xgettext} to choose rules
+with @code{-L} option, instead of the file name matching.
-The associated ITS file is indicated by @code{target} attribute of
+The associated ITS file is indicated by the @code{target} attribute of
@code{locatingRule} or @code{documentRule}.
-Locating rule file must have the @file{.loc} file extension. Both ITS
+Locating rule files must have the @file{.loc} file extension. Both ITS
rule files and locating rule files must be installed in the
-@file{GETTEXTDATADIR/its} directory, where @code{GETTEXTDATADIR} is the
-gettext data directory (typically @file{/usr/share/gettext}).
+@file{$prefix/share/gettext/its} directory.
-Once those files are properly installed, extracting translatable strings
-with @code{xgettext} is done through @code{--its} option.
+Once those files are properly installed, @code{xgettext} can extract
+translatable strings from the matching XML files.
@c This is the template for new data formats.
@ignore
xmlNode *node,
const char *logical_filename,
flag_context_list_table_ty *flag_table,
- message_list_ty *mlp)
+ message_list_ty *mlp,
+ its_extract_callback_ty callback)
{
if (node->type == XML_ELEMENT_NODE
|| node->type == XML_ATTRIBUTE_NODE)
free (values);
content = _its_collect_text_content (node, whitespace);
- if (*content == '\0')
- free (content);
- else
+ if (*content != '\0')
{
lex_pos_ty pos;
message_ty *message;
- char *dot;
+ char *marker;
pos.file_name = xstrdup (logical_filename);
pos.line_number = xmlGetLineNo (node);
- message = remember_a_message (mlp, NULL,
- content,
- null_context, &pos,
- comment, NULL);
- if (whitespace == preserve)
- message->do_wrap = no;
-
if (node->type == XML_ELEMENT_NODE)
{
assert (node->parent);
- dot = xasprintf ("(itstool) path: %s/%s",
- node->parent->name,
- node->name);
+ marker = xasprintf ("%s/%s", node->parent->name, node->name);
}
else
{
assert (node->parent && node->parent->parent);
- dot = xasprintf ("(itstool) path: %s/%s@%s",
- node->parent->parent->name,
- node->parent->name,
- node->name);
+ marker = xasprintf ("%s/%s@%s",
+ node->parent->parent->name,
+ node->parent->name,
+ node->name);
}
- message_comment_dot_append (message, dot);
- free (dot);
+
+ message = callback (mlp, content, &pos, comment, marker);
+ free (marker);
+
+ if (whitespace == preserve)
+ message->do_wrap = no;
}
+ free (content);
free (comment);
}
}
FILE *fp, const char *real_filename,
const char *logical_filename,
flag_context_list_table_ty *flag_table,
- msgdomain_list_ty *mdlp)
+ msgdomain_list_ty *mdlp,
+ its_extract_callback_ty callback)
{
xmlDoc *doc;
struct its_node_list_ty nodes;
its_rule_list_extract_text (rules, nodes.items[i],
logical_filename,
flag_table,
- mdlp->item[0]->messages);
+ mdlp->item[0]->messages,
+ callback);
free (nodes.items);
xmlFreeDoc (doc);
typedef struct its_rule_list_ty its_rule_list_ty;
+typedef message_ty * (*its_extract_callback_ty) (message_list_ty *mlp,
+ const char *msgid,
+ lex_pos_ty *pos,
+ const char *extracted_comment,
+ const char *marker);
+
/* Creates a fresh its_rule_list_ty holding global ITS rules. */
extern its_rule_list_ty *its_rule_list_alloc (void);
FILE *fp, const char *real_filename,
const char *logical_filename,
flag_context_list_table_ty *flag_table,
- msgdomain_list_ty *mdlp);
+ msgdomain_list_ty *mdlp,
+ its_extract_callback_ty callback);
#ifdef __cplusplus
}
struct locating_rule_ty
{
char *pattern;
+ char *language;
struct document_locating_rule_list_ty doc_rules;
char *target;
static const char *
locating_rule_match (struct locating_rule_ty *rule,
- const char *filename)
+ const char *filename,
+ const char *language)
{
- if (fnmatch (rule->pattern, filename, FNM_PATHNAME) != 0)
+ if (language == NULL && fnmatch (rule->pattern, filename, FNM_PATHNAME) != 0)
+ return NULL;
+
+ if (language != NULL
+ && (rule->language == NULL || strcmp (language, rule->language) != 0))
return NULL;
if (rule->target != NULL)
const char *
locating_rule_list_locate (struct locating_rule_list_ty *rules,
- const char *path)
+ const char *filename,
+ const char *language)
{
const char *target = NULL;
size_t i;
for (i = 0; i < rules->nitems; i++)
{
- target = locating_rule_match (&rules->items[i], path);
+ target = locating_rule_match (&rules->items[i], filename, language);
if (target != NULL)
return target;
}
for (i = 0; i < rule->doc_rules.nitems; i++)
document_locating_rule_destroy (&rule->doc_rules.items[i]);
+ free (rule->language);
free (rule->pattern);
free (rule->target);
}
memset (&rule, 0, sizeof (struct locating_rule_ty));
rule.pattern = get_attribute (node, "pattern");
+ if (xmlHasProp (node, BAD_CAST "language"))
+ rule.language = get_attribute (node, "language");
if (xmlHasProp (node, BAD_CAST "target"))
rule.target = get_attribute (node, "target");
else
locating_rule_list_add_directory (locating_rule_list_ty *rules,
const char *directory);
-/* Determines the location of resource associated with PATH, accoding
- to the loaded locating rules. */
+/* Determines the location of resource associated with FILENAME,
+ accoding to the loaded locating rules. */
extern const char *locating_rule_list_locate (locating_rule_list_ty *rules,
- const char *path);
+ const char *filename,
+ const char *language);
/* Releases memory allocated for RULES. */
extern void locating_rule_list_free (locating_rule_list_ty *rules);
/* A convenience macro. I don't like writing gettext() every time. */
#define _(str) gettext (str)
-#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
-
#include "x-c.h"
#include "x-po.h"
#include "x-desktop.h"
+#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
+#define ENDOF(a) ((a) + SIZEOF(a))
+
+
/* If nonzero add all comments immediately preceding one of the keywords. */
static bool add_all_comments = false;
static locating_rule_list_ty *its_locating_rules;
+/* If nonzero add comments used by itstool. */
+static bool add_itstool_comments = false;
+
/* Long options. */
static const struct option long_options[] =
{
{ "from-code", required_argument, NULL, CHAR_MAX + 3 },
{ "help", no_argument, NULL, 'h' },
{ "indent", no_argument, NULL, 'i' },
- { "its", no_argument, NULL, CHAR_MAX + 19 },
+ { "itstool", no_argument, NULL, CHAR_MAX + 19 },
{ "join-existing", no_argument, NULL, 'j' },
{ "kde", no_argument, NULL, CHAR_MAX + 10 },
{ "keyword", optional_argument, NULL, 'k' },
bool some_additional_keywords = false;
bool sort_by_msgid = false;
bool sort_by_filepos = false;
- bool its = false;
char *its_dirs[2] = { NULL, NULL };
const char *file_name;
const char *files_from = NULL;
x_tcl_extract_all ();
x_perl_extract_all ();
x_php_extract_all ();
- x_glade_extract_all ();
x_lua_extract_all ();
x_javascript_extract_all ();
x_vala_extract_all ();
x_tcl_keyword (optarg);
x_perl_keyword (optarg);
x_php_keyword (optarg);
- x_glade_keyword (optarg);
x_lua_keyword (optarg);
x_javascript_keyword (optarg);
x_vala_keyword (optarg);
error (EXIT_FAILURE, 0, _("sentence end type '%s' unknown"), optarg);
break;
- case CHAR_MAX + 19: /* --its */
- its = true;
+ case CHAR_MAX + 19: /* --itstool */
+ add_itstool_comments = true;
break;
default:
usage (EXIT_FAILURE);
}
- if (its)
- {
- const char *gettextdatadir;
- char *versioned_gettextdatadir;
-
- /* Make it possible to override the locator file location. This
- is necessary for running the testsuite before "make
- install". */
- gettextdatadir = getenv ("GETTEXTDATADIR");
- if (gettextdatadir == NULL || gettextdatadir[0] == '\0')
- gettextdatadir = relocate (GETTEXTDATADIR);
-
- its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL);
-
- versioned_gettextdatadir =
- xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX);
- its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its",
- NULL);
- free (versioned_gettextdatadir);
-
- its_locating_rules = locating_rule_list_alloc ();
- for (i = 0; i < SIZEOF (its_dirs); i++)
- locating_rule_list_add_directory (its_locating_rules, its_dirs[i]);
- }
+ {
+ const char *gettextdatadir;
+ char *versioned_gettextdatadir;
+
+ /* Make it possible to override the locator file location. This
+ is necessary for running the testsuite before "make
+ install". */
+ gettextdatadir = getenv ("GETTEXTDATADIR");
+ if (gettextdatadir == NULL || gettextdatadir[0] == '\0')
+ gettextdatadir = relocate (GETTEXTDATADIR);
+
+ its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL);
+
+ versioned_gettextdatadir =
+ xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX);
+ its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its",
+ NULL);
+ free (versioned_gettextdatadir);
+
+ its_locating_rules = locating_rule_list_alloc ();
+ for (i = 0; i < SIZEOF (its_dirs); i++)
+ locating_rule_list_add_directory (its_locating_rules, its_dirs[i]);
+ }
/* Determine extractor from language. */
if (language != NULL)
if (language == NULL && its_locating_rules != NULL)
{
const char *its_basename =
- locating_rule_list_locate (its_locating_rules, filename);
+ locating_rule_list_locate (its_locating_rules, filename,
+ language);
if (its_basename != NULL)
{
size_t j;
printf (_("\
(only language C++)\n"));
printf (_("\
- --its extract from XML file using ITS rules\n"));
- printf (_("\
- (only XML files)\n"));
- printf (_("\
--debug more detailed formatstring recognition result\n"));
printf ("\n");
printf (_("\
printf (_("\
--stringtable-output write out a NeXTstep/GNUstep .strings file\n"));
printf (_("\
+ --itstool write out itstool comments\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
free (real_file_name);
}
+static message_ty *
+xgettext_its_extract_callback (message_list_ty *mlp,
+ const char *msgid,
+ lex_pos_ty *pos,
+ const char *extracted_comment,
+ const char *marker)
+{
+ message_ty *message;
+
+ message = remember_a_message (mlp, NULL,
+ xstrdup (msgid),
+ null_context, pos,
+ extracted_comment, NULL);
+
+ if (add_itstool_comments)
+ {
+ char *dot = xasprintf ("(itstool) path: %s", marker);
+ message_comment_dot_append (message, dot);
+ free (dot);
+ }
+
+ return message;
+}
+
static void
extract_from_xml_file (const char *file_name,
its_rule_list_ty *rules,
its_rule_list_extract (rules, fp, real_file_name, logical_file_name,
NULL,
- mdlp);
+ mdlp,
+ xgettext_its_extract_callback);
if (fp != stdin)
fclose (fp);
}
-#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
-#define ENDOF(a) ((a) + SIZEOF(a))
-
-
static extractor_ty
language_to_extractor (const char *name)
{
# Test of ITS support.
: ${XGETTEXT=xgettext}
-: ${GETTEXTDATADIR=.}
+GETTEXTDATADIR=.
export GETTEXTDATADIR
cat <<\EOF > empty.xml
<empty></empty>
EOF
-${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
+${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
test -d its || mkdir its
<locatingRules/>
EOF
-${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
+${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
cat <<\EOF > its/empty-2.loc
<?xml version="1.0"?>
</locatingRules>
EOF
-${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
+${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
cat <<\EOF > its/empty.its
<?xml version="1.0"?>
</its:rules>
EOF
-${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
+${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
cat <<\EOF > its/messages.loc
<?xml version="1.0"?>
msgstr ""
EOF
-${XGETTEXT} --its --no-wrap --omit-header -o messages.pot messages.xml 2>messages.err || { cat messages.err; exit 1; }
+${XGETTEXT} --itstool --no-wrap --omit-header -o messages.pot messages.xml 2>messages.err || { cat messages.err; exit 1; }
: ${DIFF=diff}
${DIFF} messages.ok messages.pot
result=$?