1 #include "./lv_i18n.h"
2 #include "../../../lvgl.h"
3
4 #if LV_USE_DEMO_EBIKE
5
6 /**
7 * Define plural operands
8 * http://unicode.org/reports/tr35/tr35-numbers.html#Operands
9 */
10
11 /* Integer version, simplified */
12
op_n(int32_t val)13 static inline uint32_t op_n(int32_t val)
14 {
15 return (uint32_t)(val < 0 ? -val : val);
16 }
17
op_i(uint32_t val)18 static inline uint32_t op_i(uint32_t val)
19 {
20 return val;
21 }
22
23 /* always zero, when decimal part not exists. */
op_v(uint32_t val)24 static inline uint32_t op_v(uint32_t val)
25 {
26 LV_UNUSED(val);
27 return 0;
28 }
29
op_w(uint32_t val)30 static inline uint32_t op_w(uint32_t val)
31 {
32 LV_UNUSED(val);
33 return 0;
34 }
op_f(uint32_t val)35 static inline uint32_t op_f(uint32_t val)
36 {
37 LV_UNUSED(val);
38 return 0;
39 }
40
op_t(uint32_t val)41 static inline uint32_t op_t(uint32_t val)
42 {
43 LV_UNUSED(val);
44 return 0;
45 }
46
en_plural_fn(int32_t num)47 static uint8_t en_plural_fn(int32_t num)
48 {
49 uint32_t n = op_n(num);
50 LV_UNUSED(n);
51 uint32_t i = op_i(n);
52 LV_UNUSED(i);
53 uint32_t v = op_v(n);
54 LV_UNUSED(v);
55
56 if(i == 1 && v == 0) return LV_I18N_PLURAL_TYPE_ONE;
57 return LV_I18N_PLURAL_TYPE_OTHER;
58 }
59
60 static const lv_i18n_lang_t en_lang = {
61 .locale_name = "en",
62
63
64 .locale_plural_fn = en_plural_fn
65 };
66
67 static lv_i18n_phrase_t ar_singulars[] = {
68 {"Language", "لغة"},
69 {"Title", "عنوان"},
70 {"March 29", "29 مارس"},
71 {"Battery", "البطارية"},
72 {"Distance today", "المسافة اليوم"},
73 {"Speed today", "السرعة اليوم"},
74 {"Time today", "الوقت اليوم"},
75 {"SETTINGS", "الإعدادات"},
76 {"Bluetooth", "بلوتوث"},
77 {"Lights", "أضواء"},
78 {"Brightness", "السطوع"},
79 {"Volume", "الحجم"},
80 {"Max. speed", "الأعلى. السرعة"},
81 {"Light level", "مستوى الضوء"},
82 {"STATS", "إحصائيات"},
83 {"March %d - March %d", "مارس %d - مارس %d"},
84 {"Avg. speed", "متوسط السرعة"},
85 {"Distance", "المسافة"},
86 {"Top speed", "السرعة القصوى"},
87 {"March %d", "مارس %d"},
88 {NULL, NULL} /* End mark */
89 };
90
ar_plural_fn(int32_t num)91 static uint8_t ar_plural_fn(int32_t num)
92 {
93 uint32_t n = op_n(num);
94 LV_UNUSED(n);
95
96 uint32_t n100 = n % 100;
97 if(n == 0) return LV_I18N_PLURAL_TYPE_ZERO;
98 if(n == 1) return LV_I18N_PLURAL_TYPE_ONE;
99 if(n == 2) return LV_I18N_PLURAL_TYPE_TWO;
100 if(3 <= n100 && n100 <= 10) return LV_I18N_PLURAL_TYPE_FEW;
101 if(11 <= n100 && n100 <= 99) return LV_I18N_PLURAL_TYPE_MANY;
102 return LV_I18N_PLURAL_TYPE_OTHER;
103 }
104
105 static const lv_i18n_lang_t ar_lang = {
106 .locale_name = "ar",
107 .singulars = ar_singulars,
108
109 .locale_plural_fn = ar_plural_fn
110 };
111
112 static lv_i18n_phrase_t zh_singulars[] = {
113 {"Language", "语言"},
114 {"Title", "标题"},
115 {"March 29", "3月29日"},
116 {"Battery", "电池"},
117 {"Distance today", "今日距离"},
118 {"Speed today", "今天的速度"},
119 {"Time today", "今天时间"},
120 {"SETTINGS", "设置"},
121 {"Bluetooth", "蓝牙"},
122 {"Lights", "灯"},
123 {"Brightness", "亮度"},
124 {"Volume", "音量"},
125 {"Max. speed", "最大速度"},
126 {"Light level", "光照强度"},
127 {"STATS", "统计"},
128 {"March %d - March %d", "三月 %d - 三月 %d"},
129 {"Avg. speed", "平均速度"},
130 {"Distance", "距离"},
131 {"Top speed", "最高时速"},
132 {"March %d", "三月 %d"},
133 {NULL, NULL} /* End mark */
134 };
135
zh_plural_fn(int32_t num)136 static uint8_t zh_plural_fn(int32_t num)
137 {
138 LV_UNUSED(num);
139
140 return LV_I18N_PLURAL_TYPE_OTHER;
141 }
142
143 static const lv_i18n_lang_t zh_lang = {
144 .locale_name = "zh",
145 .singulars = zh_singulars,
146
147 .locale_plural_fn = zh_plural_fn
148 };
149
150 const lv_i18n_language_pack_t lv_i18n_language_pack[] = {
151 &en_lang,
152 &ar_lang,
153 &zh_lang,
154 NULL /* End mark */
155 };
156
157 /* Internal state */
158 static const lv_i18n_language_pack_t * current_lang_pack;
159 static const lv_i18n_lang_t * current_lang;
160
161
162 /**
163 * Reset internal state. For testing.
164 */
__lv_i18n_reset(void)165 void __lv_i18n_reset(void)
166 {
167 current_lang_pack = NULL;
168 current_lang = NULL;
169 }
170
171 /**
172 * Set the languages for internationalization
173 * @param langs pointer to the array of languages. (Last element has to be `NULL`)
174 */
lv_i18n_init(const lv_i18n_language_pack_t * langs)175 int lv_i18n_init(const lv_i18n_language_pack_t * langs)
176 {
177 if(langs == NULL) return -1;
178 if(langs[0] == NULL) return -1;
179
180 current_lang_pack = langs;
181 current_lang = langs[0]; /*Automatically select the first language*/
182 return 0;
183 }
184
185 /**
186 * Change the localization (language)
187 * @param l_name name of the translation locale to use. E.g. "en-GB"
188 */
lv_i18n_set_locale(const char * l_name)189 int lv_i18n_set_locale(const char * l_name)
190 {
191 if(current_lang_pack == NULL) return -1;
192
193 uint16_t i;
194
195 for(i = 0; current_lang_pack[i] != NULL; i++) {
196 /* Found -> finish */
197 if(lv_strcmp(current_lang_pack[i]->locale_name, l_name) == 0) {
198 current_lang = current_lang_pack[i];
199 return 0;
200 }
201 }
202
203 return -1;
204 }
205
206
__lv_i18n_get_text_core(lv_i18n_phrase_t * trans,const char * msg_id)207 static const char * __lv_i18n_get_text_core(lv_i18n_phrase_t * trans, const char * msg_id)
208 {
209 uint16_t i;
210 for(i = 0; trans[i].msg_id != NULL; i++) {
211 if(lv_strcmp(trans[i].msg_id, msg_id) == 0) {
212 /*The msg_id has found. Check the translation*/
213 if(trans[i].translation) return trans[i].translation;
214 }
215 }
216
217 return NULL;
218 }
219
220
221 /**
222 * Get the translation from a message ID
223 * @param msg_id message ID
224 * @return the translation of `msg_id` on the set local
225 */
lv_i18n_get_text(const char * msg_id)226 const char * lv_i18n_get_text(const char * msg_id)
227 {
228 if(current_lang == NULL) return msg_id;
229
230 const lv_i18n_lang_t * lang = current_lang;
231 const void * txt;
232
233 /* Search in current locale */
234 if(lang->singulars != NULL) {
235 txt = __lv_i18n_get_text_core(lang->singulars, msg_id);
236 if(txt != NULL) return txt;
237 }
238
239 /* Try to fallback */
240 if(lang == current_lang_pack[0]) return msg_id;
241 lang = current_lang_pack[0];
242
243 /* Repeat search for default locale */
244 if(lang->singulars != NULL) {
245 txt = __lv_i18n_get_text_core(lang->singulars, msg_id);
246 if(txt != NULL) return txt;
247 }
248
249 return msg_id;
250 }
251
252 /**
253 * Get the translation from a message ID and apply the language's plural rule to get correct form
254 * @param msg_id message ID
255 * @param num an integer to select the correct plural form
256 * @return the translation of `msg_id` on the set local
257 */
lv_i18n_get_text_plural(const char * msg_id,int32_t num)258 const char * lv_i18n_get_text_plural(const char * msg_id, int32_t num)
259 {
260 if(current_lang == NULL) return msg_id;
261
262 const lv_i18n_lang_t * lang = current_lang;
263 const void * txt;
264 lv_i18n_plural_type_t ptype;
265
266 /* Search in current locale */
267 if(lang->locale_plural_fn != NULL) {
268 ptype = lang->locale_plural_fn(num);
269
270 if(lang->plurals[ptype] != NULL) {
271 txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id);
272 if(txt != NULL) return txt;
273 }
274 }
275
276 /* Try to fallback */
277 if(lang == current_lang_pack[0]) return msg_id;
278 lang = current_lang_pack[0];
279
280 /* Repeat search for default locale */
281 if(lang->locale_plural_fn != NULL) {
282 ptype = lang->locale_plural_fn(num);
283
284 if(lang->plurals[ptype] != NULL) {
285 txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id);
286 if(txt != NULL) return txt;
287 }
288 }
289
290 return msg_id;
291 }
292
293 /**
294 * Get the name of the currently used locale.
295 * @return name of the currently used locale. E.g. "en-GB"
296 */
lv_i18n_get_current_locale(void)297 const char * lv_i18n_get_current_locale(void)
298 {
299 if(!current_lang) return NULL;
300 return current_lang->locale_name;
301 }
302
303 #endif /*#if LV_USE_DEMO_EBIKE*/
304