2017-01-26 02:58:14 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "LocaleService.h"
|
2017-02-05 23:29:39 +03:00
|
|
|
|
2017-02-25 04:23:39 +03:00
|
|
|
#include <algorithm> // find_if()
|
2017-01-26 02:58:14 +03:00
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2017-09-23 14:46:28 +03:00
|
|
|
#include "mozilla/Omnijar.h"
|
2017-03-07 00:24:45 +03:00
|
|
|
#include "mozilla/Preferences.h"
|
2017-09-23 14:46:28 +03:00
|
|
|
#include "mozilla/Services.h"
|
2018-01-06 11:23:09 +03:00
|
|
|
#include "mozilla/intl/MozLocale.h"
|
2017-03-07 00:24:45 +03:00
|
|
|
#include "mozilla/intl/OSPreferences.h"
|
2017-01-26 02:58:14 +03:00
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIToolkitChromeRegistry.h"
|
2017-09-23 14:46:28 +03:00
|
|
|
#include "nsStringEnumerator.h"
|
2017-03-15 01:28:47 +03:00
|
|
|
#include "nsXULAppAPI.h"
|
2017-09-23 14:46:28 +03:00
|
|
|
#include "nsZipArchive.h"
|
2017-01-26 02:58:14 +03:00
|
|
|
|
2017-02-25 04:23:39 +03:00
|
|
|
#include "unicode/uloc.h"
|
|
|
|
|
2017-10-05 19:43:38 +03:00
|
|
|
#define INTL_SYSTEM_LOCALES_CHANGED "intl:system-locales-changed"
|
|
|
|
|
2017-11-02 06:16:21 +03:00
|
|
|
#define REQUESTED_LOCALES_PREF "intl.locale.requested"
|
2017-03-07 00:24:45 +03:00
|
|
|
|
|
|
|
static const char* kObservedPrefs[] = {
|
2017-11-02 06:16:21 +03:00
|
|
|
REQUESTED_LOCALES_PREF,
|
2017-03-07 00:24:45 +03:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
2017-01-26 02:58:14 +03:00
|
|
|
using namespace mozilla::intl;
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
using namespace mozilla;
|
2017-01-26 02:58:14 +03:00
|
|
|
|
2017-09-09 03:51:43 +03:00
|
|
|
NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService, nsIObserver,
|
|
|
|
nsISupportsWeakReference)
|
2017-02-05 23:29:39 +03:00
|
|
|
|
|
|
|
mozilla::StaticRefPtr<LocaleService> LocaleService::sInstance;
|
|
|
|
|
2017-03-13 18:31:43 +03:00
|
|
|
/**
|
|
|
|
* This function transforms a canonical Mozilla Language Tag, into it's
|
|
|
|
* BCP47 compilant form.
|
|
|
|
*
|
|
|
|
* Example: "ja-JP-mac" -> "ja-JP-x-lvariant-mac"
|
|
|
|
*
|
|
|
|
* The BCP47 form should be used for all calls to ICU/Intl APIs.
|
|
|
|
* The canonical form is used for all internal operations.
|
|
|
|
*/
|
2017-11-02 06:16:21 +03:00
|
|
|
static bool
|
|
|
|
SanitizeForBCP47(nsACString& aLocale, bool strict)
|
2017-03-13 18:31:43 +03:00
|
|
|
{
|
|
|
|
// Currently, the only locale code we use that's not BCP47-conformant is
|
|
|
|
// "ja-JP-mac" on OS X, but let's try to be more general than just
|
|
|
|
// hard-coding that here.
|
|
|
|
const int32_t LANG_TAG_CAPACITY = 128;
|
|
|
|
char langTag[LANG_TAG_CAPACITY];
|
|
|
|
nsAutoCString locale(aLocale);
|
2017-11-02 06:16:21 +03:00
|
|
|
locale.Trim(" ");
|
2017-03-13 18:31:43 +03:00
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
|
// This is a fail-safe method that will set langTag to "und" if it cannot
|
|
|
|
// match any part of the input locale code.
|
|
|
|
int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
|
2017-11-02 06:16:21 +03:00
|
|
|
strict, &err);
|
2017-03-13 18:31:43 +03:00
|
|
|
if (U_SUCCESS(err) && len > 0) {
|
|
|
|
aLocale.Assign(langTag, len);
|
|
|
|
}
|
2017-11-02 06:16:21 +03:00
|
|
|
return U_SUCCESS(err);
|
2017-03-13 18:31:43 +03:00
|
|
|
}
|
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
static bool
|
|
|
|
ReadRequestedLocales(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
2017-11-02 06:16:21 +03:00
|
|
|
nsAutoCString str;
|
|
|
|
nsresult rv = Preferences::GetCString(REQUESTED_LOCALES_PREF, str);
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
|
2017-11-02 06:16:21 +03:00
|
|
|
// We handle three scenarios here:
|
|
|
|
//
|
|
|
|
// 1) The pref is not set - use default locale
|
|
|
|
// 2) The pref is set to "" - use OS locales
|
|
|
|
// 3) The pref is set to a value - parse the locale list and use it
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (str.Length() > 0) {
|
|
|
|
for (const nsACString& part : str.Split(',')) {
|
|
|
|
nsAutoCString locale(part);
|
2017-12-07 22:51:31 +03:00
|
|
|
if (locale.EqualsLiteral("ja-JP-mac")) {
|
|
|
|
// This is a hack required to handle the special Mozilla `ja-JP-mac` locale.
|
|
|
|
if (!aRetVal.Contains(locale)) {
|
|
|
|
aRetVal.AppendElement(locale);
|
2017-11-02 06:16:21 +03:00
|
|
|
}
|
2017-12-07 22:51:31 +03:00
|
|
|
} else if (SanitizeForBCP47(locale, true)) {
|
2017-11-02 06:16:21 +03:00
|
|
|
if (!aRetVal.Contains(locale)) {
|
|
|
|
aRetVal.AppendElement(locale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If the pref string is empty, we'll take requested locales
|
|
|
|
// from the OS.
|
|
|
|
OSPreferences::GetInstance()->GetSystemLocales(aRetVal);
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
2017-11-02 06:16:21 +03:00
|
|
|
} else {
|
|
|
|
nsAutoCString defaultLocale;
|
|
|
|
LocaleService::GetInstance()->GetDefaultLocale(defaultLocale);
|
|
|
|
aRetVal.AppendElement(defaultLocale);
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
|
|
|
|
2017-11-16 06:09:15 +03:00
|
|
|
// Last fallback locale is a locale for the requested locale chain.
|
|
|
|
// In the future we'll want to make the fallback chain differ per-locale.
|
2017-11-06 20:01:35 +03:00
|
|
|
//
|
|
|
|
// Notice: This is not the same as DefaultLocale,
|
|
|
|
// which follows the default locale the build is in.
|
2017-11-02 06:16:21 +03:00
|
|
|
LocaleService::GetInstance()->GetLastFallbackLocale(str);
|
|
|
|
if (!aRetVal.Contains(str)) {
|
|
|
|
aRetVal.AppendElement(str);
|
2017-11-06 20:01:35 +03:00
|
|
|
}
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ReadAvailableLocales(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIToolkitChromeRegistry> cr =
|
|
|
|
mozilla::services::GetToolkitChromeRegistryService();
|
|
|
|
if (!cr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIUTF8StringEnumerator> localesEnum;
|
|
|
|
|
|
|
|
nsresult rv =
|
|
|
|
cr->GetLocalesForPackage(NS_LITERAL_CSTRING("global"), getter_AddRefs(localesEnum));
|
|
|
|
if (!NS_SUCCEEDED(rv)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool more;
|
|
|
|
while (NS_SUCCEEDED(rv = localesEnum->HasMore(&more)) && more) {
|
|
|
|
nsAutoCString localeStr;
|
|
|
|
rv = localesEnum->GetNext(localeStr);
|
|
|
|
if (!NS_SUCCEEDED(rv)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetVal.AppendElement(localeStr);
|
|
|
|
}
|
|
|
|
return !aRetVal.IsEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
LocaleService::LocaleService(bool aIsServer)
|
|
|
|
:mIsServer(aIsServer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-01-26 02:58:14 +03:00
|
|
|
/**
|
|
|
|
* This function performs the actual language negotiation for the API.
|
|
|
|
*
|
|
|
|
* Currently it collects the locale ID used by nsChromeRegistry and
|
2017-11-16 06:09:15 +03:00
|
|
|
* adds hardcoded default locale as a fallback.
|
2017-01-26 02:58:14 +03:00
|
|
|
*/
|
2017-03-15 01:28:47 +03:00
|
|
|
void
|
|
|
|
LocaleService::NegotiateAppLocales(nsTArray<nsCString>& aRetVal)
|
2017-01-26 02:58:14 +03:00
|
|
|
{
|
2017-03-15 01:28:47 +03:00
|
|
|
nsAutoCString defaultLocale;
|
|
|
|
GetDefaultLocale(defaultLocale);
|
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
if (mIsServer) {
|
2017-03-15 01:28:47 +03:00
|
|
|
AutoTArray<nsCString, 100> availableLocales;
|
|
|
|
AutoTArray<nsCString, 10> requestedLocales;
|
|
|
|
GetAvailableLocales(availableLocales);
|
|
|
|
GetRequestedLocales(requestedLocales);
|
|
|
|
|
|
|
|
NegotiateLanguages(requestedLocales, availableLocales, defaultLocale,
|
|
|
|
LangNegStrategy::Filtering, aRetVal);
|
|
|
|
} else {
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
// In content process, we will not do any language negotiation.
|
|
|
|
// Instead, the language is set manually by SetAppLocales.
|
|
|
|
//
|
|
|
|
// If this method has been called, it means that we did not fire
|
|
|
|
// SetAppLocales yet (happens during initialization).
|
|
|
|
// In that case, all we can do is return the default locale.
|
|
|
|
// Once SetAppLocales will be called later, it'll fire an event
|
|
|
|
// allowing callers to update the locale.
|
|
|
|
aRetVal.AppendElement(defaultLocale);
|
2017-01-26 02:58:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-05 23:29:39 +03:00
|
|
|
LocaleService*
|
|
|
|
LocaleService::GetInstance()
|
2017-01-26 02:58:14 +03:00
|
|
|
{
|
|
|
|
if (!sInstance) {
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
sInstance = new LocaleService(XRE_IsParentProcess());
|
2017-03-07 00:24:45 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
if (sInstance->IsServer()) {
|
|
|
|
// We're going to observe for requested languages changes which come
|
|
|
|
// from prefs.
|
2017-09-09 03:51:43 +03:00
|
|
|
DebugOnly<nsresult> rv = Preferences::AddWeakObservers(sInstance, kObservedPrefs);
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Adding observers failed.");
|
2017-10-05 19:43:38 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->AddObserver(sInstance, INTL_SYSTEM_LOCALES_CHANGED, true);
|
|
|
|
}
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
2017-10-05 19:43:38 +03:00
|
|
|
ClearOnShutdown(&sInstance, ShutdownPhase::Shutdown);
|
2017-01-26 02:58:14 +03:00
|
|
|
}
|
|
|
|
return sInstance;
|
|
|
|
}
|
|
|
|
|
2017-03-07 00:24:45 +03:00
|
|
|
LocaleService::~LocaleService()
|
|
|
|
{
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
if (mIsServer) {
|
2017-09-09 03:51:43 +03:00
|
|
|
Preferences::RemoveObservers(this, kObservedPrefs);
|
2017-10-05 19:43:38 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->RemoveObserver(this, INTL_SYSTEM_LOCALES_CHANGED);
|
|
|
|
}
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
2017-03-07 00:24:45 +03:00
|
|
|
}
|
|
|
|
|
2017-01-26 02:58:14 +03:00
|
|
|
void
|
2017-03-13 18:31:43 +03:00
|
|
|
LocaleService::GetAppLocalesAsLangTags(nsTArray<nsCString>& aRetVal)
|
2017-01-26 02:58:14 +03:00
|
|
|
{
|
|
|
|
if (mAppLocales.IsEmpty()) {
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(mAppLocales);
|
2017-01-26 02:58:14 +03:00
|
|
|
}
|
|
|
|
aRetVal = mAppLocales;
|
|
|
|
}
|
|
|
|
|
2017-03-13 18:31:43 +03:00
|
|
|
void
|
|
|
|
LocaleService::GetAppLocalesAsBCP47(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
if (mAppLocales.IsEmpty()) {
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(mAppLocales);
|
2017-03-13 18:31:43 +03:00
|
|
|
}
|
|
|
|
for (uint32_t i = 0; i < mAppLocales.Length(); i++) {
|
|
|
|
nsAutoCString locale(mAppLocales[i]);
|
2017-11-02 06:16:21 +03:00
|
|
|
SanitizeForBCP47(locale, false);
|
2017-03-13 18:31:43 +03:00
|
|
|
aRetVal.AppendElement(locale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-08 23:54:04 +03:00
|
|
|
void
|
|
|
|
LocaleService::GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
bool useOSLocales = Preferences::GetBool("intl.regional_prefs.use_os_locales", false);
|
|
|
|
|
2017-10-17 00:32:29 +03:00
|
|
|
// If the user specified that they want to use OS Regional Preferences locales,
|
|
|
|
// try to retrieve them and use.
|
|
|
|
if (useOSLocales) {
|
|
|
|
if (OSPreferences::GetInstance()->GetRegionalPrefsLocales(aRetVal)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we fail to retrieve them, return the app locales.
|
|
|
|
GetAppLocalesAsBCP47(aRetVal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, fetch OS Regional Preferences locales and compare the first one
|
|
|
|
// to the app locale. If the language subtag matches, we can safely use
|
|
|
|
// the OS Regional Preferences locale.
|
|
|
|
//
|
|
|
|
// This facilitates scenarios such as Firefox in "en-US" and User sets
|
|
|
|
// regional prefs to "en-GB".
|
|
|
|
nsAutoCString appLocale;
|
|
|
|
AutoTArray<nsCString, 10> regionalPrefsLocales;
|
|
|
|
LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
|
|
|
|
|
|
|
|
if (!OSPreferences::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales)) {
|
|
|
|
GetAppLocalesAsBCP47(aRetVal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LocaleService::LanguagesMatch(appLocale, regionalPrefsLocales[0])) {
|
|
|
|
aRetVal = regionalPrefsLocales;
|
2017-07-08 23:54:04 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 00:32:29 +03:00
|
|
|
// Otherwise use the app locales.
|
2017-07-08 23:54:04 +03:00
|
|
|
GetAppLocalesAsBCP47(aRetVal);
|
|
|
|
}
|
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
void
|
|
|
|
LocaleService::AssignAppLocales(const nsTArray<nsCString>& aAppLocales)
|
2017-03-07 00:24:45 +03:00
|
|
|
{
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
MOZ_ASSERT(!mIsServer, "This should only be called for LocaleService in client mode.");
|
2017-03-07 00:24:45 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
mAppLocales = aAppLocales;
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr);
|
|
|
|
}
|
|
|
|
}
|
2017-03-07 00:24:45 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
void
|
|
|
|
LocaleService::AssignRequestedLocales(const nsTArray<nsCString>& aRequestedLocales)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mIsServer, "This should only be called for LocaleService in client mode.");
|
|
|
|
|
|
|
|
mRequestedLocales = aRequestedLocales;
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(nullptr, "intl:requested-locales-changed", nullptr);
|
2017-03-07 00:24:45 +03:00
|
|
|
}
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
2017-03-07 00:24:45 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
bool
|
|
|
|
LocaleService::GetRequestedLocales(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
if (mRequestedLocales.IsEmpty()) {
|
|
|
|
ReadRequestedLocales(mRequestedLocales);
|
2017-03-07 00:24:45 +03:00
|
|
|
}
|
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
aRetVal = mRequestedLocales;
|
2017-03-07 00:24:45 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-14 03:33:24 +03:00
|
|
|
bool
|
|
|
|
LocaleService::GetAvailableLocales(nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
if (mAvailableLocales.IsEmpty()) {
|
|
|
|
ReadAvailableLocales(mAvailableLocales);
|
|
|
|
}
|
2017-03-14 03:33:24 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
aRetVal = mAvailableLocales;
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-14 03:33:24 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
void
|
2017-10-05 19:43:38 +03:00
|
|
|
LocaleService::AvailableLocalesChanged()
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
|
|
|
|
mAvailableLocales.Clear();
|
|
|
|
// In the future we may want to trigger here intl:available-locales-changed
|
2017-10-05 19:43:38 +03:00
|
|
|
LocalesChanged();
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
}
|
2017-03-14 03:33:24 +03:00
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
void
|
2017-10-05 19:43:38 +03:00
|
|
|
LocaleService::RequestedLocalesChanged()
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
|
|
|
|
|
|
|
|
nsTArray<nsCString> newLocales;
|
|
|
|
ReadRequestedLocales(newLocales);
|
|
|
|
|
|
|
|
if (mRequestedLocales != newLocales) {
|
|
|
|
mRequestedLocales = Move(newLocales);
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(nullptr, "intl:requested-locales-changed", nullptr);
|
|
|
|
}
|
2017-10-05 19:43:38 +03:00
|
|
|
LocalesChanged();
|
2017-03-14 03:33:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-26 02:58:14 +03:00
|
|
|
void
|
2017-10-05 19:43:38 +03:00
|
|
|
LocaleService::LocalesChanged()
|
2017-01-26 02:58:14 +03:00
|
|
|
{
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
|
|
|
|
|
2017-03-15 01:28:47 +03:00
|
|
|
// if mAppLocales has not been initialized yet, just return
|
|
|
|
if (mAppLocales.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-26 02:58:14 +03:00
|
|
|
nsTArray<nsCString> newLocales;
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(newLocales);
|
2017-01-26 02:58:14 +03:00
|
|
|
|
|
|
|
if (mAppLocales != newLocales) {
|
|
|
|
mAppLocales = Move(newLocales);
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr);
|
2017-03-15 01:28:47 +03:00
|
|
|
|
|
|
|
// Deprecated, please use `intl:app-locales-changed`.
|
|
|
|
// Kept for now for compatibility reasons
|
|
|
|
obs->NotifyObservers(nullptr, "selected-locale-has-changed", nullptr);
|
2017-01-26 02:58:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-05 23:29:39 +03:00
|
|
|
|
2017-02-25 04:23:39 +03:00
|
|
|
// After trying each step of the negotiation algorithm for each requested locale,
|
|
|
|
// if a match was found we use this macro to decide whether to return immediately,
|
|
|
|
// skip to the next requested locale, or continue searching for additional matches,
|
|
|
|
// according to the desired negotiation strategy.
|
|
|
|
#define HANDLE_STRATEGY \
|
|
|
|
switch (aStrategy) { \
|
|
|
|
case LangNegStrategy::Lookup: \
|
|
|
|
return; \
|
|
|
|
case LangNegStrategy::Matching: \
|
|
|
|
continue; \
|
|
|
|
case LangNegStrategy::Filtering: \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the raw algorithm for language negotiation based roughly
|
|
|
|
* on RFC4647 language filtering, with changes from LDML language matching.
|
|
|
|
*
|
Bug 1400006 - Extend language negotiation in LocaleService to support looking for the best likelySubtag for the locale with region stripped. r=Pike
Add additional logic to our language negotation to do apply likelySubtags when a direct match is not available.
Currently, if the user specifies the locale with region, and we do not have a direct for that region, we pick all locales for the same language and other regions in no order.
The example of where it returns suboptimal results:
1) Requested locale "en-CA"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-ZA", "en-GB", "en-US"]
This would not happen, if the user requested a generic "de", "en" etc.:
1) Requested locale "en"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-US", "en-ZA", "en-GB"]
because after not finding a direct match, we would use likelySubtags to extend "en" to "en-Latn-US" and then find the priority match in "en-US".
This patch extends this logic to "en-US" or "de-LU" by adding a step which strips the region tag and then applies likelySubtag on the result.
This means that in absence of direct match the following fallbacks would happen:
"de-LU" -> "de-DE"
"es-CL" -> "es-ES"
"en-CA" -> "en-US"
This does not affect languages that use multiple scripts, so ar, sr and zh are not affected.
MozReview-Commit-ID: BR1WrgXSf6a
--HG--
extra : rebase_source : abc205c4f993680ab0cd0c8b8c016543d5462d01
2017-09-15 01:21:33 +03:00
|
|
|
* The exact algorithm is custom, and consists of a 6 level strategy:
|
2017-02-25 04:23:39 +03:00
|
|
|
*
|
|
|
|
* 1) Attempt to find an exact match for each requested locale in available
|
|
|
|
* locales.
|
|
|
|
* Example: ['en-US'] * ['en-US'] = ['en-US']
|
|
|
|
*
|
|
|
|
* 2) Attempt to match a requested locale to an available locale treated
|
|
|
|
* as a locale range.
|
|
|
|
* Example: ['en-US'] * ['en'] = ['en']
|
|
|
|
* ^^
|
|
|
|
* |-- becomes 'en-*-*-*'
|
|
|
|
*
|
|
|
|
* 3) Attempt to use the maximized version of the requested locale, to
|
|
|
|
* find the best match in available locales.
|
|
|
|
* Example: ['en'] * ['en-GB', 'en-US'] = ['en-US']
|
|
|
|
* ^^
|
|
|
|
* |-- ICU likelySubtags expands it to 'en-Latn-US'
|
|
|
|
*
|
|
|
|
* 4) Attempt to look up for a different variant of the same locale.
|
|
|
|
* Example: ['ja-JP-win'] * ['ja-JP-mac'] = ['ja-JP-mac']
|
|
|
|
* ^^^^^^^^^
|
|
|
|
* |----------- replace variant with range: 'ja-JP-*'
|
|
|
|
*
|
Bug 1400006 - Extend language negotiation in LocaleService to support looking for the best likelySubtag for the locale with region stripped. r=Pike
Add additional logic to our language negotation to do apply likelySubtags when a direct match is not available.
Currently, if the user specifies the locale with region, and we do not have a direct for that region, we pick all locales for the same language and other regions in no order.
The example of where it returns suboptimal results:
1) Requested locale "en-CA"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-ZA", "en-GB", "en-US"]
This would not happen, if the user requested a generic "de", "en" etc.:
1) Requested locale "en"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-US", "en-ZA", "en-GB"]
because after not finding a direct match, we would use likelySubtags to extend "en" to "en-Latn-US" and then find the priority match in "en-US".
This patch extends this logic to "en-US" or "de-LU" by adding a step which strips the region tag and then applies likelySubtag on the result.
This means that in absence of direct match the following fallbacks would happen:
"de-LU" -> "de-DE"
"es-CL" -> "es-ES"
"en-CA" -> "en-US"
This does not affect languages that use multiple scripts, so ar, sr and zh are not affected.
MozReview-Commit-ID: BR1WrgXSf6a
--HG--
extra : rebase_source : abc205c4f993680ab0cd0c8b8c016543d5462d01
2017-09-15 01:21:33 +03:00
|
|
|
* 5) Attempt to look up for a maximized version of the requested locale,
|
|
|
|
* stripped of the region code.
|
|
|
|
* Example: ['en-CA'] * ['en-ZA', 'en-US'] = ['en-US', 'en-ZA']
|
|
|
|
* ^^^^^
|
|
|
|
* |----------- look for likelySubtag of 'en': 'en-Latn-US'
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* 6) Attempt to look up for a different region of the same locale.
|
2017-02-25 04:23:39 +03:00
|
|
|
* Example: ['en-GB'] * ['en-AU'] = ['en-AU']
|
|
|
|
* ^^^^^
|
|
|
|
* |----- replace region with range: 'en-*'
|
|
|
|
*
|
|
|
|
* It uses one of the strategies described in LocaleService.h.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
LocaleService::FilterMatches(const nsTArray<nsCString>& aRequested,
|
|
|
|
const nsTArray<nsCString>& aAvailable,
|
|
|
|
LangNegStrategy aStrategy,
|
|
|
|
nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
// Local copy of the list of available locales, in Locale form for flexible
|
2018-01-31 23:28:51 +03:00
|
|
|
// matching. We will invalidate entries in this list when they are matched
|
|
|
|
// and the corresponding strings from aAvailable added to aRetVal, so that
|
|
|
|
// no available locale will be found more than once.
|
2017-02-25 04:23:39 +03:00
|
|
|
AutoTArray<Locale, 100> availLocales;
|
|
|
|
for (auto& avail : aAvailable) {
|
2018-01-26 01:50:32 +03:00
|
|
|
availLocales.AppendElement(Locale(avail));
|
2017-02-25 04:23:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& requested : aRequested) {
|
2018-01-26 01:50:32 +03:00
|
|
|
if (requested.IsEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-02-25 04:23:39 +03:00
|
|
|
|
|
|
|
// 1) Try to find a simple (case-insensitive) string match for the request.
|
2018-01-26 01:50:32 +03:00
|
|
|
auto matchesExactly = [&](Locale& aLoc) {
|
2017-02-25 04:23:39 +03:00
|
|
|
return requested.Equals(aLoc.AsString(),
|
|
|
|
nsCaseInsensitiveCStringComparator());
|
|
|
|
};
|
|
|
|
auto match = std::find_if(availLocales.begin(), availLocales.end(),
|
|
|
|
matchesExactly);
|
|
|
|
if (match != availLocales.end()) {
|
2018-01-31 23:28:51 +03:00
|
|
|
aRetVal.AppendElement(aAvailable[match - availLocales.begin()]);
|
|
|
|
match->Invalidate();
|
2017-02-25 04:23:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!aRetVal.IsEmpty()) {
|
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2) Try to match against the available locales treated as ranges.
|
2018-01-26 01:50:32 +03:00
|
|
|
auto findRangeMatches = [&](Locale& aReq, bool aAvailRange, bool aReqRange) {
|
|
|
|
auto matchesRange = [&](Locale& aLoc) {
|
|
|
|
return aLoc.Matches(aReq, aAvailRange, aReqRange);
|
2017-02-25 04:23:39 +03:00
|
|
|
};
|
|
|
|
bool foundMatch = false;
|
|
|
|
auto match = availLocales.begin();
|
|
|
|
while ((match = std::find_if(match, availLocales.end(),
|
|
|
|
matchesRange)) != availLocales.end()) {
|
2018-01-31 23:28:51 +03:00
|
|
|
aRetVal.AppendElement(aAvailable[match - availLocales.begin()]);
|
|
|
|
match->Invalidate();
|
2017-02-25 04:23:39 +03:00
|
|
|
foundMatch = true;
|
|
|
|
if (aStrategy != LangNegStrategy::Filtering) {
|
|
|
|
return true; // we only want the first match
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return foundMatch;
|
|
|
|
};
|
|
|
|
|
2018-01-26 01:50:32 +03:00
|
|
|
Locale requestedLocale = Locale(requested);
|
|
|
|
if (findRangeMatches(requestedLocale, true, false)) {
|
2017-02-25 04:23:39 +03:00
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3) Try to match against a maximized version of the requested locale
|
|
|
|
if (requestedLocale.AddLikelySubtags()) {
|
2018-01-26 01:50:32 +03:00
|
|
|
if (findRangeMatches(requestedLocale, true, false)) {
|
2017-02-25 04:23:39 +03:00
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 4) Try to match against a variant as a range
|
2018-01-26 01:50:32 +03:00
|
|
|
requestedLocale.ClearVariants();
|
|
|
|
if (findRangeMatches(requestedLocale, true, true)) {
|
2017-02-25 04:23:39 +03:00
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
|
Bug 1400006 - Extend language negotiation in LocaleService to support looking for the best likelySubtag for the locale with region stripped. r=Pike
Add additional logic to our language negotation to do apply likelySubtags when a direct match is not available.
Currently, if the user specifies the locale with region, and we do not have a direct for that region, we pick all locales for the same language and other regions in no order.
The example of where it returns suboptimal results:
1) Requested locale "en-CA"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-ZA", "en-GB", "en-US"]
This would not happen, if the user requested a generic "de", "en" etc.:
1) Requested locale "en"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-US", "en-ZA", "en-GB"]
because after not finding a direct match, we would use likelySubtags to extend "en" to "en-Latn-US" and then find the priority match in "en-US".
This patch extends this logic to "en-US" or "de-LU" by adding a step which strips the region tag and then applies likelySubtag on the result.
This means that in absence of direct match the following fallbacks would happen:
"de-LU" -> "de-DE"
"es-CL" -> "es-ES"
"en-CA" -> "en-US"
This does not affect languages that use multiple scripts, so ar, sr and zh are not affected.
MozReview-Commit-ID: BR1WrgXSf6a
--HG--
extra : rebase_source : abc205c4f993680ab0cd0c8b8c016543d5462d01
2017-09-15 01:21:33 +03:00
|
|
|
// 5) Try to match against the likely subtag without region
|
2018-01-26 01:50:32 +03:00
|
|
|
requestedLocale.ClearRegion();
|
|
|
|
if (requestedLocale.AddLikelySubtags()) {
|
|
|
|
if (findRangeMatches(requestedLocale, true, false)) {
|
Bug 1400006 - Extend language negotiation in LocaleService to support looking for the best likelySubtag for the locale with region stripped. r=Pike
Add additional logic to our language negotation to do apply likelySubtags when a direct match is not available.
Currently, if the user specifies the locale with region, and we do not have a direct for that region, we pick all locales for the same language and other regions in no order.
The example of where it returns suboptimal results:
1) Requested locale "en-CA"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-ZA", "en-GB", "en-US"]
This would not happen, if the user requested a generic "de", "en" etc.:
1) Requested locale "en"
2) Available locales ["en-ZA", "en-GB", "en-US"]
3) Negotiated locales ["en-US", "en-ZA", "en-GB"]
because after not finding a direct match, we would use likelySubtags to extend "en" to "en-Latn-US" and then find the priority match in "en-US".
This patch extends this logic to "en-US" or "de-LU" by adding a step which strips the region tag and then applies likelySubtag on the result.
This means that in absence of direct match the following fallbacks would happen:
"de-LU" -> "de-DE"
"es-CL" -> "es-ES"
"en-CA" -> "en-US"
This does not affect languages that use multiple scripts, so ar, sr and zh are not affected.
MozReview-Commit-ID: BR1WrgXSf6a
--HG--
extra : rebase_source : abc205c4f993680ab0cd0c8b8c016543d5462d01
2017-09-15 01:21:33 +03:00
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 6) Try to match against a region as a range
|
2018-01-26 01:50:32 +03:00
|
|
|
requestedLocale.ClearRegion();
|
|
|
|
if (findRangeMatches(requestedLocale, true, true)) {
|
2017-02-25 04:23:39 +03:00
|
|
|
HANDLE_STRATEGY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
LocaleService::NegotiateLanguages(const nsTArray<nsCString>& aRequested,
|
|
|
|
const nsTArray<nsCString>& aAvailable,
|
|
|
|
const nsACString& aDefaultLocale,
|
|
|
|
LangNegStrategy aStrategy,
|
|
|
|
nsTArray<nsCString>& aRetVal)
|
|
|
|
{
|
|
|
|
// If the strategy is Lookup, we require the defaultLocale to be set.
|
|
|
|
if (aStrategy == LangNegStrategy::Lookup && aDefaultLocale.IsEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FilterMatches(aRequested, aAvailable, aStrategy, aRetVal);
|
|
|
|
|
|
|
|
if (aStrategy == LangNegStrategy::Lookup) {
|
|
|
|
if (aRetVal.Length() == 0) {
|
|
|
|
// If the strategy is Lookup and Filtering returned no matches, use
|
|
|
|
// the default locale.
|
|
|
|
aRetVal.AppendElement(aDefaultLocale);
|
|
|
|
}
|
|
|
|
} else if (!aDefaultLocale.IsEmpty() && !aRetVal.Contains(aDefaultLocale)) {
|
|
|
|
// If it's not a Lookup strategy, add the default locale only if it's
|
|
|
|
// set and it's not in the results already.
|
|
|
|
aRetVal.AppendElement(aDefaultLocale);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-14 22:35:06 +03:00
|
|
|
bool
|
|
|
|
LocaleService::IsAppLocaleRTL()
|
|
|
|
{
|
|
|
|
nsAutoCString locale;
|
|
|
|
GetAppLocaleAsBCP47(locale);
|
|
|
|
|
|
|
|
int pref = Preferences::GetInt("intl.uidirection", -1);
|
|
|
|
if (pref >= 0) {
|
|
|
|
return (pref > 0);
|
|
|
|
}
|
|
|
|
return uloc_isRightToLeft(locale.get());
|
|
|
|
}
|
|
|
|
|
2017-03-07 00:24:45 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::Observe(nsISupports *aSubject, const char *aTopic,
|
|
|
|
const char16_t *aData)
|
|
|
|
{
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
|
|
|
|
|
2017-10-05 19:43:38 +03:00
|
|
|
if (!strcmp(aTopic, INTL_SYSTEM_LOCALES_CHANGED)) {
|
|
|
|
RequestedLocalesChanged();
|
|
|
|
} else {
|
|
|
|
NS_ConvertUTF16toUTF8 pref(aData);
|
|
|
|
// At the moment the only thing we're observing are settings indicating
|
|
|
|
// user requested locales.
|
2017-11-02 06:16:21 +03:00
|
|
|
if (pref.EqualsLiteral(REQUESTED_LOCALES_PREF)) {
|
2017-10-05 19:43:38 +03:00
|
|
|
RequestedLocalesChanged();
|
|
|
|
}
|
2017-03-07 00:24:45 +03:00
|
|
|
}
|
2017-10-05 19:43:38 +03:00
|
|
|
|
2017-03-07 00:24:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-02-25 04:23:39 +03:00
|
|
|
|
2017-03-03 03:39:17 +03:00
|
|
|
bool
|
2018-01-26 01:50:32 +03:00
|
|
|
LocaleService::LanguagesMatch(const nsACString& aRequested,
|
|
|
|
const nsACString& aAvailable)
|
2017-03-03 03:39:17 +03:00
|
|
|
{
|
2018-01-26 01:50:32 +03:00
|
|
|
Locale requested = Locale(aRequested);
|
|
|
|
Locale available = Locale(aAvailable);
|
|
|
|
return requested.GetLanguage().Equals(available.GetLanguage());
|
2017-03-03 03:39:17 +03:00
|
|
|
}
|
|
|
|
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
|
|
|
|
bool
|
|
|
|
LocaleService::IsServer()
|
|
|
|
{
|
|
|
|
return mIsServer;
|
|
|
|
}
|
|
|
|
|
2017-02-05 23:29:39 +03:00
|
|
|
/**
|
|
|
|
* mozILocaleService methods
|
|
|
|
*/
|
2017-03-07 00:24:45 +03:00
|
|
|
|
|
|
|
static char**
|
|
|
|
CreateOutArray(const nsTArray<nsCString>& aArray)
|
|
|
|
{
|
|
|
|
uint32_t n = aArray.Length();
|
|
|
|
char** result = static_cast<char**>(moz_xmalloc(n * sizeof(char*)));
|
|
|
|
for (uint32_t i = 0; i < n; i++) {
|
|
|
|
result[i] = moz_xstrdup(aArray[i].get());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-03-14 23:04:59 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetDefaultLocale(nsACString& aRetVal)
|
|
|
|
{
|
2017-09-23 14:46:28 +03:00
|
|
|
// We don't allow this to change during a session (it's set at build/package
|
|
|
|
// time), so we cache the result the first time we're called.
|
|
|
|
if (mDefaultLocale.IsEmpty()) {
|
|
|
|
// Try to get the package locale from update.locale in omnijar. If the
|
|
|
|
// update.locale file is not found, item.len will remain 0 and we'll
|
|
|
|
// just use our hard-coded default below.
|
|
|
|
// (We could also search for an update.locale file in the GRE resources
|
|
|
|
// directory, to support non-packaged builds, but that seems like a lot
|
|
|
|
// of extra code for what is probably not an important use case.)
|
|
|
|
RefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE);
|
|
|
|
if (zip) {
|
|
|
|
nsZipItemPtr<char> item(zip, "update.locale");
|
|
|
|
size_t len = item.Length();
|
|
|
|
// Ignore any trailing spaces, newlines, etc.
|
|
|
|
while (len > 0 && item.Buffer()[len - 1] <= ' ') {
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
mDefaultLocale.Assign(item.Buffer(), len);
|
|
|
|
}
|
2017-11-16 06:09:15 +03:00
|
|
|
|
2017-09-23 14:46:28 +03:00
|
|
|
// Hard-coded fallback, e.g. for non-packaged developer builds.
|
|
|
|
if (mDefaultLocale.IsEmpty()) {
|
2017-11-16 06:09:15 +03:00
|
|
|
GetLastFallbackLocale(mDefaultLocale);
|
2017-09-23 14:46:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetVal = mDefaultLocale;
|
2017-03-14 23:04:59 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-11-16 06:09:15 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetLastFallbackLocale(nsACString& aRetVal)
|
|
|
|
{
|
|
|
|
aRetVal.AssignLiteral("en-US");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-02-05 23:29:39 +03:00
|
|
|
NS_IMETHODIMP
|
2017-03-13 18:31:43 +03:00
|
|
|
LocaleService::GetAppLocalesAsLangTags(uint32_t* aCount, char*** aOutArray)
|
2017-02-05 23:29:39 +03:00
|
|
|
{
|
|
|
|
if (mAppLocales.IsEmpty()) {
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(mAppLocales);
|
2017-02-05 23:29:39 +03:00
|
|
|
}
|
|
|
|
|
2017-02-21 00:14:25 +03:00
|
|
|
*aCount = mAppLocales.Length();
|
2017-03-07 00:24:45 +03:00
|
|
|
*aOutArray = CreateOutArray(mAppLocales);
|
2017-02-05 23:29:39 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2017-03-13 18:31:43 +03:00
|
|
|
LocaleService::GetAppLocalesAsBCP47(uint32_t* aCount, char*** aOutArray)
|
|
|
|
{
|
|
|
|
AutoTArray<nsCString, 32> locales;
|
|
|
|
GetAppLocalesAsBCP47(locales);
|
|
|
|
|
|
|
|
*aCount = locales.Length();
|
|
|
|
*aOutArray = CreateOutArray(locales);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetAppLocaleAsLangTag(nsACString& aRetVal)
|
|
|
|
{
|
|
|
|
if (mAppLocales.IsEmpty()) {
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(mAppLocales);
|
2017-03-13 18:31:43 +03:00
|
|
|
}
|
|
|
|
aRetVal = mAppLocales[0];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetAppLocaleAsBCP47(nsACString& aRetVal)
|
2017-02-05 23:29:39 +03:00
|
|
|
{
|
2017-02-09 00:12:16 +03:00
|
|
|
if (mAppLocales.IsEmpty()) {
|
2017-03-15 01:28:47 +03:00
|
|
|
NegotiateAppLocales(mAppLocales);
|
2017-02-09 00:12:16 +03:00
|
|
|
}
|
|
|
|
aRetVal = mAppLocales[0];
|
Bug 1348042 - Refactor LocaleService to operate in server-client mode. r=Ehsan,qdot
LocaleService serves two main functions. It is a central place for all code in the
engine to learn about locales, but it also does the language negotiation and selection.
The former is relevant in all processes, but the latter should only be performed
by the "main" process. In case of current Desktop Firefox, the parent process
is the one performing all the language negotiation, and content processes should
operate in the "client" mode.
In Fennec, there's a Java app on top of Gecko which should work as a "server"
and then all processes, including parent process of Gecko is merely a "client" for that.
This refactor finalizes this duality making it easily configurable to define in
which mode a given LocaleService operates.
The server-client model allows all clients to stay in sync with the server,
but operate transparently for all callers just returning the right values.
In order to initialize LocaleService in the client mode in child process with the
right locales I'm adding the list of app locales to the XPCOMInitData,
and then fire LocaleService::SetAppLocales in the child process initialization.
In order to keep the list up to date, I'm adding intl:app-locales-changed to
the list of observed topics, and when triggered, I send the updated list
to the child process, which updates LocaleService::SetAppLocales with the new
list.
MozReview-Commit-ID: K9X6berF3IO
--HG--
extra : rebase_source : ca5e502d064023fddfd63fe6fe5eccefce8dee52
2017-03-26 08:09:45 +03:00
|
|
|
|
2017-11-02 06:16:21 +03:00
|
|
|
SanitizeForBCP47(aRetVal, false);
|
2017-02-05 23:29:39 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-02-25 04:23:39 +03:00
|
|
|
|
2017-07-08 23:54:04 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetRegionalPrefsLocales(uint32_t* aCount, char*** aOutArray)
|
|
|
|
{
|
|
|
|
AutoTArray<nsCString,10> rgLocales;
|
|
|
|
|
|
|
|
GetRegionalPrefsLocales(rgLocales);
|
|
|
|
|
|
|
|
*aCount = rgLocales.Length();
|
|
|
|
*aOutArray = static_cast<char**>(moz_xmalloc(*aCount * sizeof(char*)));
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < *aCount; i++) {
|
|
|
|
(*aOutArray)[i] = moz_xstrdup(rgLocales[i].get());
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-02-25 04:23:39 +03:00
|
|
|
static LocaleService::LangNegStrategy
|
|
|
|
ToLangNegStrategy(int32_t aStrategy)
|
|
|
|
{
|
|
|
|
switch (aStrategy) {
|
|
|
|
case 1:
|
|
|
|
return LocaleService::LangNegStrategy::Matching;
|
|
|
|
case 2:
|
|
|
|
return LocaleService::LangNegStrategy::Lookup;
|
|
|
|
default:
|
|
|
|
return LocaleService::LangNegStrategy::Filtering;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::NegotiateLanguages(const char** aRequested,
|
|
|
|
const char** aAvailable,
|
|
|
|
const char* aDefaultLocale,
|
|
|
|
int32_t aStrategy,
|
|
|
|
uint32_t aRequestedCount,
|
|
|
|
uint32_t aAvailableCount,
|
|
|
|
uint32_t* aCount, char*** aRetVal)
|
|
|
|
{
|
|
|
|
if (aStrategy < 0 || aStrategy > 2) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the given string contains only ASCII characters valid in tags
|
|
|
|
// (i.e. alphanumerics, plus '-' and '_'), and is non-empty.
|
|
|
|
auto validTagChars = [](const char* s) {
|
2017-03-20 22:14:58 +03:00
|
|
|
if (!s || !*s) {
|
2017-02-25 04:23:39 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
while (*s) {
|
|
|
|
if (isalnum((unsigned char)*s) || *s == '-' || *s == '_' || *s == '*') {
|
|
|
|
s++;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
AutoTArray<nsCString, 100> requestedLocales;
|
|
|
|
for (uint32_t i = 0; i < aRequestedCount; i++) {
|
|
|
|
if (!validTagChars(aRequested[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
requestedLocales.AppendElement(aRequested[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
AutoTArray<nsCString, 100> availableLocales;
|
|
|
|
for (uint32_t i = 0; i < aAvailableCount; i++) {
|
|
|
|
if (!validTagChars(aAvailable[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
availableLocales.AppendElement(aAvailable[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString defaultLocale(aDefaultLocale);
|
|
|
|
|
|
|
|
LangNegStrategy strategy = ToLangNegStrategy(aStrategy);
|
|
|
|
|
|
|
|
AutoTArray<nsCString, 100> supportedLocales;
|
|
|
|
bool result = NegotiateLanguages(requestedLocales, availableLocales,
|
|
|
|
defaultLocale, strategy, supportedLocales);
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aRetVal =
|
|
|
|
static_cast<char**>(moz_xmalloc(sizeof(char*) * supportedLocales.Length()));
|
|
|
|
|
|
|
|
*aCount = 0;
|
|
|
|
for (const auto& supported : supportedLocales) {
|
|
|
|
(*aRetVal)[(*aCount)++] = moz_xstrdup(supported.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-07 00:24:45 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetRequestedLocales(uint32_t* aCount, char*** aOutArray)
|
|
|
|
{
|
|
|
|
AutoTArray<nsCString, 16> requestedLocales;
|
|
|
|
bool res = GetRequestedLocales(requestedLocales);
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
NS_ERROR("Couldn't retrieve selected locales from prefs!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aCount = requestedLocales.Length();
|
|
|
|
*aOutArray = CreateOutArray(requestedLocales);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-03-12 22:34:56 +03:00
|
|
|
|
2017-03-12 05:43:11 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetRequestedLocale(nsACString& aRetVal)
|
|
|
|
{
|
|
|
|
AutoTArray<nsCString, 16> requestedLocales;
|
|
|
|
bool res = GetRequestedLocales(requestedLocales);
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
NS_ERROR("Couldn't retrieve selected locales from prefs!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (requestedLocales.Length() > 0) {
|
|
|
|
aRetVal = requestedLocales[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-12 22:34:56 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::SetRequestedLocales(const char** aRequested,
|
|
|
|
uint32_t aRequestedCount)
|
|
|
|
{
|
2017-11-02 06:16:21 +03:00
|
|
|
nsAutoCString str;
|
2017-03-12 22:34:56 +03:00
|
|
|
|
2017-11-02 06:16:21 +03:00
|
|
|
for (uint32_t i = 0; i < aRequestedCount; i++) {
|
|
|
|
nsAutoCString locale(aRequested[i]);
|
2017-12-07 22:51:31 +03:00
|
|
|
if (!locale.EqualsLiteral("ja-JP-mac") &&
|
|
|
|
!SanitizeForBCP47(locale, true)) {
|
2017-11-02 06:16:21 +03:00
|
|
|
NS_ERROR("Invalid language tag provided to SetRequestedLocales!");
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0) {
|
|
|
|
str.AppendLiteral(",");
|
|
|
|
}
|
|
|
|
str.Append(locale);
|
2017-03-12 22:34:56 +03:00
|
|
|
}
|
2017-11-02 06:16:21 +03:00
|
|
|
Preferences::SetCString(REQUESTED_LOCALES_PREF, str);
|
2017-03-12 22:34:56 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-03-14 03:33:24 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetAvailableLocales(uint32_t* aCount, char*** aOutArray)
|
|
|
|
{
|
|
|
|
AutoTArray<nsCString, 100> availableLocales;
|
|
|
|
bool res = GetAvailableLocales(availableLocales);
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
NS_ERROR("Couldn't retrieve available locales!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aCount = availableLocales.Length();
|
|
|
|
*aOutArray = CreateOutArray(availableLocales);
|
2017-03-14 22:35:06 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-03-14 03:33:24 +03:00
|
|
|
|
2017-03-14 22:35:06 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
LocaleService::GetIsAppLocaleRTL(bool* aRetVal)
|
|
|
|
{
|
|
|
|
(*aRetVal) = IsAppLocaleRTL();
|
2017-03-14 03:33:24 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|