2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/icu/ext_icu_locale.h"
18 #include "hphp/runtime/ext/icu/icu.h"
19 #include "hphp/runtime/ext/ext_string.h"
21 #include <unicode/ures.h>
22 #include <unicode/uloc.h>
27 namespace HPHP
{ namespace Intl
{
28 //////////////////////////////////////////////////////////////////////////////
31 #define ULOC_CHECK(err, ret) \
32 if (U_FAILURE(err)) { \
33 s_intl_error->setError(err); \
37 #define MAX_LOCALE_LEN 80
39 /*returns TRUE if a is an ID separator FALSE otherwise*/
40 #define isIDSeparator(a) (a == '_' || a == '-')
41 #define isKeywordSeparator(a) (a == '@' )
42 #define isEndOfTag(a) (a == '\0' )
44 #define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
46 /*returns TRUE if one of the special prefixes is here (s=string)
48 #define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))
49 #define isKeywordPrefix(s) ( isKeywordSeparator(s[0]) )
51 /* Dot terminates it because of POSIX form where dot precedes the codepage
52 * * except for variant */
53 #define isTerminator(a) ((a==0)||(a=='.')||(a=='@'))
55 static std::vector
<std::string
> g_grandfathered
= {
56 "art-lojban", "i-klingon", "i-lux", "i-navajo", "no-bok", "no-nyn",
57 "cel-gaulish", "en-GB-oed", "i-ami", "i-bnn", "i-default", "i-enochian",
58 "i-mingo", "i-pwn", "i-tao", "i-tay", "i-tsu", "sgn-BE-fr", "sgn-BE-nl",
59 "sgn-CH-de", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hant", "zh-gan", "zh-guoyu",
60 "zh-hakka", "zh-min", "zh-min-nan", "zh-wuu", "zh-xiang", "zh-yue"
63 /* Preferred locale codes for the first N entries of g_grandfathered
64 * Must be kept in sync with above.
66 static std::vector
<std::string
> g_grandfathered_preferred
= {
67 "jbo", "tlh", "lb", "nv", "nb", "nn"
70 static int getGrandfatheredOffset(const String
& locale
) {
71 auto it
= std::find(g_grandfathered
.begin(),
72 g_grandfathered
.end(), locale
.data());
73 if (it
== g_grandfathered
.end()) return -1;
74 return (it
- g_grandfathered
.begin());
77 static String
getGrandfatheredPreferred(int ofs
) {
78 if ((ofs
< 0) || (ofs
>= g_grandfathered
.size())) {
81 if (ofs
< g_grandfathered_preferred
.size()) {
82 return g_grandfathered_preferred
[ofs
];
84 return g_grandfathered
[ofs
];
99 s_DEFAULT_LOCALE("DEFAULT_LOCALE"),
100 s_LANG_TAG("LANG_TAG"),
101 s_EXTLANG_TAG("EXTLANG_TAG"),
102 s_SCRIPT_TAG("SCRIPT_TAG"),
103 s_REGION_TAG("REGION_TAG"),
104 s_VARIANT_TAG("VARIANT_TAG"),
105 s_GRANDFATHERED_LANG_TAG("GRANDFATHERED_LANG_TAG"),
106 s_PRIVATE_TAG("PRIVATE_TAG"),
107 s_LOC_SCRIPT("script"),
108 s_LOC_LANG("language"),
109 s_LOC_REGION("region"),
110 s_LOC_VARIANT("variant"),
111 s_LOC_CANONICALIZE("canonicalize"),
112 s_LOC_PRIVATE("private"),
113 s_LOC_DISPLAY("display"),
114 s_LOC_EXTLANG("extlang"),
115 s_GRANDFATHERED("grandfathered"),
119 static const StaticString
LocaleName(LocaleTag tag
) {
121 case LOC_SCRIPT
: return s_LOC_SCRIPT
;
122 case LOC_LANG
: return s_LOC_LANG
;
123 case LOC_REGION
: return s_LOC_REGION
;
124 case LOC_VARIANT
: return s_LOC_VARIANT
;
125 case LOC_CANONICALIZE
: return s_LOC_CANONICALIZE
;
126 case LOC_PRIVATE
: return s_LOC_PRIVATE
;
127 case LOC_DISPLAY
: return s_LOC_DISPLAY
;
128 case LOC_EXTLANG
: return s_LOC_EXTLANG
;
133 static int singleton_pos(const String
& str
) {
134 auto len
= str
.size();
135 for (int i
= 0; i
< (len
- 2); ++i
) {
136 if (!isIDSeparator(str
[i
])) continue;
137 if (i
== 1) return 0;
138 if (isIDSeparator(str
[i
+2])) return i
+1;
144 static Variant
get_icu_value(const String
&locale
, LocaleTag tag
,
145 bool fromParseLocale
= false) {
146 String
locale_name(locale
);
147 if (tag
!= LOC_CANONICALIZE
) {
148 if (getGrandfatheredOffset(locale
) >= 0) {
149 if (tag
== LOC_LANG
) {
154 if (fromParseLocale
) {
155 auto localecstr
= locale
.c_str();
156 if (tag
== LOC_LANG
&& locale
.size() > 1 && isIDPrefix(localecstr
)) {
159 int pos
= singleton_pos(locale
);
162 } else if (pos
> 0) {
163 locale_name
= f_substr(locale
, 0, pos
- 1);
168 int32_t (*ulocfunc
)(const char *loc
, char *val
, int32_t len
, UErrorCode
*err
);
170 case LOC_SCRIPT
: ulocfunc
= uloc_getScript
; break;
171 case LOC_LANG
: ulocfunc
= uloc_getLanguage
; break;
172 case LOC_REGION
: ulocfunc
= uloc_getCountry
; break;
173 case LOC_VARIANT
: ulocfunc
= uloc_getVariant
; break;
174 case LOC_CANONICALIZE
: ulocfunc
= uloc_canonicalize
; break;
180 String
buf(64, ReserveString
);
182 UErrorCode error
= U_ZERO_ERROR
;
183 int32_t len
= ulocfunc(locale_name
.c_str(),
184 buf
.get()->mutableData(), buf
.get()->capacity(),
186 if (error
!= U_BUFFER_OVERFLOW_ERROR
&&
187 error
!= U_STRING_NOT_TERMINATED_WARNING
) {
188 if (U_FAILURE(error
)) {
189 s_intl_error
->setError(error
, "unable to get locale info");
195 if (len
<= buf
.get()->capacity()) {
196 // Avoid infinite loop
197 s_intl_error
->setError(U_INTERNAL_PROGRAM_ERROR
,
198 "Got invalid response from ICU");
201 buf
= String(len
, ReserveString
);
208 static Variant
get_icu_display_value(const String
& locale
,
209 const String
& disp_locale
,
211 String
locname(locale
);
212 if (tag
!= LOC_DISPLAY
) {
213 int ofs
= getGrandfatheredOffset(locale
);
215 if (tag
== LOC_LANG
) {
216 locname
= getGrandfatheredPreferred(ofs
);
223 // Hack around buffer overflow in libicu. ures_getByKeyWithFallback is a
225 if (locname
.size() >= 255 || disp_locale
.size() >= 255) return false;
227 int32_t (*ulocfunc
)(const char *loc
, const char *dloc
,
228 UChar
*dest
, int32_t destcap
, UErrorCode
*err
);
230 case LOC_LANG
: ulocfunc
= uloc_getDisplayLanguage
; break;
231 case LOC_SCRIPT
: ulocfunc
= uloc_getDisplayScript
; break;
232 case LOC_REGION
: ulocfunc
= uloc_getDisplayCountry
; break;
233 case LOC_VARIANT
: ulocfunc
= uloc_getDisplayVariant
; break;
234 case LOC_DISPLAY
: ulocfunc
= uloc_getDisplayName
; break;
240 icu::UnicodeString buf
;
241 auto ubuf
= buf
.getBuffer(64);
243 UErrorCode error
= U_ZERO_ERROR
;
244 int32_t len
= ulocfunc(locname
.c_str(), disp_locale
.c_str(),
245 ubuf
, buf
.getCapacity(), &error
);
246 if (error
!= U_BUFFER_OVERFLOW_ERROR
&&
247 error
!= U_STRING_NOT_TERMINATED_WARNING
) {
248 if (U_FAILURE(error
)) {
249 s_intl_error
->setError(error
, "locale_get_display_%s : unable to "
251 LocaleName(tag
).c_str(),
252 LocaleName(tag
).c_str());
255 buf
.releaseBuffer(len
);
257 error
= U_ZERO_ERROR
;
258 String
out(u8(buf
, error
));
259 if (U_FAILURE(error
)) {
260 s_intl_error
->setError(error
, "Unable to convert result from "
261 "locale_get_display_%s to UTF-8",
262 LocaleName(tag
).c_str());
267 if (len
<= buf
.getCapacity()) {
268 // Avoid infinite loop
269 buf
.releaseBuffer(0);
270 s_intl_error
->setError(U_INTERNAL_PROGRAM_ERROR
,
271 "Got invalid response from ICU");
275 // Grow the buffer to sufficient size
276 buf
.releaseBuffer(0);
277 ubuf
= buf
.getBuffer(len
);
284 static Variant
HHVM_STATIC_METHOD(Locale
, acceptFromHttp
,
285 const String
& header
) {
286 UErrorCode error
= U_ZERO_ERROR
;
287 UEnumeration
*avail
= ures_openAvailableLocales(nullptr, &error
);
288 ULOC_CHECK(error
, false);
289 char out
[MAX_LOCALE_LEN
];
290 UAcceptResult result
;
291 error
= U_ZERO_ERROR
;
292 int len
= uloc_acceptLanguageFromHTTP(out
, sizeof(out
), &result
,
293 header
.c_str(), avail
, &error
);
295 ULOC_CHECK(error
, false);
296 if (len
< 0 || result
== ULOC_ACCEPT_FAILED
) {
299 return String(out
, len
, CopyString
);
302 static Variant
HHVM_STATIC_METHOD(Locale
, canonicalize
, const String
& locale
) {
303 return get_icu_value(localeOrDefault(locale
), LOC_CANONICALIZE
);
306 inline void element_not_string() {
307 s_intl_error
->setError(U_ILLEGAL_ARGUMENT_ERROR
,
308 "locale_compose: parameter array element is "
312 static bool append_key_value(String
& ret
,
313 const Array
& subtags
,
315 auto name
= LocaleName(tag
);
316 if (!subtags
.exists(name
)) return true;
317 auto val
= subtags
[name
];
318 if (!val
.isString()) {
319 element_not_string();
322 ret
+= s_SEPARATOR
+ val
.toString();
326 static bool append_multiple_key_values(String
& ret
,
327 const Array
& subtags
,
329 auto name
= LocaleName(tag
);
330 if (subtags
.exists(name
)) {
331 // Sane version: [tag] => string, [tag] => array<tring>
332 auto val
= subtags
[name
];
333 if (val
.isString()) {
334 if (tag
== LOC_PRIVATE
) {
335 ret
+= s_SEPARATOR_x
;
337 ret
+= s_SEPARATOR
+ val
.toString();
340 if (!val
.isArray()) {
344 for (ArrayIter
it(val
.toArray()); it
; ++it
) {
345 auto v
= it
.second();
347 element_not_string();
351 if (tag
== LOC_PRIVATE
) {
352 ret
+= s_SEPARATOR
+ "x";
356 ret
+= s_SEPARATOR
+ v
.toString();
361 // clowny version [tag$n] => string
362 // Only extlang, variant, and private
363 if (tag
!= LOC_EXTLANG
&&
364 tag
!= LOC_VARIANT
&&
365 tag
!= LOC_PRIVATE
) {
369 int max
= (tag
== LOC_EXTLANG
) ? 3 : 15;
371 for (int i
= 0; i
< max
; ++i
) {
372 auto namenum
= name
+ String(i
, CopyString
);
373 if (!subtags
.exists(namenum
)) continue;
374 auto val
= subtags
[namenum
];
375 if (!val
.isString()) {
376 element_not_string();
380 if (tag
== LOC_PRIVATE
) {
381 ret
+= s_SEPARATOR
+ "x";
385 ret
+= s_SEPARATOR
+ val
.toString();
390 static Variant
HHVM_STATIC_METHOD(Locale
, composeLocale
, const Array
& subtags
) {
391 s_intl_error
->clearError();
393 if (subtags
.exists(s_GRANDFATHERED
)) {
394 auto val
= subtags
[s_GRANDFATHERED
];
395 if (val
.isString()) {
400 if (!subtags
.exists(s_LOC_LANG
)) {
401 s_intl_error
->setError(U_ILLEGAL_ARGUMENT_ERROR
, "locale_compose: "
402 "parameter array does not contain 'language' tag.");
405 String
ret(subtags
[s_LOC_LANG
].toString());
406 if (!append_multiple_key_values(ret
, subtags
, LOC_EXTLANG
) ||
407 !append_key_value(ret
, subtags
, LOC_SCRIPT
) ||
408 !append_key_value(ret
, subtags
, LOC_REGION
) ||
409 !append_multiple_key_values(ret
, subtags
, LOC_VARIANT
) ||
410 !append_multiple_key_values(ret
, subtags
, LOC_PRIVATE
)) {
416 static Array
HHVM_STATIC_METHOD(Locale
, getAllVariants
, const String
& locale
) {
417 Variant val
= get_icu_value(localeOrDefault(locale
), LOC_VARIANT
);
418 String strval
= val
.toString();
419 if (strval
.empty()) {
422 Array ret
= Array::Create();
423 const char *s
= strval
.c_str(), *e
= s
+ strval
.size(), *p
;
424 for (p
= s
; p
< e
; ++p
) {
425 if (!isIDSeparator(*p
)) continue;
429 ret
.append(String(s
, p
- s
, CopyString
));
433 ret
.append(String(s
, e
- s
, CopyString
));
438 static String
HHVM_STATIC_METHOD(Locale
, getDefault
) {
439 return GetDefaultLocale();
442 static String
HHVM_STATIC_METHOD(Locale
, getDisplayLanguage
,
443 const String
& locale
,
444 const String
& in_locale
) {
445 return get_icu_display_value(localeOrDefault(locale
),
446 localeOrDefault(in_locale
), LOC_LANG
);
449 static String
HHVM_STATIC_METHOD(Locale
, getDisplayName
,
450 const String
& locale
,
451 const String
& in_locale
) {
452 return get_icu_display_value(localeOrDefault(locale
),
453 localeOrDefault(in_locale
), LOC_DISPLAY
);
456 static String
HHVM_STATIC_METHOD(Locale
, getDisplayRegion
,
457 const String
& locale
,
458 const String
& in_locale
) {
459 return get_icu_display_value(localeOrDefault(locale
),
460 localeOrDefault(in_locale
), LOC_REGION
);
463 static String
HHVM_STATIC_METHOD(Locale
, getDisplayScript
,
464 const String
& locale
,
465 const String
& in_locale
) {
466 return get_icu_display_value(localeOrDefault(locale
),
467 localeOrDefault(in_locale
), LOC_SCRIPT
);
470 static String
HHVM_STATIC_METHOD(Locale
, getDisplayVariant
,
471 const String
& locale
,
472 const String
& in_locale
) {
473 return get_icu_display_value(localeOrDefault(locale
),
474 localeOrDefault(in_locale
), LOC_VARIANT
);
477 static Array
HHVM_STATIC_METHOD(Locale
, getKeywords
, const String
& locale
) {
478 UErrorCode error
= U_ZERO_ERROR
;
479 String locname
= localeOrDefault(locale
);
480 UEnumeration
*e
= uloc_openKeywords(locname
.c_str(), &error
);
481 if (!e
) return null_array
;
483 Array ret
= Array::Create();
486 String
val(128, ReserveString
);
487 char *ptr
= val
.get()->mutableData();
488 error
= U_ZERO_ERROR
;
489 while ((key
= uenum_next(e
, &key_len
, &error
))) {
491 error
= U_ZERO_ERROR
;
492 int val_len
= uloc_getKeywordValue(locname
.c_str(), key
,
493 ptr
, val
.get()->capacity(), &error
);
494 if (error
== U_BUFFER_OVERFLOW_ERROR
) {
495 val
= String(val_len
+ 128, ReserveString
);
496 ptr
= val
.get()->mutableData();
499 if (U_FAILURE(error
)) {
500 s_intl_error
->setError(error
, "locale_get_keywords: Error encountered "
501 "while getting the keyword value for the "
505 ret
.set(String(key
, key_len
, CopyString
), String(ptr
, val_len
, CopyString
));
510 static String
HHVM_STATIC_METHOD(Locale
, getPrimaryLanguage
,
511 const String
& locale
) {
512 return get_icu_value(localeOrDefault(locale
), LOC_LANG
);
515 static Variant
HHVM_STATIC_METHOD(Locale
, getRegion
, const String
& locale
) {
516 return get_icu_value(localeOrDefault(locale
), LOC_REGION
);
519 static Variant
HHVM_STATIC_METHOD(Locale
, getScript
, const String
& locale
) {
520 return get_icu_value(localeOrDefault(locale
), LOC_SCRIPT
);
523 static String
locale_suffix_strip(const String
& locale
) {
524 for (int i
= locale
.size(); i
>= 0; --i
) {
525 if (isIDSeparator(locale
[i
])) {
526 if ((i
>=2) && isIDSeparator(locale
[i
-2])) {
527 return f_substr(locale
, 0, i
- 2);
529 return f_substr(locale
, 0, i
);
536 inline void normalize_for_match(String
& v
) {
537 for (char *ptr
= v
.get()->mutableData(), *end
= ptr
+ v
.size(); ptr
< end
;
542 *ptr
= tolower(*ptr
);
545 v
.get()->invalidateHash();
548 static String
HHVM_STATIC_METHOD(Locale
, lookup
, const Array
& langtag
,
549 const String
& locale
,
550 bool canonicalize
, const String
& def
) {
551 String
locname(localeOrDefault(locale
), CopyString
);
552 std::vector
<std::pair
<String
,String
>> cur_arr
;
553 for (ArrayIter
iter(langtag
); iter
; ++iter
) {
554 auto val
= iter
.second();
555 if (!val
.isString()) {
556 s_intl_error
->setError(U_ILLEGAL_ARGUMENT_ERROR
, "lookup_loc_range: "
557 "locale array element is not a string");
560 String
normalized(val
.toString(), CopyString
);
561 normalize_for_match(normalized
);
563 normalized
= get_icu_value(normalized
, LOC_CANONICALIZE
);
564 if (normalized
.isNull()) {
565 s_intl_error
->setError(U_ILLEGAL_ARGUMENT_ERROR
, "lookup_loc_range: "
566 "unable to canonicalize lang_tag");
569 normalize_for_match(normalized
);
571 cur_arr
.push_back(std::make_pair(val
.toString(),normalized
));
575 locname
= get_icu_value(locname
, LOC_CANONICALIZE
);
576 if (locname
.isNull()) {
577 s_intl_error
->setError(U_ILLEGAL_ARGUMENT_ERROR
, "lookup_loc_range: "
578 "unable to canonicalize loc_range");
583 normalize_for_match(locname
);
584 while (locname
.size() > 0) {
585 for (auto &p
: cur_arr
) {
586 if (locname
.same(p
.second
)) {
587 return canonicalize
? p
.second
: p
.first
;
590 locname
= locale_suffix_strip(locname
);
595 static Variant
get_private_subtags(const String
& locname
) {
596 if (locname
.empty()) return uninit_null();
597 String
locale(locname
);
599 while ((pos
= singleton_pos(locale
)) >= 0) {
600 if ((locale
[pos
] == 'x') || (locale
[pos
] == 'X')) {
601 if ((pos
+ 2) == locale
.size()) {
602 /* loc_name ends with '-x-' */
603 return uninit_null();
605 return f_substr(locale
, pos
);
607 if ((pos
+ 1) >= locale
.size()) {
608 return uninit_null();
610 locale
= f_substr(locale
, pos
+ 1);
612 return uninit_null();
615 static void add_array_entry(Array
& ret
,
616 const String
& locname
,
619 if (tag
== LOC_PRIVATE
) {
620 val
= get_private_subtags(locname
);
622 val
= get_icu_value(locname
, tag
, true);
624 if (val
.isNull()) return;
625 String strval
= val
.toString();
626 if (strval
.empty()) {
630 auto name
= LocaleName(tag
);
631 if ((tag
!= LOC_PRIVATE
) && (tag
!= LOC_VARIANT
)) {
632 ret
.set(name
, strval
);
636 const char *s
= strval
.c_str(), *e
= s
+ strval
.size(), *p
;
638 for (cnt
= 0, p
= s
; p
< e
; ++p
) {
639 if (!isIDSeparator(*p
)) continue;
641 ret
.set(name
+ String(cnt
++), String(s
, p
- s
, CopyString
));
646 ret
.set(name
+ String(cnt
++), String(s
, e
- s
, CopyString
));
650 static Array
HHVM_STATIC_METHOD(Locale
, parseLocale
, const String
& locale
) {
651 String locname
= localeOrDefault(locale
);
652 Array ret
= Array::Create();
653 if (std::find(g_grandfathered
.begin(),
654 g_grandfathered
.end(), locale
.data()) !=
655 g_grandfathered
.end()) {
656 ret
.set(s_GRANDFATHERED
, locname
);
659 add_array_entry(ret
, locname
, LOC_LANG
);
660 add_array_entry(ret
, locname
, LOC_SCRIPT
);
661 add_array_entry(ret
, locname
, LOC_REGION
);
662 add_array_entry(ret
, locname
, LOC_VARIANT
);
663 add_array_entry(ret
, locname
, LOC_PRIVATE
);
667 static bool HHVM_STATIC_METHOD(Locale
, setDefault
, const String
& locale
) {
668 return SetDefaultLocale(locale
);
671 //////////////////////////////////////////////////////////////////////////////
673 const StaticString
s_Locale("Locale");
675 void IntlExtension::initLocale() {
676 HHVM_STATIC_ME(Locale
, acceptFromHttp
);
677 HHVM_STATIC_ME(Locale
, canonicalize
);
678 HHVM_STATIC_ME(Locale
, composeLocale
);
679 HHVM_STATIC_ME(Locale
, getAllVariants
);
680 HHVM_STATIC_ME(Locale
, getDefault
);
681 HHVM_STATIC_ME(Locale
, getDisplayLanguage
);
682 HHVM_STATIC_ME(Locale
, getDisplayName
);
683 HHVM_STATIC_ME(Locale
, getDisplayRegion
);
684 HHVM_STATIC_ME(Locale
, getDisplayScript
);
685 HHVM_STATIC_ME(Locale
, getDisplayVariant
);
686 HHVM_STATIC_ME(Locale
, getKeywords
);
687 HHVM_STATIC_ME(Locale
, getPrimaryLanguage
);
688 HHVM_STATIC_ME(Locale
, getRegion
);
689 HHVM_STATIC_ME(Locale
, getScript
);
690 HHVM_STATIC_ME(Locale
, lookup
);
691 HHVM_STATIC_ME(Locale
, parseLocale
);
692 HHVM_STATIC_ME(Locale
, setDefault
);
694 #define ULOC_CONST(nm,val) Native::registerClassConstant<KindOfStaticString>\
695 (s_Locale.get(), s_##nm.get(), s_##val.get())
697 Native::registerClassConstant
<KindOfNull
>(s_Locale
.get(),
698 s_DEFAULT_LOCALE
.get());
699 ULOC_CONST(LANG_TAG
, LOC_LANG
);
700 ULOC_CONST(EXTLANG_TAG
, LOC_EXTLANG
);
701 ULOC_CONST(SCRIPT_TAG
, LOC_SCRIPT
);
702 ULOC_CONST(REGION_TAG
, LOC_REGION
);
703 ULOC_CONST(VARIANT_TAG
, LOC_VARIANT
);
704 ULOC_CONST(GRANDFATHERED_LANG_TAG
, GRANDFATHERED
);
705 ULOC_CONST(PRIVATE_TAG
, LOC_PRIVATE
);
709 #define ULOC_LOCALE_CONST(cns) \
710 Native::registerConstant<KindOfInt64>\
711 (makeStaticString("ULOC_" #cns), ULOC_##cns); \
712 Native::registerClassConstant<KindOfInt64>\
713 (s_Locale.get(), makeStaticString(#cns), ULOC_##cns);
715 ULOC_LOCALE_CONST(ACTUAL_LOCALE
);
716 ULOC_LOCALE_CONST(VALID_LOCALE
);
717 #undef ULOC_LOCALE_CONST
719 loadSystemlib("icu_locale");
722 //////////////////////////////////////////////////////////////////////////////
723 }} // namespace HPHP::Intl