Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 518 lines (412 sloc) 10.244 kB
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
1 /*
2 * Internationalization
3 * Copyright (C) 2007-2011 Andreas Öman
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20
21 #include "showtime.h"
22 #include "settings.h"
23 #include "i18n.h"
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
24 #include "misc/string.h"
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
25 #include "fileaccess/fileaccess.h"
b83de0c @andoma i18n: Make it possible to load translation via HTTP server
andoma authored
26 #include "networking/http_server.h"
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
27
28 static void nls_init(prop_t *parent, htsmsg_t *store);
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
29
30
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
31
32 static char *lang_audio[3];
33 static char *lang_subtitle[3];
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
34 static const uint16_t *srt_charset;
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
35
36 static void
37 set_lang(void *opaque, const char *str)
38 {
39 char **s = opaque;
40 mystrset(s, str);
41 }
42
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
43 static void
44 set_srt_charset(void *opaque, const char *str)
45 {
f7d2dae @andoma Refactor character set handling a bit
andoma authored
46 const charset_t *cs = charset_get(str);
47
48 if(cs != NULL) {
49 srt_charset = cs->ptr;
50 TRACE(TRACE_DEBUG, "i18n", "SRT charset is %s", cs->title);
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
51 }
52 }
53
54
55
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
56 void
57 i18n_init(void)
58 {
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
59 prop_t *s = settings_add_dir(NULL, _p("Languages"), NULL, NULL,
60 _p("Preferred languages"));
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
61 setting_t *x;
62 int i;
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
63
64 htsmsg_t *store = htsmsg_store_load("i18n");
65 if(store == NULL)
66 store = htsmsg_create_map();
67
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
68 nls_init(s, store);
69
70
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
71 settings_create_info(s,
72 NULL,
78d3705 @andoma Fix missing translation
andoma authored
73 _p("Language codes should be configured as three character ISO codes, example (eng, swe, fra)"));
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
74
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
75 settings_create_string(s, "audio1", _p("Primary audio language code"), NULL,
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
76 store, set_lang, &lang_audio[0],
77 SETTINGS_INITIAL_UPDATE, NULL,
78 settings_generic_save_settings,
79 (void *)"i18n");
80
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
81 settings_create_string(s, "audio2", _p("Secondary audio language code"),
82 NULL,
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
83 store, set_lang, &lang_audio[1],
84 SETTINGS_INITIAL_UPDATE, NULL,
85 settings_generic_save_settings,
86 (void *)"i18n");
87
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
88 settings_create_string(s, "audio3", _p("Tertiary audio language code"), NULL,
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
89 store, set_lang, &lang_audio[2],
90 SETTINGS_INITIAL_UPDATE, NULL,
91 settings_generic_save_settings,
92 (void *)"i18n");
93
94
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
95 settings_create_string(s, "subtitle1", _p("Primary subtitle language code"),
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
96 NULL, store, set_lang, &lang_subtitle[0],
97 SETTINGS_INITIAL_UPDATE, NULL,
98 settings_generic_save_settings,
99 (void *)"i18n");
100
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
101 settings_create_string(s, "subtitle2", _p("Secondary subtitle language code"),
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
102 NULL, store, set_lang, &lang_subtitle[1],
103 SETTINGS_INITIAL_UPDATE, NULL,
104 settings_generic_save_settings,
105 (void *)"i18n");
106
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
107 settings_create_string(s, "subtitle3", _p("Tertiary subtitle language code"),
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
108 NULL, store, set_lang, &lang_subtitle[2],
109 SETTINGS_INITIAL_UPDATE, NULL,
110 settings_generic_save_settings,
111 (void *)"i18n");
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
112
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
113 x = settings_create_multiopt(s, "srt_charset", _p("SRT character set"),
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
114 set_srt_charset, NULL);
115
f7d2dae @andoma Refactor character set handling a bit
andoma authored
116 const charset_t *cs;
117 for(i = 0; (cs = charset_get_idx(i)) != NULL; i++)
118 settings_multiopt_add_opt_cstr(x, cs->id, cs->title, i == 0);
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
119
120 settings_multiopt_initiate(x, store, settings_generic_save_settings,
121 (void *)"i18n");
488c19e @andoma Add support for setting preferred audio / subtitle languages
andoma authored
122 }
123
124
125 /**
126 *
127 */
128 static int
129 findscore(const char *str, char *vec[])
130 {
131 int i;
132 if(str == NULL || *str == 0)
133 return 0;
134
135 for(i = 0; i < 3; i++)
136 if(vec[i] && !strcasecmp(vec[i], str))
137 return 100 * (3 - i);
138 return 0;
139 }
140
141
142 /**
143 *
144 */
145 int
146 i18n_audio_score(const char *str)
147 {
148 return findscore(str, lang_audio);
149 }
150
151 /**
152 *
153 */
154 int
155 i18n_subtitle_score(const char *str)
156 {
157 return findscore(str, lang_subtitle);
158 }
4159b05 @andoma Add support for all ISO 8859 character encodings
andoma authored
159
160
161 /**
162 *
163 */
164 const uint16_t *
165 i18n_get_srt_charset(void)
166 {
167 return srt_charset;
168 }
169
170
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
171 LIST_HEAD(nls_string_queue, nls_string);
172
173
174 /**
175 *
176 */
177 typedef struct nls_string {
178 rstr_t *ns_key;
179 LIST_ENTRY(nls_string) ns_link;
180 prop_t *ns_prop;
181 rstr_t *ns_value;
182 } nls_string_t;
183
184 static struct nls_string_queue nls_strings;
185
186
187
188 /**
189 *
190 */
191 static nls_string_t *
192 nls_string_find(const char *key)
193 {
194 nls_string_t *ns;
195
196 LIST_FOREACH(ns, &nls_strings, ns_link)
197 if(!strcmp(rstr_get(ns->ns_key), key))
198 break;
199
200 if(ns == NULL) {
201
202 ns = calloc(1, sizeof(nls_string_t));
203 ns->ns_key = rstr_alloc(key);
204 ns->ns_prop = prop_create_root(NULL);
205 prop_set_rstring(ns->ns_prop, ns->ns_key);
206
207 } else {
208 LIST_REMOVE(ns, ns_link);
209 }
210 LIST_INSERT_HEAD(&nls_strings, ns, ns_link);
211 return ns;
212 }
213
214
215 /**
216 *
217 */
218 prop_t *
219 nls_get_prop(const char *string)
220 {
221 nls_string_t *ns = nls_string_find(string);
222 return ns->ns_prop;
223 }
224
225
226 /**
227 *
228 */
229 rstr_t *
230 nls_get_rstring(const char *string)
231 {
232 nls_string_t *ns = nls_string_find(string);
233 if(ns->ns_value == NULL)
234 return rstr_dup(ns->ns_key);
235 return rstr_dup(ns->ns_value);
236 }
237
238
239 /**
240 *
241 */
242 static void
243 nls_clear(void)
244 {
245 nls_string_t *ns;
246 LIST_FOREACH(ns, &nls_strings, ns_link) {
247 rstr_release(ns->ns_value);
248 ns->ns_value = NULL;
249 prop_set_rstring(ns->ns_prop, ns->ns_key);
250 }
251 }
252
253
254 /**
255 *
256 */
257 static void
258 deescape_cstyle(char *src)
259 {
260 char *dst = src;
261 while(*src) {
262 if(*src == '\\') {
263 src++;
264 if(*src == 0)
265 break;
266 if(*src == 'n')
267 *dst++ = '\n';
268 src++;
269 } else {
270 *dst++ = *src++;
271 }
272 }
273 *dst = 0;
274 }
275
276
277 /**
278 *
279 */
280 static void
b83de0c @andoma i18n: Make it possible to load translation via HTTP server
andoma authored
281 nls_load_from_data(char *s)
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
282 {
283 const char *s2;
284
00fb912 @andoma i18n: Skip utf-8 BOMs in lang files
andoma authored
285 // Skip UTF-8 BOM
286 if(!memcmp(s, (const uint8_t []){0xef, 0xbb, 0xbf}, 3))
287 s+=3;
288
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
289 int l;
290 nls_string_t *ns = NULL;
291 for(; l = strcspn(s, "\r\n"), *s; s += l+1+strspn(s+l+1, "\r\n")) {
292 s[l] = 0;
293 if(s[0] == '#')
294 continue;
295
296 if((s2 = mystrbegins(s, "id:")) != NULL) {
297 while(*s2 <33 && *s2)
298 s2++;
299
300 deescape_cstyle((char *)s2);
301 ns = nls_string_find(s2);
302 continue;
303 }
304
305 if(ns == NULL)
306 continue;
307
308 if((s2 = mystrbegins(s, "msg:")) != NULL) {
309
310 while(*s2 <33 && *s2)
311 s2++;
312
313 if(*s2) {
314 rstr_release(ns->ns_value);
315 deescape_cstyle((char *)s2);
316 ns->ns_value = rstr_alloc(s2);
317 prop_set_rstring(ns->ns_prop, ns->ns_value);
318 }
319 }
320 }
b83de0c @andoma i18n: Make it possible to load translation via HTTP server
andoma authored
321 }
322
323 /**
324 *
325 */
326 static void
327 nls_load_lang(const char *path)
328 {
329 char errbuf[200];
330 fa_stat_t fs;
331 char *data = fa_quickload(path, &fs, NULL, errbuf, sizeof(errbuf));
332
333 if(data == NULL) {
334 TRACE(TRACE_ERROR, "NLS", "Unable to load %s -- %s", path, errbuf);
335 return;
336 }
337
338 nls_load_from_data(data);
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
339 free(data);
340 }
341
342
343 /**
344 *
345 */
346 static void
347 set_language(void *opaque, const char *str)
348 {
349 char buf[200];
350
351 nls_clear();
352
353 if(!strcmp(str, "none")) {
354 TRACE(TRACE_INFO, "i18n", "Unloading language definition");
355 return;
356 }
357
358 snprintf(buf, sizeof(buf), "%s/%s.lang", SHOWTIME_LANGUAGES_URL, str);
359 TRACE(TRACE_INFO, "i18n", "Loading language %s", str);
360 nls_load_lang(buf);
361 }
362
363
364 static int
365 nls_lang_metadata(const char *path, char *errbuf, size_t errlen,
366 char *language, size_t languagesize,
367 char *native, size_t nativesize)
368 {
369 fa_stat_t fs;
370
371 char *data = fa_quickload(path, &fs, NULL, errbuf, errlen);
372 char *s;
373 const char *s2;
374 if(data == NULL)
375 return -1;
376
377
378 *language = 0;
379 *native = 0;
380
381 s = data;
00fb912 @andoma i18n: Skip utf-8 BOMs in lang files
andoma authored
382 // Skip UTF-8 BOM
383 if(!memcmp(s, (const uint8_t []){0xef, 0xbb, 0xbf}, 3))
384 s+=3;
385
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
386 int l;
387 for(; l = strcspn(s, "\r\n"), *s; s += l+1+strspn(s+l+1, "\r\n")) {
388 s[l] = 0;
389 if(s[0] == '#')
390 continue;
391
392
393 if((s2 = mystrbegins(s, "language:")) != NULL) {
394 while(*s2 <33 && *s2)
395 s2++;
396 snprintf(language, languagesize, "%s", s2);
397 }
398
399 if((s2 = mystrbegins(s, "native:")) != NULL) {
400 while(*s2 <33 && *s2)
401 s2++;
402 snprintf(native, nativesize, "%s", s2);
403 }
404 if(*language && *native)
405 break;
406 }
407
408 free(data);
409
410 if(*language && *native)
411 return 0;
412
413 snprintf(errbuf, errlen, "Not a valid language file");
414 return -1;
415 }
416
b83de0c @andoma i18n: Make it possible to load translation via HTTP server
andoma authored
417 /**
418 *
419 */
420 static int
421 upload_translation(http_connection_t *hc, const char *remain, void *opaque,
422 http_cmd_t method)
423 {
424 size_t len;
425 void *data = http_get_post_data(hc, &len, 0);
426
427 if(method != HTTP_CMD_POST || data == NULL)
428 return 405;
429
430 nls_clear();
431 nls_load_from_data(data);
432 TRACE(TRACE_INFO, "i18n", "Loading language from HTTP POST");
433 return HTTP_STATUS_OK;
434 }
435
436
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
437 typedef struct lang {
438 LIST_ENTRY(lang) link;
439 const char *id;
440 const char *str;
441 } lang_t;
442
443 /**
444 *
445 */
446 static int
447 langcmp(lang_t *a, lang_t *b)
448 {
449 return dictcmp(a->str, b->str);
450 }
451
452
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
453
454 /**
455 *
456 */
457 static void
458 nls_init(prop_t *parent, htsmsg_t *store)
459 {
460 setting_t *x;
461 char buf[200];
462 char buf2[200];
463 fa_dir_t *fd = fa_scandir(SHOWTIME_LANGUAGES_URL, buf, sizeof(buf));
464 fa_dir_entry_t *fde;
465 char language[64];
466 char native[64];
467 char *e;
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
468 LIST_HEAD(, lang) list;
469 lang_t *l;
b83de0c @andoma i18n: Make it possible to load translation via HTTP server
andoma authored
470
471 http_path_add("/showtime/translation", NULL, upload_translation);
472
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
473 if(fd == NULL) {
474 TRACE(TRACE_ERROR, "i18n", "Unable to scan languages in %s -- %s",
475 SHOWTIME_LANGUAGES_URL, buf);
476 return;
477 }
478
479 x = settings_create_multiopt(parent, "language", _p("Language"),
480 set_language, NULL);
481
482 settings_multiopt_add_opt_cstr(x, "none", "English (default)", 1);
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
483 LIST_INIT(&list);
484
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
485 TAILQ_FOREACH(fde, &fd->fd_entries, fde_link) {
486
487 if(fde->fde_filename[strlen(fde->fde_filename) - 1] == '~')
488 continue;
489
490 snprintf(buf, sizeof(buf), "%s", fde->fde_filename);
491 if((e = strstr(buf, ".lang")) == NULL)
492 continue;
493 *e = 0;
494
495 if(nls_lang_metadata(fde->fde_url,
496 buf2, sizeof(buf2),
497 language, sizeof(language),
498 native, sizeof(native))) {
499 TRACE(TRACE_ERROR, "i18n", "Unable to load language from %s -- %s",
500 fde->fde_url, buf2);
501 continue;
502 }
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
503 l = alloca(sizeof(lang_t));
504 l->id = mystrdupa(buf);
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
505 snprintf(buf2, sizeof(buf2), "%s (%s)", native, language);
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
506 l->str = mystrdupa(buf2);
507 LIST_INSERT_SORTED(&list, l, link, langcmp);
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
508 }
509
52b13bf @andoma i18n: Sort languages based on displayed title
andoma authored
510 LIST_FOREACH(l, &list, link)
511 settings_multiopt_add_opt_cstr(x, l->id, l->str, 0);
512
cf1274f @andoma i18n: Initial work on NLS (Native Language Support)
andoma authored
513 settings_multiopt_initiate(x, store, settings_generic_save_settings,
514 (void *)"i18n");
515
516 fa_dir_free(fd);
517 }
Something went wrong with that request. Please try again.