diff --git a/compose/asc-utils-l10n.c b/compose/asc-utils-l10n.c index 2b9ccc4a..857e1405 100644 --- a/compose/asc-utils-l10n.c +++ b/compose/asc-utils-l10n.c @@ -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); } diff --git a/docs/xml/metainfo-component.xml b/docs/xml/metainfo-component.xml index 6a1ef992..cd5989fe 100644 --- a/docs/xml/metainfo-component.xml +++ b/docs/xml/metainfo-component.xml @@ -1259,6 +1259,11 @@ In case a software components gets its translation from multiple translation domains, the <translation/> tag may be defined more than once. + + The source strings in the component are assumed to be in the en_US locale. If that is not the case, specify the source locale using + the source_locale attribute on the <translation/> tag. The metadata generator will use the source locale + to synthesize a <lang/> tag for the source locale, with 100% translation. + For Gettext translations, localization data will be looked for in ${prefix}/share/locale/${locale}/LC_MESSAGES/${id}.mo, where ${id} is replaced with the translation domain specified in the <translation/> tag. @@ -1270,6 +1275,7 @@ Example: foobar +foobar FooBar/translations/foobar]]> diff --git a/src/as-translation.c b/src/as-translation.c index 16fd97fa..3ed45656 100644 --- a/src/as-translation.c +++ b/src/as-translation.c @@ -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); } /** diff --git a/src/as-translation.h b/src/as-translation.h index 24fd78b1..1a072d66 100644 --- a/src/as-translation.h +++ b/src/as-translation.h @@ -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 */ diff --git a/tests/samples/appdata.xml b/tests/samples/appdata.xml index c7c18d3f..0bba771d 100644 --- a/tests/samples/appdata.xml +++ b/tests/samples/appdata.xml @@ -30,5 +30,5 @@ web http://www.mozilla.com - firefox + firefox diff --git a/tests/test-compose.c b/tests/test-compose.c index 1093c2ae..1bda4bc2 100644 --- a/tests/test-compose.c +++ b/tests/test-compose.c @@ -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, "", &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); diff --git a/tests/test-xmldata.c b/tests/test-xmldata.c index d76a2adc..3d7abb23 100644 --- a/tests/test-xmldata.c +++ b/tests/test-xmldata.c @@ -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 () " x-scheme-handler/http\n" " x-scheme-handler/https\n" " \n" - " firefox\n" + " firefox\n" " \n" " internet\n" " web\n"