commit 786d8a9520d12834983b6e74973e263fe1007d07 parent b86d2953fa5f57676f6115f4b9acfc80e3dbade0 Author: Eemeli Aro <eemeli@mozilla.com> Date: Thu, 30 Oct 2025 10:57:47 +0000 Bug 1760013 - Use Services.locale.acceptLanguages. r=glandium,necko-reviewers,search-reviewers,dom-storage-reviewers,translations-reviewers,toolkit-telemetry-reviewers,firefox-svg-reviewers,valentin,asuth,jdescottes,Gijs,mstriemer,jesup Differential Revision: https://phabricator.services.mozilla.com/D267413 Diffstat:
21 files changed, 86 insertions(+), 101 deletions(-)
diff --git a/browser/actors/AboutProtectionsParent.sys.mjs b/browser/actors/AboutProtectionsParent.sys.mjs @@ -303,10 +303,7 @@ export class AboutProtectionsParent extends JSWindowActorParent { */ async shouldShowProxyCard() { const region = lazy.Region.home || ""; - const languages = Services.prefs.getComplexValue( - "intl.accept_languages", - Ci.nsIPrefLocalizedString - ); + const languages = Services.locale.acceptLanguages; const alreadyInstalled = await lazy.AddonManager.getAddonByID( SECURE_PROXY_ADDON_ID ); @@ -314,7 +311,7 @@ export class AboutProtectionsParent extends JSWindowActorParent { return ( region.toLowerCase() === "us" && !alreadyInstalled && - languages.data.toLowerCase().includes("en-us") + languages.toLowerCase().includes("en-us") ); } diff --git a/browser/base/content/nsContextMenu.sys.mjs b/browser/base/content/nsContextMenu.sys.mjs @@ -2494,10 +2494,7 @@ export class nsContextMenu { var locale = "-"; try { - locale = Services.prefs.getComplexValue( - "intl.accept_languages", - Ci.nsIPrefLocalizedString - ).data; + locale = Services.locale.acceptLanguages; } catch (e) {} var version = "-"; diff --git a/browser/components/enterprisepolicies/Policies.sys.mjs b/browser/components/enterprisepolicies/Policies.sys.mjs @@ -2892,9 +2892,9 @@ export var Policies = { // translations panel intro. Setting a language value simulates a // first translation, which skips the intro panel for users with // FeatureRecommendations disabled. - const topWebPreferredLanguage = Services.prefs - .getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString) - .data.split(/\s*,\s*/g)[0]; + const topWebPreferredLanguage = Services.locale.acceptLanguages + .split(",")[0] + .trim(); const preferredLanguage = topWebPreferredLanguage.length ? topWebPreferredLanguage diff --git a/browser/components/preferences/dialogs/languages.js b/browser/components/preferences/dialogs/languages.js @@ -6,12 +6,21 @@ /* import-globals-from /toolkit/content/preferencesBindings.js */ Preferences.addAll([ - { id: "intl.accept_languages", type: "wstring" }, + { id: "intl.accept_languages", type: "string" }, { id: "pref.browser.language.disable_button.up", type: "bool" }, { id: "pref.browser.language.disable_button.down", type: "bool" }, { id: "pref.browser.language.disable_button.remove", type: "bool" }, { id: "privacy.spoof_english", type: "int" }, ]); +Preferences.addSetting({ + id: "acceptLanguages", + pref: "intl.accept_languages", + get(prefVal, _, setting) { + return setting.pref.defaultValue != prefVal + ? prefVal + : Services.locale.acceptLanguages; + }, +}); var gLanguagesDialog = { _availableLanguagesList: [], @@ -28,7 +37,7 @@ var gLanguagesDialog = { gLanguagesDialog.writeSpoofEnglish() ); - Preferences.get("intl.accept_languages").on("change", () => + Preferences.getSetting("acceptLanguages").on("change", () => this._readAcceptLanguages().catch(console.error) ); @@ -156,7 +165,7 @@ var gLanguagesDialog = { } var selectedIndex = 0; - var preference = Preferences.get("intl.accept_languages"); + var preference = Preferences.getSetting("acceptLanguages"); if (preference.value == "") { this._activeLanguages.selectedIndex = -1; this.onLanguageSelect(); @@ -248,7 +257,7 @@ var gLanguagesDialog = { addLanguage() { var selectedID = this._availableLanguages.selectedItem.id; - var preference = Preferences.get("intl.accept_languages"); + var preference = Preferences.getSetting("acceptLanguages"); var arrayOfPrefs = preference.value.toLowerCase().split(/\s*,\s*/); for (var i = 0; i < arrayOfPrefs.length; ++i) { if (arrayOfPrefs[i] == selectedID) { @@ -295,7 +304,7 @@ var gLanguagesDialog = { this._selectedItemID = selectItem; // Update the preference and force a UI rebuild - var preference = Preferences.get("intl.accept_languages"); + var preference = Preferences.getSetting("acceptLanguages"); preference.value = string; this._buildAvailableLanguageList().catch(console.error); @@ -340,7 +349,7 @@ var gLanguagesDialog = { this._selectedItemID = selectedItem.id; // Update the preference and force a UI rebuild - var preference = Preferences.get("intl.accept_languages"); + var preference = Preferences.getSetting("acceptLanguages"); preference.value = string; }, @@ -364,7 +373,7 @@ var gLanguagesDialog = { this._selectedItemID = selectedItem.id; // Update the preference and force a UI rebuild - var preference = Preferences.get("intl.accept_languages"); + var preference = Preferences.getSetting("acceptLanguages"); preference.value = string; }, diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp @@ -344,16 +344,16 @@ void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) { aLanguages.Clear(); // E.g. "de-de, en-us,en". - nsAutoString acceptLang; - Preferences::GetLocalizedString("intl.accept_languages", acceptLang); + nsAutoCString acceptLang; + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang); // Split values on commas. - for (nsDependentSubstring lang : - nsCharSeparatedTokenizer(acceptLang, ',').ToRange()) { + for (nsDependentCSubstring lang : + nsCCharSeparatedTokenizer(acceptLang, ',').ToRange()) { // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation. // NOTE: we should probably rely on the pref being set correctly. - if (lang.Length() > 2 && lang[2] == char16_t('_')) { - lang.Replace(2, 1, char16_t('-')); + if (lang.Length() > 2 && lang[2] == '_') { + lang.Replace(2, 1, '-'); } // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47 @@ -362,10 +362,10 @@ void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) { if (lang.Length() > 2) { int32_t pos = 0; bool first = true; - for (const nsAString& code : - nsCharSeparatedTokenizer(lang, '-').ToRange()) { + for (const nsACString& code : + nsCCharSeparatedTokenizer(lang, '-').ToRange()) { if (code.Length() == 2 && !first) { - nsAutoString upper(code); + nsAutoCString upper(code); ToUpperCase(upper); lang.Replace(pos, code.Length(), upper); } @@ -375,7 +375,7 @@ void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) { } } - aLanguages.AppendElement(lang); + aLanguages.AppendElement(NS_ConvertUTF8toUTF16(lang)); } if (aLanguages.Length() == 0) { nsTArray<nsCString> locales; diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -34,6 +34,7 @@ #include "mozilla/dom/quota/PromiseUtils.h" #include "mozilla/dom/quota/ResultExtensions.h" #include "mozilla/intl/LocaleCanonicalizer.h" +#include "mozilla/intl/LocaleService.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" #include "nsCharSeparatedTokenizer.h" @@ -778,7 +779,7 @@ nsresult IndexedDatabaseManager::EnsureLocale() { } nsAutoCString acceptLang; - Preferences::GetLocalizedCString("intl.accept_languages", acceptLang); + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang); // Split values on commas. for (const auto& lang : diff --git a/dom/svg/SVGTests.cpp b/dom/svg/SVGTests.cpp @@ -7,8 +7,8 @@ #include "mozilla/dom/SVGTests.h" #include "DOMSVGStringList.h" -#include "mozilla/Preferences.h" #include "mozilla/dom/SVGSwitchElement.h" +#include "mozilla/intl/LocaleService.h" #include "mozilla/intl/oxilangtag_ffi_generated.h" #include "nsCharSeparatedTokenizer.h" #include "nsIContent.h" @@ -68,7 +68,7 @@ static int32_t FindBestLanguage(const nsTArray<nsCString>& aAvailLangs, reqLangs.AppendElements(Span(std::array{"en-US", "en"})); } else { nsCString acceptLangs; - Preferences::GetLocalizedCString("intl.accept_languages", acceptLangs); + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLangs); nsCCharSeparatedTokenizer languageTokenizer(acceptLangs, ','); while (languageTokenizer.hasMoreTokens()) { reqLangs.AppendElement(languageTokenizer.nextToken()); diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp @@ -940,14 +940,11 @@ void gfxFontUtils::ParseFontList(const nsACString& aFamilyList, } void gfxFontUtils::GetPrefsFontList(const char* aPrefName, - nsTArray<nsCString>& aFontList, - bool aLocalized) { + nsTArray<nsCString>& aFontList) { aFontList.Clear(); nsAutoCString fontlistValue; - nsresult rv = aLocalized - ? Preferences::GetLocalizedCString(aPrefName, fontlistValue) - : Preferences::GetCString(aPrefName, fontlistValue); + nsresult rv = Preferences::GetCString(aPrefName, fontlistValue); if (NS_FAILED(rv)) { return; } diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h @@ -1111,8 +1111,7 @@ class gfxFontUtils { // for a given pref name, initialize a list of font names static void GetPrefsFontList(const char* aPrefName, - nsTArray<nsCString>& aFontList, - bool aLocalized = false); + nsTArray<nsCString>& aFontList); // generate a unique font name static nsresult MakeUniqueUserFontName(nsAString& aName); diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp @@ -2498,13 +2498,21 @@ void gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], // temp array eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; uint32_t tempLen = 0; + auto* localeService = LocaleService::GetInstance(); // Add the CJK pref fonts from accept languages, the order should be same - // order. We use gfxFontUtils::GetPrefsFontList to read the list even - // though it's not actually a list of fonts but of lang codes; the format - // is the same. + // order. + nsAutoCString acceptLang; + nsresult rv = localeService->GetAcceptLanguages(acceptLang); + + // We use gfxFontUtils::ParseFontList to read the list even + // though it's not actually a list of fonts but of locale codes; + // the format is the same. AutoTArray<nsCString, 5> list; - gfxFontUtils::GetPrefsFontList("intl.accept_languages", list, true); + if (NS_SUCCEEDED(rv)) { + gfxFontUtils::ParseFontList(acceptLang, list); + } + for (const auto& lang : list) { eFontPrefLang fpl = GetFontPrefLangFor(lang.get()); switch (fpl) { @@ -2522,7 +2530,7 @@ void gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], // Try using app's locale nsAutoCString localeStr; - LocaleService::GetInstance()->GetAppLocaleAsBCP47(localeStr); + localeService->GetAppLocaleAsBCP47(localeStr); { Locale locale; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js @@ -1485,7 +1485,10 @@ pref("network.proxy.enable_wpad_over_dhcp", true); pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u) pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention -pref("intl.accept_languages", "chrome://global/locale/intl.properties"); +// The default value of this pref depends on the current app locale, +// and so should always be read via Services.locale.acceptLanguages. +pref("intl.accept_languages", "und"); + // this pref allows user to request that all internationalization formatters // like date/time formatting, unit formatting, calendars etc. should use // OS locale set instead of the app locale set. diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp @@ -71,6 +71,7 @@ #include "mozilla/net/RequestContextService.h" #include "mozilla/net/SocketProcessParent.h" #include "mozilla/net/SocketProcessChild.h" +#include "mozilla/intl/LocaleService.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/glean/NetwerkProtocolHttpMetrics.h" #include "mozilla/AntiTrackingRedirectHeuristic.h" @@ -2090,7 +2091,7 @@ nsresult nsHttpHandler::SetAcceptLanguages() { mAcceptLanguagesIsDirty = false; nsAutoCString acceptLanguages; - Preferences::GetLocalizedCString(INTL_ACCEPT_LANGUAGES, acceptLanguages); + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLanguages); nsAutoCString buf; nsresult rv = PrepareAcceptLanguages(acceptLanguages.get(), buf); diff --git a/services/common/hawkrequest.sys.mjs b/services/common/hawkrequest.sys.mjs @@ -146,52 +146,44 @@ export async function deriveHawkCredentials(tokenHex, context, size = 96) { // To keep the number of times we read this pref at a minimum, maintain the // preference in a stateful object that notices and updates itself when the // pref is changed. -function Intl() { +class HawkIntl { // We won't actually query the pref until the first time we need it - this._accepted = ""; - this._everRead = false; - this.init(); -} + #accepted = ""; + #everRead = false; -Intl.prototype = { - init() { + constructor() { Services.prefs.addObserver("intl.accept_languages", this); - }, + } uninit() { Services.prefs.removeObserver("intl.accept_languages", this); - }, + } observe() { this.readPref(); - }, + } readPref() { - this._everRead = true; + this.#everRead = true; try { - this._accepted = Services.prefs.getComplexValue( - "intl.accept_languages", - Ci.nsIPrefLocalizedString - ).data; + this.#accepted = Services.locale.acceptLanguages; } catch (err) { let log = Log.repository.getLogger("Services.Common.RESTRequest"); - log.error("Error reading intl.accept_languages pref", err); + log.error("Error reading Services.locale.acceptLanguages", err); } - }, + } get accept_languages() { - if (!this._everRead) { + if (!this.#everRead) { this.readPref(); } - return this._accepted; - }, -}; + return this.#accepted; + } +} // Singleton getter for Intl, creating an instance only when we first need it. var intl = null; function getIntl() { - if (!intl) { - intl = new Intl(); - } + intl ??= new HawkIntl(); return intl; } diff --git a/services/common/tests/unit/test_hawkrequest.js b/services/common/tests/unit/test_hawkrequest.js @@ -153,11 +153,8 @@ add_task(async function test_hawk_authenticated_request() { Assert.equal(request.response.body, "yay"); Services.prefs.clearUserPref("intl.accept_languages"); - let pref = Services.prefs.getComplexValue( - "intl.accept_languages", - Ci.nsIPrefLocalizedString - ); - Assert.notEqual(acceptLanguage, pref.data); + let pref = Services.locale.acceptLanguages; + Assert.notEqual(acceptLanguage, pref); await promiseStopServer(server); }); diff --git a/toolkit/components/extensions/ExtensionCommon.sys.mjs b/toolkit/components/extensions/ExtensionCommon.sys.mjs @@ -2204,11 +2204,7 @@ LocaleData.prototype = { }, get acceptLanguages() { - let result = Services.prefs.getComplexValue( - "intl.accept_languages", - Ci.nsIPrefLocalizedString - ).data; - return result.split(/\s*,\s*/g); + return Services.locale.acceptLanguages.split(/\s*,\s*/g); }, get uiLocale() { diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -55,6 +55,7 @@ #include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/dom/MediaDeviceInfoBinding.h" #include "mozilla/dom/quota/QuotaManager.h" +#include "mozilla/intl/LocaleService.h" #include "mozilla/XorShift128PlusRNG.h" #include "mozilla/dom/CanvasUtils.h" @@ -2941,8 +2942,8 @@ void nsRFPService::CalculateFontLocaleAllowlist() { } nsAutoCString acceptLang; - nsresult rv = Preferences::GetLocalizedCString(INTL_ACCEPT_LANGUAGES_PREF, - acceptLang); + nsresult rv = + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang); NS_ENSURE_SUCCESS_VOID(rv); ToLowerCase(acceptLang); diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp @@ -384,7 +384,7 @@ already_AddRefed<PopulatePromise> PopulateFingerprintedFonts() { void PopulatePrefs() { nsAutoCString acceptLang; - Preferences::GetLocalizedCString("intl.accept_languages", acceptLang); + intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang); glean::characteristics::prefs_intl_accept_languages.Set(acceptLang); glean::characteristics::prefs_media_eme_enabled.Set( diff --git a/toolkit/components/search/SearchEngine.sys.mjs b/toolkit/components/search/SearchEngine.sys.mjs @@ -167,11 +167,7 @@ function paramSubstitution(paramValue, searchTerms, queryCharset) { // Handle languages for URL results. if (name == PARAM_ACCEPT_LANGUAGES) { - let languages = Services.prefs - .getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString) - .data.replace(/\s+/g, ""); - - return languages || ""; + return Services.locale.acceptLanguages.replace(/\s+/g, ""); } // Handle the less common OpenSearch parameters we're confident about. diff --git a/toolkit/components/search/tests/xpcshell/test_getSubmission_params.js b/toolkit/components/search/tests/xpcshell/test_getSubmission_params.js @@ -20,9 +20,7 @@ const TESTS = [ { param: "{language?}", expected: Services.locale.requestedLocale }, { param: "{acceptLanguages}", - expected: Services.prefs - .getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString) - .data.replace(/\s+/g, ""), + expected: Services.locale.acceptLanguages.replace(/\s+/g, ""), }, { param: "{inputEncoding}", charset: "UTF-8", expected: "UTF-8" }, diff --git a/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs b/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs @@ -467,10 +467,7 @@ function getIntlSettings() { appLocales: Services.locale.appLocalesAsBCP47, systemLocales: getSystemLocales(), regionalPrefsLocales: getRegionalPrefsLocales(), - acceptLanguages: Services.prefs - .getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString) - .data.split(",") - .map(str => str.trim()), + acceptLanguages: Services.locale.acceptLanguages.split(/\s*,\s*/g), }; Glean.intl.requestedLocales.set(intl.requestedLocales); Glean.intl.availableLocales.set(intl.availableLocales); diff --git a/toolkit/components/translations/actors/TranslationsParent.sys.mjs b/toolkit/components/translations/actors/TranslationsParent.sys.mjs @@ -1118,18 +1118,14 @@ export class TranslationsParent extends JSWindowActorParent { * The "Accept-Language" values that the localizer or user has indicated for * the preferences for the web. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language * - * Note that this preference always has English in the fallback chain, even if the + * Note that this preference often has English in the fallback chain, even if the * user doesn't actually speak English, and to other languages they potentially do * not speak. However, this preference will be used as an indication that a user may * prefer this language. - * - * https://transvision.flod.org/string/?entity=toolkit/chrome/global/intl.properties:intl.accept_languages&repo=gecko_strings */ static getWebContentLanguages() { if (!TranslationsParent.#webContentLanguages) { - const values = Services.prefs - .getComplexValue(ACCEPT_LANGUAGES_PREF, Ci.nsIPrefLocalizedString) - .data.split(/\s*,\s*/g); + const values = Services.locale.acceptLanguages.split(/\s*,\s*/g); TranslationsParent.#webContentLanguages = new Set();