aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src/i18n')
-rw-r--r--packages/main/src/i18n/loadLocalization.ts11
-rw-r--r--packages/main/src/i18n/synchronizeLocalizationSettings.ts99
2 files changed, 104 insertions, 6 deletions
diff --git a/packages/main/src/i18n/loadLocalization.ts b/packages/main/src/i18n/loadLocalization.ts
index ec3cf84..0413373 100644
--- a/packages/main/src/i18n/loadLocalization.ts
+++ b/packages/main/src/i18n/loadLocalization.ts
@@ -18,33 +18,31 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { fallbackLng } from '@sophie/shared'; 21import { FALLBACK_LOCALE } from '@sophie/shared';
22import i18next from 'i18next'; 22import i18next from 'i18next';
23import { autorun } from 'mobx'; 23import { autorun } from 'mobx';
24import { addDisposer } from 'mobx-state-tree'; 24import { addDisposer } from 'mobx-state-tree';
25 25
26import type Resources from '../infrastructure/resources/Resources';
27import type MainStore from '../stores/MainStore'; 26import type MainStore from '../stores/MainStore';
28import { getLogger } from '../utils/log'; 27import { getLogger } from '../utils/log';
29 28
30import I18nStore from './I18nStore'; 29import I18nStore from './I18nStore';
30import LocatlizationRepository from './LocalizationRepository';
31import RepositoryBasedI18nBackend from './RepositoryBasedI18nBackend'; 31import RepositoryBasedI18nBackend from './RepositoryBasedI18nBackend';
32import i18nLog from './i18nLog'; 32import i18nLog from './i18nLog';
33import LocalizationFiles from './impl/LocaltizationFiles';
34 33
35const log = getLogger('loadLocationzation'); 34const log = getLogger('loadLocationzation');
36 35
37export default async function loadLocalization( 36export default async function loadLocalization(
38 store: MainStore, 37 store: MainStore,
39 resources: Resources, 38 repository: LocatlizationRepository,
40 devMode: boolean, 39 devMode: boolean,
41): Promise<void> { 40): Promise<void> {
42 const repository = new LocalizationFiles(resources);
43 const backend = new RepositoryBasedI18nBackend(repository, devMode); 41 const backend = new RepositoryBasedI18nBackend(repository, devMode);
44 const i18n = i18next 42 const i18n = i18next
45 .createInstance({ 43 .createInstance({
46 lng: store.shared.language, 44 lng: store.shared.language,
47 fallbackLng, 45 fallbackLng: [FALLBACK_LOCALE],
48 debug: devMode, 46 debug: devMode,
49 saveMissing: devMode, 47 saveMissing: devMode,
50 }) 48 })
@@ -58,6 +56,7 @@ export default async function loadLocalization(
58 shared: { language }, 56 shared: { language },
59 } = store; 57 } = store;
60 if (i18n.language !== language) { 58 if (i18n.language !== language) {
59 log.debug('Setting language', language);
61 i18n.changeLanguage(language).catch((error) => { 60 i18n.changeLanguage(language).catch((error) => {
62 log.error('Failed to change language', error); 61 log.error('Failed to change language', error);
63 }); 62 });
diff --git a/packages/main/src/i18n/synchronizeLocalizationSettings.ts b/packages/main/src/i18n/synchronizeLocalizationSettings.ts
new file mode 100644
index 0000000..971a593
--- /dev/null
+++ b/packages/main/src/i18n/synchronizeLocalizationSettings.ts
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
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 Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { FALLBACK_LOCALE, SYSTEM_LOCALE } from '@sophie/shared';
22import { reaction } from 'mobx';
23import { addDisposer } from 'mobx-state-tree';
24
25import type MainStore from '../stores/MainStore';
26import { getLogger } from '../utils/log';
27
28const log = getLogger('synchronizeLocalizationSettings');
29
30export const TEST_LOCALE = 'cimode';
31
32/**
33 * Finds the closes requested supported language for the requested one.
34 *
35 * If `language` is supported, this function will return it.
36 * Otherwise, it returns a supported language with the same ISO639 code but
37 * no country code (e.g., `en` for `en-GB`) if it exists.
38 * If no supported language matches, `FALLBACK_LOCALE` will be returned.
39 *
40 * @param language The requested language.
41 * @param supportedLanguages The set of supported languages.
42 * @returns The language to load.
43 */
44function getMatchingLocale(
45 language: string,
46 supportedLanguages: Set<string>,
47): string {
48 // Also let the test locale (i.e., show localization keys directly) through.
49 if (language === TEST_LOCALE || supportedLanguages.has(language)) {
50 return language;
51 }
52 const separatorIndex = language.indexOf('-');
53 if (separatorIndex < 0) {
54 return FALLBACK_LOCALE;
55 }
56 const iso639 = language.slice(0, Math.max(0, separatorIndex));
57 if (supportedLanguages.has(iso639)) {
58 return iso639;
59 }
60 return FALLBACK_LOCALE;
61}
62
63export async function synchronizeLocalizationSettings(
64 store: MainStore,
65 supportedLanguages: string[],
66 osLocale: () => Promise<string>,
67): Promise<void> {
68 const { settings, shared } = store;
69 const supportedLangaugesSet = new Set(supportedLanguages);
70 const setLanguageAsync = async (languageSetting: string) => {
71 const requestedLanguage =
72 languageSetting === SYSTEM_LOCALE ? await osLocale() : languageSetting;
73 const matchingLanguage = getMatchingLocale(
74 requestedLanguage,
75 supportedLangaugesSet,
76 );
77 log.debug(
78 'Setting language',
79 matchingLanguage,
80 'for requested language',
81 requestedLanguage,
82 );
83 shared.setLanguage(matchingLanguage);
84 };
85 const disposer = reaction(
86 () => settings.language,
87 (languageSetting) => {
88 setLanguageAsync(languageSetting).catch((error) => {
89 log.error('Failed to update language', error);
90 });
91 },
92 {
93 fireImmediately: false,
94 },
95 );
96 addDisposer(store, disposer);
97 // Make sure that the language is already set when we resolve.
98 await setLanguageAsync(settings.language);
99}