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