From e78a53fede4000810e88e30850e73f09ef4eaa58 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2019 13:49:38 +0100 Subject: [PATCH 1/5] config: Accept `C` and `POSIX` as languages They are listed as languages in `locale -a` output. Signed-off-by: Philip Withnall --- app/flatpak-builtins-config.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/flatpak-builtins-config.c b/app/flatpak-builtins-config.c index 6fb40952..b491b12f 100644 --- a/app/flatpak-builtins-config.c +++ b/app/flatpak-builtins-config.c @@ -51,6 +51,10 @@ looks_like_a_language (const char *s) int len = strlen (s); int i; + if (g_str_equal (s, "C") || + g_str_equal (s, "POSIX")) + return TRUE; + if (len < 2 || len > 3) return FALSE; From a3a7f3214cd0ad8fb63c8faeb4acd954fead3d88 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2019 13:50:22 +0100 Subject: [PATCH 2/5] config: Accept `bokmal` as a language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s listed in `locale -a` output, even though it should canonically be represented as `nb`. Signed-off-by: Philip Withnall --- app/flatpak-builtins-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/flatpak-builtins-config.c b/app/flatpak-builtins-config.c index b491b12f..5d24dc73 100644 --- a/app/flatpak-builtins-config.c +++ b/app/flatpak-builtins-config.c @@ -55,7 +55,7 @@ looks_like_a_language (const char *s) g_str_equal (s, "POSIX")) return TRUE; - if (len < 2 || len > 3) + if (len < 2) return FALSE; for (i = 0; i < len; i++) From cc7474d0e9d489f72006f4a33570a0b427a43c90 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2019 13:52:32 +0100 Subject: [PATCH 3/5] config: Rework handling of extra-languages to change locale format Accept the locale format as documented by `setlocale(3)`, rather than another arbitrary format. This reworks the validation code, and was tested to accept all the locales on my F30 system using: ``` flatpak config --user --set extra-languages $(locale -a | tr -s '\n' ';' | head -c -1) ``` Signed-off-by: Philip Withnall --- app/flatpak-builtins-config.c | 82 ++++++++++++++++++++++------------- common/flatpak-dir.c | 7 +-- common/flatpak-installation.c | 11 +++-- 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/app/flatpak-builtins-config.c b/app/flatpak-builtins-config.c index 5d24dc73..8b4855fd 100644 --- a/app/flatpak-builtins-config.c +++ b/app/flatpak-builtins-config.c @@ -68,49 +68,73 @@ looks_like_a_language (const char *s) } static gboolean -looks_like_a_region (const char *s) +looks_like_a_territory (const char *s) { - g_auto(GStrv) locale = g_strsplit (s, "_", 3); - int i; - int len; + gsize len = strlen (s); + gsize i; - if (!looks_like_a_language(locale[0])) + if (len < 2) return FALSE; - if (locale[1] != NULL) + for (i = 0; i < len; i++) { - len = strlen (locale[1]); - - // This can be either GB or Latn - if (len < 2 || len > 4) + if (!g_ascii_isalpha (s[i]) || !g_ascii_isupper (s[i])) return FALSE; - - for (i = 0; i < len; i++) - { - if ((locale[2] == NULL) && (!g_ascii_isalpha (locale[1][i]) || !g_ascii_isupper (locale[1][i]))) - return FALSE; - else if (!g_ascii_isalpha (locale[1][i])) - return FALSE; - } } - if (g_strv_length (locale) > 2) + return TRUE; +} + +static gboolean +looks_like_a_codeset_or_modifier (const char *s) +{ + gsize len = strlen (s); + gsize i; + + if (len < 1) + return FALSE; + + for (i = 0; i < len; i++) { - len = strlen (locale[2]); - - if (len < 2 || len > 3) + if (!g_ascii_isalnum (s[i]) && s[i] != '-') return FALSE; - - for (i = 0; i < len; i++) - { - if (!g_ascii_isalpha (locale[2][i]) || !g_ascii_isupper (locale[2][i])) - return FALSE; - } } return TRUE; } +static gboolean +looks_like_a_locale (const char *s) +{ + g_autofree gchar *locale = g_strdup (s); + gchar *language, *territory, *codeset, *modifier; + + modifier = strchr (locale, '@'); + if (modifier != NULL) + *modifier++ = '\0'; + + codeset = strchr (locale, '.'); + if (codeset != NULL) + *codeset++ = '\0'; + + territory = strchr (locale, '_'); + if (territory != NULL) + *territory++ = '\0'; + + language = locale; + + if (!looks_like_a_language (language)) + return FALSE; + if (territory != NULL && !looks_like_a_territory (territory)) + return FALSE; + if (codeset != NULL && !looks_like_a_codeset_or_modifier (codeset)) + return FALSE; + if (modifier != NULL && !looks_like_a_codeset_or_modifier (modifier)) + return FALSE; + + return TRUE; +} + static char * parse_locale (const char *value, GError **error) { @@ -120,7 +144,7 @@ parse_locale (const char *value, GError **error) strs = g_strsplit (value, ";", 0); for (i = 0; strs[i]; i++) { - if (!looks_like_a_language (strs[i]) && !looks_like_a_region (strs[i])) + if (!looks_like_a_language (strs[i]) && !looks_like_a_locale (strs[i])) { flatpak_fail (error, _("'%s' does not look like a language/locale code"), strs[i]); return NULL; diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 6a68da43..65a07922 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -14607,9 +14607,10 @@ flatpak_dir_get_default_locale_languages (FlatpakDir *self) extra_languages = flatpak_dir_get_config_strv (self, "xa.extra-languages"); for (i = 0; extra_languages != NULL && extra_languages[i] != NULL; i++) { - g_auto(GStrv) locales = g_strsplit (extra_languages[i], "_", -1); - g_free (extra_languages[i]); - extra_languages[i] = g_strdup (locales[0]); + /* Strip the locale, modifier or codeset, if present. */ + gchar *match = strpbrk (extra_languages[i], "._@"); + if (match != NULL) + *match = '\0'; } if (flatpak_dir_is_user (self)) diff --git a/common/flatpak-installation.c b/common/flatpak-installation.c index ad730671..d6935b1d 100644 --- a/common/flatpak-installation.c +++ b/common/flatpak-installation.c @@ -1687,12 +1687,15 @@ flatpak_installation_get_default_languages (FlatpakInstallation *self, * @self: a #FlatpakInstallation * @error: return location for a #GError * - * Like flatpak_installation_get_default_languages() but includes region - * information (e.g. en_US rather than en) which may be included in the - * xa.extra-languages configuration. + * Like flatpak_installation_get_default_languages() but includes territory + * information (e.g. `en_US` rather than `en`) which may be included in the + * `xa.extra-languages` configuration. + * + * Strings returned by this function are in the format specified by + * [`setlocale()`](man:setlocale): `language[_territory][.codeset][@modifier]`. * * Returns: (array zero-terminated=1) (element-type utf8) (transfer full): - * A possibly empty array of language and locale strings, or %NULL on error. + * A possibly empty array of locale strings, or %NULL on error. * Since: 1.5.1 */ char ** From 62cb538440661aa499c24fa33d2e36513d4b30a7 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2019 10:27:42 +0100 Subject: [PATCH 4/5] doc: Add some missing docbook tags Makes the documentation a little clearer to read. Signed-off-by: Philip Withnall --- doc/flatpak-config.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/flatpak-config.xml b/doc/flatpak-config.xml index 32d5420e..131def69 100644 --- a/doc/flatpak-config.xml +++ b/doc/flatpak-config.xml @@ -61,8 +61,8 @@ The languages that are included when installing Locale extensions. The value is a semicolon-separated list of two-letter language codes, - or one of the special values * or all. If this key is unset, flatpak - defaults to including the extra-languages key and the current locale. + or one of the special values * or all. If this key is unset, flatpak + defaults to including the extra-languages key and the current locale. From d5a11708207a1e34fe9fdaea204a59509b0954db Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2019 10:30:16 +0100 Subject: [PATCH 5/5] doc: Clarify format of locale identifiers in extra-languages key Also update the tests to use the same format, and make sure to include coverage of all forms of locale (language-only, with locale, with codeset, and with modifier). Signed-off-by: Philip Withnall --- doc/flatpak-config.xml | 6 ++++-- tests/testlibrary.c | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/flatpak-config.xml b/doc/flatpak-config.xml index 131def69..83d57e50 100644 --- a/doc/flatpak-config.xml +++ b/doc/flatpak-config.xml @@ -70,8 +70,10 @@ This key is used when languages is not set, and it defines extra locale extensions on top of the system configured languages. The value is a - semicolon-separated list of two-letter language codes or locale identifiers - (eg. en;en_DK;az_Latn_AZ). + semicolon-separated list of locale identifiers + (language, optional locale, optional codeset, optional modifier) as documented by + setlocale3 + (for example, en;en_DK;zh_HK.big5hkscs;uz_UZ.utf8@cyrillic). diff --git a/tests/testlibrary.c b/tests/testlibrary.c index 052507f7..ee2529f0 100644 --- a/tests/testlibrary.c +++ b/tests/testlibrary.c @@ -291,27 +291,30 @@ test_languages_config (void) g_assert_cmpstr (value[0], ==, "en"); g_assert_null (value[1]); - res = flatpak_installation_set_config_sync (inst, "extra-languages", "pt_BR;az_Latn_AZ;es", NULL, &error); + res = flatpak_installation_set_config_sync (inst, "extra-languages", "pt_BR;uz_UZ.utf8@cyrillic;es;zh_HK.big5hkscs;uz_UZ@cyrillic", NULL, &error); g_assert_no_error (error); g_assert_true (res); value = flatpak_installation_get_default_languages (inst, &error); g_assert_no_error (error); - g_assert_cmpstr (value[0], ==, "az"); - g_assert_cmpstr (value[1], ==, "en"); - g_assert_cmpstr (value[2], ==, "es"); - g_assert_cmpstr (value[3], ==, "pt"); - g_assert_null (value[4]); + g_assert_cmpstr (value[0], ==, "en"); + g_assert_cmpstr (value[1], ==, "es"); + g_assert_cmpstr (value[2], ==, "pt"); + g_assert_cmpstr (value[3], ==, "uz"); + g_assert_cmpstr (value[4], ==, "zh"); + g_assert_null (value[5]); g_clear_pointer (&value, g_strfreev); value = flatpak_installation_get_default_locales (inst, &error); g_assert_no_error (error); - g_assert_cmpstr (value[0], ==, "az_Latn_AZ"); - g_assert_cmpstr (value[1], ==, "en"); - g_assert_cmpstr (value[2], ==, "es"); - g_assert_cmpstr (value[3], ==, "pt_BR"); - g_assert_null (value[4]); + g_assert_cmpstr (value[0], ==, "en"); + g_assert_cmpstr (value[1], ==, "es"); + g_assert_cmpstr (value[2], ==, "pt_BR"); + g_assert_cmpstr (value[3], ==, "uz_UZ.utf8@cyrillic"); + g_assert_cmpstr (value[4], ==, "uz_UZ@cyrillic"); + g_assert_cmpstr (value[5], ==, "zh_HK.big5hkscs"); + g_assert_null (value[6]); g_clear_pointer (&value, g_strfreev);