• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include "locale_config.h"
16 #include "ohos/init_data.h"
17 #include "relative_time_format.h"
18 
19 namespace OHOS {
20 namespace Global {
21 namespace I18n {
22 std::unordered_map<std::string, UDateRelativeDateTimeFormatterStyle> RelativeTimeFormat::relativeFormatStyle = {
23     { "long", UDAT_STYLE_LONG },
24     { "short", UDAT_STYLE_SHORT },
25     { "narrow", UDAT_STYLE_NARROW }
26 };
27 
28 std::unordered_map<std::string, URelativeDateTimeUnit> RelativeTimeFormat::relativeUnits = {
29     { "second", UDAT_REL_UNIT_SECOND },
30     { "seconds", UDAT_REL_UNIT_SECOND },
31     { "minute", UDAT_REL_UNIT_MINUTE },
32     { "minutes", UDAT_REL_UNIT_MINUTE },
33     { "hour", UDAT_REL_UNIT_HOUR },
34     { "hours", UDAT_REL_UNIT_HOUR },
35     { "day", UDAT_REL_UNIT_DAY },
36     { "days", UDAT_REL_UNIT_DAY },
37     { "week", UDAT_REL_UNIT_WEEK },
38     { "weeks", UDAT_REL_UNIT_WEEK },
39     { "month", UDAT_REL_UNIT_MONTH },
40     { "months", UDAT_REL_UNIT_MONTH },
41     { "quarter", UDAT_REL_UNIT_QUARTER },
42     { "quarters", UDAT_REL_UNIT_QUARTER },
43     { "year", UDAT_REL_UNIT_YEAR },
44     { "years", UDAT_REL_UNIT_YEAR },
45 };
46 
RelativeTimeFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)47 RelativeTimeFormat::RelativeTimeFormat(const std::vector<std::string> &localeTags,
48     std::map<std::string, std::string> &configs)
49 {
50     UErrorCode status = U_ZERO_ERROR;
51     ParseConfigs(configs);
52     for (size_t i = 0; i < localeTags.size(); i++) {
53         std::string curLocale = localeTags[i];
54         locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
55         if (status != U_ZERO_ERROR) {
56             status = U_ZERO_ERROR;
57             continue;
58         }
59         if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
60             localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
61             if (!localeInfo->InitSuccess()) {
62                 continue;
63             }
64             locale = localeInfo->GetLocale();
65             localeBaseName = localeInfo->GetBaseName();
66             relativeTimeFormat = std::make_unique<icu::RelativeDateTimeFormatter>(locale, nullptr, style,
67                 UDISPCTX_CAPITALIZATION_NONE, status);
68             if (!U_SUCCESS(status)) {
69                 status = U_ZERO_ERROR;
70                 continue;
71             }
72             createSuccess = true;
73             break;
74         }
75     }
76     if (!createSuccess) {
77         localeInfo = std::make_unique<LocaleInfo>(LocaleConfig::GetSystemLocale(), configs);
78         if (localeInfo->InitSuccess()) {
79             locale = localeInfo->GetLocale();
80             localeBaseName = localeInfo->GetBaseName();
81             relativeTimeFormat = std::make_unique<icu::RelativeDateTimeFormatter>(locale, nullptr, style,
82                 UDISPCTX_CAPITALIZATION_NONE, status);
83             if (U_SUCCESS(status)) {
84                 createSuccess = true;
85             }
86         }
87     }
88     numberingSystem = localeInfo->GetNumberingSystem();
89     if (numberingSystem == "") {
90         numberingSystem = "latn";
91     }
92 }
93 
~RelativeTimeFormat()94 RelativeTimeFormat::~RelativeTimeFormat()
95 {
96 }
97 
ParseConfigs(std::map<std::string,std::string> & configs)98 void RelativeTimeFormat::ParseConfigs(std::map<std::string, std::string> &configs)
99 {
100     if (configs.count("style") > 0) {
101         styleString = configs["style"];
102         if (relativeFormatStyle.count(styleString) > 0) {
103             style = relativeFormatStyle[styleString];
104         }
105     }
106     if (configs.count("numeric") > 0) {
107         numeric = configs["numeric"];
108     }
109 }
110 
Format(double number,const std::string & unit)111 std::string RelativeTimeFormat::Format(double number, const std::string &unit)
112 {
113     if (!createSuccess || !relativeUnits.count(unit)) {
114         return "";
115     }
116     UErrorCode status = U_ZERO_ERROR;
117     icu::UnicodeString formattedTime;
118     std::string result;
119     if (!strcmp(numeric.c_str(), "always")) {
120         formattedTime = relativeTimeFormat->formatNumericToValue(number, relativeUnits[unit], status).toString(status);
121     } else {
122         formattedTime = relativeTimeFormat->formatToValue(number, relativeUnits[unit], status).toString(status);
123     }
124     formattedTime.toUTF8String(result);
125     return result;
126 }
127 
InsertInfo(std::vector<std::vector<std::string>> & timeVector,const std::string & unit,bool isInteger,const std::string & value)128 void RelativeTimeFormat::InsertInfo(std::vector<std::vector<std::string>> &timeVector,
129     const std::string &unit, bool isInteger, const std::string &value)
130 {
131     std::vector<std::string> info;
132     if (isInteger) {
133         info.push_back("integer");
134         info.push_back(value);
135         info.push_back(unit);
136     } else {
137         info.push_back("literal");
138         info.push_back(value);
139     }
140     timeVector.push_back(info);
141 }
142 
ProcessIntegerField(const std::map<size_t,size_t> & indexMap,std::vector<std::vector<std::string>> & timeVector,size_t & startIndex,const std::string & unit,const std::string & result)143 void RelativeTimeFormat::ProcessIntegerField(const std::map<size_t, size_t> &indexMap,
144     std::vector<std::vector<std::string>> &timeVector, size_t &startIndex, const std::string &unit,
145     const std::string &result)
146 {
147     for (auto iter = indexMap.begin(); iter != indexMap.end(); iter++) {
148         if (iter->first > startIndex) {
149             InsertInfo(timeVector, unit, true, result.substr(startIndex, iter->first - startIndex));
150             InsertInfo(timeVector, unit, true, result.substr(iter->first, iter->second - iter->first));
151             startIndex = iter->second;
152         }
153     }
154 }
155 
FormatToParts(double number,const std::string & unit,std::vector<std::vector<std::string>> & timeVector)156 void RelativeTimeFormat::FormatToParts(double number, const std::string &unit,
157     std::vector<std::vector<std::string>> &timeVector)
158 {
159     if (!createSuccess || !relativeUnits.count(unit)) {
160         return;
161     }
162     UErrorCode status = U_ZERO_ERROR;
163     std::string result;
164     icu::FormattedRelativeDateTime fmtRelativeTime;
165     if (numeric.empty() || !strcmp(numeric.c_str(), "always")) {
166         fmtRelativeTime = relativeTimeFormat->formatNumericToValue(number, relativeUnits[unit], status);
167     } else {
168         fmtRelativeTime = relativeTimeFormat->formatToValue(number, relativeUnits[unit], status);
169     }
170     fmtRelativeTime.toString(status).toUTF8String(result);
171     icu::ConstrainedFieldPosition constrainedPos;
172     constrainedPos.constrainCategory(UFIELD_CATEGORY_NUMBER);
173     size_t prevIndex = 0;
174     size_t length = result.length();
175     std::map<size_t, size_t> indexMap;
176     while (fmtRelativeTime.nextPosition(constrainedPos, status)) {
177         size_t startIndex = (size_t)constrainedPos.getStart();
178         if (constrainedPos.getCategory() == UFIELD_CATEGORY_NUMBER) {
179             if (constrainedPos.getField() == UNUM_GROUPING_SEPARATOR_FIELD) {
180                 indexMap.insert(std::make_pair(startIndex, (size_t)constrainedPos.getLimit()));
181                 continue;
182             }
183             if (startIndex > prevIndex) {
184                 InsertInfo(timeVector, unit, false, result.substr(prevIndex, startIndex - prevIndex));
185             }
186             if (constrainedPos.getField() == UNUM_INTEGER_FIELD) {
187                 ProcessIntegerField(indexMap, timeVector, startIndex, unit, result);
188             }
189             InsertInfo(timeVector, unit, true, result.substr(startIndex,
190                 (size_t)constrainedPos.getLimit() - startIndex));
191             prevIndex = (size_t)constrainedPos.getLimit();
192         }
193     }
194     if (prevIndex < length) {
195         InsertInfo(timeVector, unit, false, result.substr(prevIndex, length - prevIndex));
196     }
197 }
198 
GetResolvedOptions(std::map<std::string,std::string> & map)199 void RelativeTimeFormat::GetResolvedOptions(std::map<std::string, std::string> &map)
200 {
201     map.insert(std::make_pair("locale", localeBaseName));
202     if (!styleString.empty()) {
203         map.insert(std::make_pair("style", styleString));
204     }
205     if (!numeric.empty()) {
206         map.insert(std::make_pair("numeric", numeric));
207     }
208     if (!numberingSystem.empty()) {
209         map.insert(std::make_pair("numberingSystem", numberingSystem));
210     }
211 }
212 } // namespace I18n
213 } // namespace Global
214 } // namespace OHOS
215