1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
import log from 'electron-log';
import fs from 'fs';
import { po } from 'gettext-parser';
import Gettext from 'node-gettext';
import path from 'path';
import { LocalizationContexts } from './localization-contexts';
const SOURCE_LANGUAGE = 'en';
const LOCALES_DIR = path.resolve(__dirname, '../../locales');
export function loadTranslations(currentLocale: string, catalogue: Gettext) {
// First look for exact match of the current locale
const preferredLocales = [];
if (currentLocale !== SOURCE_LANGUAGE) {
preferredLocales.push(currentLocale);
}
// In case of region bound locale like en-US, fallback to en.
const language = Gettext.getLanguageCode(currentLocale);
if (currentLocale !== language) {
preferredLocales.push(language);
}
const domain = catalogue.domain;
for (const locale of preferredLocales) {
if (parseTranslation(locale, domain, catalogue)) {
log.info(`Loaded translations ${locale}/${domain}`);
catalogue.setLocale(locale);
return;
}
}
// Reset the locale to source language if we couldn't load the catalogue for the requested locale
// Add empty translations to suppress some of the warnings produces by node-gettext
catalogue.addTranslations(SOURCE_LANGUAGE, domain, {});
catalogue.setLocale(SOURCE_LANGUAGE);
}
function parseTranslation(locale: string, domain: string, catalogue: Gettext): boolean {
const filename = path.join(LOCALES_DIR, locale, `${domain}.po`);
let contents: string;
try {
contents = fs.readFileSync(filename, { encoding: 'utf8' });
} catch (error) {
if (error.code !== 'ENOENT') {
log.error(`Cannot read the gettext file "${filename}": ${error.message}`);
}
return false;
}
let translations: object;
try {
translations = po.parse(contents);
} catch (error) {
log.error(`Cannot parse the gettext file "${filename}": ${error.message}`);
return false;
}
catalogue.addTranslations(locale, domain, translations);
return true;
}
function setErrorHandler(catalogue: Gettext) {
catalogue.on('error', (error) => {
log.warn(`Gettext error: ${error}`);
});
}
const gettextOptions = { sourceLocale: SOURCE_LANGUAGE };
declare class GettextWithAppContexts extends Gettext {
pgettext(msgctxt: LocalizationContexts, msgid: string): string;
npgettext(
msgctxt: LocalizationContexts,
msgid: string,
msgidPlural: string,
count: number,
): string;
}
export const messages = new Gettext(gettextOptions) as GettextWithAppContexts;
messages.setTextDomain('messages');
setErrorHandler(messages);
export const relayLocations = new Gettext(gettextOptions);
relayLocations.setTextDomain('relay-locations');
setErrorHandler(relayLocations);
|