Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: Add support for source locales #351

Merged
merged 3 commits into from Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -488,6 +488,19 @@ asc_read_translation_status (AscResult *cres,
if (!have_results)
asc_result_add_hint_simple (cres, cpt, "translations-not-found");

/* Add a fake entry for the source locale. Do so after checking
* !have_results since the source locale is always guaranteed
* to exist, so would break that check.
* as_component_add_language() will deduplicate in case that’s
* needed. */
for (guint i = 0; i < ctx->translations->len; i++) {
AsTranslation *t = g_ptr_array_index (ctx->translations, i);

as_component_add_language (cpt,
as_translation_get_source_locale (t),
100);
}

/* remove translation elements, they should no longer be in the resulting component */
g_ptr_array_set_size (ctx->translations, 0);
}
@@ -1259,6 +1259,11 @@
In case a software components gets its translation from multiple translation domains, the <code>&lt;translation/&gt;</code> tag may be defined more
than once.
</para>
<para>
The source strings in the component are assumed to be in the <code>en_US</code> locale. If that is not the case, specify the source locale using
the <code>source_locale</code> attribute on the <code>&lt;translation/&gt;</code> tag. The metadata generator will use the source locale
to synthesize a <code>&lt;lang/&gt;</code> tag for the source locale, with 100% translation.
</para>
<para>
For Gettext translations, localization data will be looked for in <filename>${prefix}/share/locale/${locale}/LC_MESSAGES/${id}.mo</filename>, where
<code>${id}</code> is replaced with the translation domain specified in the <code>&lt;translation/&gt;</code> tag.
@@ -1270,6 +1275,7 @@
Example:
</para>
<programlisting language="XML"><![CDATA[<translation type="gettext">foobar</translation>
<translation type="gettext" source_locale="de_DE">foobar</translation>
<translation type="qt">FooBar/translations/foobar</translation>]]></programlisting>
</listitem>
</varlistentry>
@@ -42,6 +42,7 @@ typedef struct
{
AsTranslationKind kind;
GRefString *id;
GRefString *source_locale;
} AsTranslationPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (AsTranslation, as_translation, G_TYPE_OBJECT)
@@ -103,6 +104,7 @@ as_translation_finalize (GObject *object)
AsTranslationPrivate *priv = GET_PRIVATE (tr);

as_ref_string_release (priv->id);
as_ref_string_release (priv->source_locale);

G_OBJECT_CLASS (as_translation_parent_class)->finalize (object);
}
@@ -173,6 +175,42 @@ as_translation_set_id (AsTranslation *tr, const gchar *id)
as_ref_string_assign_safe (&priv->id, id);
}

/**
* as_translation_get_source_locale:
* @tr: a #AsTranslation instance.
*
* The locale of the source strings for this component. If this has not been
* explicitly specified, `en_US` will be returned.
*
* Returns: (not nullable): The locale of the source strings for this component.
* Since: 0.14.6
*/
const gchar*
as_translation_get_source_locale (AsTranslation *tr)
{
AsTranslationPrivate *priv = GET_PRIVATE (tr);
return (priv->source_locale != NULL) ? priv->source_locale : "en_US";
}

/**
* as_translation_set_source_locale:
* @tr: a #AsTranslation instance.
* @locale: (nullable): The locale that the source strings are in, or %NULL if
* unknown or default.
*
* Set the locale of the source strings for this component. In gettext, this is
* referred to as the `C` locale. It’s almost always `en_US`, but for some
* components it may not be.
*
* Since: 0.14.6
*/
void
as_translation_set_source_locale (AsTranslation *tr, const gchar *locale)
{
AsTranslationPrivate *priv = GET_PRIVATE (tr);
as_ref_string_assign_safe (&priv->source_locale, locale);
}

/**
* as_translation_load_from_xml:
* @tr: a #AsTranslation instance.
@@ -194,6 +232,9 @@ as_translation_load_from_xml (AsTranslation *tr, AsContext *ctx, xmlNode *node,
if (priv->kind == AS_TRANSLATION_KIND_UNKNOWN)
return FALSE;

as_ref_string_assign_transfer (&priv->source_locale,
as_xml_get_prop_value_refstr (node, "source_locale"));

content = as_xml_get_node_value (node);
as_translation_set_id (tr, content);

@@ -221,6 +262,8 @@ as_translation_to_xml_node (AsTranslation *tr, AsContext *ctx, xmlNode *root)
n = xmlNewTextChild (root, NULL, (xmlChar*) "translation", (xmlChar*) priv->id);
xmlNewProp (n, (xmlChar*) "type",
(xmlChar*) as_translation_kind_to_string (priv->kind));

as_xml_add_text_prop (n, "source_locale", priv->source_locale);
}

/**
@@ -73,6 +73,10 @@ const gchar *as_translation_get_id (AsTranslation *tr);
void as_translation_set_id (AsTranslation *tr,
const gchar *id);

const gchar *as_translation_get_source_locale (AsTranslation *tr);
void as_translation_set_source_locale (AsTranslation *tr,
const gchar *locale);

G_END_DECLS

#endif /* __AS_TRANSLATION_H */
@@ -30,5 +30,5 @@
<category>web</category>
</categories>
<url type="homepage">http://www.mozilla.com</url>
<translation type="gettext">firefox</translation>
<translation type="gettext" source_locale="de">firefox</translation>
</component>
@@ -628,6 +628,9 @@ test_compose_locale_stats ()
g_assert_cmpint (as_component_get_language (cpt, "en_GB"), ==, 100);
g_assert_cmpint (as_component_get_language (cpt, "ru"), ==, 33);

/* the source locale should be 100% translated */
g_assert_cmpint (as_component_get_language (cpt, "en_US"), ==, 100);

/* try loading Qt translations, style 1 */
as_component_clear_languages (cpt);
as_translation_set_kind (tr, AS_TRANSLATION_KIND_QT);
@@ -642,6 +645,9 @@ test_compose_locale_stats ()
g_assert_cmpint (as_component_get_language (cpt, "fr"), ==, 100);
g_assert_cmpint (as_component_get_language (cpt, "de"), ==, -1);

/* the source locale should be 100% translated */
g_assert_cmpint (as_component_get_language (cpt, "en_US"), ==, 100);

/* try loading Qt translations, style 2 */
as_component_clear_languages (cpt);
as_translation_set_kind (tr, AS_TRANSLATION_KIND_QT);
@@ -671,6 +677,53 @@ test_compose_locale_stats ()
g_assert_cmpint (as_component_get_language (cpt, "de"), ==, 100);
}

static void
test_compose_source_locale (void)
{
gboolean ret;
g_autoptr(GError) error = NULL;
g_autoptr(AscResult) cres = NULL;
g_autoptr(AsComponent) cpt = NULL;
g_autoptr(AsTranslation) tr = NULL;
g_autoptr(AscDirectoryUnit) dirunit = asc_directory_unit_new (datadir);

/* open sample data directory unit */
ret = asc_unit_open (ASC_UNIT (dirunit), &error);
g_assert_no_error (error);
g_assert_true (ret);

/* create dummy result with a dummy component, and set a non-standard
* source locale on the translation */
cpt = as_component_new ();
as_component_set_id (cpt, "org.freedesktop.appstream.dummy");

tr = as_translation_new ();
as_translation_set_kind (tr, AS_TRANSLATION_KIND_GETTEXT);
as_translation_set_id (tr, "app");
as_translation_set_source_locale (tr, "de");
as_component_add_translation (cpt, tr);

cres = asc_result_new ();
ret = asc_result_add_component_with_string (cres, cpt, "<testdata>", &error);
g_assert_no_error (error);
g_assert_true (ret);

/* try loading a Gettext translation */
asc_read_translation_status (cres,
ASC_UNIT (dirunit),
"/usr",
25);
asc_assert_no_hints_in_result (cres);
g_assert_cmpint (as_component_get_language (cpt, "en_GB"), ==, 100);
g_assert_cmpint (as_component_get_language (cpt, "ru"), ==, 33);

/* the source locale should be 100% translated */
g_assert_cmpint (as_component_get_language (cpt, "de"), ==, 100);

/* and the default source locale should not be translated */
g_assert_cmpint (as_component_get_language (cpt, "en_US"), ==, -1);
}

int
main (int argc, char **argv)
{
@@ -701,6 +754,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/Compose/DesktopEntry", test_compose_desktop_entry);
g_test_add_func ("/AppStream/Compose/DirectoryUnit", test_compose_directory_unit);
g_test_add_func ("/AppStream/Compose/LocaleStats", test_compose_locale_stats);
g_test_add_func ("/AppStream/Compose/SourceLocale", test_compose_source_locale);

ret = g_test_run ();
g_free (datadir);
@@ -192,6 +192,7 @@ test_appstream_parser_locale ()
g_assert_cmpint (trs->len, ==, 1);
tr = AS_TRANSLATION (g_ptr_array_index (trs, 0));
g_assert_cmpstr (as_translation_get_id (tr), ==, "firefox");
g_assert_cmpstr (as_translation_get_source_locale (tr), ==, "de");

/* check if we loaded the right amount of icons */
g_assert_cmpint (as_component_get_icons (cpt)->len, ==, 2);
@@ -236,7 +237,7 @@ test_appstream_write_locale ()
" <mediatype>x-scheme-handler/http</mediatype>\n"
" <mediatype>x-scheme-handler/https</mediatype>\n"
" </provides>\n"
" <translation type=\"gettext\">firefox</translation>\n"
" <translation type=\"gettext\" source_locale=\"de\">firefox</translation>\n"
" <keywords>\n"
" <keyword>internet</keyword>\n"
" <keyword>web</keyword>\n"