diff --git a/mobile/android/base/LocaleManager.java b/mobile/android/base/LocaleManager.java index 95f9593a4ffe..9cc57abbc53b 100644 --- a/mobile/android/base/LocaleManager.java +++ b/mobile/android/base/LocaleManager.java @@ -123,6 +123,35 @@ public class LocaleManager { } } + /** + * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale} + * stringifies as "es_ES". + * + * This method approximates the Java 7 method Locale#toLanguageTag(). + * + * @return a locale string suitable for passing to Gecko. + */ + public static String getLanguageTag(final Locale locale) { + // If this were Java 7: + // return locale.toLanguageTag(); + + String language = locale.getLanguage(); // Can, but should never be, an empty string. + // Modernize certain language codes. + if (language.equals("iw")) { + language = "he"; + } else if (language.equals("in")) { + language = "id"; + } else if (language.equals("ji")) { + language = "yi"; + } + + String country = locale.getCountry(); // Can be an empty string. + if (country.equals("")) { + return language; + } + return language + "-" + country; + } + public static Locale getCurrentLocale() { if (currentLocale != null) { return currentLocale; @@ -136,9 +165,13 @@ public class LocaleManager { } /** - * Returns the persisted locale if it differed from the current. + * Updates the Java locale and the Android configuration. + * + * Returns the persisted locale if it differed. + * + * Does not notify Gecko. */ - public static String updateLocale(String localeCode) { + private static String updateLocale(String localeCode) { // Fast path. final Locale defaultLocale = Locale.getDefault(); if (defaultLocale.toString().equals(localeCode)) { @@ -161,13 +194,15 @@ public class LocaleManager { config.locale = locale; res.updateConfiguration(config, res.getDisplayMetrics()); - // Tell Gecko. - GeckoEvent ev = GeckoEvent.createBroadcastEvent("Locale:Changed", locale.toString()); - GeckoAppShell.sendEventToGecko(ev); - return locale.toString(); } + public static void notifyGeckoOfLocaleChange(Locale locale) { + // Tell Gecko. + GeckoEvent ev = GeckoEvent.createBroadcastEvent("Locale:Changed", getLanguageTag(locale)); + GeckoAppShell.sendEventToGecko(ev); + } + private static String getPrefName() { return getContext().getPackageName() + ".locale"; } @@ -198,18 +233,30 @@ public class LocaleManager { return null; } + // Note that we don't tell Gecko about this. We notify Gecko when the + // locale is set, not when we update Java. updateLocale(localeCode); + final long t2 = android.os.SystemClock.uptimeMillis(); Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms."); return localeCode; } /** - * Returns the set locale if it changed. Always persists. + * Returns the set locale if it changed. + * + * Always persists and notifies Gecko. */ public static String setSelectedLocale(String localeCode) { final String resultant = updateLocale(localeCode); + + // We always persist and notify Gecko, even if nothing seemed to + // change. This might happen if you're picking a locale that's the same + // as the current OS locale. The OS locale might change next time we + // launch, and we need the Gecko pref and persisted locale to have been + // set by the time that happens. persistLocale(localeCode); + notifyGeckoOfLocaleChange(getCurrentLocale()); return resultant; } } diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 71a78bd765b1..507bf00c6f8c 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1521,6 +1521,10 @@ var BrowserApp = { break; case "Locale:Changed": + // The value provided to Locale:Changed should be a BCP47 language tag + // understood by Gecko -- for example, "es-ES" or "de". + console.log("Locale:Changed: " + aData); + // TODO: do we need to be more nuanced here -- e.g., checking for the // OS locale -- or should it always be false on Fennec? Services.prefs.setBoolPref("intl.locale.matchOS", false);