aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/i18n/loadLocalization.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src/i18n/loadLocalization.ts')
-rw-r--r--packages/main/src/i18n/loadLocalization.ts125
1 files changed, 125 insertions, 0 deletions
diff --git a/packages/main/src/i18n/loadLocalization.ts b/packages/main/src/i18n/loadLocalization.ts
new file mode 100644
index 0000000..19da9e2
--- /dev/null
+++ b/packages/main/src/i18n/loadLocalization.ts
@@ -0,0 +1,125 @@
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 i18next, { i18n } from 'i18next';
23import { reaction } from 'mobx';
24import { addDisposer } from 'mobx-state-tree';
25
26import type MainStore from '../stores/MainStore.js';
27import getLogger from '../utils/getLogger.js';
28
29import I18nStore from './I18nStore.js';
30import type LocatlizationRepository from './LocalizationRepository.js';
31import RepositoryBasedI18nBackend from './RepositoryBasedI18nBackend.js';
32import i18nLog from './i18nLog.js';
33
34const log = getLogger('loadLocationzation');
35
36const TEST_LOCALE = 'cimode';
37
38function getLanguage(
39 language: string,
40 systemLocale: string,
41 supportedLanguages: string[],
42): string {
43 const selectedLanguage = language === SYSTEM_LOCALE ? systemLocale : language;
44 if (selectedLanguage === TEST_LOCALE) {
45 return selectedLanguage;
46 }
47 // Even though i18next has a `supportedLngs` array from which it can pick a supported language,
48 // we still have to do this ourselves to avoid spurious warnings like
49 // https://github.com/i18next/i18next/issues/1564
50 if (supportedLanguages.includes(selectedLanguage)) {
51 return selectedLanguage;
52 }
53 if (selectedLanguage.includes('-')) {
54 const iso639 = selectedLanguage.split('-')[0];
55 if (supportedLanguages.includes(iso639)) {
56 return iso639;
57 }
58 }
59 return FALLBACK_LOCALE;
60}
61
62function updateSharedStoreLanguage(store: MainStore, i18nInstance: i18n): void {
63 const resolvedLanguage =
64 i18nInstance.language === TEST_LOCALE
65 ? TEST_LOCALE
66 : i18nInstance.resolvedLanguage;
67 const dir = i18nInstance.dir();
68 // We do not want to pass the list of supported languages to the renderer process,
69 // so we extract the resolved languages from `i18n` as pass only that to the renderer.
70 // Thus, the renderer always selects a language that is actually supported.
71 store.shared.setLanguage(resolvedLanguage, dir);
72 log.debug('Loaded language', resolvedLanguage, 'with direction', dir);
73}
74
75export default async function loadLocalization(
76 store: MainStore,
77 systemLocale: string,
78 supportedLanguages: string[],
79 repository: LocatlizationRepository,
80 devMode: boolean,
81): Promise<void> {
82 const backend = new RepositoryBasedI18nBackend(repository, devMode);
83 const i18nInstance = i18next
84 .createInstance({
85 lng: getLanguage(
86 store.settings.language,
87 systemLocale,
88 supportedLanguages,
89 ),
90 supportedLngs: supportedLanguages,
91 fallbackLng: [FALLBACK_LOCALE],
92 debug: devMode,
93 saveMissing: devMode,
94 })
95 .use(backend)
96 .use(i18nLog);
97 const i18nStore = new I18nStore(i18nInstance);
98 store.setI18n(i18nStore);
99
100 await i18nInstance.init();
101 updateSharedStoreLanguage(store, i18nInstance);
102
103 const disposeChangeLanguage = reaction(
104 () => store.settings.language,
105 (languageSetting) => {
106 (async () => {
107 const languageToSet = getLanguage(
108 languageSetting,
109 systemLocale,
110 supportedLanguages,
111 );
112 if (i18nInstance.language !== languageToSet) {
113 await i18nInstance.changeLanguage(languageToSet);
114 updateSharedStoreLanguage(store, i18nInstance);
115 }
116 })().catch((error) => {
117 log.error('Failed to change language', error);
118 });
119 },
120 {
121 fireImmediately: true,
122 },
123 );
124 addDisposer(store, disposeChangeLanguage);
125}