tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LocaleService.h (8359B)


      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/. */
      5 
      6 #ifndef mozilla_intl_LocaleService_h__
      7 #define mozilla_intl_LocaleService_h__
      8 
      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"
     16 
     17 namespace mozilla {
     18 namespace intl {
     19 
     20 /**
     21 * LocaleService is a manager of language negotiation in Gecko.
     22 *
     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.
     26 *
     27 * Client / Server
     28 *
     29 * LocaleService may operate in one of two modes:
     30 *
     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.
     35 *
     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.
     42 *
     43 *   In both modes, all get* methods should work the same way and all
     44 *   static methods are available.
     45 *
     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.
     50 *
     51 *   At the moment desktop apps use the parent process in the server mode, and
     52 *   content processes in the client mode.
     53 *
     54 * Locale / Language
     55 *
     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.
     60 *
     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.
     64 *
     65 * An example of a Locale ID is `en-Latn-US-x-hc-h12-ca-gregory`
     66 *
     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.
     70 */
     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
     78 
     79  /**
     80   * List of available language negotiation strategies.
     81   *
     82   * See the mozILocaleService.idl for detailed description of the
     83   * strategies.
     84   */
     85  static const int32_t kLangNegStrategyFiltering = 0;
     86  static const int32_t kLangNegStrategyMatching = 1;
     87  static const int32_t kLangNegStrategyLookup = 2;
     88 
     89  explicit LocaleService(bool aIsServer);
     90 
     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);
     97   */
     98  static LocaleService* GetInstance();
     99 
    100  /**
    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.
    103   */
    104  static already_AddRefed<LocaleService> GetInstanceAddRefed() {
    105    return RefPtr<LocaleService>(GetInstance()).forget();
    106  }
    107 
    108  /**
    109   * Canonicalize a Unicode Language Identifier string.
    110   *
    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`)
    118   *
    119   * This operation should be used on any external input before
    120   * it gets used in internal operations.
    121   */
    122  static bool CanonicalizeLanguageId(nsACString& aLocale) {
    123    return ffi::unic_langid_canonicalize(&aLocale);
    124  }
    125  /**
    126   * This method should only be called in the client mode.
    127   *
    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.
    131   *
    132   * Currently, it's called by the IPC code.
    133   */
    134  void AssignAppLocales(const nsTArray<nsCString>& aAppLocales);
    135  void AssignRequestedLocales(const nsTArray<nsCString>& aRequestedLocales);
    136 
    137  /**
    138   * Those two functions allow to trigger cache invalidation on one of the
    139   * three cached values.
    140   *
    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.
    144   *
    145   * If the result differs from the previous list, it will additionally
    146   * trigger a corresponding event
    147   *
    148   * This code should be called only in the server mode..
    149   */
    150  void RequestedLocalesChanged();
    151  void LocalesChanged();
    152 
    153  /**
    154   * This function keeps the pref setting updated.
    155   */
    156  void WebExposedLocalesChanged();
    157 
    158  /**
    159   * Returns whether the locale is RTL.
    160   */
    161  static bool IsLocaleRTL(const nsACString& aLocale);
    162 
    163  /**
    164   * Returns whether the current app locale is RTL.
    165   *
    166   * This method respects this override:
    167   *  - `intl.l10n.pseudo`
    168   */
    169  bool IsAppLocaleRTL();
    170 
    171  /**
    172   * If true, accesskeys should always be appended for the current app locale.
    173   */
    174  bool AlwaysAppendAccesskeys();
    175 
    176  /**
    177   * If true, accesskeys should always be separated from the label.
    178   */
    179  bool InsertSeparatorBeforeAccesskeys();
    180 
    181  static bool LanguagesMatch(const nsACString& aRequested,
    182                             const nsACString& aAvailable);
    183 
    184  bool IsServer();
    185 
    186  /**
    187   * Create a component from intl/components with the current app's locale. This
    188   * is a convenience method for efficient string management with the app
    189   * locale.
    190   */
    191  template <typename T, typename... Args>
    192  static Result<UniquePtr<T>, ICUError> TryCreateComponent(Args... args) {
    193    // 32 is somewhat arbitrary for the length, but it should fit common
    194    // locales, but locales such as the following will be heap allocated:
    195    //
    196    //  "de-u-ca-gregory-fw-mon-hc-h23-co-phonebk-ka-noignore-kb-false-kc-
    197    //    false-kf-false-kh-false-kk-false-kn-false-kr-space-ks-level1-kv-space-cf-
    198    //    standard-cu-eur-ms-metric-nu-latn-lb-strict-lw-normal-ss-none-tz-atvie-em-
    199    //    default-rg-atzzzz-sd-atat1-va-posix"
    200    nsAutoCStringN<32> appLocale;
    201    mozilla::intl::LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
    202 
    203    return T::TryCreate(appLocale.get(), args...);
    204  }
    205 
    206  /**
    207   * Create a component from intl/components with a given locale, but fallback
    208   * to the app locale if it doesn't work.
    209   */
    210  template <typename T, typename... Args>
    211  static Result<UniquePtr<T>, ICUError> TryCreateComponentWithLocale(
    212      const char* aLocale, Args... args) {
    213    auto result = T::TryCreate(aLocale, args...);
    214    if (result.isOk()) {
    215      return result;
    216    }
    217    return TryCreateComponent<T>(args...);
    218  }
    219 
    220 private:
    221  void NegotiateAppLocales(nsTArray<nsCString>& aRetVal);
    222 
    223  void InitPackagedLocales();
    224 
    225  void RemoveObservers();
    226 
    227  virtual ~LocaleService() = default;
    228 
    229  nsAutoCStringN<16> mDefaultLocale;
    230  nsTArray<nsCString> mAppLocales;
    231  nsTArray<nsCString> mRequestedLocales;
    232  nsTArray<nsCString> mAvailableLocales;
    233  nsTArray<nsCString> mPackagedLocales;
    234  nsTArray<nsCString> mWebExposedLocales;
    235  const bool mIsServer;
    236 
    237  static StaticRefPtr<LocaleService> sInstance;
    238 };
    239 }  // namespace intl
    240 }  // namespace mozilla
    241 
    242 #endif /* mozilla_intl_LocaleService_h__ */