intl-objects.h 13 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6 7 8 9 10
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif  // V8_INTL_SUPPORT

#ifndef V8_OBJECTS_INTL_OBJECTS_H_
#define V8_OBJECTS_INTL_OBJECTS_H_
11

12
#include <map>
13
#include <memory>
14 15 16
#include <set>
#include <string>

Frank Tang's avatar
Frank Tang committed
17
#include "src/base/timezone-cache.h"
18
#include "src/objects/contexts.h"
19
#include "src/objects/managed.h"
20
#include "src/objects/objects.h"
21
#include "unicode/locid.h"
22
#include "unicode/uversion.h"
23

24
#define V8_MINIMUM_ICU_VERSION 67
25

26
namespace U_ICU_NAMESPACE {
27
class BreakIterator;
28
class Collator;
29
class FormattedValue;
30
class UnicodeString;
31
}  // namespace U_ICU_NAMESPACE
32

33 34
namespace v8 {
namespace internal {
35

36 37
template <typename T>
class Handle;
38
class JSCollator;
marja's avatar
marja committed
39

40
class Intl {
41
 public:
42 43 44 45 46
  enum class BoundFunctionContextSlot {
    kBoundFunction = Context::MIN_CONTEXT_SLOTS,
    kLength
  };

47 48 49 50 51
  // Build a set of ICU locales from a list of Locales. If there is a locale
  // with a script tag then the locales also include a locale without the
  // script; eg, pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India)
  // would include pa_IN.
  static std::set<std::string> BuildLocaleSet(
52
      const std::vector<std::string>& locales, const char* path,
53
      const char* validate_key);
54

55
  static Maybe<std::string> ToLanguageTag(const icu::Locale& locale);
56

57 58 59 60 61 62
  // Get the name of the numbering system from locale.
  // ICU doesn't expose numbering system in any way, so we have to assume that
  // for given locale NumberingSystem constructor produces the same digits as
  // NumberFormat/Calendar would.
  static std::string GetNumberingSystem(const icu::Locale& icu_locale);

63
  static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> SupportedLocalesOf(
64 65
      Isolate* isolate, const char* method,
      const std::set<std::string>& available_locales, Handle<Object> locales_in,
66
      Handle<Object> options_in);
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
  // ecma402/#sec-getoption
  //
  // This is specialized for the case when type is string.
  //
  // Instead of passing undefined for the values argument as the spec
  // defines, pass in an empty vector.
  //
  // Returns true if options object has the property and stores the
  // result in value. Returns false if the value is not found. The
  // caller is required to use fallback value appropriately in this
  // case.
  //
  // service is a string denoting the type of Intl object; used when
  // printing the error message.
83
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> GetStringOption(
84 85 86 87
      Isolate* isolate, Handle<JSReceiver> options, const char* property,
      std::vector<const char*> values, const char* service,
      std::unique_ptr<char[]>* result);

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
  // A helper template to get string from option into a enum.
  // The enum in the enum_values is the corresponding value to the strings
  // in the str_values. If the option does not contains name,
  // default_value will be return.
  template <typename T>
  V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOption(
      Isolate* isolate, Handle<JSReceiver> options, const char* name,
      const char* method, const std::vector<const char*>& str_values,
      const std::vector<T>& enum_values, T default_value) {
    DCHECK_EQ(str_values.size(), enum_values.size());
    std::unique_ptr<char[]> cstr;
    Maybe<bool> found = Intl::GetStringOption(isolate, options, name,
                                              str_values, method, &cstr);
    MAYBE_RETURN(found, Nothing<T>());
    if (found.FromJust()) {
      DCHECK_NOT_NULL(cstr.get());
      for (size_t i = 0; i < str_values.size(); i++) {
        if (strcmp(cstr.get(), str_values[i]) == 0) {
          return Just(enum_values[i]);
        }
      }
      UNREACHABLE();
    }
    return Just(default_value);
  }

114 115 116 117 118 119 120 121 122 123 124 125
  // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
  // ecma402/#sec-getoption
  //
  // This is specialized for the case when type is boolean.
  //
  // Returns true if options object has the property and stores the
  // result in value. Returns false if the value is not found. The
  // caller is required to use fallback value appropriately in this
  // case.
  //
  // service is a string denoting the type of Intl object; used when
  // printing the error message.
126
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> GetBoolOption(
127 128
      Isolate* isolate, Handle<JSReceiver> options, const char* property,
      const char* service, bool* result);
129

130 131 132 133
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
      Isolate* isolate, Handle<JSReceiver> options, Handle<String> property,
      int min, int max, int fallback);

134 135 136 137 138 139
  // https://tc39.github.io/ecma402/#sec-canonicalizelocalelist
  // {only_return_one_result} is an optimization for callers that only
  // care about the first result.
  static Maybe<std::vector<std::string>> CanonicalizeLocaleList(
      Isolate* isolate, Handle<Object> locales,
      bool only_return_one_result = false);
140

141 142 143 144
  // ecma-402 #sec-intl.getcanonicallocales
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> GetCanonicalLocales(
      Isolate* isolate, Handle<Object> locales);

145 146 147 148
  // For locale sensitive functions
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> StringLocaleConvertCase(
      Isolate* isolate, Handle<String> s, bool is_upper,
      Handle<Object> locales);
149

Frank Tang's avatar
Frank Tang committed
150 151 152 153 154 155
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ConvertToUpper(
      Isolate* isolate, Handle<String> s);

  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ConvertToLower(
      Isolate* isolate, Handle<String> s);

156 157
  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> StringLocaleCompare(
      Isolate* isolate, Handle<String> s1, Handle<String> s2,
158
      Handle<Object> locales, Handle<Object> options, const char* method);
159

160
  V8_WARN_UNUSED_RESULT static Handle<Object> CompareStrings(
161
      Isolate* isolate, const icu::Collator& collator, Handle<String> s1,
162
      Handle<String> s2);
163 164 165 166

  // ecma402/#sup-properties-of-the-number-prototype-object
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> NumberToLocaleString(
      Isolate* isolate, Handle<Object> num, Handle<Object> locales,
167
      Handle<Object> options, const char* method);
168

169
  // ecma402/#sec-setnfdigitoptions
170 171 172 173 174 175 176 177 178
  struct NumberFormatDigitOptions {
    int minimum_integer_digits;
    int minimum_fraction_digits;
    int maximum_fraction_digits;
    int minimum_significant_digits;
    int maximum_significant_digits;
  };
  V8_WARN_UNUSED_RESULT static Maybe<NumberFormatDigitOptions>
  SetNumberFormatDigitOptions(Isolate* isolate, Handle<JSReceiver> options,
Frank Tang's avatar
Frank Tang committed
179 180
                              int mnfd_default, int mxfd_default,
                              bool notation_is_compact);
181

182 183 184 185 186 187 188 189 190
  // Helper funciton to convert a UnicodeString to a Handle<String>
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
      Isolate* isolate, const icu::UnicodeString& string);

  // Helper function to convert a substring of UnicodeString to a Handle<String>
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
      Isolate* isolate, const icu::UnicodeString& string, int32_t begin,
      int32_t end);

191 192 193 194
  // Helper function to convert a FormattedValue to String
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormattedToString(
      Isolate* isolate, const icu::FormattedValue& formatted);

195 196 197 198 199
  // Helper function to convert number field id to type string.
  static Handle<String> NumberFieldToType(Isolate* isolate,
                                          Handle<Object> numeric_obj,
                                          int32_t field_id);

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
  // A helper function to implement formatToParts which add element to array as
  // $array[$index] = { type: $field_type_string, value: $value }
  static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
                         Handle<String> field_type_string,
                         Handle<String> value);

  // A helper function to implement formatToParts which add element to array as
  // $array[$index] = {
  //   type: $field_type_string, value: $value,
  //   $additional_property_name: $additional_property_value
  // }
  static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
                         Handle<String> field_type_string, Handle<String> value,
                         Handle<String> additional_property_name,
                         Handle<String> additional_property_value);
215

216 217 218 219 220 221 222 223 224 225 226 227 228
  // In ECMA 402 v1, Intl constructors supported a mode of operation
  // where calling them with an existing object as a receiver would
  // transform the receiver into the relevant Intl instance with all
  // internal slots. In ECMA 402 v2, this capability was removed, to
  // avoid adding internal slots on existing objects. In ECMA 402 v3,
  // the capability was re-added as "normative optional" in a mode
  // which chains the underlying Intl instance on any object, when the
  // constructor is called
  //
  // See ecma402/#legacy-constructor.
  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> LegacyUnwrapReceiver(
      Isolate* isolate, Handle<JSReceiver> receiver,
      Handle<JSFunction> constructor, bool has_initialized_slot);
229

230 231 232 233 234 235
  // enum for "localeMatcher" option: shared by many Intl objects.
  enum class MatcherOption { kBestFit, kLookup };

  // Shared function to read the "localeMatcher" option.
  V8_WARN_UNUSED_RESULT static Maybe<MatcherOption> GetLocaleMatcher(
      Isolate* isolate, Handle<JSReceiver> options, const char* method);
236

237 238 239 240 241
  // Shared function to read the "numberingSystem" option.
  V8_WARN_UNUSED_RESULT static Maybe<bool> GetNumberingSystem(
      Isolate* isolate, Handle<JSReceiver> options, const char* method,
      std::unique_ptr<char[]>* result);

242 243 244 245
  // Check the calendar is valid or not for that locale.
  static bool IsValidCalendar(const icu::Locale& locale,
                              const std::string& value);

246 247 248 249
  // Check the collation is valid or not for that locale.
  static bool IsValidCollation(const icu::Locale& locale,
                               const std::string& value);

250 251 252 253 254 255
  // Check the numberingSystem is valid.
  static bool IsValidNumberingSystem(const std::string& value);

  // Check the calendar is well formed.
  static bool IsWellFormedCalendar(const std::string& value);

256 257 258
  // Check the currency is well formed.
  static bool IsWellFormedCurrency(const std::string& value);

259 260 261 262 263 264
  struct ResolvedLocale {
    std::string locale;
    icu::Locale icu_locale;
    std::map<std::string, std::string> extensions;
  };

265
  static Maybe<ResolvedLocale> ResolveLocale(
266 267 268
      Isolate* isolate, const std::set<std::string>& available_locales,
      const std::vector<std::string>& requested_locales, MatcherOption options,
      const std::set<std::string>& relevant_extension_keys);
269

270 271 272 273 274 275 276
  // A helper template to implement the GetAvailableLocales
  // Usage in src/objects/js-XXX.cc
  // const std::set<std::string>& JSXxx::GetAvailableLocales() {
  //   static base::LazyInstance<Intl::AvailableLocales<icu::YYY>>::type
  //       available_locales = LAZY_INSTANCE_INITIALIZER;
  //   return available_locales.Pointer()->Get();
  // }
277 278 279 280 281 282

  struct SkipResourceCheck {
    static const char* key() { return nullptr; }
    static const char* path() { return nullptr; }
  };

283
  template <typename C = SkipResourceCheck>
284 285 286
  class AvailableLocales {
   public:
    AvailableLocales() {
287 288 289 290 291 292 293
      UErrorCode status = U_ZERO_ERROR;
      UEnumeration* uenum =
          uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
      DCHECK(U_SUCCESS(status));

      std::vector<std::string> all_locales;
      const char* loc;
294
      while ((loc = uenum_next(uenum, nullptr, &status)) != nullptr) {
295 296 297 298 299 300 301 302 303 304
        DCHECK(U_SUCCESS(status));
        std::string locstr(loc);
        std::replace(locstr.begin(), locstr.end(), '_', '-');
        // Handle special case
        if (locstr == "en-US-POSIX") locstr = "en-US-u-va-posix";
        all_locales.push_back(locstr);
      }
      uenum_close(uenum);

      set_ = Intl::BuildLocaleSet(all_locales, C::path(), C::key());
305
    }
306
    const std::set<std::string>& Get() const { return set_; }
307 308

   private:
309
    std::set<std::string> set_;
310 311
  };

312
  // Utility function to set text to BreakIterator.
313
  static Handle<Managed<icu::UnicodeString>> SetTextToBreakIterator(
314 315
      Isolate* isolate, Handle<String> text,
      icu::BreakIterator* break_iterator);
Frank Tang's avatar
Frank Tang committed
316

317 318 319
  // ecma262 #sec-string.prototype.normalize
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> Normalize(
      Isolate* isolate, Handle<String> string, Handle<Object> form_input);
Frank Tang's avatar
Frank Tang committed
320 321 322 323 324 325 326 327
  static base::TimezoneCache* CreateTimeZoneCache();

  // Convert a Handle<String> to icu::UnicodeString
  static icu::UnicodeString ToICUUnicodeString(Isolate* isolate,
                                               Handle<String> string);

  static const uint8_t* ToLatin1LowerTable();

328
  static String ConvertOneByteToLower(String src, String dst);
329

330
  static const std::set<std::string>& GetAvailableLocales();
331 332

  static const std::set<std::string>& GetAvailableLocalesForDateFormat();
333 334
};

335 336
}  // namespace internal
}  // namespace v8
337

338
#endif  // V8_OBJECTS_INTL_OBJECTS_H_