Bug 1787947 - pref on CSS named pages in Nightly r=dholbert
[gecko.git] / intl / locale / LocaleService.h
blobf5b2c8dadc4982d12e9ab8c43ed059b3d6cb9f7b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_intl_LocaleService_h__
7 #define mozilla_intl_LocaleService_h__
9 #include "nsIObserver.h"
10 #include "nsString.h"
11 #include "nsTArray.h"
12 #include "nsWeakReference.h"
13 #include "MozLocaleBindings.h"
14 #include "mozilla/intl/ICU4CGlue.h"
15 #include "mozILocaleService.h"
17 namespace mozilla {
18 namespace intl {
20 /**
21 * LocaleService is a manager of language negotiation in Gecko.
23 * It's intended to be the core place for collecting available and
24 * requested languages and negotiating them to produce a fallback
25 * chain of locales for the application.
27 * Client / Server
29 * LocaleService may operate in one of two modes:
31 * server
32 * in the server mode, LocaleService is collecting and negotiating
33 * languages. It also subscribes to relevant observers.
34 * There should be at most one server per application instance.
36 * client
37 * in the client mode, LocaleService is not responsible for collecting
38 * or reacting to any system changes. It still distributes information
39 * about locales, but internally, it gets information from the server
40 * instance instead of collecting it on its own. This prevents any data
41 * desynchronization and minimizes the cost of running the service.
43 * In both modes, all get* methods should work the same way and all
44 * static methods are available.
46 * In the server mode, other components may inform LocaleService about their
47 * status either via calls to set* methods or via observer events.
48 * In the client mode, only the process communication should provide data
49 * to the LocaleService.
51 * At the moment desktop apps use the parent process in the server mode, and
52 * content processes in the client mode.
54 * Locale / Language
56 * The terms `Locale ID` and `Language ID` are used slightly differently
57 * by different organizations. Mozilla uses the term `Language ID` to describe
58 * a string that contains information about the language itself, script,
59 * region and variant. For example "en-Latn-US-mac" is a correct Language ID.
61 * Locale ID contains a Language ID plus a number of extension tags that
62 * contain information that go beyond language inforamation such as
63 * preferred currency, date/time formatting etc.
65 * An example of a Locale ID is `en-Latn-US-x-hc-h12-ca-gregory`
67 * At the moment we do not support full extension tag system, but we
68 * try to be specific when naming APIs, so the service is for locales,
69 * but we negotiate between languages etc.
71 class LocaleService final : public mozILocaleService,
72 public nsIObserver,
73 public nsSupportsWeakReference {
74 public:
75 NS_DECL_ISUPPORTS
76 NS_DECL_NSIOBSERVER
77 NS_DECL_MOZILOCALESERVICE
79 /**
80 * List of available language negotiation strategies.
82 * See the mozILocaleService.idl for detailed description of the
83 * strategies.
85 static const int32_t kLangNegStrategyFiltering = 0;
86 static const int32_t kLangNegStrategyMatching = 1;
87 static const int32_t kLangNegStrategyLookup = 2;
89 explicit LocaleService(bool aIsServer);
91 /**
92 * Create (if necessary) and return a raw pointer to the singleton instance.
93 * Use this accessor in C++ code that just wants to call a method on the
94 * instance, but does not need to hold a reference, as in
95 * nsAutoCString str;
96 * LocaleService::GetInstance()->GetAppLocaleAsLangTag(str);
98 static LocaleService* GetInstance();
101 * Return an addRef'd pointer to the singleton instance. This is used by the
102 * XPCOM constructor that exists to support usage from JS.
104 static already_AddRefed<LocaleService> GetInstanceAddRefed() {
105 return RefPtr<LocaleService>(GetInstance()).forget();
109 * Canonicalize a Unicode Language Identifier string.
111 * The operation is:
112 * * Normalizing casing (`eN-Us-Windows` -> `en-US-windows`)
113 * * Switching `_` to `-` (`en_US` -> `en-US`)
114 * * Rejecting invalid identifiers (`e21-X` sets aLocale to `und` and
115 * returns false)
116 * * Normalizing Mozilla's `ja-JP-mac` to `ja-JP-macos`
117 * * Cutting off POSIX dot postfix (`en-US.utf8` -> `en-US`)
119 * This operation should be used on any external input before
120 * it gets used in internal operations.
122 static bool CanonicalizeLanguageId(nsACString& aLocale) {
123 return ffi::unic_langid_canonicalize(&aLocale);
126 * This method should only be called in the client mode.
128 * It replaces all the language negotiation and is supposed to be called
129 * in order to bring the client LocaleService in sync with the server
130 * LocaleService.
132 * Currently, it's called by the IPC code.
134 void AssignAppLocales(const nsTArray<nsCString>& aAppLocales);
135 void AssignRequestedLocales(const nsTArray<nsCString>& aRequestedLocales);
138 * Those two functions allow to trigger cache invalidation on one of the
139 * three cached values.
141 * In most cases, the functions will be called by the observer in
142 * LocaleService itself, but in a couple special cases, we have the
143 * other component call this manually instead of sending a global event.
145 * If the result differs from the previous list, it will additionally
146 * trigger a corresponding event
148 * This code should be called only in the server mode..
150 void RequestedLocalesChanged();
151 void LocalesChanged();
154 * This function keeps the pref setting updated.
156 void WebExposedLocalesChanged();
159 * Returns whether the locale is RTL.
161 static bool IsLocaleRTL(const nsACString& aLocale);
164 * Returns whether the current app locale is RTL.
166 * This method respects this override:
167 * - `intl.l10n.pseudo`
169 bool IsAppLocaleRTL();
171 static bool LanguagesMatch(const nsACString& aRequested,
172 const nsACString& aAvailable);
174 bool IsServer();
177 * Create a component from intl/components with the current app's locale. This
178 * is a convenience method for efficient string management with the app
179 * locale.
181 template <typename T, typename... Args>
182 static Result<UniquePtr<T>, ICUError> TryCreateComponent(Args... args) {
183 // 32 is somewhat arbitrary for the length, but it should fit common
184 // locales, but locales such as the following will be heap allocated:
186 // "de-u-ca-gregory-fw-mon-hc-h23-co-phonebk-ka-noignore-kb-false-kc-
187 // false-kf-false-kh-false-kk-false-kn-false-kr-space-ks-level1-kv-space-cf-
188 // standard-cu-eur-ms-metric-nu-latn-lb-strict-lw-normal-ss-none-tz-atvie-em-
189 // default-rg-atzzzz-sd-atat1-va-posix"
190 nsAutoCStringN<32> appLocale;
191 mozilla::intl::LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
193 return T::TryCreate(appLocale.get(), args...);
197 * Create a component from intl/components with a given locale, but fallback
198 * to the app locale if it doesn't work.
200 template <typename T, typename... Args>
201 static Result<UniquePtr<T>, ICUError> TryCreateComponentWithLocale(
202 const char* aLocale, Args... args) {
203 auto result = T::TryCreate(aLocale, args...);
204 if (result.isOk()) {
205 return result;
207 return TryCreateComponent<T>(args...);
210 private:
211 void NegotiateAppLocales(nsTArray<nsCString>& aRetVal);
213 void InitPackagedLocales();
215 void RemoveObservers();
217 virtual ~LocaleService() = default;
219 nsAutoCStringN<16> mDefaultLocale;
220 nsTArray<nsCString> mAppLocales;
221 nsTArray<nsCString> mRequestedLocales;
222 nsTArray<nsCString> mAvailableLocales;
223 nsTArray<nsCString> mPackagedLocales;
224 nsTArray<nsCString> mWebExposedLocales;
225 const bool mIsServer;
227 static StaticRefPtr<LocaleService> sInstance;
229 } // namespace intl
230 } // namespace mozilla
232 #endif /* mozilla_intl_LocaleService_h__ */