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 <withnall@endlessm.com>
This commit is contained in:
Philip Withnall 2019-10-24 13:52:32 +01:00
parent a3a7f3214c
commit cc7474d0e9
3 changed files with 64 additions and 36 deletions

View File

@ -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;

View File

@ -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))

View File

@ -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 **