-Version 0.23 - September 2024
+Version 0.23 - October 2024
* Programming languages support:
- XML:
o XML schemas for .its and .loc files are now provided.
o The value of the xml:lang attribute, inserted by msgfmt, now conforms
to W3C standards.
+ o 'msgfmt --xml' accept an option --replace-text, that causes the output
+ to be a mono-lingual XML file instead of a multi-lingual XML file.
- Python:
o xgettext now assumes source code for Python 3 rather than Python 2.
This affects the interpretation of escape sequences in string literals.
The @samp{-l} and @samp{-d} options are mandatory. The @file{.msg} file is
written in the specified directory.
-@subsection Desktop Entry mode operations
+@subsection Desktop Entry mode options
@table @samp
@item --template=@var{template}
For either operation modes, the @samp{-o} and @samp{--template}
options are mandatory.
-@subsection XML mode operations
+@subsection XML mode options
@table @samp
@item --template=@var{template}
@opindex -d@r{, @code{msgfmt} option}
Specify the base directory of @file{.po} message catalogs.
+@item --replace-text
+@opindex --replace-text@r{, @code{msgfmt} option}
+Output XML with translated text replacing the original text,
+not augmenting the original text.
+With this option, @code{msgfmt} produces a mono-lingual XML file.
+Without this option, it produces a multi-lingual XML file.
@end table
To generate an XML file for a single locale, you can use it as follows.
its_merge_context_merge_node (struct its_merge_context_ty *context,
xmlNode *node,
const char *language,
- message_list_ty *mlp)
+ message_list_ty *mlp,
+ bool replace_text)
{
if (node->type == XML_ELEMENT_NODE)
{
xmlNode *translated;
char language_bcp47[BCP47_MAX];
- /* Create a new element node, of the same name, with the same
- attributes. */
- translated = _its_copy_node_with_attributes (node);
+ if (replace_text)
+ {
+ /* Reuse the node. But first, clear its text content and all
+ its children nodes (except the attributes). */
+ xmlNodeSetContent (node, NULL);
+ translated = node;
+ }
+ else
+ {
+ /* Create a new element node, of the same name, with the same
+ attributes. */
+ translated = _its_copy_node_with_attributes (node);
+ }
/* Set the xml:lang attribute.
<https://www.w3.org/International/questions/qa-when-xmllang.en.html>
free (middle_ground);
}
- xmlAddNextSibling (node, translated);
+ if (!replace_text)
+ xmlAddNextSibling (node, translated);
}
}
free (msgctxt);
void
its_merge_context_merge (its_merge_context_ty *context,
const char *language,
- message_list_ty *mlp)
+ message_list_ty *mlp,
+ bool replace_text)
{
size_t i;
for (i = 0; i < context->nodes.nitems; i++)
its_merge_context_merge_node (context, context->nodes.items[i],
language,
- mlp);
+ mlp,
+ replace_text);
}
struct its_merge_context_ty *
extern void its_merge_context_free (its_merge_context_ty *context);
extern void its_merge_context_merge (its_merge_context_ty *context,
const char *language,
- message_list_ty *mlp);
+ message_list_ty *mlp,
+ bool replace_text);
extern void its_merge_context_write (its_merge_context_ty *context,
FILE *fp);
/* XML mode output file specification. */
static bool xml_mode;
+static bool xml_replace_text;
static const char *xml_locale_name;
static const char *xml_template_name;
static const char *xml_base_directory;
{ "output-file", required_argument, NULL, 'o' },
{ "properties-input", no_argument, NULL, 'P' },
{ "qt", no_argument, NULL, CHAR_MAX + 9 },
+ { "replace-text", no_argument, NULL, CHAR_MAX + 19 },
{ "resource", required_argument, NULL, 'r' },
{ "source", no_argument, NULL, CHAR_MAX + 14 },
{ "statistics", no_argument, &do_statistics, 1 },
case CHAR_MAX + 18: /* --no-redundancy */
no_redundancy = true;
break;
+ case CHAR_MAX + 19: /* --replace-text */
+ xml_replace_text = true;
+ break;
default:
usage (EXIT_FAILURE);
break;
first_option, second_option);
}
}
+ if (!xml_mode && xml_replace_text)
+ {
+ error (EXIT_SUCCESS, 0, _("%s is only valid with %s"),
+ "--replace-text", "--xml");
+ usage (EXIT_FAILURE);
+ }
if (java_mode)
{
if (output_file_name != NULL)
"--xml");
usage (EXIT_FAILURE);
}
+ if (xml_replace_text && xml_base_directory != NULL)
+ error (EXIT_FAILURE, 0,
+ _("%s and %s are mutually exclusive in %s"),
+ "--replace-text", "-d", "--xml");
if (xml_base_directory != NULL && xml_locale_name != NULL)
error (EXIT_FAILURE, 0,
_("%s and %s are mutually exclusive in %s"),
xml_locale_name,
xml_template_name,
xml_its_rules,
+ xml_replace_text,
domain->file_name))
exit_status = EXIT_FAILURE;
}
printf (_("\
-d DIRECTORY base directory of .po files\n"));
printf (_("\
+ --replace-text output XML with translated text replacing the\n\
+ original text, not augmenting the original text\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");
status = msgdomain_write_xml_bulk (&operands,
template_file_name,
its_rules,
+ false,
file_name);
msgfmt_operand_list_destroy (&operands);
msgdomain_write_xml_bulk (msgfmt_operand_list_ty *operands,
const char *template_file_name,
its_rule_list_ty *its_rules,
+ bool replace_text,
const char *file_name)
{
its_merge_context_ty *context;
for (i = 0; i < operands->nitems; i++)
its_merge_context_merge (context,
operands->items[i].language,
- operands->items[i].mlp);
+ operands->items[i].mlp,
+ replace_text);
its_merge_context_write (context, fp);
its_merge_context_free (context);
const char *locale_name,
const char *template_file_name,
its_rule_list_ty *its_rules,
+ bool replace_text,
const char *file_name)
{
msgfmt_operand_ty operand;
return msgdomain_write_xml_bulk (&operands,
template_file_name,
its_rules,
+ replace_text,
file_name);
}
/* Writing XML files.
- Copyright (C) 2024 Free Software Foundation, Inc.
+ Copyright (C) 2015-2024 Free Software Foundation, Inc.
This file was written by Daiki Ueno <ueno@gnu.org>.
This program is free software: you can redistribute it and/or modify
const char *locale_name,
const char *template_file_name,
its_rule_list_ty *its_rules,
+ bool replace_text,
const char *file_name);
extern int
msgdomain_write_xml_bulk (msgfmt_operand_list_ty *operands,
const char *template_file_name,
its_rule_list_ty *its_rules,
+ bool replace_text,
const char *file_name);
#ifdef __cplusplus
msgfmt-tcl-1 msgfmt-tcl-2 \
msgfmt-qt-1 msgfmt-qt-2 \
msgfmt-desktop-1 msgfmt-desktop-2 msgfmt-desktop-3 \
- msgfmt-xml-1 msgfmt-xml-2 msgfmt-xml-3 \
+ msgfmt-xml-1 msgfmt-xml-2 msgfmt-xml-3 msgfmt-xml-4 \
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 \
--- /dev/null
+#! /bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test msgfmt --xml: --replace-text option
+
+cat <<\EOF > mf.appdata.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE component PUBLIC "" "" [
+<!ENTITY author1 "Giovanni Campagna">
+<!ENTITY author2 "Daiki Ueno">
+<!ENTITY author3 "Bilal Elmoussaoui">
+]>
+<component type="desktop" xmlns:gt="https://www.gnu.org/s/gettext/ns/its/extensions/1.0">
+ <id>org.gnome.Characters.desktop</id>
+ <name>GNOME Characters</name>
+ <summary>Character map application</summary>
+ <licence>CC0</licence>
+ <description>
+ <p>
+ Characters is a simple utility application to find and insert
+ unusual characters. It allows you to quickly find the character
+ you are looking for by searching for keywords.
+ </p>
+ <p>
+ You can also browse characters by categories, such as
+ Punctuation, Pictures, etc.
+ </p>
+ <p gt:escape="yes">
+ Did you know that the copyright sign (©, U+00A9) can be written in HTML
+ as &#xa9;,
+ as &#169;,
+ or as &copy;?
+ </p>
+ <p>Written by &author1;, &author2;, and &author3;.</p>
+ <p gt:escape="no">Escape gallery: operator x&y, standard XML entities & " ' & < >, character reference ©, escaped character reference &#xa9;, entity references © &author1;</p>
+ <p gt:escape="yes">Escape gallery: operator x&y, standard XML entities & " ' & < >, character reference ©, escaped character reference &#xa9;, entity references © &author1;</p>
+ </description>
+ <url type="homepage">https://wiki.gnome.org/Design/Apps/CharacterMap</url>
+ <updatecontact>dueno_at_src.gnome.org</updatecontact>
+</component>
+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 <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-03-17 07:36+0900\n"
+"PO-Revision-Date: 2014-03-17 08:40+0900\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid ""
+"Characters is a simple utility application to find and insert unusual "
+"characters. It allows you to quickly find the character you are looking for "
+"by searching for keywords."
+msgstr ""
+"Caractères est un utilitaire pour chercher et insérer des caractères "
+"inhabituels. Il vous permet de trouver rapidement le caractère que vous "
+"cherchez par le biais de mots-clés."
+
+#, fuzzy
+msgid ""
+"You can also browse characters by categories, such as Punctuation, Pictures, "
+"etc."
+msgstr ""
+"Vous pouvez aussi naviguer dans les caractères par catégories, comme par "
+"Ponctuation, Images, etc."
+
+msgid ""
+"Did you know that the copyright sign (©, U+00A9) can be written in HTML as "
+"©, as ©, or as ©?"
+msgstr ""
+"Saviez-vous que le signe de copyright (©, U+00A9) peut être écrit en HTML "
+"comme ©, comme © ou comme © ?"
+
+msgid "Written by &author1;, &author2;, and &author3;."
+msgstr "Écrit par &author1;, &author2;, et &author3;."
+
+msgid ""
+"Escape gallery: operator x&y, standard XML entities & \" ' & < >, character "
+"reference ©, escaped character reference ©, entity references © "
+"&author1;"
+msgstr ""
+"Exposition d'échappements: operateur x&y, entités XML standard & \" ' & < >, "
+"caractère ©, caractère échappé ©, entités © &author1;"
+EOF
+
+cat <<\EOF > mf.appdata.xml.ok
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE component PUBLIC "" "" [
+<!ENTITY author1 "Giovanni Campagna">
+<!ENTITY author2 "Daiki Ueno">
+<!ENTITY author3 "Bilal Elmoussaoui">
+]>
+<component xmlns:gt="https://www.gnu.org/s/gettext/ns/its/extensions/1.0" type="desktop">
+ <id>org.gnome.Characters.desktop</id>
+ <name>GNOME Characters</name>
+ <summary>Character map application</summary>
+ <licence>CC0</licence>
+ <description>
+ <p xml:lang="fr">Caractères est un utilitaire pour chercher et insérer des caractères inhabituels. Il vous permet de trouver rapidement le caractère que vous cherchez par le biais de mots-clés.</p>
+ <p>
+ You can also browse characters by categories, such as
+ Punctuation, Pictures, etc.
+ </p>
+ <p gt:escape="yes" xml:lang="fr">Saviez-vous que le signe de copyright (©, U+00A9) peut être écrit en HTML comme &#xa9;, comme &#169; ou comme &copy; ?</p>
+ <p xml:lang="fr">Écrit par &author1;, &author2;, et &author3;.</p>
+ <p gt:escape="no" xml:lang="fr">Exposition d'échappements: operateur x&y, entités XML standard & " ' & < >, caractère ©, caractère échappé &#xa9;, entités © &author1;</p>
+ <p gt:escape="yes" xml:lang="fr">Exposition d'échappements: operateur x&y, entités XML standard & " ' & < >, caractère ©, caractère échappé &#xa9;, entités &copy; &author1;</p>
+ </description>
+ <url type="homepage">https://wiki.gnome.org/Design/Apps/CharacterMap</url>
+ <updatecontact>dueno_at_src.gnome.org</updatecontact>
+</component>
+EOF
+
+# Sanity checks for contradicting options.
+
+${MSGFMT} --replace-text fr.po \
+ >/dev/null 2>/dev/null \
+ && Exit 1
+
+${MSGFMT} --xml --template=mf.appdata.xml --replace-text -d po -o mf.appdata.xml.out \
+ >/dev/null 2>/dev/null \
+ && Exit 1
+
+# Proceed to the XML file generation.
+
+${MSGFMT} --xml --template=mf.appdata.xml --replace-text -l fr fr.po -o mf.appdata.xml.out \
+ || Exit 1
+
+: ${DIFF=diff}
+${DIFF} mf.appdata.xml.ok mf.appdata.xml.out
+test $? = 0 || Exit 1