From a3d5a112ddb2d665b0c7ac2919b6f4fc6c97366c Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Mon, 11 Mar 2024 02:46:19 +0000 Subject: [PATCH] Bug 1847701 - Accept-language format should be language-region format like Dekstop and Chrome/Android. r=geckoview-reviewers,necko-reviewers,platform-i18n-reviewers,valentin As spec (RFC 7231), accept-language can accept language tag (BCP 47). Currently, Firefox Android uses `Locale.toLanguageTag` API. But it may append variant and extensions etc. But Chrome/Android and desktop browser use - format for this header, so we should use same format for compatibility. Differential Revision: https://phabricator.services.mozilla.com/D203121 --- .../org/mozilla/geckoview/test/LocaleTest.kt | 12 ++++++++++++ .../java/org/mozilla/gecko/GeckoAppShell.java | 15 --------------- .../mozilla/geckoview/GeckoRuntimeSettings.java | 17 +++++++---------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt index 69deac1c89a9..608681d7d9b9 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt @@ -40,4 +40,16 @@ class LocaleTest : BaseSessionTest() { equalTo(listOf("en-GB", "en-US", "en-FR")), ) } + + @Test + fun acceptLangaugeFormat() { + // No way to override default language settings from unit test. + // So we only test this on current settings. + + val intlAcceptLanauge = "intl.accept_languages" + val prefValue = (sessionRule.getPrefs(intlAcceptLanauge)[0] as String).split(",") + for (value in prefValue) { + assertThat("Accept-Lanauge format should be language or language-region", value.filter { it == '-' }.count(), lessThanOrEqualTo(1)) + } + } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 568fc3a0bbda..bcd5762a9221 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -46,7 +46,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.Vibrator; import android.provider.Settings; -import android.text.TextUtils; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.Display; @@ -1527,20 +1526,6 @@ public class GeckoAppShell { } } - private static String getLanguageTag(final Locale locale) { - final StringBuilder out = new StringBuilder(locale.getLanguage()); - final String country = locale.getCountry(); - final String variant = locale.getVariant(); - if (!TextUtils.isEmpty(country)) { - out.append('-').append(country); - } - if (!TextUtils.isEmpty(variant)) { - out.append('-').append(variant); - } - // e.g. "en", "en-US", or "en-US-POSIX". - return out.toString(); - } - @WrapForJNI public static String[] getDefaultLocales() { // XXX We may have to convert some language codes such as "id" vs "in". diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java index 9a66c034879d..27bcba80f997 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java @@ -1056,7 +1056,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { } } // OS prefs come second: - for (final String locale : getDefaultLocales()) { + for (final String locale : getSystemLocalesForAcceptLanguage()) { final String localeLowerCase = locale.toLowerCase(Locale.ROOT); if (!locales.containsKey(localeLowerCase)) { locales.put(localeLowerCase, locale); @@ -1066,32 +1066,29 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { return TextUtils.join(",", locales.values()); } - private static String[] getDefaultLocales() { + private static String[] getSystemLocalesForAcceptLanguage() { if (VERSION.SDK_INT >= 24) { final LocaleList localeList = LocaleList.getDefault(); final String[] locales = new String[localeList.size()]; for (int i = 0; i < localeList.size(); i++) { - locales[i] = localeList.get(i).toLanguageTag(); + // accept-language should be language or language-region format. + locales[i] = getLanguageTagForAcceptLanguage(localeList.get(i)); } return locales; } final String[] locales = new String[1]; final Locale locale = Locale.getDefault(); - locales[0] = locale.toLanguageTag(); + locales[0] = getLanguageTagForAcceptLanguage(locale); return locales; } - private static String getLanguageTag(final Locale locale) { + private static String getLanguageTagForAcceptLanguage(final Locale locale) { final StringBuilder out = new StringBuilder(locale.getLanguage()); final String country = locale.getCountry(); - final String variant = locale.getVariant(); if (!TextUtils.isEmpty(country)) { out.append('-').append(country); } - if (!TextUtils.isEmpty(variant)) { - out.append('-').append(variant); - } - // e.g. "en", "en-US", or "en-US-POSIX". + // e.g. "en", "en-US" return out.toString(); }