summaryrefslogtreecommitdiffstats
path: root/intl/locale/OSPreferences.h
blob: e8d95f823bcea4053db7122790c325dbc2b7411a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* -*- 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_IntlOSPreferences_h__
#define mozilla_intl_IntlOSPreferences_h__

#include "mozilla/StaticPtr.h"
#include "nsTHashMap.h"
#include "nsString.h"
#include "nsTArray.h"

#include "mozIOSPreferences.h"

namespace mozilla {
namespace intl {

/**
 * OSPreferences API provides a set of methods for retrieving information from
 * the host environment on topics such as:
 *   - Internationalization
 *   - Localization
 *   - Regional preferences
 *
 * The API is meant to remain as simple as possible, relaying information from
 * the host environment to the user without too much logic.
 *
 * Saying that, there are two exceptions to that paradigm.
 *
 * First one is normalization. We do intend to translate host environment
 * concepts to unified Intl/L10n vocabulary used by Mozilla.
 * That means that we will format locale IDs, timezone names, currencies etc.
 * into a chosen format.
 *
 * Second is caching. This API does cache values and where possible will
 * hook into the environment for some event-driven cache invalidation.
 *
 * This means that on platforms that do not support a mechanism to
 * notify apps about changes, new OS-level settings may not be reflected
 * in the app until it is relaunched.
 */
class OSPreferences : public mozIOSPreferences {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_MOZIOSPREFERENCES

  enum class DateTimeFormatStyle {
    Invalid = -1,
    None,
    Short,   // e.g. time: HH:mm, date: Y/m/d
    Medium,  // likely same as Short
    Long,    // e.g. time: including seconds, date: including weekday
    Full     // e.g. time: with timezone, date: with long weekday, month
  };

  /**
   * Constructor, to do any necessary initialization such as registering for
   * notifications from the system when prefs are modified.
   */
  OSPreferences();

  /**
   * 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;
   *    OSPreferences::GetInstance()->GetSystemLocale(str);
   *
   * NOTE that this is not safe for off-main-thread use, because it is possible
   * that XPCOM shutdown on the main thread could invalidate it at any moment!
   */
  static OSPreferences* 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<OSPreferences> GetInstanceAddRefed();

  static bool GetPatternForSkeleton(const nsACString& aSkeleton,
                                    const nsACString& aLocale,
                                    nsACString& aRetVal);

  static bool GetDateTimeConnectorPattern(const nsACString& aLocale,
                                          nsACString& aRetVal);

  /**
   * Triggers a refresh of retrieving data from host environment.
   *
   * If the result differs from the previous list, it will additionally
   * trigger global events for changed values:
   *
   *  * SystemLocales: "intl:system-locales-changed"
   *
   * This method should not be called from anywhere except of per-platform
   * hooks into OS events.
   */
  void Refresh();

 protected:
  nsTArray<nsCString> mSystemLocales;
  nsTArray<nsCString> mRegionalPrefsLocales;

  const size_t kMaxCachedPatterns = 15;
  nsTHashMap<nsCStringHashKey, nsCString> mPatternCache;

 private:
  virtual ~OSPreferences();

  static StaticRefPtr<OSPreferences> sInstance;

  static bool CanonicalizeLanguageTag(nsCString& aLoc);

  /**
   * Helper methods to get formats from ICU; these will return false
   * in case of error, in which case the caller cannot rely on aRetVal.
   */
  bool GetDateTimePatternForStyle(DateTimeFormatStyle aDateStyle,
                                  DateTimeFormatStyle aTimeStyle,
                                  const nsACString& aLocale,
                                  nsACString& aRetVal);

  bool GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
                                   DateTimeFormatStyle aTimeStyle,
                                   const nsACString& aLocale,
                                   nsACString& aRetVal);

  bool OverrideDateTimePattern(DateTimeFormatStyle aDateStyle,
                               DateTimeFormatStyle aTimeStyle,
                               const nsACString& aLocale, nsACString& aRetVal);

  /**
   * This is a host environment specific method that will be implemented
   * separately for each platform.
   *
   * It is only called when the cache is empty or invalidated.
   *
   * The return value indicates whether the function successfully
   * resolved at least one locale.
   */
  bool ReadSystemLocales(nsTArray<nsCString>& aRetVal);

  bool ReadRegionalPrefsLocales(nsTArray<nsCString>& aRetVal);

  /**
   * This is a host environment specific method that will be implemented
   * separately for each platform.
   *
   * It is `best-effort` kind of API that attempts to construct the best
   * possible date/time pattern for the given styles and locales.
   *
   * In case we fail to, or don't know how to retrieve the pattern in a
   * given environment this function will return false.
   * Callers should always be prepared to handle that scenario.
   *
   * The heuristic may depend on the OS API and HIG guidelines.
   */
  bool ReadDateTimePattern(DateTimeFormatStyle aDateFormatStyle,
                           DateTimeFormatStyle aTimeFormatStyle,
                           const nsACString& aLocale, nsACString& aRetVal);

  /**
   * This is called to override the hour cycle in the skeleton based upon
   * the OS preference for AM/PM or 24 hour display.
   */
  void OverrideSkeletonHourCycle(bool aIs24Hour, nsAutoCString& aSkeleton);

  /**
   * This is called by the destructor to clean up any OS specific observers
   * that are registered.
   */
  void RemoveObservers();

  /**
   * This is called by the destructor to clean up any OS specific observers
   * that are registered.
   */
  static void PreferenceChanged(const char* aPrefName, void* /* aClosure */);
};

}  // namespace intl
}  // namespace mozilla

#endif /* mozilla_intl_IntlOSPreferences_h__ */