• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "language_ui.h"
16 
17 #include "json_node.h"
18 #include "log/log.h"
19 #include "utils.h"
20 #include "misc_info/misc_info.h"
21 
22 namespace Updater {
23 namespace Lang {
24 constexpr int MIN_LVL = 0; // 0 : min resource level
25 constexpr int MAX_LVL = 2; // 2 : max resource level
26 constexpr const char *DEFAULT_KEY = "DEFAULT_STRING";
27 
28 // map value zh/en/spa is used in string.json to specify language type for each string key
29 std::unordered_map<Language, std::string> g_languageDataVars = {
30     {Language::CHINESE, "zh"},
31     {Language::ENGLISH, "en"},
32     {Language::SPANISH, "spa"},
33 };
34 
35 // map key zh/es/en is used in locale file to specify locale env for updater
36 const std::unordered_map<std::string, Language> LanguageUI::LOCALES {
37     {"zh", Language::CHINESE},
38     {"en", Language::ENGLISH},
39     {"es", Language::SPANISH}
40 };
41 
LanguageUI()42 LanguageUI::LanguageUI() : strMap_ {}, res_ {}, langRes_ {}, language_ {Language::ENGLISH}
43 {
44     res_.resize(MAX_LVL + 1);
45 }
46 
GetInstance()47 LanguageUI &LanguageUI::GetInstance()
48 {
49     static LanguageUI instance;
50     return instance;
51 }
52 
Init(Language language)53 bool LanguageUI::Init(Language language)
54 {
55     language_ = language;
56     if (!Parse()) {
57         LOG(ERROR) << "parse language resources failed";
58         return false;
59     }
60     return true;
61 }
62 
SetRes(const Res & res)63 bool LanguageUI::SetRes(const Res &res)
64 {
65     if (!CheckLevel(res.level)) {
66         return false;
67     }
68     res_[res.level] = res.path;
69     return true;
70 }
71 
Parse()72 bool LanguageUI::Parse()
73 {
74     strMap_.clear();
75     for (auto &file : res_) {
76         if (file.empty()) {
77             LOG(WARNING) << "file name empty";
78             continue;
79         }
80         if (!ParseJson(file)) {
81             LOG(ERROR) << "parse file " << file << " error";
82             return false;
83         }
84     }
85     return true;
86 }
87 
ParseJson(const std::string & file)88 bool LanguageUI::ParseJson(const std::string &file)
89 {
90     JsonNode root {std::filesystem::path { file }};
91     /*
92      * an example:
93      *	{
94      *      "LABEL_REBOOT_DEVICE": {
95      *            "zh" : "",
96      *            "en" : "",
97      *            "spa" : ""
98      *      }
99      *  }
100      *  , this is an object node
101      */
102     if (root.Type() != NodeType::OBJECT) {
103         LOG(ERROR) << file << " is invalid, nodetype is " << static_cast<int>(root.Type());
104         return false;
105     }
106     for (auto &node : root) {
107         const JsonNode &strNode = node.get();
108         std::string key = strNode.Key().value_or("");
109         if (key.empty()) {
110             LOG(ERROR) << "key is empty";
111             return false;
112         }
113         if (auto optionalStr = strNode[g_languageDataVars[language_]].As<std::string>();
114             optionalStr != std::nullopt) {
115             strMap_[key] = *optionalStr;
116             continue;
117         }
118         LOG(ERROR) << "dont have a " << g_languageDataVars[language_] << " string";
119         return false;
120     }
121     return true;
122 }
123 
CheckLevel(int level)124 bool LanguageUI::CheckLevel(int level)
125 {
126     if (level < MIN_LVL || level > MAX_LVL) {
127         LOG(ERROR) << "level invalid : " << level;
128         return false;
129     }
130     return true;
131 }
132 
Translate(const std::string & key) const133 const std::string &LanguageUI::Translate(const std::string &key) const
134 {
135     static std::string emptyStr;
136     if (auto it = strMap_.find(key); it != strMap_.end() && !it->second.empty()) {
137         return it->second;
138     }
139     if (auto it = strMap_.find(DEFAULT_KEY); it != strMap_.end()) {
140         return it->second;
141     }
142     return emptyStr;
143 }
144 
LoadLangRes(const JsonNode & node)145 bool LanguageUI::LoadLangRes(const JsonNode &node)
146 {
147     langRes_ = {};
148     if (!Visit<SETVAL>(node[LANG_RES_KEY], langRes_)) {
149         LOG(ERROR) << "parse language res error";
150         return false;
151     }
152     // clear resources
153     std::vector<std::string>{3, ""}.swap(res_);
154     // load resources
155     for (auto &res : langRes_.res) {
156         if (!SetRes(res)) {
157             return false;
158         }
159     }
160     if (!Init(ParseLanguage())) {
161         LOG(ERROR) << "init failed";
162         return false;
163     }
164     LOG(INFO) << "load language resource success";
165     return true;
166 }
167 
ParseLanguage() const168 Language LanguageUI::ParseLanguage() const
169 {
170     constexpr Language DEFAULT_LOCALE = Language::ENGLISH;
171 #ifndef UPDATER_UT
172     //read language type(en-Latn-US/zh-Hans) from misc
173     constexpr const char *CHINSES_LANGUAGE_PREFIX = "zh";
174     constexpr const char *ENGLISH_LANGUAGE_PREFIX = "en";
175     struct UpdaterPara para {};
176     if (!ReadUpdaterParaMisc(para)) {
177         LOG(ERROR) << "ReadUpdaterParaMisc failed";
178         return DEFAULT_LOCALE;
179     }
180     if (strcmp(para.language, "") == 0) {
181         LOG(INFO) << "Language in misc is empty";
182         return Language::CHINESE;
183     } else if (strncmp(para.language, CHINSES_LANGUAGE_PREFIX, strlen(CHINSES_LANGUAGE_PREFIX)) == 0) {
184         return Language::CHINESE;
185     } else if (strncmp(para.language, ENGLISH_LANGUAGE_PREFIX, strlen(ENGLISH_LANGUAGE_PREFIX)) == 0) {
186         return Language::ENGLISH;
187     }
188 #endif
189     constexpr size_t localeLen = 2; // zh|es|en
190     std::string realPath {};
191     if (!Utils::PathToRealPath(langRes_.localeFile, realPath)) {
192         LOG(ERROR) << "get real path failed";
193         return DEFAULT_LOCALE;
194     }
195 
196     std::ifstream ifs(realPath);
197     std::string content {std::istreambuf_iterator<char> {ifs}, {}};
198     const std::string &locale = content.substr(0, localeLen);
199     if (auto it = LOCALES.find(locale); it != LOCALES.end()) {
200         return it->second;
201     }
202     LOG(ERROR) << "locale " << locale << " not recognized";
203     return DEFAULT_LOCALE;
204 }
205 
GetCurLanguage() const206 Language LanguageUI::GetCurLanguage() const
207 {
208     return language_;
209 }
210 }
211 } // namespace Updater
212