1 #include "../langs/i18n_decls.h"
2
3 #include "sized_string.h"
4 #include "macros.h"
5
6 #include <stdint.h>
7 #include <string.h>
8
9 #ifdef msgid
10 #error "msgid is already defined"
11 #endif
12 #ifdef msgstr
13 #error "msgstr is already defined"
14 #endif
15 #ifdef LANG_POSIX_LOCALE
16 #error "LANG_POSIX_LOCALE is already defined"
17 #endif
18 #ifdef LANG_WINDOWS_ID
19 #error "LANG_WINDOWS_ID is already defined"
20 #endif
21 #ifdef LANG_PRIORITY
22 #error "LANG_PRIORITY is already defined"
23 #endif
24
25 /***** Parsing localized strings *****/
26
27 #define msgid(x) curr_id = (STR_##x);
28 #define msgstr(x) \
29 localized_strings[_LANG_ID][curr_id].str = (x); \
30 localized_strings[_LANG_ID][curr_id].length = sizeof(x) - 1;
31 #define LANG_WINDOWS_ID(x)
32 #define LANG_POSIX_LOCALE(x)
33 #define LANG_PRIORITY(x)
34
35 static STRING canary = STRING_INIT("BUG. PLEASE REPORT.");
36
init_strings(STRING (* localized_strings)[NUM_STRS])37 static void init_strings(STRING (*localized_strings)[NUM_STRS]) {
38 for (UTOX_LANG i = 0; i < NUM_LANGS; i++) {
39 for (UTOX_I18N_STR j = 0; j < NUM_STRS; j++) {
40 localized_strings[i][j] = canary;
41 }
42 }
43
44 UTOX_I18N_STR curr_id = 0;
45
46 #include "ui_i18n.h"
47 }
48
49 #undef LANG_PRIORITY
50 #undef LANG_POSIX_LOCALE
51 #undef LANG_WINDOWS_ID
52 #undef msgstr
53 #undef msgid
54
ui_gettext(UTOX_LANG lang,UTOX_I18N_STR string_id)55 STRING *ui_gettext(UTOX_LANG lang, UTOX_I18N_STR string_id) {
56 static STRING localized_strings[NUM_LANGS][NUM_STRS];
57 static int ready = 0;
58
59 if (!ready) {
60 init_strings(localized_strings);
61 ready = 1;
62 }
63
64 if ((lang >= NUM_LANGS) || (string_id >= NUM_STRS)) {
65 return &canary;
66 }
67
68 return &localized_strings[lang][string_id];
69 }
70
71 /***** Parsing detection by POSIX locale *****/
72
73 #define msgid(x)
74 #define msgstr(x)
75 #define LANG_WINDOWS_ID(x)
76 #define LANG_POSIX_LOCALE(x) posix_locales[_LANG_ID] = (x);
77 #define LANG_PRIORITY(x) priorities[_LANG_ID] = (x);
78
init_posix_locales(const char * UNUSED (posix_locales[]),int8_t UNUSED (priorities[]))79 static void init_posix_locales(const char *UNUSED(posix_locales[]), int8_t UNUSED(priorities[])) {
80
81 #include "ui_i18n.h"
82 }
83
84 #undef LANG_PRIORITY
85 #undef LANG_POSIX_LOCALE
86 #undef LANG_WINDOWS_ID
87 #undef msgstr
88 #undef msgid
89
ui_guess_lang_by_posix_locale(const char * locale,UTOX_LANG deflt)90 UTOX_LANG ui_guess_lang_by_posix_locale(const char *locale, UTOX_LANG deflt) {
91 static const char *posix_locales[NUM_LANGS];
92 static int8_t priorities[NUM_LANGS];
93 static int ready = 0;
94
95 if (!ready) {
96 init_posix_locales(posix_locales, priorities);
97 ready = 1;
98 }
99
100 UTOX_LANG found_lang = 0;
101 int8_t found_prio = INT8_MAX;
102
103 // Try detecting by full prefix match first.
104 for (UTOX_LANG i = 0; i < NUM_LANGS; i++) {
105 const char *l = posix_locales[i];
106 if (!l) {
107 continue;
108 }
109
110 if (strstr(locale, l)) {
111 if (found_prio > priorities[i]) {
112 found_lang = i;
113 found_prio = priorities[i];
114 }
115 }
116 }
117
118 if (found_prio < INT8_MAX) {
119 return found_lang;
120 }
121
122 // It appears we haven't found exact language_territory
123 // match (e.g. zh_TW) for given locale. ,
124 // Try stripping territory off and search only by language part.
125 for (UTOX_LANG i = 0; i < NUM_LANGS; i++) {
126 const char *l = posix_locales[i];
127 if (!l) {
128 continue;
129 }
130
131 char *sep = strchr(l, '_');
132 if (!sep) {
133 continue;
134 }
135
136 if (!strncmp(locale, l, sep - l)) {
137 if (found_prio > priorities[i]) {
138 found_lang = i;
139 found_prio = priorities[i];
140 }
141 }
142 }
143
144 return found_prio < INT8_MAX ? found_lang : deflt;
145 }
146
147 /***** Parsing detection by Windows language id *****/
148
149 #define msgid(x)
150 #define msgstr(x)
151 #define LANG_WINDOWS_ID(x) windows_lang_ids[_LANG_ID] = (x);
152 #define LANG_POSIX_LOCALE(x)
153 #define LANG_PRIORITY(x) priorities[_LANG_ID] = (x);
154
init_windows_lang_ids(uint16_t UNUSED (windows_lang_ids[]),int8_t UNUSED (priorities[]))155 static void init_windows_lang_ids(uint16_t UNUSED(windows_lang_ids[]), int8_t UNUSED(priorities[])) {
156
157 #include "ui_i18n.h"
158 }
159
160 #undef LANG_PRIORITY
161 #undef LANG_POSIX_LOCALE
162 #undef LANG_WINDOWS_ID
163 #undef msgstr
164 #undef msgid
165
ui_guess_lang_by_windows_lang_id(uint16_t lang_id,UTOX_LANG deflt)166 UTOX_LANG ui_guess_lang_by_windows_lang_id(uint16_t lang_id, UTOX_LANG deflt) {
167 static uint16_t windows_lang_ids[NUM_LANGS];
168 static int8_t priorities[NUM_LANGS];
169 static int ready = 0;
170
171 if (!ready) {
172 init_windows_lang_ids(windows_lang_ids, priorities);
173 ready = 1;
174 }
175
176 UTOX_LANG found_lang = 0;
177 int8_t found_prio = INT8_MAX;
178
179 // Try detecting by full match first, including sublanguage part.
180 for (UTOX_LANG i = 0; i < NUM_LANGS; i++) {
181 uint16_t l = windows_lang_ids[i];
182 if (!l) {
183 continue;
184 }
185
186 if (l == lang_id) {
187 if (found_prio > priorities[i]) {
188 found_lang = i;
189 found_prio = priorities[i];
190 }
191 }
192 }
193
194 if (found_prio < INT8_MAX) {
195 return found_lang;
196 }
197
198 // It appears we haven't found exact id match.
199 // Try matching by the lower 8 bits, which contain language family part.
200 for (UTOX_LANG i = 0; i < NUM_LANGS; i++) {
201 uint16_t l = windows_lang_ids[i];
202 if (!l) {
203 continue;
204 }
205
206 if ((l & 0xFF) == (lang_id & 0xFF)) {
207 if (found_prio > priorities[i]) {
208 found_lang = i;
209 found_prio = priorities[i];
210 }
211 }
212 }
213
214 return found_prio < INT8_MAX ? found_lang : deflt;
215 }
216