app: Allow locales to be stored in the extra-languages key

In order to configure gnome-software to show specific apps in one region
without showing to all language speakers, we allow the storage of full
locales on the extra-languages key. However, these locales are ignored when
calling flatpak_installation_get_default_languages, so locales will be reduced
to their language identifier (eg. en_IN locale will be returned as 'en', and
az_Latn_AZ will be returned as 'az'). In order to get the full locales, we can
call flatpak_installation_get_default_locales instead, which can return languages
and locales.
This commit is contained in:
Mazen Asef
2019-10-03 15:26:24 -03:00
parent 1e589c1b74
commit 65912f27fe
7 changed files with 291 additions and 33 deletions

View File

@@ -63,12 +63,79 @@ looks_like_a_language (const char *s)
return TRUE;
}
static gboolean
looks_like_a_region (const char *s)
{
g_auto(GStrv) locale = g_strsplit (s, "_", 3);
int i;
int len;
if (!looks_like_a_language(locale[0]))
return FALSE;
if (locale[1] != NULL)
{
len = strlen (locale[1]);
// This can be either GB or Latn
if (len < 2 || len > 4)
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)
{
len = strlen (locale[2]);
if (len < 2 || len > 3)
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 char *
parse_locale (const char *value, GError **error)
{
g_auto(GStrv) strs = NULL;
int i;
strs = g_strsplit (value, ";", 0);
for (i = 0; strs[i]; i++)
{
if (!looks_like_a_language (strs[i]) && !looks_like_a_region (strs[i]))
{
flatpak_fail (error, _("'%s' does not look like a language/locale code"), strs[i]);
return NULL;
}
}
return g_strdup (value);
}
static char *
parse_lang (const char *value, GError **error)
{
g_auto(GStrv) strs = NULL;
int i;
if (strcmp (value, "*") == 0 ||
strcmp (value, "*all*") == 0)
return g_strdup ("");
strs = g_strsplit (value, ";", 0);
for (i = 0; strs[i]; i++)
{
@@ -83,27 +150,17 @@ parse_lang (const char *value, GError **error)
}
static char *
parse_special_lang (const char *value, GError **error)
{
if (strcmp (value, "*") == 0 ||
strcmp (value, "*all*") == 0)
return g_strdup ("");
return parse_lang (value, error);
}
static char *
print_lang (const char *value)
print_locale (const char *value)
{
return g_strdup (value);
}
static char *
print_special_lang (const char *value)
print_lang (const char *value)
{
if (*value == 0)
return g_strdup ("*all*");
return print_lang (value);
return g_strdup (value);
}
static char *
@@ -123,8 +180,8 @@ typedef struct
} ConfigKey;
ConfigKey keys[] = {
{ "languages", parse_special_lang, print_special_lang, get_lang_default },
{ "extra-languages", parse_lang, print_lang, NULL },
{ "languages", parse_lang, print_lang, get_lang_default },
{ "extra-languages", parse_locale, print_locale, NULL },
};
static ConfigKey *

View File

@@ -955,7 +955,9 @@ gboolean flatpak_dir_resolve_p2p_refs (FlatpakDir *self,
GError **error);
char ** flatpak_dir_get_default_locales (FlatpakDir *self);
char ** flatpak_dir_get_default_locale_languages (FlatpakDir *self);
char ** flatpak_dir_get_locales (FlatpakDir *self);
char ** flatpak_dir_get_locale_languages (FlatpakDir *self);
char ** flatpak_dir_get_locale_subpaths (FlatpakDir *self);

View File

@@ -14561,20 +14561,13 @@ flatpak_dir_get_config_strv (FlatpakDir *self, char *key)
return NULL;
}
char **
flatpak_dir_get_default_locale_languages (FlatpakDir *self)
static void
get_system_locales (FlatpakDir *self, GPtrArray *langs)
{
g_autoptr(GPtrArray) langs = g_ptr_array_new_with_free_func (g_free);
g_autoptr(GDBusProxy) localed_proxy = NULL;
g_autoptr(GDBusProxy) accounts_proxy = NULL;
g_auto(GStrv) extra_languages = NULL;
extra_languages = flatpak_dir_get_config_strv (self, "xa.extra-languages");
if (flatpak_dir_is_user (self))
return sort_strv (flatpak_strv_merge (extra_languages, flatpak_get_current_locale_langs ()));
/* Then get the system default locales */
/* Get the system default locales */
localed_proxy = get_localed_dbus_proxy ();
if (localed_proxy != NULL)
get_locale_langs_from_localed_dbus (localed_proxy, langs);
@@ -14584,12 +14577,67 @@ flatpak_dir_get_default_locale_languages (FlatpakDir *self)
accounts_proxy = get_accounts_dbus_proxy ();
if (accounts_proxy != NULL)
get_locale_langs_from_accounts_dbus (accounts_proxy, langs);
g_ptr_array_add (langs, NULL);
}
char **
flatpak_dir_get_default_locales (FlatpakDir *self)
{
g_autoptr(GPtrArray) langs = g_ptr_array_new_with_free_func (g_free);
g_auto(GStrv) extra_languages = NULL;
extra_languages = flatpak_dir_get_config_strv (self, "xa.extra-languages");
if (flatpak_dir_is_user (self))
return sort_strv (flatpak_strv_merge (extra_languages, flatpak_get_current_locale_langs ()));
/* Then get the system default locales */
get_system_locales (self, langs);
return sort_strv (flatpak_strv_merge (extra_languages, (char **) langs->pdata));
}
char **
flatpak_dir_get_default_locale_languages (FlatpakDir *self)
{
g_autoptr(GPtrArray) langs = g_ptr_array_new_with_free_func (g_free);
g_auto(GStrv) extra_languages = NULL;
int i;
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]);
}
if (flatpak_dir_is_user (self))
return sort_strv (flatpak_strv_merge (extra_languages, flatpak_get_current_locale_langs ()));
/* Then get the system default locales */
get_system_locales (self, langs);
return sort_strv (flatpak_strv_merge (extra_languages, (char **) langs->pdata));
}
char **
flatpak_dir_get_locales (FlatpakDir *self)
{
char **langs = NULL;
/* Fetch the list of languages specified by xa.languages - if this key is empty,
* this would mean that all languages are accepted. You can read the man for the
* flatpak-config section for more info.
*/
langs = flatpak_dir_get_config_strv (self, "xa.languages");
if (langs)
return sort_strv (langs);
return flatpak_dir_get_default_locales (self);
}
char **
flatpak_dir_get_locale_languages (FlatpakDir *self)
{

View File

@@ -1682,6 +1682,32 @@ flatpak_installation_get_default_languages (FlatpakInstallation *self,
return flatpak_dir_get_locale_languages (dir);
}
/**
* flatpak_installation_get_default_locales:
* @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.
*
* Returns: (array zero-terminated=1) (element-type utf8) (transfer full):
* A possibly empty array of language and locale strings, or %NULL on error.
* Since: 1.5.1
*/
char **
flatpak_installation_get_default_locales (FlatpakInstallation *self,
GError **error)
{
g_autoptr(FlatpakDir) dir = NULL;
dir = flatpak_installation_get_dir (self, error);
if (dir == NULL)
return NULL;
return flatpak_dir_get_locales (dir);
}
/**
* flatpak_installation_get_min_free_space_bytes:
* @self: a #FlatpakInstallation

View File

@@ -298,6 +298,8 @@ FLATPAK_EXTERN char * flatpak_installation_get_config (FlatpakIns
GError **error);
FLATPAK_EXTERN char ** flatpak_installation_get_default_languages (FlatpakInstallation *self,
GError **error);
FLATPAK_EXTERN char ** flatpak_installation_get_default_locales (FlatpakInstallation *self,
GError **error);
FLATPAK_EXTERN char * flatpak_installation_load_app_overrides (FlatpakInstallation *self,
const char *app_id,
GCancellable *cancellable,

View File

@@ -70,7 +70,8 @@
<listitem><para>
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.
semicolon-separated list of two-letter language codes or locale identifiers
(eg. en;en_DK;az_Latn_AZ).
</para></listitem>
</varlistentry>
</variablelist>

View File

@@ -253,6 +253,22 @@ clean_languages (void)
run_test_subprocess (argv, RUN_TEST_SUBPROCESS_DEFAULT);
}
static void
configure_extra_languages (void)
{
char *argv[] = { "flatpak", "config", "--user", "--set", "extra-languages", "de_DE", NULL };
run_test_subprocess (argv, RUN_TEST_SUBPROCESS_DEFAULT);
}
static void
clean_extra_languages (void)
{
char *argv[] = { "flatpak", "config", "--user", "--unset", "extra-languages", NULL };
run_test_subprocess (argv, RUN_TEST_SUBPROCESS_DEFAULT);
}
static void
test_languages_config (void)
{
@@ -273,18 +289,31 @@ test_languages_config (void)
value = flatpak_installation_get_default_languages (inst, &error);
g_assert_no_error (error);
g_assert_cmpstr (value[0], ==, "en");
g_assert_null (value[1]);
res = flatpak_installation_set_config_sync (inst, "extra-languages", "en;pt", NULL, &error);
res = flatpak_installation_set_config_sync (inst, "extra-languages", "pt_BR;az_Latn_AZ;es", 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], ==, "en");
g_assert_cmpstr (value[1], ==, "pt");
g_assert_null (value[2]);
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_clear_pointer (&value, g_free);
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_clear_pointer (&value, g_strfreev);
res = flatpak_installation_set_config_sync (inst, "languages", "ar;es", NULL, &error);
g_assert_no_error (error);
@@ -296,7 +325,8 @@ test_languages_config (void)
g_assert_cmpstr (value[1], ==, "es");
g_assert_null (value[2]);
g_clear_pointer (&value, g_free);
g_clear_pointer (&value, g_strfreev);
clean_extra_languages ();
configure_languages ();
}
@@ -1083,6 +1113,45 @@ test_list_remote_related_refs (void)
g_assert_true (should_download);
g_assert_true (should_delete);
g_assert_false (should_autoprune);
// Make the test with extra-languages, instead of languages
clean_languages();
configure_extra_languages();
inst = flatpak_installation_new_user (NULL, &error);
g_assert_no_error (error);
refs = flatpak_installation_list_remote_related_refs_sync (inst, repo_name, app, NULL, &error);
g_assert_nonnull (refs);
g_assert_no_error (error);
g_assert_cmpint (refs->len, ==, 1);
ref = g_ptr_array_index (refs, 0);
g_assert_cmpstr (flatpak_ref_get_name (FLATPAK_REF (ref)), ==, "org.test.Hello.Locale");
g_assert_true (flatpak_related_ref_should_download (ref));
g_assert_true (flatpak_related_ref_should_delete (ref));
g_assert_false (flatpak_related_ref_should_autoprune (ref));
g_assert (g_strv_length ((char **) flatpak_related_ref_get_subpaths (ref)) == 2);
g_assert_cmpstr (flatpak_related_ref_get_subpaths (ref)[0], ==, "/de");
g_assert_cmpstr (flatpak_related_ref_get_subpaths (ref)[1], ==, "/en");
g_object_get (ref,
"subpaths", &subpaths,
"should-download", &should_download,
"should-delete", &should_delete,
"should-autoprune", &should_autoprune,
NULL);
g_assert (g_strv_length (subpaths) == 2);
g_assert_cmpstr (subpaths[0], ==, "/de");
g_assert_cmpstr (subpaths[1], ==, "/en");
g_assert_true (should_download);
g_assert_true (should_delete);
g_assert_false (should_autoprune);
configure_languages();
clean_extra_languages();
}
static void
@@ -3578,6 +3647,59 @@ test_list_installed_related_refs (void)
g_assert_false (flatpak_related_ref_should_autoprune (ref));
g_assert (g_strv_length ((char **) flatpak_related_ref_get_subpaths (ref)) == 1);
g_assert_cmpstr (flatpak_related_ref_get_subpaths (ref)[0], ==, "/de");
// Make the test with extra-languages, instead of languages
clean_languages();
configure_extra_languages();
empty_installation (inst);
refs = flatpak_installation_list_installed_related_refs_sync (inst, repo_name, app, NULL, &error);
g_assert_error (error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED);
g_assert_null (refs);
g_clear_error (&error);
iref = flatpak_installation_install (inst, repo_name, FLATPAK_REF_KIND_APP, "org.test.Hello", NULL, "master", NULL, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (iref);
g_clear_object (&iref);
refs = flatpak_installation_list_installed_related_refs_sync (inst, repo_name, app, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (refs);
g_assert_cmpint (refs->len, ==, 0);
g_clear_pointer (&refs, g_ptr_array_unref);
transaction = flatpak_transaction_new_for_installation (inst, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (transaction);
res = flatpak_transaction_add_update (transaction, app, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
flatpak_transaction_run (transaction, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
g_clear_object (&transaction);
refs = flatpak_installation_list_installed_related_refs_sync (inst, repo_name, app, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (refs);
g_assert_cmpint (refs->len, ==, 1);
ref = g_ptr_array_index (refs, 0);
g_assert_cmpstr (flatpak_ref_get_name (FLATPAK_REF (ref)), ==, "org.test.Hello.Locale");
g_assert_true (flatpak_related_ref_should_download (ref));
g_assert_true (flatpak_related_ref_should_delete (ref));
g_assert_false (flatpak_related_ref_should_autoprune (ref));
g_assert (g_strv_length ((char **) flatpak_related_ref_get_subpaths (ref)) == 2);
g_assert_cmpstr (flatpak_related_ref_get_subpaths (ref)[0], ==, "/de");
g_assert_cmpstr (flatpak_related_ref_get_subpaths (ref)[1], ==, "/en");
configure_languages();
clean_extra_languages();
}
static void