Extract ICU locale relevant processing from JSLocale

Issue:Extract ICU locale relevant processing from JSLocale

Signed-off-by: Zhenyu Pan <panzhenyu1@huawei.com>
Change-Id: I796890fa7999d8ec9c40646fc3fe899bc439f12f
This commit is contained in:
Zhenyu Pan 2022-12-29 17:22:35 +08:00
parent c91ddc64a9
commit 24b217ca04
33 changed files with 1215 additions and 908 deletions

View File

@ -400,6 +400,7 @@ ecma_source = [
"ecmascript/base/json_parser.cpp",
"ecmascript/base/json_stringifier.cpp",
"ecmascript/base/number_helper.cpp",
"ecmascript/base/locale_helper.cpp",
"ecmascript/base/string_helper.cpp",
"ecmascript/base/typed_array_helper.cpp",
"ecmascript/base/utf_helper.cpp",

View File

@ -0,0 +1,466 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/object_factory.h"
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include "unicode/localebuilder.h"
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace panda::ecmascript::base {
JSHandle<EcmaString> LocaleHelper::UStringToString(JSThread *thread, const icu::UnicodeString &string)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(string.getBuffer()), string.length());
}
JSHandle<EcmaString> LocaleHelper::UStringToString(JSThread *thread, const icu::UnicodeString &string, int32_t begin,
int32_t end)
{
return UStringToString(thread, string.tempSubStringBetween(begin, end));
}
// 9.2.1 CanonicalizeLocaleList ( locales )
JSHandle<TaggedArray> LocaleHelper::CanonicalizeLocaleList(JSThread *thread, const JSHandle<JSTaggedValue> &locales)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// 1. If locales is undefined, then
// a. Return a new empty List.
if (locales->IsUndefined()) {
return factory->EmptyArray();
}
// 2. Let seen be a new empty List.
JSHandle<TaggedArray> localeSeen = factory->NewTaggedArray(1);
// 3. If Type(locales) is String or Type(locales) is Object and locales has an [[InitializedLocale]] internal slot,
// then
// a. Let O be CreateArrayFromList(« locales »).
// 4. Else,
// a.Let O be ? ToObject(locales).
if (locales->IsString()) {
JSHandle<EcmaString> tag = JSHandle<EcmaString>::Cast(locales);
JSHandle<TaggedArray> temp = factory->NewTaggedArray(1);
temp->Set(thread, 0, tag.GetTaggedValue());
JSHandle<JSArray> obj = JSArray::CreateArrayFromList(thread, temp);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSArray>(thread, obj, localeSeen);
return finalSeen;
} else if (locales->IsJSLocale()) {
JSHandle<EcmaString> tag = JSLocale::ToString(thread, JSHandle<JSLocale>::Cast(locales));
JSHandle<TaggedArray> temp = factory->NewTaggedArray(1);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
temp->Set(thread, 0, tag.GetTaggedValue());
JSHandle<JSArray> obj = JSArray::CreateArrayFromList(thread, temp);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSArray>(thread, obj, localeSeen);
return finalSeen;
} else {
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSObject>(thread, obj, localeSeen);
return finalSeen;
}
return localeSeen;
}
template<typename T>
JSHandle<TaggedArray> LocaleHelper::CanonicalizeHelper(JSThread *thread, JSHandle<T> &obj, JSHandle<TaggedArray> &seen)
{
OperationResult operationResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj),
thread->GlobalConstants()->GetHandledLengthString());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSTaggedNumber len = JSTaggedValue::ToLength(thread, operationResult.GetValue());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// 2. Let seen be a new empty List.
uint32_t requestedLocalesLen = len.ToUint32();
seen = factory->NewTaggedArray(requestedLocalesLen);
// 6. Let k be 0.
// 7. Repeat, while k < len
JSMutableHandle<JSTaggedValue> pk(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> tag(thread, JSTaggedValue::Undefined());
uint32_t index = 0;
JSHandle<JSTaggedValue> objTagged = JSHandle<JSTaggedValue>::Cast(obj);
for (uint32_t k = 0; k < requestedLocalesLen; k++) {
// a. Let Pk be ToString(k).
JSHandle<JSTaggedValue> kHandle(thread, JSTaggedValue(k));
JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, kHandle);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
pk.Update(str.GetTaggedValue());
// b. Let kPresent be ? HasProperty(O, Pk).
bool kPresent = JSTaggedValue::HasProperty(thread, objTagged, pk);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
// c. If kPresent is true, then
if (kPresent) {
// i. Let kValue be ? Get(O, Pk).
OperationResult result = JSTaggedValue::GetProperty(thread, objTagged, pk);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<JSTaggedValue> kValue = result.GetValue();
// ii. If Type(kValue) is not String or Object, throw a TypeError exception.
if (!kValue->IsString() && !kValue->IsJSObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "kValue is not String or Object.", factory->EmptyArray());
}
// iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then
// 1. Let tag be kValue.[[Locale]].
// iv. Else,
// 1. Let tag be ? ToString(kValue).
if (kValue->IsJSLocale()) {
JSHandle<EcmaString> kValueStr = JSLocale::ToString(thread, JSHandle<JSLocale>::Cast(kValue));
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
tag.Update(kValueStr.GetTaggedValue());
} else {
JSHandle<EcmaString> kValueString = JSTaggedValue::ToString(thread, kValue);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<EcmaString> canonicalStr = CanonicalizeUnicodeLocaleId(thread, kValueString);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
tag.Update(canonicalStr.GetTaggedValue());
}
// vii. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen.
bool isExist = false;
uint32_t seenLen = seen->GetLength();
for (uint32_t i = 0; i < seenLen; i++) {
if (JSTaggedValue::SameValue(seen->Get(thread, i), tag.GetTaggedValue())) {
isExist = true;
}
}
if (!isExist) {
seen->Set(thread, index++, JSHandle<JSTaggedValue>::Cast(tag));
}
}
// d. Increase k by 1.
}
// set capacity
seen = TaggedArray::SetCapacity(thread, seen, index);
// 8. Return seen.
return seen;
}
// 6.2.3 CanonicalizeUnicodeLocaleId( locale )
JSHandle<EcmaString> LocaleHelper::CanonicalizeUnicodeLocaleId(JSThread *thread, const JSHandle<EcmaString> &locale)
{
[[maybe_unused]] ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
if (!IsStructurallyValidLanguageTag(locale)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
if (EcmaStringAccessor(locale).GetLength() == 0 || EcmaStringAccessor(locale).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
std::string localeCStr = ConvertToStdString(locale);
std::transform(localeCStr.begin(), localeCStr.end(), localeCStr.begin(), AsciiAlphaToLower);
UErrorCode status = U_ZERO_ERROR;
icu::Locale formalLocale = icu::Locale::forLanguageTag(localeCStr.c_str(), status);
if ((U_FAILURE(status) != 0) || (formalLocale.isBogus() != 0)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
// Resets the LocaleBuilder to match the locale.
// Returns an instance of Locale created from the fields set on this builder.
formalLocale = icu::LocaleBuilder().setLocale(formalLocale).build(status);
// Canonicalize the locale ID of this object according to CLDR.
formalLocale.canonicalize(status);
if ((U_FAILURE(status) != 0) || (formalLocale.isBogus() != 0)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
JSHandle<EcmaString> languageTag = ToLanguageTag(thread, formalLocale);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
return languageTag;
}
JSHandle<EcmaString> LocaleHelper::ToLanguageTag(JSThread *thread, const icu::Locale &locale)
{
UErrorCode status = U_ZERO_ERROR;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
auto result = locale.toLanguageTag<std::string>(status);
bool flag = (U_FAILURE(status) == 0) ? true : false;
if (!flag) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
size_t findBeginning = result.find("-u-");
std::string finalRes;
std::string tempRes;
if (findBeginning == std::string::npos) {
return factory->NewFromStdString(result);
}
size_t specialBeginning = findBeginning + INTL_INDEX_THREE;
size_t specialCount = 0;
while ((specialBeginning < result.size()) && (result[specialBeginning] != '-')) {
specialCount++;
specialBeginning++;
}
if (findBeginning != std::string::npos) {
// It begin with "-u-xx" or with more elements.
tempRes = result.substr(0, findBeginning + INTL_INDEX_THREE + specialCount);
if (result.size() <= findBeginning + INTL_INDEX_THREE + specialCount) {
return factory->NewFromStdString(result);
}
std::string leftStr = result.substr(findBeginning + INTL_INDEX_THREE + specialCount + 1);
std::istringstream temp(leftStr);
std::string buffer;
std::vector<std::string> resContainer;
while (getline(temp, buffer, '-')) {
if (buffer != "true" && buffer != "yes") {
resContainer.push_back(buffer);
}
}
for (auto it = resContainer.begin(); it != resContainer.end(); it++) {
std::string tag = "-";
tag += *it;
finalRes += tag;
}
}
if (!finalRes.empty()) {
tempRes += finalRes;
}
result = tempRes;
return factory->NewFromStdString(result);
}
// 6.2.2 IsStructurallyValidLanguageTag( locale )
bool LocaleHelper::IsStructurallyValidLanguageTag(const JSHandle<EcmaString> &tag)
{
std::string tagCollection = ConvertToStdString(tag);
std::vector<std::string> containers;
std::string substring;
std::set<std::string> uniqueSubtags;
size_t address = 1;
for (auto it = tagCollection.begin(); it != tagCollection.end(); it++) {
if (*it != '-' && it != tagCollection.end() - 1) {
substring += *it;
} else {
if (it == tagCollection.end() - 1) {
substring += *it;
}
containers.push_back(substring);
if (IsVariantSubtag(substring)) {
std::transform(substring.begin(), substring.end(), substring.begin(), AsciiAlphaToLower);
if (!uniqueSubtags.insert(substring).second) {
return false;
}
}
substring.clear();
}
}
bool result = DealwithLanguageTag(containers, address);
return result;
}
std::string LocaleHelper::ConvertToStdString(const JSHandle<EcmaString> &ecmaStr)
{
return std::string(ConvertToString(*ecmaStr, StringConvertedUsage::LOGICOPERATION));
}
bool LocaleHelper::DealwithLanguageTag(const std::vector<std::string> &containers, size_t &address)
{
// The abstract operation returns true if locale can be generated from the ABNF grammar in section 2.1 of the RFC,
// starting with Language-Tag, and does not contain duplicate variant or singleton subtags
// If language tag is empty, return false.
if (containers.empty()) {
return false;
}
// a. if the first tag is not language, return false.
if (!IsLanguageSubtag(containers[0])) {
return false;
}
// if the tag include language only, like "zh" or "de", return true;
if (containers.size() == 1) {
return true;
}
// Else, then
// if is unique singleton subtag, script and region tag.
if (IsExtensionSingleton(containers[1])) {
return true;
}
if (IsScriptSubtag(containers[address])) {
address++;
if (containers.size() == address) {
return true;
}
}
if (IsRegionSubtag(containers[address])) {
address++;
}
for (size_t i = address; i < containers.size(); i++) {
if (IsExtensionSingleton(containers[i])) {
return true;
}
if (!IsVariantSubtag(containers[i])) {
return false;
}
}
return true;
}
// 6.2.4 DefaultLocale ()
JSHandle<EcmaString> LocaleHelper::DefaultLocale(JSThread *thread)
{
icu::Locale defaultLocale;
auto globalConst = thread->GlobalConstants();
if (strcmp(defaultLocale.getName(), "en_US_POSIX") == 0 || strcmp(defaultLocale.getName(), "c") == 0) {
return JSHandle<EcmaString>::Cast(globalConst->GetHandledEnUsString());
}
if (defaultLocale.isBogus() != 0) {
return JSHandle<EcmaString>::Cast(globalConst->GetHandledUndString());
}
return ToLanguageTag(thread, defaultLocale);
}
void LocaleHelper::HandleLocaleExtension(size_t &start, size_t &extensionEnd, const std::string result, size_t len)
{
while (start < len - INTL_INDEX_TWO) {
if (result[start] != '-') {
start++;
continue;
}
if (result[start + INTL_INDEX_TWO] == '-') {
extensionEnd = start;
break;
}
start += INTL_INDEX_THREE;
}
}
LocaleHelper::ParsedLocale LocaleHelper::HandleLocale(const JSHandle<EcmaString> &localeString)
{
std::string result = ConvertToStdString(localeString);
size_t len = result.size();
ParsedLocale parsedResult;
// a. The single-character subtag x as the primary subtag indicates
// that the language tag consists solely of subtags whose meaning is
// defined by private agreement.
// b. Extensions cannot be used in tags that are entirely private use.
if (IsPrivateSubTag(result, len)) {
parsedResult.base = result;
return parsedResult;
}
// If cannot find "-u-", return the whole string as base.
size_t foundExtension = result.find("-u-");
if (foundExtension == std::string::npos) {
parsedResult.base = result;
return parsedResult;
}
// Let privateIndex be Call(%StringProto_indexOf%, foundLocale, « "-x-" »).
size_t privateIndex = result.find("-x-");
if (privateIndex != std::string::npos && privateIndex < foundExtension) {
parsedResult.base = result;
return parsedResult;
}
const std::string basis = result.substr(0, foundExtension);
size_t extensionEnd = len;
ASSERT(len > INTL_INDEX_TWO);
size_t start = foundExtension + 1;
HandleLocaleExtension(start, extensionEnd, result, len);
const std::string end = result.substr(extensionEnd);
parsedResult.base = basis + end;
parsedResult.extension = result.substr(foundExtension, extensionEnd - foundExtension);
return parsedResult;
}
std::vector<std::string> LocaleHelper::GetAvailableLocales(JSThread *thread, const char *localeKey,
const char *localePath)
{
UErrorCode status = U_ZERO_ERROR;
auto globalConst = thread->GlobalConstants();
JSHandle<EcmaString> specialValue = JSHandle<EcmaString>::Cast(globalConst->GetHandledEnUsPosixString());
std::string specialString = ConvertToStdString(specialValue);
UEnumeration *uenum = uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
std::vector<std::string> allLocales;
const char *loc = nullptr;
for (loc = uenum_next(uenum, nullptr, &status); loc != nullptr; loc = uenum_next(uenum, nullptr, &status)) {
ASSERT(U_SUCCESS(status));
std::string locStr(loc);
std::replace(locStr.begin(), locStr.end(), '_', '-');
if (locStr == specialString) {
locStr = "en-US-u-va-posix";
}
if (localePath != nullptr || localeKey != nullptr) {
icu::Locale locale(locStr.c_str());
bool res = false;
if (!CheckLocales(locale, localeKey, localePath, res)) {
continue;
}
}
bool isScript = false;
allLocales.push_back(locStr);
icu::Locale formalLocale = icu::Locale::createCanonical(locStr.c_str());
std::string scriptStr = formalLocale.getScript();
isScript = scriptStr.empty() ? false : true;
if (isScript) {
std::string languageStr = formalLocale.getLanguage();
std::string countryStr = formalLocale.getCountry();
std::string shortLocale = icu::Locale(languageStr.c_str(), countryStr.c_str()).getName();
std::replace(shortLocale.begin(), shortLocale.end(), '_', '-');
allLocales.push_back(shortLocale);
}
}
uenum_close(uenum);
return allLocales;
}
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
std::string LocaleHelper::BestAvailableLocale(const std::vector<std::string> &availableLocales,
const std::string &locale)
{
// 1. Let candidate be locale.
std::string localeCandidate = locale;
std::string undefined = std::string();
// 2. Repeat,
uint32_t length = availableLocales.size();
while (true) {
// a. If availableLocales contains an element equal to candidate, return candidate.
for (uint32_t i = 0; i < length; ++i) {
std::string itemStr = availableLocales[i];
if (itemStr == localeCandidate) {
return localeCandidate;
}
}
// b. Let pos be the character index of the last occurrence of "-" (U+002D) within candidate.
// If that character does not occur, return undefined.
size_t pos = localeCandidate.rfind('-');
if (pos == std::string::npos) {
return undefined;
}
// c. If pos ≥ 2 and the character "-" occurs at index pos-2 of candidate, decrease pos by 2.
if (pos >= INTL_INDEX_TWO && localeCandidate[pos - INTL_INDEX_TWO] == '-') {
pos -= INTL_INDEX_TWO;
}
// d. Let candidate be the substring of candidate from position 0, inclusive, to position pos, exclusive.
localeCandidate = localeCandidate.substr(0, pos);
}
}
} // namespace panda::ecmascript::base

View File

@ -0,0 +1,201 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BASE_LOCALE_HELPER_H
#define ECMASCRIPT_BASE_LOCALE_HELPER_H
#include "ecmascript/js_handle.h"
#include "ecmascript/js_locale.h"
namespace panda::ecmascript::base {
constexpr uint8_t INTL_INDEX_TWO = 2;
constexpr uint8_t INTL_INDEX_THREE = 3;
constexpr uint8_t INTL_INDEX_FOUR = 4;
constexpr uint8_t INTL_INDEX_FIVE = 5;
constexpr uint8_t INTL_INDEX_EIGHT = 8;
class LocaleHelper {
public:
struct ParsedLocale {
std::string base;
std::string extension;
};
static JSHandle<EcmaString> UStringToString(JSThread *thread, const icu::UnicodeString &string);
static JSHandle<EcmaString> UStringToString(JSThread *thread, const icu::UnicodeString &string, int32_t begin,
int32_t end);
// 9.2.1 CanonicalizeLocaleList ( locales )
static JSHandle<TaggedArray> CanonicalizeLocaleList(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
// 6.2.3 CanonicalizeUnicodeLocaleId ( locale )
static JSHandle<EcmaString> CanonicalizeUnicodeLocaleId(JSThread *thread, const JSHandle<EcmaString> &locale);
static JSHandle<EcmaString> ToLanguageTag(JSThread *thread, const icu::Locale &locale);
static std::vector<std::string> GetAvailableLocales(JSThread *thread, const char *key, const char *path);
static bool IsStructurallyValidLanguageTag(const JSHandle<EcmaString> &tag);
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
static std::string BestAvailableLocale(const std::vector<std::string> &availableLocales,
const std::string &locale);
static JSHandle<EcmaString> DefaultLocale(JSThread *thread);
static LocaleHelper::ParsedLocale HandleLocale(const JSHandle<EcmaString> &localeString);
static void HandleLocaleExtension(size_t &start, size_t &extensionEnd, const std::string result, size_t len);
static std::string ConvertToStdString(const JSHandle<EcmaString> &ecmaStr);
private:
template<typename T>
static JSHandle<TaggedArray> CanonicalizeHelper(JSThread *thread, JSHandle<T> &obj, JSHandle<TaggedArray> &seen);
static bool DealwithLanguageTag(const std::vector<std::string> &containers, size_t &address);
static inline constexpr int AsciiAlphaToLower(uint32_t c)
{
constexpr uint32_t FLAG = 0x20;
return static_cast<int>(c | FLAG);
}
static bool IsLanguageSubtag(const std::string &value)
{
return IsAlpha(value, INTL_INDEX_TWO, INTL_INDEX_THREE) || IsAlpha(value, INTL_INDEX_FIVE, INTL_INDEX_EIGHT);
}
static bool IsScriptSubtag(const std::string &value)
{
return IsAlpha(value, INTL_INDEX_FOUR, INTL_INDEX_FOUR);
}
static bool IsRegionSubtag(const std::string &value)
{
return IsAlpha(value, INTL_INDEX_TWO, INTL_INDEX_TWO) || IsDigit(value, INTL_INDEX_THREE, INTL_INDEX_THREE);
}
static bool IsVariantSubtag(const std::string &value)
{
return IsThirdDigitAlphanum(value) || IsAlphanum(value, INTL_INDEX_FIVE, INTL_INDEX_EIGHT);
}
static bool IsThirdDigitAlphanum(const std::string &value)
{
return InRange(value[0], '0', '9') && value.length() == INTL_INDEX_FOUR &&
IsAlphanum(value.substr(1), INTL_INDEX_THREE, INTL_INDEX_THREE);
}
static bool IsExtensionSingleton(const std::string &value)
{
return IsAlphanum(value, 1, 1);
}
static bool IsPrivateSubTag(std::string result, size_t len)
{
if ((len > 1) && (result[1] == '-')) {
ASSERT(result[0] == 'x' || result[0] == 'i');
return true;
}
return false;
}
template<typename T, typename U>
static bool InRange(T value, U start, U end)
{
ASSERT(start <= end);
ASSERT(sizeof(T) >= sizeof(U));
return (value >= static_cast<T>(start)) && (value <= static_cast<T>(end));
}
static bool IsAsciiAlpha(char ch)
{
return InRange(ch, 'A', 'Z') || InRange(ch, 'a', 'z');
}
static bool IsAlpha(const std::string &str, size_t min, size_t max)
{
if (!InRange(str.length(), min, max)) {
return false;
}
for (char c : str) {
if (!IsAsciiAlpha(c)) {
return false;
}
}
return true;
}
static bool IsDigit(const std::string &str, size_t min, size_t max)
{
if (!InRange(str.length(), min, max)) {
return false;
}
for (char i : str) {
if (!InRange(i, '0', '9')) {
return false;
}
}
return true;
}
static bool IsAlphanum(const std::string &str, size_t min, size_t max)
{
if (!InRange(str.length(), min, max)) {
return false;
}
for (char i : str) {
if (!IsAsciiAlpha(i) && !InRange(i, '0', '9')) {
return false;
}
}
return true;
}
static bool ValidateOtherTags(const icu::Locale &locale, const char *packageName, const char *key, bool &res)
{
const char *localeCountry = locale.getCountry();
const char *localeScript = locale.getScript();
if (localeCountry[0] != '\0' && localeScript[0] != '\0') {
std::string removeCountry = locale.getLanguage();
removeCountry.append("-");
removeCountry.append(localeScript);
return CheckLocales(removeCountry.c_str(), key, packageName, res);
}
if (localeCountry[0] != '\0' || localeScript[0] != '\0') {
std::string language = locale.getLanguage();
return CheckLocales(language.c_str(), key, packageName, res);
}
return res;
}
static bool CheckLocales(const icu::Locale &locale, const char *key, const char *packageName, bool &res)
{
res = false;
UErrorCode status = U_ZERO_ERROR;
const char *formalLocale = locale.getName();
UResourceBundle *localeRes = ures_open(packageName, formalLocale, &status);
if (localeRes != nullptr && status == U_ZERO_ERROR) {
bool flag = (key == nullptr) ? true : false;
if (flag) {
res = true;
} else {
UResourceBundle *keyRes = ures_getByKey(localeRes, key, nullptr, &status);
if (keyRes != nullptr && status == U_ZERO_ERROR) {
res = true;
}
ures_close(keyRes);
}
}
ures_close(localeRes);
if (res) {
return res;
} else {
ValidateOtherTags(locale, packageName, key, res);
}
return res;
}
};
}
#endif // ECMASCRIPT_BASE_LOCALE_HELPER_H

View File

@ -15,6 +15,7 @@
#include "builtins_collator.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_collator.h"
@ -68,7 +69,7 @@ JSTaggedValue BuiltinsCollator::SupportedLocalesOf(EcmaRuntimeCallInfo *argv)
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -15,6 +15,7 @@
#include "builtins_date_time_format.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_date.h"
@ -86,7 +87,7 @@ JSTaggedValue BuiltinsDateTimeFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *ar
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -15,6 +15,7 @@
#include "builtins_displaynames.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_displaynames.h"
@ -64,7 +65,7 @@ JSTaggedValue BuiltinsDisplayNames::SupportedLocalesOf(EcmaRuntimeCallInfo *argv
// 2. Let requestedLocales be ? CanonicaliezLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).
@ -98,7 +99,7 @@ JSTaggedValue BuiltinsDisplayNames::Of(EcmaRuntimeCallInfo *argv)
JSHandle<JSDisplayNames> displayNames = JSHandle<JSDisplayNames>::Cast(thisValue);
TypednsOption typeOpt = displayNames->GetType();
JSHandle<EcmaString> code = JSDisplayNames::CanonicalCodeForDisplayNames(thread, displayNames, typeOpt, codeTemp);
std::string codeString = JSLocale::ConvertToStdString(code);
std::string codeString = base::LocaleHelper::ConvertToStdString(code);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (codeString.size()) {
JSHandle<JSTaggedValue> codeStr = JSHandle<JSTaggedValue>::Cast(code);

View File

@ -15,6 +15,7 @@
#include "ecmascript/builtins/builtins_intl.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_locale.h"
#include "ecmascript/js_tagged_value.h"
@ -28,7 +29,7 @@ JSTaggedValue BuiltinsIntl::GetCanonicalLocales(EcmaRuntimeCallInfo *argv)
// 1.Let ll be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> elements = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> elements = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 2.Return CreateArrayFromList(ll).

View File

@ -15,6 +15,7 @@
#include "ecmascript/builtins/builtins_list_format.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_list_format.h"
@ -65,7 +66,7 @@ JSTaggedValue BuiltinsListFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *argv)
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -15,6 +15,7 @@
#include "ecmascript/builtins/builtins_locale.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_locale.h"
@ -56,7 +57,7 @@ JSTaggedValue BuiltinsLocale::LocaleConstructor(EcmaRuntimeCallInfo *argv)
localeString = JSTaggedValue::ToString(thread, tag);
} else {
icu::Locale *icuLocale = (JSHandle<JSLocale>::Cast(tag))->GetIcuLocale();
localeString = JSLocale::ToLanguageTag(thread, *icuLocale);
localeString = base::LocaleHelper::ToLanguageTag(thread, *icuLocale);
}
// 10. If options is undefined, then
// a.Let options be ! ObjectCreate(null).
@ -170,7 +171,7 @@ JSTaggedValue BuiltinsLocale::GetBaseName(EcmaRuntimeCallInfo *argv)
// 4. Return the substring of locale corresponding to the unicode_language_id production.
JSHandle<JSLocale> locale = JSHandle<JSLocale>::Cast(loc);
icu::Locale icuLocale = icu::Locale::createFromName(locale->GetIcuLocale()->getBaseName());
JSHandle<EcmaString> baseName = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> baseName = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
return baseName.GetTaggedValue();
}

View File

@ -15,6 +15,7 @@
#include "ecmascript/builtins/builtins_number_format.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
@ -88,7 +89,7 @@ JSTaggedValue BuiltinsNumberFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *argv
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -15,6 +15,7 @@
#include "ecmascript/builtins/builtins_plural_rules.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_locale.h"
#include "ecmascript/js_object.h"
@ -62,7 +63,7 @@ JSTaggedValue BuiltinsPluralRules::SupportedLocalesOf(EcmaRuntimeCallInfo *argv)
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -15,6 +15,8 @@
#include "ecmascript/builtins/builtins_relative_time_format.h"
#include "ecmascript/base/locale_helper.h"
namespace panda::ecmascript::builtins {
JSTaggedValue BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(EcmaRuntimeCallInfo *argv)
{
@ -66,12 +68,13 @@ JSTaggedValue BuiltinsRelativeTimeFormat::SupportedLocalesOf(EcmaRuntimeCallInfo
[[maybe_unused]] EcmaHandleScope scope(thread);
// 1. Let availableLocales be %RelativeTimeFormat%.[[AvailableLocales]].
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, "calendar", nullptr);
std::vector<std::string> availableStringLocales =
base::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

View File

@ -17,6 +17,7 @@
#include <algorithm>
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/builtins/builtins_json.h"
@ -31,7 +32,6 @@
#include "ecmascript/js_array.h"
#include "ecmascript/js_collator.h"
#include "ecmascript/js_hclass.h"
#include "ecmascript/js_locale.h"
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/js_regexp.h"
@ -722,7 +722,7 @@ JSTaggedValue BuiltinsString::Normalize(EcmaRuntimeCallInfo *argv)
int32_t option = 0;
icu::Normalizer::normalize(src, uForm, option, res, errorCode);
JSHandle<EcmaString> str = JSLocale::IcuToString(thread, res);
JSHandle<EcmaString> str = base::LocaleHelper::UStringToString(thread, res);
return JSTaggedValue(*str);
}
@ -1509,29 +1509,29 @@ JSTaggedValue BuiltinsString::ToLocaleLowerCase(EcmaRuntimeCallInfo *argv)
EcmaString *result = EcmaStringAccessor::TryToLower(ecmaVm, string);
return JSTaggedValue(result);
}
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// If requestedLocales is not an empty List, then Let requestedLocale be requestedLocales[0].
// Else, Let requestedLocale be DefaultLocale().
JSHandle<EcmaString> requestedLocale = JSLocale::DefaultLocale(thread);
JSHandle<EcmaString> requestedLocale = base::LocaleHelper::DefaultLocale(thread);
if (requestedLocales->GetLength() != 0) {
requestedLocale = JSHandle<EcmaString>(thread, requestedLocales->Get(0));
}
// Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences
// removed.
JSLocale::ParsedLocale noExtensionsLocale = JSLocale::HandleLocale(requestedLocale);
base::LocaleHelper::ParsedLocale noExtensionsLocale = base::LocaleHelper::HandleLocale(requestedLocale);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// Let availableLocales be a List with language tags that includes the languages for which the Unicode Character
// Database contains language sensitive case mappings. Implementations may add additional language tags
// if they support case mapping for additional locales.
std::vector<std::string> availableLocales = JSLocale::GetAvailableLocales(thread, nullptr, nullptr);
std::vector<std::string> availableLocales = base::LocaleHelper::GetAvailableLocales(thread, nullptr, nullptr);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale).
std::string locale = JSLocale::BestAvailableLocale(availableLocales, noExtensionsLocale.base);
std::string locale = base::LocaleHelper::BestAvailableLocale(availableLocales, noExtensionsLocale.base);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// If locale is undefined, let locale be "und".
@ -1565,29 +1565,29 @@ JSTaggedValue BuiltinsString::ToLocaleUpperCase(EcmaRuntimeCallInfo *argv)
// Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// If requestedLocales is not an empty List, then Let requestedLocale be requestedLocales[0].
// Else, Let requestedLocale be DefaultLocale().
JSHandle<EcmaString> requestedLocale = JSLocale::DefaultLocale(thread);
JSHandle<EcmaString> requestedLocale = base::LocaleHelper::DefaultLocale(thread);
if (requestedLocales->GetLength() != 0) {
requestedLocale = JSHandle<EcmaString>(thread, requestedLocales->Get(0));
}
// Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences
// removed.
JSLocale::ParsedLocale noExtensionsLocale = JSLocale::HandleLocale(requestedLocale);
base::LocaleHelper::ParsedLocale noExtensionsLocale = base::LocaleHelper::HandleLocale(requestedLocale);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// Let availableLocales be a List with language tags that includes the languages for which the Unicode Character
// Database contains language sensitive case mappings. Implementations may add additional language tags
// if they support case mapping for additional locales.
std::vector<std::string> availableLocales = JSLocale::GetAvailableLocales(thread, nullptr, nullptr);
std::vector<std::string> availableLocales = base::LocaleHelper::GetAvailableLocales(thread, nullptr, nullptr);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale).
std::string locale = JSLocale::BestAvailableLocale(availableLocales, noExtensionsLocale.base);
std::string locale = base::LocaleHelper::BestAvailableLocale(availableLocales, noExtensionsLocale.base);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// If locale is undefined, let locale be "und".

View File

@ -15,6 +15,7 @@
#include "ecmascript/js_collator.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/mem/c_string.h"
#include "ecmascript/mem/barriers-inl.h"
@ -40,7 +41,7 @@ JSHandle<TaggedArray> JSCollator::GetAvailableLocales(JSThread *thread)
{
const char *key = nullptr;
const char *path = JSCollator::uIcuDataColl.c_str();
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
return availableLocales;
}
@ -73,7 +74,7 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
ObjectFactory *factory = ecmaVm->GetFactory();
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSCollator, thread);
// 2. If options is undefined, then
@ -112,7 +113,7 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
std::string collationStr;
if (!collation->IsUndefined()) {
JSHandle<EcmaString> collationEcmaStr = JSHandle<EcmaString>::Cast(collation);
collationStr = JSLocale::ConvertToStdString(collationEcmaStr);
collationStr = base::LocaleHelper::ConvertToStdString(collationEcmaStr);
if (!JSLocale::IsWellAlphaNumList(collationStr)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid collation", collator);
}
@ -147,7 +148,7 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
ResolvedLocale r =
JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys);
icu::Locale icuLocale = r.localeData;
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
collator->SetLocale(thread, localeStr.GetTaggedValue());
ASSERT_PRINT(!icuLocale.isBogus(), "icuLocale is bogus");

View File

@ -15,6 +15,7 @@
#include "ecmascript/js_date_time_format.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
@ -201,7 +202,7 @@ JSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread);
// 2. Let options be ? ToDateTimeOptions(options, "any", "date").
@ -227,7 +228,7 @@ JSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *
std::string calendarStr;
if (!calendar->IsUndefined()) {
JSHandle<EcmaString> calendarEcmaStr = JSHandle<EcmaString>::Cast(calendar);
calendarStr = JSLocale::ConvertToStdString(calendarEcmaStr);
calendarStr = base::LocaleHelper::ConvertToStdString(calendarEcmaStr);
if (!JSLocale::IsNormativeCalendar(calendarStr)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid calendar", dateTimeFormat);
}
@ -246,7 +247,7 @@ JSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *
std::string nsStr;
if (!numberingSystem->IsUndefined()) {
JSHandle<EcmaString> nsEcmaStr = JSHandle<EcmaString>::Cast(numberingSystem);
nsStr = JSLocale::ConvertToStdString(nsEcmaStr);
nsStr = base::LocaleHelper::ConvertToStdString(nsEcmaStr);
if (!JSLocale::IsWellNumberingSystem(nsStr)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", dateTimeFormat);
}
@ -310,7 +311,7 @@ JSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *
if (!operationResult.GetValue()->IsUndefined()) {
JSHandle<EcmaString> timezone = JSTaggedValue::ToString(thread, operationResult.GetValue());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread);
icuTimeZone = ConstructTimeZone(JSLocale::ConvertToStdString(timezone));
icuTimeZone = ConstructTimeZone(base::LocaleHelper::ConvertToStdString(timezone));
if (icuTimeZone == nullptr) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid timeZone", dateTimeFormat);
}
@ -485,7 +486,7 @@ JSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *
ASSERT_PRINT(U_SUCCESS(status), "resolvedIcuLocaleCopy set hc failed");
}
}
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, resolvedIcuLocaleCopy);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, resolvedIcuLocaleCopy);
dateTimeFormat->SetLocale(thread, localeStr.GetTaggedValue());
// Set dateTimeFormat.[[boundFormat]].
@ -663,7 +664,7 @@ JSHandle<EcmaString> JSDateTimeFormat::FormatDateTime(JSThread *thread,
simpleDateFormat->format(xValue, result);
// 4. Return result.
return JSLocale::IcuToString(thread, result);
return base::LocaleHelper::UStringToString(thread, result);
}
// 13.1.8 FormatDateTimeToParts (dateTimeFormat, x)
@ -711,8 +712,8 @@ JSHandle<JSArray> JSDateTimeFormat::FormatDateTimeToParts(JSThread *thread,
// 4. For each part in parts, do
for (auto part : parts) {
substring.Update(JSLocale::IcuToString(thread, formattedParts, part.fBeginIndex,
part.fEndIndex).GetTaggedValue());
substring.Update(base::LocaleHelper::UStringToString(thread, formattedParts, part.fBeginIndex,
part.fEndIndex).GetTaggedValue());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
// Let O be ObjectCreate(%ObjectPrototype%).
// Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
@ -874,7 +875,7 @@ void JSDateTimeFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSDateTi
(canonicalTimezone == UNICODE_STRING_SIMPLE("Etc/GMT")) != 0) {
timezoneValue.Update(globalConst->GetUTCString());
} else {
timezoneValue.Update(JSLocale::IcuToString(thread, canonicalTimezone).GetTaggedValue());
timezoneValue.Update(base::LocaleHelper::UStringToString(thread, canonicalTimezone).GetTaggedValue());
}
}
property = globalConst->GetHandledTimeZoneString();
@ -990,7 +991,7 @@ JSHandle<EcmaString> JSDateTimeFormat::NormDateTimeRange(JSThread *thread, const
break;
}
}
result = JSLocale::IcuToString(thread, formatResult);
result = base::LocaleHelper::UStringToString(thread, formatResult);
if (!outputRange) {
return FormatDateTime(thread, dtf, x);
}
@ -1026,7 +1027,7 @@ JSHandle<TaggedArray> JSDateTimeFormat::GainAvailableLocales(JSThread *thread)
const char *key = "calendar";
const char *path = nullptr;
if (dateTimeFormatLocales->IsUndefined()) {
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
env->SetDateTimeFormatLocales(thread, availableLocales);
return availableLocales;
@ -1098,8 +1099,8 @@ JSHandle<JSArray> JSDateTimeFormat::ConstructFDateIntervalToJSArray(JSThread *th
parts.emplace_back(CommonDateFormatPart(-1, preEndPos, length, index, true));
}
for (auto part : parts) {
substring.Update(JSLocale::IcuToString(thread, formattedValue, part.fBeginIndex,
part.fEndIndex).GetTaggedValue());
substring.Update(base::LocaleHelper::UStringToString(thread, formattedValue, part.fBeginIndex,
part.fEndIndex).GetTaggedValue());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
JSHandle<JSObject> element;
if (part.isPreExist) {

View File

@ -17,6 +17,7 @@
#include <cstring>
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/global_env_constants.h"
@ -83,7 +84,7 @@ JSHandle<TaggedArray> JSDisplayNames::GetAvailableLocales(JSThread *thread)
{
const char *key = "calendar";
const char *path = nullptr;
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
return availableLocales;
}
@ -117,7 +118,7 @@ JSHandle<JSDisplayNames> JSDisplayNames::InitializeDisplayNames(JSThread *thread
ObjectFactory *factory = ecmaVm->GetFactory();
auto globalConst = thread->GlobalConstants();
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
// 4. If options is undefined, throw a TypeError exception.
@ -192,7 +193,7 @@ JSHandle<JSDisplayNames> JSDisplayNames::InitializeDisplayNames(JSThread *thread
displayNames->SetFallback(fallback);
// 18. Set displayNames.[[Locale]] to the value of r.[[Locale]].
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
displayNames->SetLocale(thread, localeStr.GetTaggedValue());
// 19. Let dataLocale be r.[[dataLocale]].
// 20. Let dataLocaleData be localeData.[[<dataLocale>]].
@ -236,7 +237,7 @@ JSHandle<EcmaString> JSDisplayNames::CanonicalCodeForDisplayNames(JSThread *thre
if (typeOpt == TypednsOption::LANGUAGE) {
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
UErrorCode status = U_ZERO_ERROR;
std::string codeSt = JSLocale::ConvertToStdString(code);
std::string codeSt = base::LocaleHelper::ConvertToStdString(code);
icu::Locale loc = icu::Locale(icu::Locale::forLanguageTag(codeSt, status).getBaseName());
std::string checked = loc.toLanguageTag<std::string>(status);
if (checked.size() == 0) {
@ -248,19 +249,19 @@ JSHandle<EcmaString> JSDisplayNames::CanonicalCodeForDisplayNames(JSThread *thre
// b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.
// c. Set code to CanonicalizeUnicodeLocaleId(code).
// d. Return code.
if (!JSLocale::IsStructurallyValidLanguageTag(code)) {
if (!base::LocaleHelper::IsStructurallyValidLanguageTag(code)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "not a structurally valid", code);
}
JSHandle<EcmaString> codeStr = JSLocale::CanonicalizeUnicodeLocaleId(thread, code);
JSHandle<EcmaString> codeStr = base::LocaleHelper::CanonicalizeUnicodeLocaleId(thread, code);
icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
icu::UnicodeString result;
std::string codeString = JSLocale::ConvertToStdString(codeStr);
std::string codeString = base::LocaleHelper::ConvertToStdString(codeStr);
icuLocaldisplaynames->languageDisplayName(codeString.c_str(), result);
JSHandle<EcmaString> codeResult = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> codeResult = base::LocaleHelper::UStringToString(thread, result);
return codeResult;
} else if (typeOpt == TypednsOption::REGION) {
// a. If code does not match the unicode_region_subtag production, throw a RangeError exception.
std::string regionCode = JSLocale::ConvertToStdString(code);
std::string regionCode = base::LocaleHelper::ConvertToStdString(code);
if (!IsUnicodeRegionSubtag(regionCode)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid region", code);
}
@ -269,30 +270,30 @@ JSHandle<EcmaString> JSDisplayNames::CanonicalCodeForDisplayNames(JSThread *thre
icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
icu::UnicodeString result;
icuLocaldisplaynames->regionDisplayName(regionCode.c_str(), result);
JSHandle<EcmaString> codeResult = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> codeResult = base::LocaleHelper::UStringToString(thread, result);
return codeResult;
} else if (typeOpt == TypednsOption::SCRIPT) {
std::string scriptCode = JSLocale::ConvertToStdString(code);
std::string scriptCode = base::LocaleHelper::ConvertToStdString(code);
if (!IsUnicodeScriptSubtag(scriptCode)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid script", code);
}
icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
icu::UnicodeString result;
icuLocaldisplaynames->scriptDisplayName(scriptCode.c_str(), result);
JSHandle<EcmaString> codeResult = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> codeResult = base::LocaleHelper::UStringToString(thread, result);
return codeResult;
}
// 4. 4. Assert: type is "currency".
// 5. If ! IsWellFormedCurrencyCode(code) is false, throw a RangeError exception.
ASSERT(typeOpt == TypednsOption::CURRENCY);
std::string cCode = JSLocale::ConvertToStdString(code);
std::string cCode = base::LocaleHelper::ConvertToStdString(code);
if (!JSLocale::IsWellFormedCurrencyCode(cCode)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "not a wellformed currency code", code);
}
icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
icu::UnicodeString result;
icuLocaldisplaynames->keyValueDisplayName("currency", cCode.c_str(), result);
JSHandle<EcmaString> codeResult = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> codeResult = base::LocaleHelper::UStringToString(thread, result);
return codeResult;
}

View File

@ -18,6 +18,7 @@
#include <cstring>
#include <vector>
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/global_env.h"
#include "ecmascript/global_env_constants.h"
@ -77,7 +78,7 @@ JSHandle<TaggedArray> JSListFormat::GetAvailableLocales(JSThread *thread)
}
const char *key = "listPattern";
const char *path = nullptr;
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
env->SetListFormatLocales(thread, availableLocales);
return availableLocales;
@ -95,7 +96,7 @@ JSHandle<JSListFormat> JSListFormat::InitializeListFormat(JSThread *thread,
auto globalConst = thread->GlobalConstants();
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSListFormat, thread);
// 4. Let options be ? GetOptionsObject(options).
@ -132,7 +133,7 @@ JSHandle<JSListFormat> JSListFormat::InitializeListFormat(JSThread *thread,
// 10. Set listFormat.[[Locale]] to r.[[locale]].
icu::Locale icuLocale = r.localeData;
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
listFormat->SetLocale(thread, localeStr.GetTaggedValue());
// 11. Let type be ? GetOption(options, "type", "string", « "conjunction", "disjunction", "unit" », "conjunction").
@ -264,7 +265,7 @@ namespace {
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, listArray, k);
ASSERT(kValue->IsString());
JSHandle<EcmaString> kValueString = JSTaggedValue::ToString(thread, kValue);
std::string stdString = JSLocale::ConvertToStdString(kValueString);
std::string stdString = base::LocaleHelper::ConvertToStdString(kValueString);
icu::StringPiece sp(stdString);
icu::UnicodeString uString = icu::UnicodeString::fromUTF8(sp);
result.push_back(uString);
@ -298,13 +299,13 @@ namespace {
int32_t start = cfpo.getStart();
int32_t limit = cfpo.getLimit();
if (static_cast<UListFormatterField>(fieldId) == ULISTFMT_ELEMENT_FIELD) {
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, listString, start, limit);
JSHandle<EcmaString> substring = base::LocaleHelper::UStringToString(thread, listString, start, limit);
typeString.Update(globalConst->GetElementString());
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
index++;
} else {
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, listString, start, limit);
JSHandle<EcmaString> substring = base::LocaleHelper::UStringToString(thread, listString, start, limit);
typeString.Update(globalConst->GetLiteralString());
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
@ -370,7 +371,7 @@ JSHandle<EcmaString> JSListFormat::FormatList(JSThread *thread, const JSHandle<J
if (U_FAILURE(status)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "formatted list toString failed", stringValue);
}
stringValue = JSLocale::IcuToString(thread, result);
stringValue = base::LocaleHelper::UStringToString(thread, result);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, stringValue);
// 4. Return result
return stringValue;

View File

@ -15,6 +15,7 @@
#include "ecmascript/js_locale.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
@ -39,87 +40,6 @@
namespace panda::ecmascript {
const std::string LATN_STRING = "latn";
// 6.2.2 IsStructurallyValidLanguageTag( locale )
bool JSLocale::IsStructurallyValidLanguageTag(const JSHandle<EcmaString> &tag)
{
std::string tagCollection = ConvertToStdString(tag);
std::vector<std::string> containers;
std::string substring;
std::set<std::string> uniqueSubtags;
size_t address = 1;
for (auto it = tagCollection.begin(); it != tagCollection.end(); it++) {
if (*it != '-' && it != tagCollection.end() - 1) {
substring += *it;
} else {
if (it == tagCollection.end() - 1) {
substring += *it;
}
containers.push_back(substring);
if (IsVariantSubtag(substring)) {
std::transform(substring.begin(), substring.end(), substring.begin(), AsciiAlphaToLower);
if (!uniqueSubtags.insert(substring).second) {
return false;
}
}
substring.clear();
}
}
bool result = DealwithLanguageTag(containers, address);
return result;
}
std::string JSLocale::ConvertToStdString(const JSHandle<EcmaString> &ecmaStr)
{
return std::string(ConvertToString(*ecmaStr, StringConvertedUsage::LOGICOPERATION));
}
// 6.2.3 CanonicalizeUnicodeLocaleId( locale )
JSHandle<EcmaString> JSLocale::CanonicalizeUnicodeLocaleId(JSThread *thread, const JSHandle<EcmaString> &locale)
{
[[maybe_unused]] ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
if (!IsStructurallyValidLanguageTag(locale)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
if (EcmaStringAccessor(locale).GetLength() == 0 || EcmaStringAccessor(locale).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
std::string localeCStr = ConvertToStdString(locale);
std::transform(localeCStr.begin(), localeCStr.end(), localeCStr.begin(), AsciiAlphaToLower);
UErrorCode status = U_ZERO_ERROR;
icu::Locale formalLocale = icu::Locale::forLanguageTag(localeCStr.c_str(), status);
if ((U_FAILURE(status) != 0) || (formalLocale.isBogus() != 0)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
// Resets the LocaleBuilder to match the locale.
// Returns an instance of Locale created from the fields set on this builder.
formalLocale = icu::LocaleBuilder().setLocale(formalLocale).build(status);
// Canonicalize the locale ID of this object according to CLDR.
formalLocale.canonicalize(status);
if ((U_FAILURE(status) != 0) || (formalLocale.isBogus() != 0)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
JSHandle<EcmaString> languageTag = ToLanguageTag(thread, formalLocale);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
return languageTag;
}
// 6.2.4 DefaultLocale ()
JSHandle<EcmaString> JSLocale::DefaultLocale(JSThread *thread)
{
icu::Locale defaultLocale;
auto globalConst = thread->GlobalConstants();
if (strcmp(defaultLocale.getName(), "en_US_POSIX") == 0 || strcmp(defaultLocale.getName(), "c") == 0) {
return JSHandle<EcmaString>::Cast(globalConst->GetHandledEnUsString());
}
if (defaultLocale.isBogus() != 0) {
return JSHandle<EcmaString>::Cast(globalConst->GetHandledUndString());
}
return ToLanguageTag(thread, defaultLocale);
}
// 6.4.1 IsValidTimeZoneName ( timeZone )
bool JSLocale::IsValidTimeZoneName(const icu::TimeZone &tz)
{
@ -132,204 +52,6 @@ bool JSLocale::IsValidTimeZoneName(const icu::TimeZone &tz)
return (U_SUCCESS(status) != 0) && (canonicalFlag != 0);
}
void JSLocale::HandleLocaleExtension(size_t &start, size_t &extensionEnd,
const std::string result, size_t len)
{
while (start < len - INTL_INDEX_TWO) {
if (result[start] != '-') {
start++;
continue;
}
if (result[start + INTL_INDEX_TWO] == '-') {
extensionEnd = start;
break;
}
start += INTL_INDEX_THREE;
}
}
JSLocale::ParsedLocale JSLocale::HandleLocale(const JSHandle<EcmaString> &localeString)
{
std::string result = ConvertToStdString(localeString);
size_t len = result.size();
ParsedLocale parsedResult;
// a. The single-character subtag x as the primary subtag indicates
// that the language tag consists solely of subtags whose meaning is
// defined by private agreement.
// b. Extensions cannot be used in tags that are entirely private use.
if (IsPrivateSubTag(result, len)) {
parsedResult.base = result;
return parsedResult;
}
// If cannot find "-u-", return the whole string as base.
size_t foundExtension = result.find("-u-");
if (foundExtension == std::string::npos) {
parsedResult.base = result;
return parsedResult;
}
// Let privateIndex be Call(%StringProto_indexOf%, foundLocale, « "-x-" »).
size_t privateIndex = result.find("-x-");
if (privateIndex != std::string::npos && privateIndex < foundExtension) {
parsedResult.base = result;
return parsedResult;
}
const std::string basis = result.substr(INTL_INDEX_ZERO, foundExtension);
size_t extensionEnd = len;
ASSERT(len > INTL_INDEX_TWO);
size_t start = foundExtension + INTL_INDEX_ONE;
HandleLocaleExtension(start, extensionEnd, result, len);
const std::string end = result.substr(extensionEnd);
parsedResult.base = basis + end;
parsedResult.extension = result.substr(foundExtension, extensionEnd - foundExtension);
return parsedResult;
}
// 9.2.1 CanonicalizeLocaleList ( locales )
JSHandle<TaggedArray> JSLocale::CanonicalizeLocaleList(JSThread *thread, const JSHandle<JSTaggedValue> &locales)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// 1. If locales is undefined, then
// a. Return a new empty List.
if (locales->IsUndefined()) {
return factory->EmptyArray();
}
// 2. Let seen be a new empty List.
JSHandle<TaggedArray> localeSeen = factory->NewTaggedArray(1);
// 3. If Type(locales) is String or Type(locales) is Object and locales has an [[InitializedLocale]] internal slot,
// then
// a. Let O be CreateArrayFromList(« locales »).
// 4. Else,
// a.Let O be ? ToObject(locales).
if (locales->IsString()) {
JSHandle<EcmaString> tag = JSHandle<EcmaString>::Cast(locales);
JSHandle<TaggedArray> temp = factory->NewTaggedArray(1);
temp->Set(thread, 0, tag.GetTaggedValue());
JSHandle<JSArray> obj = JSArray::CreateArrayFromList(thread, temp);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSArray>(thread, obj, localeSeen);
return finalSeen;
} else if (locales->IsJSLocale()) {
JSHandle<EcmaString> tag = JSLocale::ToString(thread, JSHandle<JSLocale>::Cast(locales));
JSHandle<TaggedArray> temp = factory->NewTaggedArray(1);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
temp->Set(thread, 0, tag.GetTaggedValue());
JSHandle<JSArray> obj = JSArray::CreateArrayFromList(thread, temp);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSArray>(thread, obj, localeSeen);
return finalSeen;
} else {
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<TaggedArray> finalSeen = CanonicalizeHelper<JSObject>(thread, obj, localeSeen);
return finalSeen;
}
return localeSeen;
}
template<typename T>
JSHandle<TaggedArray> JSLocale::CanonicalizeHelper(JSThread *thread, JSHandle<T> &obj, JSHandle<TaggedArray> &seen)
{
OperationResult operationResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj),
thread->GlobalConstants()->GetHandledLengthString());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSTaggedNumber len = JSTaggedValue::ToLength(thread, operationResult.GetValue());
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// 2. Let seen be a new empty List.
uint32_t requestedLocalesLen = len.ToUint32();
seen = factory->NewTaggedArray(requestedLocalesLen);
// 6. Let k be 0.
// 7. Repeat, while k < len
JSMutableHandle<JSTaggedValue> pk(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> tag(thread, JSTaggedValue::Undefined());
uint32_t index = 0;
JSHandle<JSTaggedValue> objTagged = JSHandle<JSTaggedValue>::Cast(obj);
for (uint32_t k = 0; k < requestedLocalesLen; k++) {
// a. Let Pk be ToString(k).
JSHandle<JSTaggedValue> kHandle(thread, JSTaggedValue(k));
JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, kHandle);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
pk.Update(str.GetTaggedValue());
// b. Let kPresent be ? HasProperty(O, Pk).
bool kPresent = JSTaggedValue::HasProperty(thread, objTagged, pk);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
// c. If kPresent is true, then
if (kPresent) {
// i. Let kValue be ? Get(O, Pk).
OperationResult result = JSTaggedValue::GetProperty(thread, objTagged, pk);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<JSTaggedValue> kValue = result.GetValue();
// ii. If Type(kValue) is not String or Object, throw a TypeError exception.
if (!kValue->IsString() && !kValue->IsJSObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "kValue is not String or Object.", factory->EmptyArray());
}
// iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then
// 1. Let tag be kValue.[[Locale]].
// iv. Else,
// 1. Let tag be ? ToString(kValue).
if (kValue->IsJSLocale()) {
JSHandle<EcmaString> kValueStr = JSLocale::ToString(thread, JSHandle<JSLocale>::Cast(kValue));
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
tag.Update(kValueStr.GetTaggedValue());
} else {
JSHandle<EcmaString> kValueString = JSTaggedValue::ToString(thread, kValue);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
JSHandle<EcmaString> canonicalStr = CanonicalizeUnicodeLocaleId(thread, kValueString);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
tag.Update(canonicalStr.GetTaggedValue());
}
// vii. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen.
bool isExist = false;
uint32_t seenLen = seen->GetLength();
for (uint32_t i = 0; i < seenLen; i++) {
if (JSTaggedValue::SameValue(seen->Get(thread, i), tag.GetTaggedValue())) {
isExist = true;
}
}
if (!isExist) {
seen->Set(thread, index++, JSHandle<JSTaggedValue>::Cast(tag));
}
}
// d. Increase k by 1.
}
// set capacity
seen = TaggedArray::SetCapacity(thread, seen, index);
// 8. Return seen.
return seen;
}
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
std::string JSLocale::BestAvailableLocale(const std::vector<std::string> &availableLocales,
const std::string &locale)
{
// 1. Let candidate be locale.
std::string localeCandidate = locale;
std::string undefined = std::string();
// 2. Repeat,
uint32_t length = availableLocales.size();
while (true) {
// a. If availableLocales contains an element equal to candidate, return candidate.
for (uint32_t i = 0; i < length; ++i) {
std::string itemStr = availableLocales[i];
if (itemStr == localeCandidate) {
return localeCandidate;
}
}
// b. Let pos be the character index of the last occurrence of "-" (U+002D) within candidate.
// If that character does not occur, return undefined.
size_t pos = localeCandidate.rfind('-');
if (pos == std::string::npos) {
return undefined;
}
// c. If pos ≥ 2 and the character "-" occurs at index pos-2 of candidate, decrease pos by 2.
if (pos >= INTL_INDEX_TWO && localeCandidate[pos - INTL_INDEX_TWO] == '-') {
pos -= INTL_INDEX_TWO;
}
// d. Let candidate be the substring of candidate from position 0, inclusive, to position pos, exclusive.
localeCandidate = localeCandidate.substr(0, pos);
}
}
// 9.2.3 LookupMatcher ( availableLocales, requestedLocales )
JSHandle<EcmaString> JSLocale::LookupMatcher(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
const JSHandle<TaggedArray> &requestedLocales)
@ -345,9 +67,10 @@ JSHandle<EcmaString> JSLocale::LookupMatcher(JSThread *thread, const JSHandle<Ta
locale.Update(requestedLocales->Get(thread, i));
// 2. a. Let noExtensionsLocale be the String value that is locale
// with all Unicode locale extension sequences removed.
ParsedLocale parsedResult = HandleLocale(locale);
base::LocaleHelper::ParsedLocale parsedResult = base::LocaleHelper::HandleLocale(locale);
// 2. b. Let availableLocale be BestAvailableLocale(availableLocales, noExtensionsLocale).
std::string availableLocale = BestAvailableLocale(availableStringLocales, parsedResult.base);
std::string availableLocale =
base::LocaleHelper::BestAvailableLocale(availableStringLocales, parsedResult.base);
// 2. c. If availableLocale is not undefined, append locale to the end of subset.
if (!availableLocale.empty()) {
result = {std::string(), std::string()};
@ -369,7 +92,7 @@ JSHandle<EcmaString> JSLocale::LookupMatcher(JSThread *thread, const JSHandle<Ta
// 3. Let defLocale be DefaultLocale();
// 4. Set result.[[locale]] to defLocale.
// 5. Return result.
std::string defLocale = ConvertToStdString(DefaultLocale(thread));
std::string defLocale = base::LocaleHelper::ConvertToStdString(base::LocaleHelper::DefaultLocale(thread));
result.locale = defLocale;
return factory->NewFromStdString(result.locale);
}
@ -377,7 +100,7 @@ JSHandle<EcmaString> JSLocale::LookupMatcher(JSThread *thread, const JSHandle<Ta
icu::LocaleMatcher BuildLocaleMatcher(JSThread *thread, uint32_t *availableLength, UErrorCode *status,
const JSHandle<TaggedArray> &availableLocales)
{
std::string locale = JSLocale::ConvertToStdString(JSLocale::DefaultLocale(thread));
std::string locale = base::LocaleHelper::ConvertToStdString(base::LocaleHelper::DefaultLocale(thread));
icu::Locale defaultLocale = icu::Locale::forLanguageTag(locale, *status);
ASSERT_PRINT(U_SUCCESS(*status), "icu::Locale::forLanguageTag failed");
icu::LocaleMatcher::Builder builder;
@ -387,7 +110,7 @@ icu::LocaleMatcher BuildLocaleMatcher(JSThread *thread, uint32_t *availableLengt
JSMutableHandle<EcmaString> item(thread, JSTaggedValue::Undefined());
for (*availableLength = 0; *availableLength < length; ++(*availableLength)) {
item.Update(availableLocales->Get(thread, *availableLength));
std::string itemStr = JSLocale::ConvertToStdString(item);
std::string itemStr = base::LocaleHelper::ConvertToStdString(item);
icu::Locale localeForLanguageTag = icu::Locale::forLanguageTag(itemStr, *status);
if (U_SUCCESS(*status) != 0) {
builder.addSupportedLocale(localeForLanguageTag);
@ -414,7 +137,7 @@ JSHandle<EcmaString> JSLocale::BestFitMatcher(JSThread *thread, const JSHandle<T
auto bestFit = matcher.getBestMatch(iter, status)->toLanguageTag<std::string>(status);
if (U_FAILURE(status) != 0) {
return DefaultLocale(thread);
return base::LocaleHelper::DefaultLocale(thread);
}
for (uint32_t i = 0; i < requestedLocalesLength; ++i) {
@ -443,8 +166,9 @@ JSHandle<TaggedArray> JSLocale::LookupSupportedLocales(JSThread *thread, const J
// c. If availableLocale is not undefined, append locale to the end of subset.
for (uint32_t i = 0; i < length; ++i) {
item.Update(requestedLocales->Get(thread, i));
ParsedLocale foundationResult = HandleLocale(item);
std::string availableLocale = BestAvailableLocale(availableStringLocales, foundationResult.base);
base::LocaleHelper::ParsedLocale foundationResult = base::LocaleHelper::HandleLocale(item);
std::string availableLocale =
base::LocaleHelper::BestAvailableLocale(availableStringLocales, foundationResult.base);
if (!availableLocale.empty()) {
subset->Set(thread, index++, item.GetTaggedValue());
}
@ -464,7 +188,7 @@ JSHandle<TaggedArray> JSLocale::BestFitSupportedLocales(JSThread *thread, const
ASSERT(U_SUCCESS(status));
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> defaultLocale = DefaultLocale(thread);
JSHandle<EcmaString> defaultLocale = base::LocaleHelper::DefaultLocale(thread);
JSHandle<TaggedArray> result = factory->NewTaggedArray(requestLength);
uint32_t index = 0;
@ -475,7 +199,7 @@ JSHandle<TaggedArray> JSLocale::BestFitSupportedLocales(JSThread *thread, const
result->Set(thread, index++, locale.GetTaggedValue());
} else {
status = U_ZERO_ERROR;
std::string localeStr = ConvertToStdString(locale);
std::string localeStr = base::LocaleHelper::ConvertToStdString(locale);
icu::Locale desired = icu::Locale::forLanguageTag(localeStr, status);
auto bestFit = matcher.getBestMatch(desired, status)->toLanguageTag<std::string>(status);
if ((U_SUCCESS(status) != 0) &&
@ -488,55 +212,6 @@ JSHandle<TaggedArray> JSLocale::BestFitSupportedLocales(JSThread *thread, const
return result;
}
JSHandle<EcmaString> JSLocale::ToLanguageTag(JSThread *thread, const icu::Locale &locale)
{
UErrorCode status = U_ZERO_ERROR;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
auto result = locale.toLanguageTag<std::string>(status);
bool flag = (U_FAILURE(status) == 0) ? true : false;
if (!flag) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid locale", factory->GetEmptyString());
}
size_t findBeginning = result.find("-u-");
std::string finalRes;
std::string tempRes;
if (findBeginning == std::string::npos) {
return factory->NewFromStdString(result);
}
size_t specialBeginning = findBeginning + INTL_INDEX_THREE;
size_t specialCount = 0;
while ((specialBeginning < result.size()) && (result[specialBeginning] != '-')) {
specialCount++;
specialBeginning++;
}
if (findBeginning != std::string::npos) {
// It begin with "-u-xx" or with more elements.
tempRes = result.substr(0, findBeginning + INTL_INDEX_THREE + specialCount);
if (result.size() <= findBeginning + INTL_INDEX_THREE + specialCount) {
return factory->NewFromStdString(result);
}
std::string leftStr = result.substr(findBeginning + INTL_INDEX_THREE + specialCount + INTL_INDEX_ONE);
std::istringstream temp(leftStr);
std::string buffer;
std::vector<std::string> resContainer;
while (getline(temp, buffer, '-')) {
if (buffer != "true" && buffer != "yes") {
resContainer.push_back(buffer);
}
}
for (auto it = resContainer.begin(); it != resContainer.end(); it++) {
std::string tag = "-";
tag += *it;
finalRes += tag;
}
}
if (!finalRes.empty()) {
tempRes += finalRes;
}
result = tempRes;
return factory->NewFromStdString(result);
}
// 9.2.10 SupportedLocales ( availableLocales, requestedLocales, options )
JSHandle<JSArray> JSLocale::SupportedLocales(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
const JSHandle<TaggedArray> &requestedLocales,
@ -640,7 +315,7 @@ bool JSLocale::GetOptionOfString(JSThread *thread, const JSHandle<JSObject> &opt
if (EcmaStringAccessor(valueEStr).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Value out of range for locale options property", false);
}
*optionValue = JSLocale::ConvertToStdString(valueEStr);
*optionValue = base::LocaleHelper::ConvertToStdString(valueEStr);
if (values.empty()) {
return true;
}
@ -776,7 +451,7 @@ ResolvedLocale JSLocale::ResolveLocale(JSThread *thread, const JSHandle<TaggedAr
// a. Let r be BestFitMatcher(availableLocales, requestedLocales).
JSMutableHandle<EcmaString> locale(thread, JSTaggedValue::Undefined());
if (availableLocales->GetLength() == 0 && requestedLocales->GetLength() == 0) {
locale.Update(DefaultLocale(thread).GetTaggedValue());
locale.Update(base::LocaleHelper::DefaultLocale(thread).GetTaggedValue());
} else {
locale.Update(LookupMatcher(thread, availableLocales, requestedLocales).GetTaggedValue());
}
@ -785,12 +460,12 @@ ResolvedLocale JSLocale::ResolveLocale(JSThread *thread, const JSHandle<TaggedAr
// 5. Let result be a new Record.
// 6. Set result.[[dataLocale]] to foundLocale.
// 7. Let supportedExtension be "-u".
std::string foundLocale = ConvertToStdString(locale);
std::string foundLocale = base::LocaleHelper::ConvertToStdString(locale);
icu::Locale foundLocaleData = BuildICULocale(foundLocale);
ResolvedLocale result;
result.localeData = foundLocaleData;
JSHandle<EcmaString> tag = ToLanguageTag(thread, foundLocaleData);
result.locale = ConvertToStdString(tag);
JSHandle<EcmaString> tag = base::LocaleHelper::ToLanguageTag(thread, foundLocaleData);
result.locale = base::LocaleHelper::ConvertToStdString(tag);
std::string supportedExtension = "-u";
icu::LocaleBuilder localeBuilder;
localeBuilder.setLocale(foundLocaleData).clearExtensions();
@ -894,13 +569,13 @@ ResolvedLocale JSLocale::ResolveLocale(JSThread *thread, const JSHandle<TaggedAr
foundLocale = preExtension + supportedExtension + postExtension;
}
tag = ToLanguageTag(thread, foundLocaleData);
if (!IsStructurallyValidLanguageTag(tag)) {
tag = base::LocaleHelper::ToLanguageTag(thread, foundLocaleData);
if (!base::LocaleHelper::IsStructurallyValidLanguageTag(tag)) {
result.extensions.erase(result.extensions.begin(), result.extensions.end());
result.locale = foundLocale;
}
tag = CanonicalizeUnicodeLocaleId(thread, tag);
foundLocale = ConvertToStdString(tag);
tag = base::LocaleHelper::CanonicalizeUnicodeLocaleId(thread, tag);
foundLocale = base::LocaleHelper::ConvertToStdString(tag);
}
// 10. Set result.[[locale]] to foundLocale.
@ -936,18 +611,6 @@ JSHandle<TaggedArray> JSLocale::ConstructLocaleList(JSThread *thread,
return locales;
}
JSHandle<EcmaString> JSLocale::IcuToString(JSThread *thread, const icu::UnicodeString &string)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(string.getBuffer()), string.length());
}
JSHandle<EcmaString> JSLocale::IcuToString(JSThread *thread, const icu::UnicodeString &string, int32_t begin,
int32_t end)
{
return IcuToString(thread, string.tempSubStringBetween(begin, end));
}
std::string JSLocale::GetNumberingSystem(const icu::Locale &icuLocale)
{
UErrorCode status = U_ZERO_ERROR;
@ -1060,8 +723,8 @@ bool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &t
if (*tag == *(factory->GetEmptyString())) {
return false;
}
// 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
if (!IsStructurallyValidLanguageTag(tag)) {
// 2. If base::LocaleHelper::IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
if (!base::LocaleHelper::IsStructurallyValidLanguageTag(tag)) {
return false;
}
@ -1073,7 +736,8 @@ bool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &t
// 4. If language is not undefined, then
// a. If language does not match the unicode_language_subtag production, throw a RangeError exception.
if (!tagElements.language->IsUndefined()) {
std::string languageStr = ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.language));
std::string languageStr =
base::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.language));
if (languageStr[INTL_INDEX_ZERO] == '\0' ||
IsAlpha(languageStr, INTL_INDEX_FOUR, INTL_INDEX_FOUR)) {
return false;
@ -1089,7 +753,8 @@ bool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &t
// 6. If script is not undefined, then
// a. If script does not match the unicode_script_subtag production, throw a RangeError exception.
if (!tagElements.script->IsUndefined()) {
std::string scriptStr = JSLocale::ConvertToStdString((JSHandle<EcmaString>::Cast(tagElements.script)));
std::string scriptStr =
base::LocaleHelper::ConvertToStdString((JSHandle<EcmaString>::Cast(tagElements.script)));
if (scriptStr[INTL_INDEX_ZERO] == '\0') {
return false;
}
@ -1104,7 +769,7 @@ bool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &t
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
if (!tagElements.region->IsUndefined()) {
std::string regionStr = ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.region));
std::string regionStr = base::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.region));
if (regionStr[INTL_INDEX_ZERO] == '\0') {
return false;
}
@ -1115,7 +780,7 @@ bool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &t
bool BuildOptionsTags(const JSHandle<EcmaString> &tag, icu::LocaleBuilder *builder, JSHandle<JSTaggedValue> language,
JSHandle<JSTaggedValue> script, JSHandle<JSTaggedValue> region)
{
std::string tagStr = JSLocale::ConvertToStdString(tag);
std::string tagStr = base::LocaleHelper::ConvertToStdString(tag);
int32_t len = static_cast<int32_t>(tagStr.length());
ASSERT(len > 0);
builder->setLanguageTag({ tagStr.c_str(), len });
@ -1128,7 +793,7 @@ bool BuildOptionsTags(const JSHandle<EcmaString> &tag, icu::LocaleBuilder *build
builder->setLocale(locale);
if (!language->IsUndefined()) {
std::string languageStr = JSLocale::ConvertToStdString(JSHandle<EcmaString>::Cast(language));
std::string languageStr = base::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(language));
builder->setLanguage(languageStr);
builder->build(status);
if ((U_FAILURE(status) != 0)) {
@ -1137,7 +802,7 @@ bool BuildOptionsTags(const JSHandle<EcmaString> &tag, icu::LocaleBuilder *build
}
if (!script->IsUndefined()) {
std::string scriptStr = JSLocale::ConvertToStdString((JSHandle<EcmaString>::Cast(script)));
std::string scriptStr = base::LocaleHelper::ConvertToStdString((JSHandle<EcmaString>::Cast(script)));
builder->setScript(scriptStr);
builder->build(status);
if ((U_FAILURE(status) != 0)) {
@ -1146,7 +811,7 @@ bool BuildOptionsTags(const JSHandle<EcmaString> &tag, icu::LocaleBuilder *build
}
if (!region->IsUndefined()) {
std::string regionStr = JSLocale::ConvertToStdString(JSHandle<EcmaString>::Cast(region));
std::string regionStr = base::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(region));
builder->setRegion(regionStr);
builder->build(status);
if ((U_FAILURE(status) != 0)) {
@ -1255,53 +920,6 @@ JSHandle<JSLocale> JSLocale::InitializeLocale(JSThread *thread, const JSHandle<J
return locale;
}
bool JSLocale::DealwithLanguageTag(const std::vector<std::string> &containers, size_t &address)
{
// The abstract operation returns true if locale can be generated from the ABNF grammar in section 2.1 of the RFC,
// starting with Language-Tag, and does not contain duplicate variant or singleton subtags
// If language tag is empty, return false.
if (containers.empty()) {
return false;
}
// a. if the first tag is not language, return false.
if (!IsLanguageSubtag(containers[0])) {
return false;
}
// if the tag include language only, like "zh" or "de", return true;
if (containers.size() == 1) {
return true;
}
// Else, then
// if is unique singleton subtag, script and region tag.
if (IsExtensionSingleton(containers[1])) {
return true;
}
if (IsScriptSubtag(containers[address])) {
address++;
if (containers.size() == address) {
return true;
}
}
if (IsRegionSubtag(containers[address])) {
address++;
}
for (size_t i = address; i < containers.size(); i++) {
if (IsExtensionSingleton(containers[i])) {
return true;
}
if (!IsVariantSubtag(containers[i])) {
return false;
}
}
return true;
}
int ConvertValue(const UErrorCode &status, std::string &value, const std::string &key)
{
if (status == U_ILLEGAL_ARGUMENT_ERROR || value.empty()) {
@ -1345,51 +963,10 @@ JSHandle<EcmaString> JSLocale::ToString(JSThread *thread, const JSHandle<JSLocal
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return factory->GetEmptyString();
}
JSHandle<EcmaString> result = ToLanguageTag(thread, *icuLocale);
JSHandle<EcmaString> result = base::LocaleHelper::ToLanguageTag(thread, *icuLocale);
return result;
}
std::vector<std::string> JSLocale::GetAvailableLocales(JSThread *thread, const char *localeKey, const char *localePath)
{
UErrorCode status = U_ZERO_ERROR;
auto globalConst = thread->GlobalConstants();
JSHandle<EcmaString> specialValue = JSHandle<EcmaString>::Cast(globalConst->GetHandledEnUsPosixString());
std::string specialString = ConvertToStdString(specialValue);
UEnumeration *uenum = uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
std::vector<std::string> allLocales;
const char *loc = nullptr;
for (loc = uenum_next(uenum, nullptr, &status); loc != nullptr; loc = uenum_next(uenum, nullptr, &status)) {
ASSERT(U_SUCCESS(status));
std::string locStr(loc);
std::replace(locStr.begin(), locStr.end(), '_', '-');
if (locStr == specialString) {
locStr = "en-US-u-va-posix";
}
if (localePath != nullptr || localeKey != nullptr) {
icu::Locale locale(locStr.c_str());
bool res = false;
if (!CheckLocales(locale, localeKey, localePath, res)) {
continue;
}
}
bool isScript = false;
allLocales.push_back(locStr);
icu::Locale formalLocale = icu::Locale::createCanonical(locStr.c_str());
std::string scriptStr = formalLocale.getScript();
isScript = scriptStr.empty() ? false : true;
if (isScript) {
std::string languageStr = formalLocale.getLanguage();
std::string countryStr = formalLocale.getCountry();
std::string shortLocale = icu::Locale(languageStr.c_str(), countryStr.c_str()).getName();
std::replace(shortLocale.begin(), shortLocale.end(), '_', '-');
allLocales.push_back(shortLocale);
}
}
uenum_close(uenum);
return allLocales;
}
std::vector<std::string> JSLocale::GetAvailableStringLocales(JSThread *thread,
const JSHandle<TaggedArray> &availableLocales)
{
@ -1398,7 +975,7 @@ std::vector<std::string> JSLocale::GetAvailableStringLocales(JSThread *thread,
uint32_t availablecalesLength = availableLocales->GetLength();
for (uint32_t i = 0; i < availablecalesLength; i++) {
availableItem.Update(availableLocales->Get(thread, i));
availableStringLocales.emplace_back(ConvertToStdString(availableItem));
availableStringLocales.emplace_back(base::LocaleHelper::ConvertToStdString(availableItem));
}
return availableStringLocales;
}

View File

@ -147,11 +147,6 @@ struct TagElements {
class JSLocale : public JSObject {
public:
struct ParsedLocale {
std::string base;
std::string extension;
};
static JSLocale *Cast(TaggedObject *object)
{
ASSERT(JSTaggedValue(object).IsJSLocale());
@ -184,32 +179,12 @@ public:
}
}
static std::string ConvertToStdString(const JSHandle<EcmaString> &ecmaStr);
// 6.2.2 IsStructurallyValidLanguageTag ( locale )
static bool IsStructurallyValidLanguageTag(const JSHandle<EcmaString> &tag);
static bool DealwithLanguageTag(const std::vector<std::string> &containers, size_t &address);
// 6.2.3 CanonicalizeUnicodeLocaleId ( locale )
static JSHandle<EcmaString> CanonicalizeUnicodeLocaleId(JSThread *thread, const JSHandle<EcmaString> &locale);
// 6.2.4 DefaultLocale ()
static JSHandle<EcmaString> DefaultLocale(JSThread *thread);
// 6.4.1 IsValidTimeZoneName ( timeZone )
static bool IsValidTimeZoneName(const icu::TimeZone &tz);
// 9.2.1 CanonicalizeLocaleList ( locales )
static JSHandle<TaggedArray> CanonicalizeLocaleList(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
template<typename T>
static JSHandle<TaggedArray> CanonicalizeHelper(JSThread *thread, JSHandle<T> &obj, JSHandle<TaggedArray> &seen);
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
static std::string BestAvailableLocale(const std::vector<std::string> &availableLocales,
const std::string &locale);
// 9.2.3 LookupMatcher ( availableLocales, requestedLocales )
static JSHandle<EcmaString> LookupMatcher(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
const JSHandle<TaggedArray> &requestedLocales);
@ -261,7 +236,7 @@ public:
// i. If values does not contain an element equal to value, throw a RangeError exception.
JSHandle<EcmaString> valueEStr = JSTaggedValue::ToString(thread, value);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, T::EXCEPTION);
std::string valueStr = ConvertToStdString(valueEStr);
std::string valueStr = std::string(ConvertToString(*valueEStr, StringConvertedUsage::LOGICOPERATION));
int existIdx = -1;
if (!enumValues.empty()) {
size_t strValuesSize = strValues.size();
@ -498,13 +473,6 @@ public:
return res;
}
static JSHandle<EcmaString> IcuToString(JSThread *thread, const icu::UnicodeString &string);
static JSHandle<EcmaString> IcuToString(JSThread *thread, const icu::UnicodeString &string, int32_t begin,
int32_t end);
static std::vector<std::string> GetAvailableLocales(JSThread *thread, const char *key, const char *path);
static std::vector<std::string> GetAvailableStringLocales(JSThread *thread,
const JSHandle<TaggedArray> &availableLocales);
@ -512,8 +480,6 @@ public:
const JSHandle<JSTaggedValue> &fieldTypeString,
const JSHandle<JSTaggedValue> &value);
static JSHandle<EcmaString> ToLanguageTag(JSThread *thread, const icu::Locale &locale);
static std::string GetNumberingSystem(const icu::Locale &icuLocale);
static bool IsWellFormedCurrencyCode(const std::string &currency);
@ -530,10 +496,6 @@ public:
static JSHandle<EcmaString> NormalizeKeywordValue(JSThread *thread, const JSHandle<JSLocale> &locale,
const std::string &key);
static void HandleLocaleExtension(size_t &start, size_t &extensionEnd, const std::string result, size_t len);
static ParsedLocale HandleLocale(const JSHandle<EcmaString> &locale);
static JSHandle<EcmaString> ToString(JSThread *thread, const JSHandle<JSLocale> &locale);
// 12.1.1 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation )

View File

@ -288,7 +288,7 @@ FractionDigitsOption SetNumberFormatUnitOptions(JSThread *thread,
if (EcmaStringAccessor(currencyStr).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "not a utf-8", fractionDigitsOption);
}
std::string currencyCStr = JSLocale::ConvertToStdString(currencyStr);
std::string currencyCStr = base::LocaleHelper::ConvertToStdString(currencyStr);
if (!JSLocale::IsWellFormedCurrencyCode(currencyCStr)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "not a wellformed code", fractionDigitsOption);
}
@ -334,7 +334,7 @@ FractionDigitsOption SetNumberFormatUnitOptions(JSThread *thread,
if (EcmaStringAccessor(unitStr).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption);
}
std::string str = JSLocale::ConvertToStdString(unitStr);
std::string str = base::LocaleHelper::ConvertToStdString(unitStr);
if (!IsWellFormedUnitIdentifier(str, icuUnit, icuPerUnit)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption);
}
@ -362,7 +362,7 @@ FractionDigitsOption SetNumberFormatUnitOptions(JSThread *thread,
UErrorCode status = U_ZERO_ERROR;
if (style == StyleOption::CURRENCY) {
JSHandle<EcmaString> currencyStr = JSHandle<EcmaString>::Cast(currency);
std::string currencyCStr = JSLocale::ConvertToStdString(currencyStr);
std::string currencyCStr = base::LocaleHelper::ConvertToStdString(currencyStr);
std::transform(currencyCStr.begin(), currencyCStr.end(), currencyCStr.begin(), toupper);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> currencyValue = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(currencyCStr));
@ -442,7 +442,7 @@ void JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandle<JSN
EcmaVM *ecmaVm = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVm->GetFactory();
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
// 2. If options is undefined, then
// a. Let options be ObjectCreate(null).
@ -481,7 +481,7 @@ void JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandle<JSN
if (EcmaStringAccessor(numberingSystemEcmaString).IsUtf16()) {
THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem");
}
numberingSystemStr = JSLocale::ConvertToStdString(numberingSystemEcmaString);
numberingSystemStr = base::LocaleHelper::ConvertToStdString(numberingSystemEcmaString);
if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStr)) {
THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem");
}
@ -503,7 +503,7 @@ void JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandle<JSN
// 12. Set numberFormat.[[Locale]] to r.[[locale]].
icu::Locale icuLocale = r.localeData;
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
numberFormat->SetLocale(thread, localeStr.GetTaggedValue());
// Set numberingSystemStr to UnicodeKeyWord "nu"
@ -738,7 +738,7 @@ JSHandle<JSTaggedValue> JSNumberFormat::FormatNumeric(JSThread *thread,
JSHandle<JSTaggedValue> errorResult(thread, JSTaggedValue::Exception());
THROW_RANGE_ERROR_AND_RETURN(thread, "formatted number toString failed", errorResult);
}
JSHandle<EcmaString> stringValue = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> stringValue = base::LocaleHelper::UStringToString(thread, result);
return JSHandle<JSTaggedValue>::Cast(stringValue);
}
@ -789,14 +789,15 @@ void GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatte
// so add a literal type with value of formattedText.sub(0, start)
// Special case when fieldId is UNUM_GROUPING_SEPARATOR_FIELD
if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, formattedText, previousLimit, start);
JSHandle<EcmaString> substring =
base::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
typeString.Update(globalConst->GetIntegerString());
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
index++;
{
typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue());
substring = JSLocale::IcuToString(thread, formattedText, start, limit);
substring = base::LocaleHelper::UStringToString(thread, formattedText, start, limit);
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
index++;
@ -806,7 +807,8 @@ void GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatte
previousLimit = limit;
continue;
} else if (start > previousLimit) {
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, formattedText, previousLimit, start);
JSHandle<EcmaString> substring =
base::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
index++;
@ -821,7 +823,7 @@ void GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatte
} else {
typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue());
}
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, formattedText, start, limit);
JSHandle<EcmaString> substring = base::LocaleHelper::UStringToString(thread, formattedText, start, limit);
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
index++;
@ -832,7 +834,7 @@ void GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatte
if (formattedText.length() > previousLimit) {
typeString.Update(globalConst->GetLiteralString());
JSHandle<EcmaString> substring =
JSLocale::IcuToString(thread, formattedText, previousLimit, formattedText.length());
base::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length());
JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
}
}
@ -900,7 +902,7 @@ JSHandle<TaggedArray> JSNumberFormat::GetAvailableLocales(JSThread *thread)
}
const char *key = "NumberElements";
const char *path = nullptr;
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
env->SetNumberFormatLocales(thread, availableLocales);
return availableLocales;

View File

@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_JS_NUMBER_FORMAT_H
#define ECMASCRIPT_JS_NUMBER_FORMAT_H
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_hclass.h"

View File

@ -15,6 +15,7 @@
#include "ecmascript/js_plural_rules.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/global_env.h"
#include "ecmascript/global_env_constants.h"
@ -154,7 +155,7 @@ JSHandle<JSPluralRules> JSPluralRules::InitializePluralRules(JSThread *thread,
auto globalConst = thread->GlobalConstants();
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread);
// 2&3. If options is undefined, then Let options be ObjectCreate(null). else Let options be ? ToObject(options).
@ -254,7 +255,7 @@ JSHandle<JSPluralRules> JSPluralRules::InitializePluralRules(JSThread *thread,
SetIcuNumberFormatter(thread, pluralRules, icuNumberFormatter, JSPluralRules::FreeIcuNumberFormatter);
// 12. Set pluralRules.[[Locale]] to the value of r.[[locale]].
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
pluralRules->SetLocale(thread, localeStr.GetTaggedValue());
// 13. Return pluralRules.
@ -360,7 +361,7 @@ void JSPluralRules::ResolvedOptions(JSThread *thread, const JSHandle<JSPluralRul
for (int32_t i = 0; i < count; i++) {
const icu::UnicodeString *category = categories->snext(status);
ASSERT(U_SUCCESS(status));
JSHandle<EcmaString> value = JSLocale::IcuToString(thread, *category);
JSHandle<EcmaString> value = base::LocaleHelper::UStringToString(thread, *category);
pluralCategories->Set(thread, i, value);
}

View File

@ -29,7 +29,7 @@ JSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeForma
ObjectFactory *factory = ecmaVm->GetFactory();
// 1.Let requestedLocales be ? CanonicalizeLocaleList(locales).
JSHandle<TaggedArray> requestedLocales = JSLocale::CanonicalizeLocaleList(thread, locales);
JSHandle<TaggedArray> requestedLocales = base::LocaleHelper::CanonicalizeLocaleList(thread, locales);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
// 2&3. If options is undefined, then Let options be ObjectCreate(null). else Let options be ? ToObject(options).
@ -63,7 +63,7 @@ JSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeForma
if (EcmaStringAccessor(numberingSystemString).IsUtf16()) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat);
}
numberingSystemStdStr = JSLocale::ConvertToStdString(numberingSystemString);
numberingSystemStdStr = base::LocaleHelper::ConvertToStdString(numberingSystemString);
if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStdStr)) {
THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat);
}
@ -76,7 +76,8 @@ JSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeForma
if (requestedLocales->GetLength() == 0) {
availableLocales = factory->EmptyArray();
} else {
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, "calendar", nullptr);
std::vector<std::string> availableStringLocales =
base::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
}
std::set<std::string> relevantExtensionKeys{"nu"};
@ -86,7 +87,7 @@ JSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeForma
icu::Locale icuLocale = r.localeData;
// 12. Let locale be r.[[Locale]].
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, icuLocale);
JSHandle<EcmaString> localeStr = base::LocaleHelper::ToLanguageTag(thread, icuLocale);
// 13. Set relativeTimeFormat.[[Locale]] to locale.
relativeTimeFormat->SetLocale(thread, localeStr.GetTaggedValue());
@ -414,7 +415,8 @@ void FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
// so add a literal type with value of formattedText.sub(0, start)
if (start > previousLimit) {
typeString.Update(globalConst->GetLiteralString());
JSHandle<EcmaString> substring = JSLocale::IcuToString(thread, formattedText, previousLimit, start);
JSHandle<EcmaString> substring =
base::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
}
@ -423,7 +425,8 @@ void FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
for (auto it = separatorFields.begin(); it != separatorFields.end(); it++) {
if (it->first > start) {
// Add Integer type element
JSHandle<EcmaString> resString = JSLocale::IcuToString(thread, formattedText, start, it->first);
JSHandle<EcmaString> resString =
base::LocaleHelper::UStringToString(thread, formattedText, start, it->first);
typeString.Update(
JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue());
JSHandle<JSObject> record =
@ -432,7 +435,7 @@ void FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit));
RETURN_IF_ABRUPT_COMPLETION(thread);
// Add Group type element
resString = JSLocale::IcuToString(thread, formattedText, it->first, it->second);
resString = base::LocaleHelper::UStringToString(thread, formattedText, it->first, it->second);
typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(),
UNUM_GROUPING_SEPARATOR_FIELD).GetTaggedValue());
record =
@ -444,7 +447,7 @@ void FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
}
}
// Add current field unit
JSHandle<EcmaString> subString = JSLocale::IcuToString(thread, formattedText, start, limit);
JSHandle<EcmaString> subString = base::LocaleHelper::UStringToString(thread, formattedText, start, limit);
typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue());
JSHandle<JSObject> record =
JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(subString));
@ -458,7 +461,7 @@ void FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
if (formattedText.length() > previousLimit) {
typeString.Update(globalConst->GetLiteralString());
JSHandle<EcmaString> substring =
JSLocale::IcuToString(thread, formattedText, previousLimit, formattedText.length());
base::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length());
JSLocale::PutElement(thread, index, array, typeString, JSHandle<JSTaggedValue>::Cast(substring));
RETURN_IF_ABRUPT_COMPLETION(thread);
}

View File

@ -18,6 +18,7 @@
#include "unicode/reldatefmt.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/common.h"
#include "ecmascript/ecma_macros.h"

View File

@ -121,6 +121,7 @@ host_unittest_action("EcmaVm_002_Test") {
"js_proxy_test.cpp",
"js_regexp_iterator_test.cpp",
"js_relative_time_format_test.cpp",
"locale_helper_test.cpp",
]
configs = [

View File

@ -13,6 +13,7 @@
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_date.h"
#include "ecmascript/js_date_time_format.h"
@ -21,6 +22,7 @@
using namespace panda;
using namespace panda::ecmascript;
using namespace panda::ecmascript::base;
namespace panda::test {
class JSDateTimeFormatTest : public testing::Test {
@ -218,7 +220,7 @@ HWTEST_F_L0(JSDateTimeFormatTest, InitializeDateTimeFormat)
JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale());
JSHandle<EcmaString> localeEcmaStr = JSHandle<EcmaString>::Cast(localeTagVal);
std::string localeStr = JSLocale::ConvertToStdString(localeEcmaStr);
std::string localeStr = LocaleHelper::ConvertToStdString(localeEcmaStr);
EXPECT_STREQ(localeStr.c_str(), "zh-Hans-CN-u-ca-chinese");
}
@ -249,17 +251,17 @@ HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_001)
options = JSDateTimeFormat::ToDateTimeOptions(
thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ALL"
auto yearEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(yearEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearEcmaStr).c_str(), "numeric");
auto monthEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(monthEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthEcmaStr).c_str(), "numeric");
auto dayEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(dayEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayEcmaStr).c_str(), "numeric");
auto hourEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(hourEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourEcmaStr).c_str(), "numeric");
auto minuteEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(minuteEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteEcmaStr).c_str(), "numeric");
auto secondEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(secondEcmaStr).c_str(), "numeric");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondEcmaStr).c_str(), "numeric");
}
HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_002)
@ -300,24 +302,24 @@ HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_002)
options = JSDateTimeFormat::ToDateTimeOptions(
thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ANY"
auto weekdayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, weekdayKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(weekdayStr).c_str(), "narrow");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(weekdayStr).c_str(), "narrow");
auto yearStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(yearStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearStr).c_str(), "2-digit");
auto monthStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(monthStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthStr).c_str(), "2-digit");
auto dayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(dayStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayStr).c_str(), "2-digit");
auto dayPeriodStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayPeriodKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(dayPeriodStr).c_str(), "narrow");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayPeriodStr).c_str(), "narrow");
auto hourStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(hourStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourStr).c_str(), "2-digit");
auto minuteStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(minuteStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteStr).c_str(), "2-digit");
auto secondStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(secondStr).c_str(), "2-digit");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondStr).c_str(), "2-digit");
auto fracSecStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, fracSecKey).GetValue());
EXPECT_STREQ(JSLocale::ConvertToStdString(fracSecStr).c_str(), "1");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(fracSecStr).c_str(), "1");
}
JSHandle<JSDateTimeFormat> CreateDateTimeFormatTest(JSThread *thread, icu::Locale icuLocale, JSHandle<JSObject> options)
@ -368,9 +370,9 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_001)
// When the option is blank, the default format is "yyyy/MM/dd", the year, month and day are all numeric,
// because the default option in initialization is "DefaultsOption::DATE".
JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30");
}
HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_002)
@ -398,9 +400,9 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_002)
// Format to include all options by "DefaultsOption::ALL".
JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25 上午11:09:34");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25 上午11:09:34");
JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30 下午10:30:12");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30 下午10:30:12");
}
HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_003)
@ -444,9 +446,9 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_003)
double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "22年05月25日星期三 上午11:09:34.000");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "22年05月25日星期三 上午11:09:34.000");
JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "22年05月30日星期一 晚上10:30:12.999");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(), "22年05月30日星期一 晚上10:30:12.999");
}
HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_004)
@ -490,10 +492,10 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_004)
double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(),
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(),
"Wednesday, 05/25/22, 11:09:34.000 in the morning");
JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(),
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(),
"Monday, 05/30/22, 10:30:12.999 at night");
}
@ -502,7 +504,7 @@ std::string GetDateTimePartStringTest(JSThread *thread, JSHandle<JSTaggedValue>
JSHandle<JSObject> partObj = JSHandle<JSObject>::Cast(part);
JSHandle<JSTaggedValue> partValue = JSObject::GetProperty(thread, partObj, key).GetValue();
JSHandle<EcmaString> partEcmaStr = JSHandle<EcmaString>::Cast(partValue);
std::string partStr = JSLocale::ConvertToStdString(partEcmaStr);
std::string partStr = LocaleHelper::ConvertToStdString(partEcmaStr);
return partStr;
}
@ -538,7 +540,7 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_001)
double timeStamp = 1653448174123; // test "2022-05-25 11:09:34.123"
// Use default date time format and format date and time to parts.
JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
JSHandle<JSArray> dateTimeArray1 = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 0).GetValue();
auto literal1 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 1).GetValue();
@ -597,7 +599,7 @@ HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_002)
thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
JSHandle<EcmaString> dateTimeEcamStr = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr).c_str(), "22年05月25日星期三 上午11:09:34.123");
EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr).c_str(), "22年05月25日星期三 上午11:09:34.123");
JSHandle<JSArray> dateTimeArray = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 0).GetValue();
@ -669,7 +671,7 @@ HWTEST_F_L0(JSDateTimeFormatTest, GainAvailableLocales)
const char *key = "calendar";
const char *path = nullptr;
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, key, path);
std::vector<std::string> availableStringLocales = base::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
env->SetDateTimeFormatLocales(thread, availableLocales);
JSHandle<TaggedArray> gainLocales1 = JSDateTimeFormat::GainAvailableLocales(thread);

View File

@ -14,6 +14,8 @@
*/
#include "ecmascript/js_displaynames.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda;
@ -83,7 +85,8 @@ HWTEST_F_L0(JSDisplayNamesTest, GetIcuLocaleDisplayNames)
thread, displayNames, iculocaledisplaynames, JSDisplayNames::FreeIcuLocaleDisplayNames);
icu::LocaleDisplayNames *resultIculocaledisplaynames = displayNames->GetIcuLocaleDisplayNames();
EXPECT_TRUE(iculocaledisplaynames == resultIculocaledisplaynames);
JSHandle<EcmaString> localeStr = JSLocale::ToLanguageTag(thread, resultIculocaledisplaynames->getLocale());
JSHandle<EcmaString> localeStr =
base::LocaleHelper::ToLanguageTag(thread, resultIculocaledisplaynames->getLocale());
EXPECT_STREQ(EcmaStringAccessor(localeStr).ToCString().c_str(), "en");
}

View File

@ -13,6 +13,7 @@
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_list_format.h"
@ -275,7 +276,7 @@ std::string GetListPartStringTest(JSThread *thread, JSHandle<JSTaggedValue> key,
JSHandle<JSObject> partObj = JSHandle<JSObject>::Cast(part);
JSHandle<JSTaggedValue> partValue = JSObject::GetProperty(thread, partObj, key).GetValue();
JSHandle<EcmaString> partEcmaStr = JSHandle<EcmaString>::Cast(partValue);
std::string partStr = JSLocale::ConvertToStdString(partEcmaStr);
std::string partStr = base::LocaleHelper::ConvertToStdString(partEcmaStr);
return partStr;
}

View File

@ -141,96 +141,6 @@ HWTEST_F_L0(JSLocaleTest, GetIcuField)
EXPECT_STREQ(result->getBaseName(), "zh_Hans_CN");
}
/**
* @tc.name: ConvertToStdString
* @tc.desc: Convert char* type to std string,check whether the returned string through "ConvertToStdString"
* function is within expectations.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, ConvertToStdString)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> handleEcmaStr = factory-> NewFromStdString("一二三四");
std::string stdString = JSLocale::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "一二三四");
handleEcmaStr = factory-> NewFromStdString("#%!\0@$");
stdString = JSLocale::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "#%!\0@$");
handleEcmaStr = factory-> NewFromStdString("123456");
stdString = JSLocale::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "123456");
handleEcmaStr = factory-> NewFromStdString("zhde");
stdString = JSLocale::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "zhde");
}
/**
* @tc.name: IsStructurallyValidLanguageTag
* @tc.desc: Call "IsStructurallyValidLanguageTag" function check Language-Tag is valid structurally.If the tag contains
* the correct language, region, script and extension, return true otherwise, return false.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, IsStructurallyValidLanguageTag)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// number-language
JSHandle<EcmaString> handleEcmaStr = factory->NewFromStdString("123-de");
EXPECT_FALSE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
// only language(zh)
handleEcmaStr = factory-> NewFromStdString("zh");
EXPECT_TRUE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
// only language and script, region
handleEcmaStr = factory-> NewFromStdString("zh-Hans-Cn");
EXPECT_TRUE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("ja-JP-u-ca-japanese");
EXPECT_TRUE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("语言脚本地区");
EXPECT_FALSE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("e-US");
EXPECT_FALSE(JSLocale::IsStructurallyValidLanguageTag(handleEcmaStr));
}
/**
* @tc.name: CanonicalizeUnicodeLocaleId
* @tc.desc: Call "CanonicalizeUnicodeLocaleId" function canonicalize locale(Language-Tag),The English case of language,
* region and script is fixed.the language is lowercase.the beginning of region is uppercase, and the script
* is lowercase.if locale string is IsUtf16,return empty string.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, CanonicalizeUnicodeLocaleId)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> locale = factory-> NewFromStdString("en-Us");
JSHandle<EcmaString> canonicalizeLocaleId = JSLocale::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("en-US", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
locale = factory-> NewFromStdString("kO-kore-kr");
canonicalizeLocaleId = JSLocale::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("ko-Kore-KR", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
locale = factory-> NewFromStdString("id-u-co-pinyin-de-ID");
canonicalizeLocaleId = JSLocale::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
// invalid locale
uint16_t localeArr[] = {0x122, 0x104, 0x45, 0x72, 0x97, 0x110, 0x115, 0x45, 0x67, 0x78}; // zh-Hans-CN
uint32_t localeArrLength = sizeof(localeArr) / sizeof(localeArr[0]);
locale = factory->NewFromUtf16(localeArr, localeArrLength);
canonicalizeLocaleId = JSLocale::CanonicalizeUnicodeLocaleId(thread, locale);
JSHandle<EcmaString> emptyString = factory->GetEmptyString();
EXPECT_EQ(EcmaStringAccessor::Compare(instance, canonicalizeLocaleId, emptyString), 0);
}
/**
* @tc.name: IsValidTimeZoneName
* @tc.desc: Call "IsValidTimeZoneName" function check whether the TimeZone is valid.if TimeZone include "GMT-Time"
@ -251,75 +161,6 @@ HWTEST_F_L0(JSLocaleTest, IsValidTimeZoneName)
delete timeZone;
}
/**
* @tc.name: CanonicalizeLocaleList
* @tc.desc: Create a list of locales and canonicalize the locales in the list through "CanonicalizeUnicodeLocaleId"
* function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, CanonicalizeLocaleList)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> ctor = env->GetLocaleFunction();
JSHandle<JSLocale> jsLocale =
JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
// Set IcuLocale
icu::Locale icuLocale("fr", "Latn", "Fr");
factory->NewJSIntlIcuData(jsLocale, icuLocale, JSLocale::FreeIcuLocale);
// test locale is jslocale
JSHandle<TaggedArray> localeArr = JSLocale::CanonicalizeLocaleList(thread, JSHandle<JSTaggedValue>(jsLocale));
EXPECT_EQ(localeArr->GetLength(), 1U);
JSHandle<EcmaString> handleEcmaStr(thread, localeArr->Get(0));
EXPECT_STREQ("fr-Latn-FR", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
// test locale is object
JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
JSHandle<JSTaggedValue> localeObj(thread, arr);
JSHandle<JSTaggedValue> localeStr1(factory->NewFromASCII("EN-us"));
PropertyDescriptor desc1(thread, localeStr1, true, true, true);
JSHandle<JSTaggedValue> key1(factory->NewFromASCII("1"));
JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key1, desc1);
JSHandle<JSTaggedValue> localeStr2(factory->NewFromASCII("en-GB"));
PropertyDescriptor desc2(thread, localeStr2, true, true, true);
JSHandle<JSTaggedValue> key2(factory->NewFromASCII("2"));
JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key2, desc2);
// check canonicalized string
localeArr = JSLocale::CanonicalizeLocaleList(thread, localeObj);
EXPECT_EQ(localeArr->GetLength(), 2U);
JSHandle<EcmaString> resultEcmaStr1(thread, localeArr->Get(0));
EXPECT_STREQ("en-US", EcmaStringAccessor(resultEcmaStr1).ToCString().c_str());
JSHandle<EcmaString> resultEcmaStr2(thread, localeArr->Get(1));
EXPECT_STREQ("en-GB", EcmaStringAccessor(resultEcmaStr2).ToCString().c_str());
}
/**
* @tc.name: IcuToString
* @tc.desc: Call "IcuToString" function Convert UnicodeString to string(Utf16).
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, IcuToString)
{
icu::UnicodeString unicodeString1("GMT-12:00"); // times
JSHandle<EcmaString> ecmaString = JSLocale::IcuToString(thread, unicodeString1);
EXPECT_STREQ("GMT-12:00", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString2("周日16:00:00周五23:00:00"); // date
ecmaString = JSLocale::IcuToString(thread, unicodeString2);
EXPECT_STREQ("周日16:00:00周五23:00:00", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString3("$654K"); // money
ecmaString = JSLocale::IcuToString(thread, unicodeString3);
EXPECT_STREQ("$654K", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString4("1 minute ago"); // moment
ecmaString = JSLocale::IcuToString(thread, unicodeString4, 0, 2);
EXPECT_STREQ("1 ", EcmaStringAccessor(ecmaString).ToCString().c_str());
}
/**
* @tc.name: PutElement
* @tc.desc: Put elements in empty JSArray and return the JSArray.call "GetProperty" function to get the value and
@ -347,43 +188,6 @@ HWTEST_F_L0(JSLocaleTest, PutElement)
EXPECT_TRUE(JSObject::GetProperty(thread, JSHandle<JSObject>(jsArray), indexKey).GetValue()->IsECMAObject());
}
/**
* @tc.name: ToLanguageTag
* @tc.desc: call "ToLanguageTag" function Convert ICU Locale into language tag.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, ToLanguageTag)
{
icu::Locale icuLocale1("en", "Latn", "US", "collation=phonebk;currency=euro");
JSHandle<EcmaString> languageTag = JSLocale::ToLanguageTag(thread, icuLocale1);
EXPECT_STREQ("en-Latn-US-u-co-phonebk-cu-euro", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale2("zh", "Hans", "CN", "collation=phonebk;kn=true");
languageTag = JSLocale::ToLanguageTag(thread, icuLocale2);
EXPECT_STREQ("zh-Hans-CN-u-co-phonebk-kn", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale3("ja", "Jpan", "JP", "collation=phonebk;co=yes");
languageTag = JSLocale::ToLanguageTag(thread, icuLocale3);
EXPECT_STREQ("ja-Jpan-JP-u-co", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale4("z", "CN"); // language is fault
languageTag = JSLocale::ToLanguageTag(thread, icuLocale4);
EXPECT_STREQ("und-CN", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale5("zh", "c"); // script is fault
languageTag = JSLocale::ToLanguageTag(thread, icuLocale5);
EXPECT_STREQ("zh-x-lvariant-c", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale6("en", "Latn", "E"); // region is fault
languageTag = JSLocale::ToLanguageTag(thread, icuLocale6);
EXPECT_STREQ("en-Latn-x-lvariant-e", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale7("en", "Latn", "EG", "kf=yes"); // key value is fault
languageTag = JSLocale::ToLanguageTag(thread, icuLocale7);
EXPECT_STREQ("en-Latn-EG-u-kf", EcmaStringAccessor(languageTag).ToCString().c_str());
}
/**
* @tc.name: GetNumberingSystem
* @tc.desc: Call "GetNumberingSystem" function get the script from the ICU Locale.
@ -445,7 +249,7 @@ HWTEST_F_L0(JSLocaleTest, ApplyOptionsToTag)
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
TagElements tagElements;
JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
JSHandle<EcmaString> languageTag = JSLocale::DefaultLocale(thread);
JSHandle<EcmaString> languageTag = base::LocaleHelper::DefaultLocale(thread);
JSHandle<JSTaggedValue> languageKey = thread->GlobalConstants()->GetHandledLanguageString();
JSHandle<JSTaggedValue> regionKey = thread->GlobalConstants()->GetHandledRegionString();
@ -470,59 +274,6 @@ HWTEST_F_L0(JSLocaleTest, ApplyOptionsToTag)
EXPECT_FALSE(result);
}
/**
* @tc.name: HandleLocaleExtension
* @tc.desc: Find position of subtag "x" or "u" in Locale through "HandleLocaleExtension" function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, HandleLocaleExtension)
{
std::string result = "en-Latn-US-u-ca-gregory-co-compat";
size_t start = 0;
size_t extensionEnd = 0;
JSLocale::HandleLocaleExtension(start, extensionEnd, result, result.size());
EXPECT_EQ(extensionEnd, 10U); // the position of "u"
// private extension("x")
result = "de-zh-x-co-phonebk-nu-kali";
start = 0;
extensionEnd = 0;
JSLocale::HandleLocaleExtension(start, extensionEnd, result, result.size());
EXPECT_EQ(extensionEnd, 5U); // the position of "x"
}
/**
* @tc.name: HandleLocale
* @tc.desc: Call "HandleLocale" function handle locale,if Locale has subtag "u" ignore it.If Locale has
* both subtag "x" and "u","x" is in front of "u","u" does not ignore,"x" is after "u","u" ignores.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, HandleLocale)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// no "u" or "x"
JSHandle<EcmaString> localeString = factory->NewFromASCII("en-Latn-US");
JSLocale::ParsedLocale parsedResult = JSLocale::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US");
// only "x"
localeString = factory->NewFromASCII("zh-CN-x-ca-pinyin");
parsedResult = JSLocale::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "zh-CN-x-ca-pinyin");
// only "u"
localeString = factory->NewFromASCII("ko-Kore-KR-u-co-phonebk");
parsedResult = JSLocale::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "ko-Kore-KR");
// both "x" and "u"
localeString = factory->NewFromASCII("en-Latn-US-u-x-co-phonebk-kn-true");
parsedResult = JSLocale::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-co-phonebk-kn-true");
localeString = factory->NewFromASCII("en-Latn-US-x-u-ca-pinyin-co-compat");
parsedResult = JSLocale::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-u-ca-pinyin-co-compat");
}
/**
* @tc.name: ConstructLocaleList
* @tc.desc: Get LocaleList numbers through "ConstructLocaleList" function.
@ -806,43 +557,6 @@ HWTEST_F_L0(JSLocaleTest, GetOptionOfBool)
EXPECT_FALSE(res);
}
/**
* @tc.name: BestAvailableLocale
* @tc.desc: Match the best Locale and return from available locale through "BestAvailableLocale" function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JSLocaleTest, BestAvailableLocale)
{
const char *path = JSCollator::uIcuDataColl.c_str();
// available locales in uIcuDataColl
std::vector<std::string> icuDataAvailableLocales = JSLocale::GetAvailableLocales(thread, nullptr, path);
// available locales(calendar)
std::vector<std::string> calendarAvailableLocales = JSLocale::GetAvailableLocales(thread, "calendar", nullptr);
// available locales(NumberElements)
std::vector<std::string> numberAvailableLocales = JSLocale::GetAvailableLocales(thread, "NumberElements", nullptr);
// "ar-001" is found
EXPECT_STREQ(JSLocale::BestAvailableLocale(icuDataAvailableLocales, "ar-001").c_str(), "ar-001");
EXPECT_STREQ(JSLocale::BestAvailableLocale(calendarAvailableLocales, "ar-001").c_str(), "ar-001");
EXPECT_STREQ(JSLocale::BestAvailableLocale(numberAvailableLocales, "ar-001").c_str(), "ar-001");
// "agq-CM" is not found in uIcuDataColl
EXPECT_STREQ(JSLocale::BestAvailableLocale(icuDataAvailableLocales, "agq-CM").c_str(), "");
EXPECT_STREQ(JSLocale::BestAvailableLocale(calendarAvailableLocales, "agq-CM").c_str(), "agq-CM");
EXPECT_STREQ(JSLocale::BestAvailableLocale(numberAvailableLocales, "agq-CM").c_str(), "agq-CM");
// language(und)-region(CN)
EXPECT_STREQ(JSLocale::BestAvailableLocale(icuDataAvailableLocales, "und-CN").c_str(), "");
EXPECT_STREQ(JSLocale::BestAvailableLocale(calendarAvailableLocales, "und-CN").c_str(), "");
EXPECT_STREQ(JSLocale::BestAvailableLocale(numberAvailableLocales, "und-CN").c_str(), "");
// language(en)-region(001)
EXPECT_STREQ(JSLocale::BestAvailableLocale(icuDataAvailableLocales, "en-001").c_str(), "en-001");
EXPECT_STREQ(JSLocale::BestAvailableLocale(calendarAvailableLocales, "en-001").c_str(), "en-001");
EXPECT_STREQ(JSLocale::BestAvailableLocale(numberAvailableLocales, "en-001").c_str(), "en-001");
// language(en)-script(Hans)-region(US)
EXPECT_STREQ(JSLocale::BestAvailableLocale(icuDataAvailableLocales, "en-Hans-US").c_str(), "en");
EXPECT_STREQ(JSLocale::BestAvailableLocale(calendarAvailableLocales, "en-Hans-US").c_str(), "en");
EXPECT_STREQ(JSLocale::BestAvailableLocale(numberAvailableLocales, "en-Hans-US").c_str(), "en");
}
/**
* @tc.name: ResolveLocale
* @tc.desc: Resolve Locale and return from available locale through "ResolveLocale" function.
@ -862,7 +576,8 @@ HWTEST_F_L0(JSLocaleTest, ResolveLocale_001)
LocaleMatcherOption::BEST_FIT, relevantExtensionKeys);
EXPECT_STREQ("en-US", result.locale.c_str()); // default locale
// availableLocales and requestLocales is not empty
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, "calendar", nullptr);
std::vector<std::string> availableStringLocales =
base::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
requestedLocales = factory->NewTaggedArray(1);
// test locale1
@ -902,7 +617,8 @@ HWTEST_F_L0(JSLocaleTest, ResolveLocale_002)
LocaleMatcherOption::BEST_FIT, relevantExtensionKeys);
EXPECT_STREQ("en-US", result.locale.c_str()); // default locale
// availableLocales and requestLocales is not empty
std::vector<std::string> availableStringLocales = JSLocale::GetAvailableLocales(thread, "calendar", nullptr);
std::vector<std::string> availableStringLocales =
base::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
requestedLocales = factory->NewTaggedArray(1);
// test locale1

View File

@ -13,6 +13,7 @@
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/js_number_format.h"
#include "ecmascript/napi/jsnapi_helper.h"
#include "ecmascript/tests/test_helper.h"
@ -86,7 +87,7 @@ HWTEST_F_L0(JSNumberFormatTest, GetIcuCallTarget)
UErrorCode status = U_ZERO_ERROR;
icu::number::FormattedNumber formattedNumber = resultIcuNumberFormatter->formatInt(value, status);
icu::UnicodeString result = formattedNumber.toString(status);
JSHandle<EcmaString> stringValue = JSLocale::IcuToString(thread, result);
JSHandle<EcmaString> stringValue = base::LocaleHelper::UStringToString(thread, result);
EXPECT_STREQ("-123,456", EcmaStringAccessor(stringValue).ToCString().c_str());
}

View File

@ -13,6 +13,7 @@
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/js_plural_rules.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/global_env.h"
@ -73,12 +74,12 @@ HWTEST_F_L0(JSPluralRulesTest, GetIcuPluralRules)
UPluralType icuType = UPLURAL_TYPE_CARDINAL; // Plural rules for cardinal numbers
icu::PluralRules *icuPluralRules(icu::PluralRules::forLocale(icuLocale, icuType, status));
icu::UnicodeString result1 = icuPluralRules->select(0);
JSHandle<EcmaString> stringValue1 = JSLocale::IcuToString(thread, result1);
JSHandle<EcmaString> stringValue1 = base::LocaleHelper::UStringToString(thread, result1);
JSPluralRules::SetIcuPluralRules(thread, pluralRules, *icuPluralRules, JSPluralRules::FreeIcuPluralRules);
icu::PluralRules *getPluralRules = pluralRules->GetIcuPluralRules();
icu::UnicodeString result2 = getPluralRules->select(0);
JSHandle<EcmaString> stringValue2 = JSLocale::IcuToString(thread, result2);
JSHandle<EcmaString> stringValue2 = base::LocaleHelper::UStringToString(thread, result2);
EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*stringValue1, *stringValue2), true);
delete icuPluralRules;
}

View File

@ -14,6 +14,7 @@
*/
#include "ecmascript/js_relative_time_format.h"
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/global_env.h"
#include "ecmascript/napi/jsnapi_helper.h"
@ -98,14 +99,14 @@ HWTEST_F_L0(JSRelativeTimeFormatTest, GetIcuRTFFormatter)
icu::RelativeDateTimeFormatter rtfFormatter(icuLocale, icuNumberFormat, UDAT_STYLE_LONG,
UDISPCTX_CAPITALIZATION_NONE, status);
icu::UnicodeString result1 = rtfFormatter.formatNumericToValue(value, UDAT_REL_UNIT_YEAR, status).toString(status);
JSHandle<EcmaString> stringValue1 = JSLocale::IcuToString(thread, result1);
JSHandle<EcmaString> stringValue1 = base::LocaleHelper::UStringToString(thread, result1);
// Set Icu RelativeDateTimeFormatter to Icu Field
factory->NewJSIntlIcuData(relativeTimeFormat, rtfFormatter, JSRelativeTimeFormat::FreeIcuRTFFormatter);
// Get Icu Field
icu::RelativeDateTimeFormatter *resultRelativeDateTimeFormatter = relativeTimeFormat->GetIcuRTFFormatter();
icu::UnicodeString result2 =
resultRelativeDateTimeFormatter->formatNumericToValue(value, UDAT_REL_UNIT_YEAR, status).toString(status);
JSHandle<EcmaString> stringValue2 = JSLocale::IcuToString(thread, result2);
JSHandle<EcmaString> stringValue2 = base::LocaleHelper::UStringToString(thread, result2);
EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*stringValue1, *stringValue2), true);
}

View File

@ -0,0 +1,351 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/locale_helper.h"
#include "ecmascript/ecma_string.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_collator.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::base;
namespace panda::test {
class LocaleHelperTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
JSRuntimeOptions options;
#if PANDA_TARGET_LINUX
// for consistency requirement, use ohos_icu4j/data as icu-data-path
options.SetIcuDataPath(ICU_PATH);
#endif
options.SetEnableForceGC(true);
instance = JSNApi::CreateEcmaVM(options);
instance->SetEnableForceGC(true);
ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
thread = instance->GetJSThread();
scope = new EcmaHandleScope(thread);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
ecmascript::EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
/**
* @tc.name: UStringToString
* @tc.desc: Call "UStringToString" function Convert UnicodeString to string(Utf16).
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, UStringToString)
{
icu::UnicodeString unicodeString1("GMT-12:00"); // times
JSHandle<EcmaString> ecmaString = LocaleHelper::UStringToString(thread, unicodeString1);
EXPECT_STREQ("GMT-12:00", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString2("周日16:00:00周五23:00:00"); // date
ecmaString = LocaleHelper::UStringToString(thread, unicodeString2);
EXPECT_STREQ("周日16:00:00周五23:00:00", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString3("$654K"); // money
ecmaString = LocaleHelper::UStringToString(thread, unicodeString3);
EXPECT_STREQ("$654K", EcmaStringAccessor(ecmaString).ToCString().c_str());
icu::UnicodeString unicodeString4("1 minute ago"); // moment
ecmaString = LocaleHelper::UStringToString(thread, unicodeString4, 0, 2);
EXPECT_STREQ("1 ", EcmaStringAccessor(ecmaString).ToCString().c_str());
}
/**
* @tc.name: CanonicalizeLocaleList
* @tc.desc: Create a list of locales and canonicalize the locales in the list through "CanonicalizeUnicodeLocaleId"
* function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, CanonicalizeLocaleList)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> ctor = env->GetLocaleFunction();
JSHandle<JSLocale> jsLocale =
JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
// Set IcuLocale
icu::Locale icuLocale("fr", "Latn", "Fr");
factory->NewJSIntlIcuData(jsLocale, icuLocale, JSLocale::FreeIcuLocale);
// test locale is jslocale
JSHandle<TaggedArray> localeArr = LocaleHelper::CanonicalizeLocaleList(thread, JSHandle<JSTaggedValue>(jsLocale));
EXPECT_EQ(localeArr->GetLength(), 1U);
JSHandle<EcmaString> handleEcmaStr(thread, localeArr->Get(0));
EXPECT_STREQ("fr-Latn-FR", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
// test locale is object
JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
JSHandle<JSTaggedValue> localeObj(thread, arr);
JSHandle<JSTaggedValue> localeStr1(factory->NewFromASCII("EN-us"));
PropertyDescriptor desc1(thread, localeStr1, true, true, true);
JSHandle<JSTaggedValue> key1(factory->NewFromASCII("1"));
JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key1, desc1);
JSHandle<JSTaggedValue> localeStr2(factory->NewFromASCII("en-GB"));
PropertyDescriptor desc2(thread, localeStr2, true, true, true);
JSHandle<JSTaggedValue> key2(factory->NewFromASCII("2"));
JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key2, desc2);
// check canonicalized string
localeArr = LocaleHelper::CanonicalizeLocaleList(thread, localeObj);
EXPECT_EQ(localeArr->GetLength(), 2U);
JSHandle<EcmaString> resultEcmaStr1(thread, localeArr->Get(0));
EXPECT_STREQ("en-US", EcmaStringAccessor(resultEcmaStr1).ToCString().c_str());
JSHandle<EcmaString> resultEcmaStr2(thread, localeArr->Get(1));
EXPECT_STREQ("en-GB", EcmaStringAccessor(resultEcmaStr2).ToCString().c_str());
}
/**
* @tc.name: CanonicalizeUnicodeLocaleId
* @tc.desc: Call "CanonicalizeUnicodeLocaleId" function canonicalize locale(Language-Tag),The English case of language,
* region and script is fixed.the language is lowercase.the beginning of region is uppercase, and the script
* is lowercase.if locale string is IsUtf16,return empty string.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, CanonicalizeUnicodeLocaleId)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> locale = factory-> NewFromStdString("en-Us");
JSHandle<EcmaString> canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("en-US", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
locale = factory-> NewFromStdString("kO-kore-kr");
canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("ko-Kore-KR", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
locale = factory-> NewFromStdString("id-u-co-pinyin-de-ID");
canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale);
EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str());
// invalid locale
uint16_t localeArr[] = {0x122, 0x104, 0x45, 0x72, 0x97, 0x110, 0x115, 0x45, 0x67, 0x78}; // zh-Hans-CN
uint32_t localeArrLength = sizeof(localeArr) / sizeof(localeArr[0]);
locale = factory->NewFromUtf16(localeArr, localeArrLength);
canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale);
JSHandle<EcmaString> emptyString = factory->GetEmptyString();
EXPECT_EQ(EcmaStringAccessor::Compare(instance, canonicalizeLocaleId, emptyString), 0);
}
/**
* @tc.name: ToLanguageTag
* @tc.desc: call "ToLanguageTag" function Convert ICU Locale into language tag.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, ToLanguageTag)
{
icu::Locale icuLocale1("en", "Latn", "US", "collation=phonebk;currency=euro");
JSHandle<EcmaString> languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale1);
EXPECT_STREQ("en-Latn-US-u-co-phonebk-cu-euro", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale2("zh", "Hans", "CN", "collation=phonebk;kn=true");
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale2);
EXPECT_STREQ("zh-Hans-CN-u-co-phonebk-kn", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale3("ja", "Jpan", "JP", "collation=phonebk;co=yes");
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale3);
EXPECT_STREQ("ja-Jpan-JP-u-co", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale4("z", "CN"); // language is fault
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale4);
EXPECT_STREQ("und-CN", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale5("zh", "c"); // script is fault
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale5);
EXPECT_STREQ("zh-x-lvariant-c", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale6("en", "Latn", "E"); // region is fault
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale6);
EXPECT_STREQ("en-Latn-x-lvariant-e", EcmaStringAccessor(languageTag).ToCString().c_str());
icu::Locale icuLocale7("en", "Latn", "EG", "kf=yes"); // key value is fault
languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale7);
EXPECT_STREQ("en-Latn-EG-u-kf", EcmaStringAccessor(languageTag).ToCString().c_str());
}
/**
* @tc.name: IsStructurallyValidLanguageTag
* @tc.desc: Call "IsStructurallyValidLanguageTag" function check Language-Tag is valid structurally.If the tag contains
* the correct language, region, script and extension, return true otherwise, return false.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, IsStructurallyValidLanguageTag)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// number-language
JSHandle<EcmaString> handleEcmaStr = factory->NewFromStdString("123-de");
EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
// only language(zh)
handleEcmaStr = factory-> NewFromStdString("zh");
EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
// only language and script, region
handleEcmaStr = factory-> NewFromStdString("zh-Hans-Cn");
EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("ja-JP-u-ca-japanese");
EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("语言脚本地区");
EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
handleEcmaStr = factory-> NewFromStdString("e-US");
EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr));
}
/**
* @tc.name: ConvertToStdString
* @tc.desc: Convert char* type to std string,check whether the returned string through "ConvertToStdString"
* function is within expectations.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, ConvertToStdString)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> handleEcmaStr = factory-> NewFromStdString("一二三四");
std::string stdString = LocaleHelper::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "一二三四");
handleEcmaStr = factory-> NewFromStdString("#%!\0@$");
stdString = LocaleHelper::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "#%!\0@$");
handleEcmaStr = factory-> NewFromStdString("123456");
stdString = LocaleHelper::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "123456");
handleEcmaStr = factory-> NewFromStdString("zhde");
stdString = LocaleHelper::ConvertToStdString(handleEcmaStr);
EXPECT_STREQ(stdString.c_str(), "zhde");
}
/**
* @tc.name: HandleLocaleExtension
* @tc.desc: Find position of subtag "x" or "u" in Locale through "HandleLocaleExtension" function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, HandleLocaleExtension)
{
std::string result = "en-Latn-US-u-ca-gregory-co-compat";
size_t start = 0;
size_t extensionEnd = 0;
LocaleHelper::HandleLocaleExtension(start, extensionEnd, result, result.size());
EXPECT_EQ(extensionEnd, 10U); // the position of "u"
// private extension("x")
result = "de-zh-x-co-phonebk-nu-kali";
start = 0;
extensionEnd = 0;
LocaleHelper::HandleLocaleExtension(start, extensionEnd, result, result.size());
EXPECT_EQ(extensionEnd, 5U); // the position of "x"
}
/**
* @tc.name: HandleLocale
* @tc.desc: Call "HandleLocale" function handle locale,if Locale has subtag "u" ignore it.If Locale has
* both subtag "x" and "u","x" is in front of "u","u" does not ignore,"x" is after "u","u" ignores.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, HandleLocale)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// no "u" or "x"
JSHandle<EcmaString> localeString = factory->NewFromASCII("en-Latn-US");
LocaleHelper::ParsedLocale parsedResult = LocaleHelper::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US");
// only "x"
localeString = factory->NewFromASCII("zh-CN-x-ca-pinyin");
parsedResult = LocaleHelper::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "zh-CN-x-ca-pinyin");
// only "u"
localeString = factory->NewFromASCII("ko-Kore-KR-u-co-phonebk");
parsedResult = LocaleHelper::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "ko-Kore-KR");
// both "x" and "u"
localeString = factory->NewFromASCII("en-Latn-US-u-x-co-phonebk-kn-true");
parsedResult = LocaleHelper::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-co-phonebk-kn-true");
localeString = factory->NewFromASCII("en-Latn-US-x-u-ca-pinyin-co-compat");
parsedResult = LocaleHelper::HandleLocale(localeString);
EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-u-ca-pinyin-co-compat");
}
/**
* @tc.name: BestAvailableLocale
* @tc.desc: Match the best Locale and return from available locale through "BestAvailableLocale" function.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(LocaleHelperTest, BestAvailableLocale)
{
const char *path = JSCollator::uIcuDataColl.c_str();
// available locales in uIcuDataColl
std::vector<std::string> icuDataAvailableLocales =
LocaleHelper::GetAvailableLocales(thread, nullptr, path);
// available locales(calendar)
std::vector<std::string> calendarAvailableLocales =
LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
// available locales(NumberElements)
std::vector<std::string> numberAvailableLocales =
LocaleHelper::GetAvailableLocales(thread, "NumberElements", nullptr);
// "ar-001" is found
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "ar-001").c_str(), "ar-001");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "ar-001").c_str(), "ar-001");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "ar-001").c_str(), "ar-001");
// "agq-CM" is not found in uIcuDataColl
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "agq-CM").c_str(), "");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "agq-CM").c_str(), "agq-CM");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "agq-CM").c_str(), "agq-CM");
// language(und)-region(CN)
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "und-CN").c_str(), "");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "und-CN").c_str(), "");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "und-CN").c_str(), "");
// language(en)-region(001)
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "en-001").c_str(), "en-001");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "en-001").c_str(), "en-001");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "en-001").c_str(), "en-001");
// language(en)-script(Hans)-region(US)
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "en-Hans-US").c_str(), "en");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "en-Hans-US").c_str(), "en");
EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "en-Hans-US").c_str(), "en");
}
} // namespace panda::test