1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "number_format_addon.h"
17
18 #include "i18n_hilog.h"
19 #include "js_utils.h"
20
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
NumberFormatAddon()24 NumberFormatAddon::NumberFormatAddon()
25 {
26 }
27
~NumberFormatAddon()28 NumberFormatAddon::~NumberFormatAddon()
29 {
30 }
31
Destructor(napi_env env,void * nativeObject,void * hint)32 void NumberFormatAddon::Destructor(napi_env env, void *nativeObject, void *hint)
33 {
34 if (!nativeObject) {
35 return;
36 }
37 delete reinterpret_cast<NumberFormatAddon *>(nativeObject);
38 nativeObject = nullptr;
39 }
40
InitNumberFormat(napi_env env,napi_value exports)41 napi_value NumberFormatAddon::InitNumberFormat(napi_env env, napi_value exports)
42 {
43 napi_status status = napi_ok;
44 napi_property_descriptor properties[] = {
45 DECLARE_NAPI_FUNCTION("format", FormatNumber),
46 DECLARE_NAPI_FUNCTION("formatRange", FormatRangeNumber),
47 DECLARE_NAPI_FUNCTION("resolvedOptions", GetNumberResolvedOptions)
48 };
49
50 napi_value constructor = nullptr;
51 status = napi_define_class(env, "NumberFormat", NAPI_AUTO_LENGTH, NumberFormatConstructor, nullptr,
52 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
53 if (status != napi_ok) {
54 HILOG_ERROR_I18N("Define class failed when InitNumberFormat");
55 return nullptr;
56 }
57
58 status = napi_set_named_property(env, exports, "NumberFormat", constructor);
59 if (status != napi_ok) {
60 HILOG_ERROR_I18N("Set property failed when InitNumberFormat");
61 return nullptr;
62 }
63 return exports;
64 }
65
NumberFormatConstructor(napi_env env,napi_callback_info info)66 napi_value NumberFormatAddon::NumberFormatConstructor(napi_env env, napi_callback_info info)
67 {
68 size_t argc = 2;
69 napi_value argv[2] = { nullptr };
70 napi_value thisVar = nullptr;
71 void *data = nullptr;
72 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
73 if (status != napi_ok) {
74 return nullptr;
75 }
76 std::vector<std::string> localeTags;
77 if (argc > 0) {
78 napi_valuetype valueType = napi_valuetype::napi_undefined;
79 napi_typeof(env, argv[0], &valueType);
80 bool isArray = false;
81 napi_is_array(env, argv[0], &isArray);
82
83 if (valueType == napi_valuetype::napi_string) {
84 JSUtils::GetLocaleTags(env, argv[0], localeTags);
85 } else if (isArray) {
86 uint32_t arrayLength = 0;
87 napi_get_array_length(env, argv[0], &arrayLength);
88 napi_value element = nullptr;
89 for (uint32_t i = 0; i < arrayLength; i++) {
90 napi_get_element(env, argv[0], i, &element);
91 JSUtils::GetLocaleTags(env, element, localeTags);
92 }
93 }
94 }
95 std::map<std::string, std::string> map = {};
96 if (argc > 1) {
97 JSUtils::GetNumberOptionValues(env, argv[1], map);
98 }
99 std::unique_ptr<NumberFormatAddon> obj = nullptr;
100 obj = std::make_unique<NumberFormatAddon>();
101 status =
102 napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), NumberFormatAddon::Destructor, nullptr, nullptr);
103 if (status != napi_ok) {
104 HILOG_ERROR_I18N("NumberFormatConstructor: Wrap NumberFormatAddon failed");
105 return nullptr;
106 }
107 if (!obj->InitNumberFormatContext(env, info, localeTags, map)) {
108 HILOG_ERROR_I18N("Init NumberFormat failed");
109 return nullptr;
110 }
111 obj.release();
112 return thisVar;
113 }
114
InitNumberFormatContext(napi_env env,napi_callback_info info,std::vector<std::string> localeTags,std::map<std::string,std::string> & map)115 bool NumberFormatAddon::InitNumberFormatContext(napi_env env, napi_callback_info info,
116 std::vector<std::string> localeTags, std::map<std::string, std::string> &map)
117 {
118 napi_value global = nullptr;
119 napi_status status = napi_get_global(env, &global);
120 if (status != napi_ok) {
121 HILOG_ERROR_I18N("InitNumberFormatContext: Get global failed");
122 return false;
123 }
124 numberfmt_ = std::make_shared<NumberFormat>(localeTags, map);
125
126 return numberfmt_ != nullptr;
127 }
128
FormatNumber(napi_env env,napi_callback_info info)129 napi_value NumberFormatAddon::FormatNumber(napi_env env, napi_callback_info info)
130 {
131 size_t argc = 1;
132 napi_value argv[1] = { 0 };
133 napi_value thisVar = nullptr;
134 void *data = nullptr;
135 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
136 double number = 0;
137 napi_get_value_double(env, argv[0], &number);
138 NumberFormatAddon *obj = nullptr;
139 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
140 if (status != napi_ok || !obj || !obj->numberfmt_) {
141 HILOG_ERROR_I18N("FormatNumber: Get NumberFormat object failed");
142 return nullptr;
143 }
144 std::string value = obj->numberfmt_->Format(number);
145 napi_value result = nullptr;
146 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
147 if (status != napi_ok) {
148 HILOG_ERROR_I18N("FormatNumber: Create format string failed");
149 return nullptr;
150 }
151 return result;
152 }
153
FormatRangeNumber(napi_env env,napi_callback_info info)154 napi_value NumberFormatAddon::FormatRangeNumber(napi_env env, napi_callback_info info)
155 {
156 size_t argc = 2;
157 napi_value argv[2] = { 0 };
158 napi_value thisVar = nullptr;
159 void *data = nullptr;
160 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
161 if (status != napi_ok) {
162 HILOG_ERROR_I18N("FormatRangeNumber: Get parameter info failed");
163 return JSUtils::CreateEmptyString(env);
164 }
165 if (argc != 2) { // 2 is parameter count
166 HILOG_ERROR_I18N("FormatRangeNumber: Insufficient parameters");
167 return JSUtils::CreateEmptyString(env);
168 }
169 double start = 0;
170 double end = 0;
171 status = napi_get_value_double(env, argv[0], &start);
172 if (status != napi_ok) {
173 HILOG_ERROR_I18N("FormatRangeNumber: Get first param value failed");
174 return JSUtils::CreateEmptyString(env);
175 }
176 status = napi_get_value_double(env, argv[1], &end);
177 if (status != napi_ok) {
178 HILOG_ERROR_I18N("FormatRangeNumber: Get second param value failed");
179 return JSUtils::CreateEmptyString(env);
180 }
181 NumberFormatAddon *obj = nullptr;
182 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
183 if (status != napi_ok || !obj || !obj->numberfmt_) {
184 HILOG_ERROR_I18N("FormatRangeNumber: Get NumberFormat object failed");
185 return JSUtils::CreateEmptyString(env);
186 }
187 std::string value = obj->numberfmt_->FormatRange(start, end);
188 napi_value result;
189 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
190 if (status != napi_ok) {
191 HILOG_ERROR_I18N("create string js variable failed.");
192 return JSUtils::CreateEmptyString(env);
193 }
194 return result;
195 }
196
GetNumberResolvedOptions(napi_env env,napi_callback_info info)197 napi_value NumberFormatAddon::GetNumberResolvedOptions(napi_env env, napi_callback_info info)
198 {
199 napi_value thisVar = nullptr;
200 void *data = nullptr;
201 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
202
203 NumberFormatAddon *obj = nullptr;
204 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
205 if (status != napi_ok || !obj || !obj->numberfmt_) {
206 HILOG_ERROR_I18N("GetNumberResolvedOptions: Get NumberFormat object failed");
207 return nullptr;
208 }
209 napi_value result = nullptr;
210 napi_create_object(env, &result);
211 std::map<std::string, std::string> options = {};
212 obj->numberfmt_->GetResolvedOptions(options);
213 JSUtils::SetOptionProperties(env, result, options, "locale");
214 JSUtils::SetOptionProperties(env, result, options, "currency");
215 JSUtils::SetOptionProperties(env, result, options, "currencySign");
216 JSUtils::SetOptionProperties(env, result, options, "currencyDisplay");
217 JSUtils::SetOptionProperties(env, result, options, "unit");
218 JSUtils::SetOptionProperties(env, result, options, "unitDisplay");
219 JSUtils::SetOptionProperties(env, result, options, "signDisplay");
220 JSUtils::SetOptionProperties(env, result, options, "compactDisplay");
221 JSUtils::SetOptionProperties(env, result, options, "notation");
222 JSUtils::SetOptionProperties(env, result, options, "style");
223 JSUtils::SetOptionProperties(env, result, options, "numberingSystem");
224 JSUtils::SetOptionProperties(env, result, options, "unitUsage");
225 JSUtils::SetBooleanOptionProperties(env, result, options, "useGrouping");
226 JSUtils::SetIntegerOptionProperties(env, result, options, "minimumIntegerDigits");
227 JSUtils::SetIntegerOptionProperties(env, result, options, "minimumFractionDigits");
228 JSUtils::SetIntegerOptionProperties(env, result, options, "maximumFractionDigits");
229 JSUtils::SetIntegerOptionProperties(env, result, options, "minimumSignificantDigits");
230 JSUtils::SetIntegerOptionProperties(env, result, options, "maximumSignificantDigits");
231 JSUtils::SetOptionProperties(env, result, options, "localeMatcher");
232 return result;
233 }
234
CopyNumberFormat()235 std::shared_ptr<NumberFormat> NumberFormatAddon::CopyNumberFormat()
236 {
237 return numberfmt_;
238 }
239 } // namespace I18n
240 } // namespace Global
241 } // namespace OHOS