add phone number format to i18n

Signed-off-by: sunyaozu <sunyaozu@huawei.com>
This commit is contained in:
sunyaozu 2021-09-29 15:03:08 +08:00
parent c535838f89
commit 6abad5a4e6
6 changed files with 365 additions and 5 deletions

View File

@ -19,6 +19,8 @@ config("intl_config") {
"//third_party/icu/icu4c/source/common",
"//third_party/icu/icu4c/source/i18n",
"//base/global/i18n_standard/frameworks/intl/include",
"//third_party/libphonenumber/cpp/src",
"//third_party/protobuf/src",
]
}
ohos_shared_library("intl_util") {
@ -39,12 +41,16 @@ ohos_shared_library("intl_util") {
"//base/telephony/core_service/interfaces/kits/include",
"//utils/native/base/include",
"//third_party/libxml2/include",
"//third_party/libphonenumber/cpp/src",
"//third_party/libphonenumber",
"//third_party/protobuf/src",
]
sources = [
"src/date_time_format.cpp",
"src/locale_config.cpp",
"src/locale_info.cpp",
"src/number_format.cpp",
"src/phone_number_format.cpp",
]
cflags_cc = [
"-Wall",
@ -58,6 +64,7 @@ ohos_shared_library("intl_util") {
"//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler",
"//third_party/icu/icu4c:shared_icui18n",
"//third_party/icu/icu4c:shared_icuuc",
"//third_party/libphonenumber/cpp:phonenumber_standard",
"//third_party/libxml2:xml2",
"//utils/native/base:utils",
]

View File

@ -0,0 +1,44 @@
/*
* 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 OHOS_GLOBAL_I18N_PHONE_NUMBER_FORMAT_H
#define OHOS_GLOBAL_I18N_PHONE_NUMBER_FORMAT_H
#include <map>
#include <string>
#include "cpp/src/phonenumbers/phonenumberutil.h"
namespace OHOS {
namespace Global {
namespace I18n {
using i18n::phonenumbers::PhoneNumberUtil;
class PhoneNumberFormat {
public:
PhoneNumberFormat(const std::string &countryTag, const std::map<std::string, std::string> &options);
virtual ~PhoneNumberFormat();
bool isValidPhoneNumber(const std::string &number) const;
std::string format(const std::string &number) const;
private:
PhoneNumberUtil *util;
std::string country;
PhoneNumberUtil::PhoneNumberFormat phoneNumberFormat;
};
}
}
}
#endif // OHOS_GLOBAL_I18N_PHONE_NUMBER_FORMAT_H

View File

@ -0,0 +1,77 @@
/*
* 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 "phone_number_format.h"
namespace OHOS {
namespace Global {
namespace I18n {
using i18n::phonenumbers::PhoneNumberUtil;
PhoneNumberFormat::PhoneNumberFormat(const std::string &countryTag,
const std::map<std::string, std::string> &options)
{
util = PhoneNumberUtil::GetInstance();
country = countryTag;
std::string type = "";
auto search = options.find("type");
if (search != options.end()) {
type = search->second;
}
std::map<std::string, PhoneNumberUtil::PhoneNumberFormat> type2PhoneNumberFormat = {
{"E164", PhoneNumberUtil::PhoneNumberFormat::E164},
{"RFC3966", PhoneNumberUtil::PhoneNumberFormat::RFC3966},
{"INTERNATIONAL", PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL},
{"NATIONAL", PhoneNumberUtil::PhoneNumberFormat::NATIONAL}
};
std::set<std::string> validType = {"E164", "RFC3966", "INTERNATIONAL", "NATIONAL"};
if (validType.find(type) != validType.end()) {
phoneNumberFormat = type2PhoneNumberFormat[type];
} else {
phoneNumberFormat = PhoneNumberUtil::PhoneNumberFormat::NATIONAL;
}
}
PhoneNumberFormat::~PhoneNumberFormat()
{
}
bool PhoneNumberFormat::isValidPhoneNumber(const std::string &number) const
{
i18n::phonenumbers::PhoneNumber phoneNumber;
PhoneNumberUtil::ErrorType type = util->Parse(number, country, &phoneNumber);
if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
return false;
}
return util->IsValidNumber(phoneNumber);
}
std::string PhoneNumberFormat::format(const std::string &number) const
{
i18n::phonenumbers::PhoneNumber phoneNumber;
PhoneNumberUtil::ErrorType type = util->Parse(number, country, &phoneNumber);
if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
return "";
}
std::string formatted_number;
util->Format(phoneNumber, phoneNumberFormat, &formatted_number);
return formatted_number;
}
}
}
}

View File

@ -24,6 +24,9 @@ ohos_shared_library("intl") {
"//third_party/icu/icu4c/source",
"//third_party/icu/icu4c/source/common",
"//third_party/icu/icu4c/source/i18n",
"//third_party/libphonenumber/cpp/src",
"//third_party/libphonenumber",
"//third_party/protobuf/src",
]
sources = [ "src/intl_addon.cpp" ]
@ -33,6 +36,7 @@ ohos_shared_library("intl") {
"//foundation/ace/napi:ace_napi",
"//third_party/icu/icu4c:shared_icui18n",
"//third_party/icu/icu4c:shared_icuuc",
"//third_party/libphonenumber/cpp:phonenumber_standard",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
relative_install_dir = "module"
@ -51,6 +55,9 @@ ohos_shared_library("i18n") {
"//third_party/icu/icu4c/source",
"//third_party/icu/icu4c/source/common",
"//third_party/icu/icu4c/source/i18n",
"//third_party/libphonenumber/cpp/src",
"//third_party/libphonenumber",
"//third_party/protobuf/src",
]
sources = [ "src/i18n_addon.cpp" ]
@ -60,10 +67,10 @@ ohos_shared_library("i18n") {
"//foundation/ace/napi:ace_napi",
"//third_party/icu/icu4c:shared_icui18n",
"//third_party/icu/icu4c:shared_icuuc",
"//third_party/libphonenumber/cpp:phonenumber_standard",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
relative_install_dir = "module"
subsystem_name = "global"
part_name = "i18n_standard"
}
}

View File

@ -19,6 +19,7 @@
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#include "locale_config.h"
#include "phone_number_format.h"
namespace OHOS {
namespace Global {
@ -40,6 +41,18 @@ public:
static napi_value SetSystemLanguage(napi_env env, napi_callback_info info);
static napi_value SetSystemRegion(napi_env env, napi_callback_info info);
static napi_value SetSystemLocale(napi_env env, napi_callback_info info);
static napi_value InitPhoneNumberFormat(napi_env env, napi_value exports);
private:
static napi_value PhoneNumberFormatConstructor(napi_env env, napi_callback_info info);
static napi_value IsValidPhoneNumber(napi_env env, napi_callback_info info);
static napi_value FormatPhoneNumber(napi_env env, napi_callback_info info);
bool InitPhoneNumberFormatContext(napi_env env, napi_callback_info info, const std::string &country,
const std::map<std::string, std::string> &options);
napi_env env_;
napi_ref wrapper_;
std::unique_ptr<PhoneNumberFormat> phonenumberfmt_;
};
} // namespace I18n
} // namespace Global

View File

@ -23,10 +23,11 @@ namespace I18n {
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "I18nJs" };
using namespace OHOS::HiviewDFX;
I18nAddon::I18nAddon() {}
I18nAddon::I18nAddon() : env_(nullptr), wrapper_(nullptr) {}
I18nAddon::~I18nAddon()
{
napi_delete_reference(env_, wrapper_);
}
void I18nAddon::Destructor(napi_env env, void *nativeObject, void *hint)
@ -55,7 +56,8 @@ napi_value I18nAddon::Init(napi_env env, napi_value exports)
};
status = napi_define_properties(env, exports,
sizeof(properties) / sizeof(napi_property_descriptor), properties);
sizeof(properties) / sizeof(napi_property_descriptor),
properties);
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set properties at init");
return nullptr;
@ -354,9 +356,219 @@ napi_value I18nAddon::SetSystemLocale(napi_env env, napi_callback_info info)
return result;
}
napi_value I18nAddon::InitPhoneNumberFormat(napi_env env, napi_value exports)
{
napi_status status;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("isValidNumber", IsValidPhoneNumber),
DECLARE_NAPI_FUNCTION("format", FormatPhoneNumber)
};
napi_value constructor;
status = napi_define_class(env, "PhoneNumberFormat", NAPI_AUTO_LENGTH, PhoneNumberFormatConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
HiLog::Error(LABEL, "Define class failed when InitPhoneNumberFormat");
return nullptr;
}
status = napi_set_named_property(env, exports, "PhoneNumberFormat", constructor);
if (status != napi_ok) {
HiLog::Error(LABEL, "Set property failed when InitPhoneNumberFormat");
return nullptr;
}
return exports;
}
void GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
std::map<std::string, std::string> &map)
{
napi_value optionValue = nullptr;
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, options, &type);
if (status != napi_ok && type != napi_object) {
HiLog::Error(LABEL, "Get option failed, option is not an object");
return;
}
bool hasProperty = false;
napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
if (propStatus == napi_ok && hasProperty) {
status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
if (status == napi_ok) {
size_t len;
napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
std::vector<char> optionBuf(len + 1);
status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
map.insert(make_pair(optionName, optionBuf.data()));
}
}
}
napi_value I18nAddon::PhoneNumberFormatConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value argv[2] = {0};
napi_value thisVar = nullptr;
void *data = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get country tag length failed");
return nullptr;
}
std::vector<char> country (len + 1);
status = napi_get_value_string_utf8(env, argv[0], country.data(), len + 1, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get country tag failed");
return nullptr;
}
std::map<std::string, std::string> options;
GetOptionValue(env, argv[1], "type", options);
std::unique_ptr<I18nAddon> obj = std::make_unique<I18nAddon>();
if (obj == nullptr) {
HiLog::Error(LABEL, "Create IntlAddon failed");
return nullptr;
}
status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
I18nAddon::Destructor, nullptr, &obj->wrapper_);
if (status != napi_ok) {
HiLog::Error(LABEL, "Wrap IntlAddon failed");
return nullptr;
}
if (!obj->InitPhoneNumberFormatContext(env, info, country.data(), options)) {
return nullptr;
}
obj.release();
return thisVar;
}
bool I18nAddon::InitPhoneNumberFormatContext(napi_env env, napi_callback_info info, const std::string &country,
const std::map<std::string, std::string> &options)
{
napi_value global;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get global failed");
return false;
}
env_ = env;
phonenumberfmt_ = std::make_unique<PhoneNumberFormat>(country, options);
return phonenumberfmt_ != nullptr;
}
napi_value I18nAddon::IsValidPhoneNumber(napi_env env, napi_callback_info info)
{
size_t argc = num;
napi_value argv[num];
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get phone number length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get phone number failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || obj == nullptr || obj->phonenumberfmt_ == nullptr) {
HiLog::Error(LABEL, "GetPhoneNumberFormat object failed");
return nullptr;
}
bool isValid = obj->phonenumberfmt_->isValidPhoneNumber(buf.data());
napi_value result;
status = napi_get_boolean(env, isValid, &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "Create boolean failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::FormatPhoneNumber(napi_env env, napi_callback_info info)
{
size_t argc = num;
napi_value argv[num];
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get phone number length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get phone number failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || obj == nullptr || obj->phonenumberfmt_ == nullptr) {
HiLog::Error(LABEL, "Get PhoneNumberFormat object failed");
return nullptr;
}
std::string formattedPhoneNumber = obj->phonenumberfmt_->format(buf.data());
napi_value result;
status = napi_create_string_utf8(env, formattedPhoneNumber.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "Create format phone number failed");
return nullptr;
}
return result;
}
napi_value Init(napi_env env, napi_value exports)
{
return I18nAddon::Init(env, exports);
napi_value val = I18nAddon::Init(env, exports);
return I18nAddon::InitPhoneNumberFormat(env, val);
}
static napi_module g_i18nModule = {