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