299 lines
8.5 KiB
C
299 lines
8.5 KiB
C
#include "./lv_i18n.h"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Define plural operands
|
|
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
|
|
|
|
// Integer version, simplified
|
|
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
static inline uint32_t op_n(int32_t val) { return (uint32_t)(val < 0 ? -val : val); }
|
|
static inline uint32_t op_i(uint32_t val) { return val; }
|
|
// always zero, when decimal part not exists.
|
|
static inline uint32_t op_v(uint32_t val) { UNUSED(val); return 0;}
|
|
static inline uint32_t op_w(uint32_t val) { UNUSED(val); return 0; }
|
|
static inline uint32_t op_f(uint32_t val) { UNUSED(val); return 0; }
|
|
static inline uint32_t op_t(uint32_t val) { UNUSED(val); return 0; }
|
|
|
|
static lv_i18n_phrase_t en_gb_singulars[] = {
|
|
{"speaking", "speaking"},
|
|
{"thinking", "thinking"},
|
|
{"service connected", "service connected"},
|
|
{"service disconnected", "service disconnected"},
|
|
{"common setting", "Common"},
|
|
{"network setting", "Network"},
|
|
{"wakeup setting", "Wakeup"},
|
|
{"alarm setting", "Alarm"},
|
|
{"volume", "volume"},
|
|
{"brightness", "brightness"},
|
|
{"WIFI", "wifi"},
|
|
{"AutoScan", "AutoScan"},
|
|
{"no alarm", "There is no alarm clock available; you can set an alarm clock via voice."},
|
|
{"listening", "listening"},
|
|
{"recognizing", "recognizing"},
|
|
{"recognition error", "recognition error"},
|
|
{"please speak", "Please speak"},
|
|
{"cancel", "Cancel"},
|
|
{"delete", "Delete"},
|
|
{"monday", "Monday"},
|
|
{"tuesday", "Tuesday"},
|
|
{"wednesday", "Wednesday"},
|
|
{"thursday", "Thursday"},
|
|
{"friday", "Friday"},
|
|
{"saturday", "Saturday"},
|
|
{"sunday", "Sunday"},
|
|
{"year", "Year"},
|
|
{"month", "Month"},
|
|
{"day", "Day"},
|
|
{"button wakeup", "Button"},
|
|
{"button wakeup description", "Press and hold the K1 button to wake up and start a conversation."},
|
|
{"voice wakeup(single)", "Voice(Single)"},
|
|
{"voice wakeup(multiple)", "Voice(Multiple)"},
|
|
{"voice wakeup single description", "Wake-up via voice, each wake-up call involves a round of dialogue"},
|
|
{"voice wakeup multiple description", "Supports multi-turn continuous dialogue via voice wake-up"},
|
|
{"Please wake me", "Please wake me"},
|
|
{NULL, NULL} // End mark
|
|
};
|
|
|
|
|
|
|
|
static uint8_t en_gb_plural_fn(int32_t num)
|
|
{
|
|
uint32_t n = op_n(num); UNUSED(n);
|
|
uint32_t i = op_i(n); UNUSED(i);
|
|
uint32_t v = op_v(n); UNUSED(v);
|
|
|
|
if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE;
|
|
return LV_I18N_PLURAL_TYPE_OTHER;
|
|
}
|
|
|
|
static const lv_i18n_lang_t en_gb_lang = {
|
|
.locale_name = "en-GB",
|
|
.singulars = en_gb_singulars,
|
|
|
|
.locale_plural_fn = en_gb_plural_fn
|
|
};
|
|
|
|
static lv_i18n_phrase_t zh_cn_singulars[] = {
|
|
{"speaking", "说话中"},
|
|
{"thinking", "思考中"},
|
|
{"service connected", "服务已连接"},
|
|
{"service disconnected", "服务未连接"},
|
|
{"common setting", "基础设置"},
|
|
{"network setting", "网络设置"},
|
|
{"wakeup setting", "唤醒交互"},
|
|
{"alarm setting", "闹钟设置"},
|
|
{"volume", "音量"},
|
|
{"brightness", "亮度"},
|
|
{"WIFI", "WIFI"},
|
|
{"AutoScan", "自动扫描"},
|
|
{"no alarm", "暂无闹钟, 可通过语音设置闹钟."},
|
|
{"listening", "我在听"},
|
|
{"recognizing", "识别中"},
|
|
{"recognition error", "识别出现错误"},
|
|
{"Please speak", "请说话"},
|
|
{"cancel", "取消"},
|
|
{"delete", "删除"},
|
|
{"monday", "星期一"},
|
|
{"tuesday", "星期二"},
|
|
{"wednesday", "星期三"},
|
|
{"thursday", "星期四"},
|
|
{"friday", "星期五"},
|
|
{"saturday", "星期六"},
|
|
{"sunday", "星期日"},
|
|
{"year", "年"},
|
|
{"month", "月"},
|
|
{"day", "日"},
|
|
{"Alarm set successfully", "闹钟设置成功"},
|
|
{"Alarm Reminder", "闹钟提醒"},
|
|
{"enter", "确定"},
|
|
{"scaning", "扫描中"},
|
|
{"no network", "无网络"},
|
|
{"wifi setting", "WiFi 设置"},
|
|
{"alarm invalid", "无效闹钟"},
|
|
{"volume: %d%%", "音量: %d%%"},
|
|
{"brightness: %d%%", "亮度: %d%%"},
|
|
{"button wakeup", "按键唤醒"},
|
|
{"button wakeup description", "长按K1按键唤醒并对话"},
|
|
{"voice wakeup(single)", "语音唤醒(单轮)"},
|
|
{"voice wakeup(multiple)", "语音唤醒(多轮)"},
|
|
{"voice wakeup single description", "通过语音唤醒,每次唤醒一轮对话"},
|
|
{"voice wakeup multiple description", "通过语音唤醒,支持多轮连续对话"},
|
|
{"Please wake me", "请唤醒我"},
|
|
{NULL, NULL} // End mark
|
|
};
|
|
|
|
|
|
|
|
static uint8_t zh_cn_plural_fn(int32_t num)
|
|
{
|
|
|
|
|
|
|
|
return LV_I18N_PLURAL_TYPE_OTHER;
|
|
}
|
|
|
|
static const lv_i18n_lang_t zh_cn_lang = {
|
|
.locale_name = "zh-CN",
|
|
.singulars = zh_cn_singulars,
|
|
|
|
.locale_plural_fn = zh_cn_plural_fn
|
|
};
|
|
|
|
const lv_i18n_language_pack_t lv_i18n_language_pack[] = {
|
|
&en_gb_lang,
|
|
&zh_cn_lang,
|
|
NULL // End mark
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// Internal state
|
|
static const lv_i18n_language_pack_t * current_lang_pack;
|
|
static const lv_i18n_lang_t * current_lang;
|
|
|
|
|
|
/**
|
|
* Reset internal state. For testing.
|
|
*/
|
|
void __lv_i18n_reset(void)
|
|
{
|
|
current_lang_pack = NULL;
|
|
current_lang = NULL;
|
|
}
|
|
|
|
/**
|
|
* Set the languages for internationalization
|
|
* @param langs pointer to the array of languages. (Last element has to be `NULL`)
|
|
*/
|
|
int lv_i18n_init(const lv_i18n_language_pack_t * langs)
|
|
{
|
|
if(langs == NULL) return -1;
|
|
if(langs[0] == NULL) return -1;
|
|
|
|
current_lang_pack = langs;
|
|
current_lang = langs[0]; /*Automatically select the first language*/
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Change the localization (language)
|
|
* @param l_name name of the translation locale to use. E.g. "en-GB"
|
|
*/
|
|
int lv_i18n_set_locale(const char * l_name)
|
|
{
|
|
if(current_lang_pack == NULL) return -1;
|
|
|
|
uint16_t i;
|
|
|
|
for(i = 0; current_lang_pack[i] != NULL; i++) {
|
|
// Found -> finish
|
|
if(strcmp(current_lang_pack[i]->locale_name, l_name) == 0) {
|
|
current_lang = current_lang_pack[i];
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static const char * __lv_i18n_get_text_core(lv_i18n_phrase_t * trans, const char * msg_id)
|
|
{
|
|
uint16_t i;
|
|
for(i = 0; trans[i].msg_id != NULL; i++) {
|
|
if(strcmp(trans[i].msg_id, msg_id) == 0) {
|
|
/*The msg_id has found. Check the translation*/
|
|
if(trans[i].translation) return trans[i].translation;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the translation from a message ID
|
|
* @param msg_id message ID
|
|
* @return the translation of `msg_id` on the set local
|
|
*/
|
|
const char * lv_i18n_get_text(const char * msg_id)
|
|
{
|
|
if(current_lang == NULL) return msg_id;
|
|
|
|
const lv_i18n_lang_t * lang = current_lang;
|
|
const void * txt;
|
|
|
|
// Search in current locale
|
|
if(lang->singulars != NULL) {
|
|
txt = __lv_i18n_get_text_core(lang->singulars, msg_id);
|
|
if (txt != NULL) return txt;
|
|
}
|
|
|
|
// Try to fallback
|
|
if(lang == current_lang_pack[0]) return msg_id;
|
|
lang = current_lang_pack[0];
|
|
|
|
// Repeat search for default locale
|
|
if(lang->singulars != NULL) {
|
|
txt = __lv_i18n_get_text_core(lang->singulars, msg_id);
|
|
if (txt != NULL) return txt;
|
|
}
|
|
|
|
return msg_id;
|
|
}
|
|
|
|
/**
|
|
* Get the translation from a message ID and apply the language's plural rule to get correct form
|
|
* @param msg_id message ID
|
|
* @param num an integer to select the correct plural form
|
|
* @return the translation of `msg_id` on the set local
|
|
*/
|
|
const char * lv_i18n_get_text_plural(const char * msg_id, int32_t num)
|
|
{
|
|
if(current_lang == NULL) return msg_id;
|
|
|
|
const lv_i18n_lang_t * lang = current_lang;
|
|
const void * txt;
|
|
lv_i18n_plural_type_t ptype;
|
|
|
|
// Search in current locale
|
|
if(lang->locale_plural_fn != NULL) {
|
|
ptype = lang->locale_plural_fn(num);
|
|
|
|
if(lang->plurals[ptype] != NULL) {
|
|
txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id);
|
|
if (txt != NULL) return txt;
|
|
}
|
|
}
|
|
|
|
// Try to fallback
|
|
if(lang == current_lang_pack[0]) return msg_id;
|
|
lang = current_lang_pack[0];
|
|
|
|
// Repeat search for default locale
|
|
if(lang->locale_plural_fn != NULL) {
|
|
ptype = lang->locale_plural_fn(num);
|
|
|
|
if(lang->plurals[ptype] != NULL) {
|
|
txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id);
|
|
if (txt != NULL) return txt;
|
|
}
|
|
}
|
|
|
|
return msg_id;
|
|
}
|
|
|
|
/**
|
|
* Get the name of the currently used locale.
|
|
* @return name of the currently used locale. E.g. "en-GB"
|
|
*/
|
|
const char * lv_i18n_get_current_locale(void)
|
|
{
|
|
if(!current_lang) return NULL;
|
|
return current_lang->locale_name;
|
|
}
|