summaryrefslogtreecommitdiffstats
path: root/intl/locale/LocaleService.h
diff options
context:
space:
mode:
Diffstat (limited to 'intl/locale/LocaleService.h')
-rw-r--r--intl/locale/LocaleService.h232
1 files changed, 232 insertions, 0 deletions
diff --git a/intl/locale/LocaleService.h b/intl/locale/LocaleService.h
new file mode 100644
index 0000000000..f5b2c8dadc
--- /dev/null
+++ b/intl/locale/LocaleService.h
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef mozilla_intl_LocaleService_h__
+#define mozilla_intl_LocaleService_h__
+
+#include "nsIObserver.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
+#include "MozLocaleBindings.h"
+#include "mozilla/intl/ICU4CGlue.h"
+#include "mozILocaleService.h"
+
+namespace mozilla {
+namespace intl {
+
+/**
+ * LocaleService is a manager of language negotiation in Gecko.
+ *
+ * It's intended to be the core place for collecting available and
+ * requested languages and negotiating them to produce a fallback
+ * chain of locales for the application.
+ *
+ * Client / Server
+ *
+ * LocaleService may operate in one of two modes:
+ *
+ * server
+ * in the server mode, LocaleService is collecting and negotiating
+ * languages. It also subscribes to relevant observers.
+ * There should be at most one server per application instance.
+ *
+ * client
+ * in the client mode, LocaleService is not responsible for collecting
+ * or reacting to any system changes. It still distributes information
+ * about locales, but internally, it gets information from the server
+ * instance instead of collecting it on its own. This prevents any data
+ * desynchronization and minimizes the cost of running the service.
+ *
+ * In both modes, all get* methods should work the same way and all
+ * static methods are available.
+ *
+ * In the server mode, other components may inform LocaleService about their
+ * status either via calls to set* methods or via observer events.
+ * In the client mode, only the process communication should provide data
+ * to the LocaleService.
+ *
+ * At the moment desktop apps use the parent process in the server mode, and
+ * content processes in the client mode.
+ *
+ * Locale / Language
+ *
+ * The terms `Locale ID` and `Language ID` are used slightly differently
+ * by different organizations. Mozilla uses the term `Language ID` to describe
+ * a string that contains information about the language itself, script,
+ * region and variant. For example "en-Latn-US-mac" is a correct Language ID.
+ *
+ * Locale ID contains a Language ID plus a number of extension tags that
+ * contain information that go beyond language inforamation such as
+ * preferred currency, date/time formatting etc.
+ *
+ * An example of a Locale ID is `en-Latn-US-x-hc-h12-ca-gregory`
+ *
+ * At the moment we do not support full extension tag system, but we
+ * try to be specific when naming APIs, so the service is for locales,
+ * but we negotiate between languages etc.
+ */
+class LocaleService final : public mozILocaleService,
+ public nsIObserver,
+ public nsSupportsWeakReference {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ NS_DECL_MOZILOCALESERVICE
+
+ /**
+ * List of available language negotiation strategies.
+ *
+ * See the mozILocaleService.idl for detailed description of the
+ * strategies.
+ */
+ static const int32_t kLangNegStrategyFiltering = 0;
+ static const int32_t kLangNegStrategyMatching = 1;
+ static const int32_t kLangNegStrategyLookup = 2;
+
+ explicit LocaleService(bool aIsServer);
+
+ /**
+ * Create (if necessary) and return a raw pointer to the singleton instance.
+ * Use this accessor in C++ code that just wants to call a method on the
+ * instance, but does not need to hold a reference, as in
+ * nsAutoCString str;
+ * LocaleService::GetInstance()->GetAppLocaleAsLangTag(str);
+ */
+ static LocaleService* GetInstance();
+
+ /**
+ * Return an addRef'd pointer to the singleton instance. This is used by the
+ * XPCOM constructor that exists to support usage from JS.
+ */
+ static already_AddRefed<LocaleService> GetInstanceAddRefed() {
+ return RefPtr<LocaleService>(GetInstance()).forget();
+ }
+
+ /**
+ * Canonicalize a Unicode Language Identifier string.
+ *
+ * The operation is:
+ * * Normalizing casing (`eN-Us-Windows` -> `en-US-windows`)
+ * * Switching `_` to `-` (`en_US` -> `en-US`)
+ * * Rejecting invalid identifiers (`e21-X` sets aLocale to `und` and
+ * returns false)
+ * * Normalizing Mozilla's `ja-JP-mac` to `ja-JP-macos`
+ * * Cutting off POSIX dot postfix (`en-US.utf8` -> `en-US`)
+ *
+ * This operation should be used on any external input before
+ * it gets used in internal operations.
+ */
+ static bool CanonicalizeLanguageId(nsACString& aLocale) {
+ return ffi::unic_langid_canonicalize(&aLocale);
+ }
+ /**
+ * This method should only be called in the client mode.
+ *
+ * It replaces all the language negotiation and is supposed to be called
+ * in order to bring the client LocaleService in sync with the server
+ * LocaleService.
+ *
+ * Currently, it's called by the IPC code.
+ */
+ void AssignAppLocales(const nsTArray<nsCString>& aAppLocales);
+ void AssignRequestedLocales(const nsTArray<nsCString>& aRequestedLocales);
+
+ /**
+ * Those two functions allow to trigger cache invalidation on one of the
+ * three cached values.
+ *
+ * In most cases, the functions will be called by the observer in
+ * LocaleService itself, but in a couple special cases, we have the
+ * other component call this manually instead of sending a global event.
+ *
+ * If the result differs from the previous list, it will additionally
+ * trigger a corresponding event
+ *
+ * This code should be called only in the server mode..
+ */
+ void RequestedLocalesChanged();
+ void LocalesChanged();
+
+ /**
+ * This function keeps the pref setting updated.
+ */
+ void WebExposedLocalesChanged();
+
+ /**
+ * Returns whether the locale is RTL.
+ */
+ static bool IsLocaleRTL(const nsACString& aLocale);
+
+ /**
+ * Returns whether the current app locale is RTL.
+ *
+ * This method respects this override:
+ * - `intl.l10n.pseudo`
+ */
+ bool IsAppLocaleRTL();
+
+ static bool LanguagesMatch(const nsACString& aRequested,
+ const nsACString& aAvailable);
+
+ bool IsServer();
+
+ /**
+ * Create a component from intl/components with the current app's locale. This
+ * is a convenience method for efficient string management with the app
+ * locale.
+ */
+ template <typename T, typename... Args>
+ static Result<UniquePtr<T>, ICUError> TryCreateComponent(Args... args) {
+ // 32 is somewhat arbitrary for the length, but it should fit common
+ // locales, but locales such as the following will be heap allocated:
+ //
+ // "de-u-ca-gregory-fw-mon-hc-h23-co-phonebk-ka-noignore-kb-false-kc-
+ // false-kf-false-kh-false-kk-false-kn-false-kr-space-ks-level1-kv-space-cf-
+ // standard-cu-eur-ms-metric-nu-latn-lb-strict-lw-normal-ss-none-tz-atvie-em-
+ // default-rg-atzzzz-sd-atat1-va-posix"
+ nsAutoCStringN<32> appLocale;
+ mozilla::intl::LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
+
+ return T::TryCreate(appLocale.get(), args...);
+ }
+
+ /**
+ * Create a component from intl/components with a given locale, but fallback
+ * to the app locale if it doesn't work.
+ */
+ template <typename T, typename... Args>
+ static Result<UniquePtr<T>, ICUError> TryCreateComponentWithLocale(
+ const char* aLocale, Args... args) {
+ auto result = T::TryCreate(aLocale, args...);
+ if (result.isOk()) {
+ return result;
+ }
+ return TryCreateComponent<T>(args...);
+ }
+
+ private:
+ void NegotiateAppLocales(nsTArray<nsCString>& aRetVal);
+
+ void InitPackagedLocales();
+
+ void RemoveObservers();
+
+ virtual ~LocaleService() = default;
+
+ nsAutoCStringN<16> mDefaultLocale;
+ nsTArray<nsCString> mAppLocales;
+ nsTArray<nsCString> mRequestedLocales;
+ nsTArray<nsCString> mAvailableLocales;
+ nsTArray<nsCString> mPackagedLocales;
+ nsTArray<nsCString> mWebExposedLocales;
+ const bool mIsServer;
+
+ static StaticRefPtr<LocaleService> sInstance;
+};
+} // namespace intl
+} // namespace mozilla
+
+#endif /* mozilla_intl_LocaleService_h__ */