diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /intl/locale/LocaleService.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'intl/locale/LocaleService.h')
-rw-r--r-- | intl/locale/LocaleService.h | 232 |
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__ */ |