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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/*
* Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
*
* This file is part of Sophie.
*
* Sophie is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { FALLBACK_LOCALE, SYSTEM_LOCALE } from '@sophie/shared';
import i18next, { i18n } from 'i18next';
import { reaction } from 'mobx';
import { addDisposer } from 'mobx-state-tree';
import type MainStore from '../stores/MainStore';
import { getLogger } from '../utils/log';
import I18nStore from './I18nStore';
import type LocatlizationRepository from './LocalizationRepository';
import RepositoryBasedI18nBackend from './RepositoryBasedI18nBackend';
import i18nLog from './i18nLog';
const log = getLogger('loadLocationzation');
const TEST_LOCALE = 'cimode';
function getLanguage(
language: string,
systemLocale: string,
supportedLanguages: string[],
): string {
const selectedLanguage = language === SYSTEM_LOCALE ? systemLocale : language;
if (selectedLanguage === TEST_LOCALE) {
return selectedLanguage;
}
// Even though i18next has a `supportedLngs` array from which it can pick a supported language,
// we still have to do this ourselves to avoid spurious warnings like
// https://github.com/i18next/i18next/issues/1564
if (supportedLanguages.includes(selectedLanguage)) {
return selectedLanguage;
}
if (selectedLanguage.includes('-')) {
const iso639 = selectedLanguage.split('-')[0];
if (supportedLanguages.includes(iso639)) {
return iso639;
}
}
return FALLBACK_LOCALE;
}
function updateSharedStoreLanguage(store: MainStore, i18nInstance: i18n): void {
const resolvedLanguage =
i18nInstance.language === TEST_LOCALE
? TEST_LOCALE
: i18nInstance.resolvedLanguage;
const dir = i18nInstance.dir();
// We do not want to pass the list of supported languages to the renderer process,
// so we extract the resolved languages from `i18n` as pass only that to the renderer.
// Thus, the renderer always selects a language that is actually supported.
store.shared.setLanguage(resolvedLanguage, dir);
log.debug('Loaded language', resolvedLanguage, 'with direction', dir);
}
export default async function loadLocalization(
store: MainStore,
systemLocale: string,
supportedLanguages: string[],
repository: LocatlizationRepository,
devMode: boolean,
): Promise<void> {
const backend = new RepositoryBasedI18nBackend(repository, devMode);
const i18nInstance = i18next
.createInstance({
lng: getLanguage(
store.settings.language,
systemLocale,
supportedLanguages,
),
supportedLngs: supportedLanguages,
fallbackLng: [FALLBACK_LOCALE],
debug: devMode,
saveMissing: devMode,
})
.use(backend)
.use(i18nLog);
const i18nStore = new I18nStore(i18nInstance);
store.setI18n(i18nStore);
await i18nInstance.init();
updateSharedStoreLanguage(store, i18nInstance);
const disposeChangeLanguage = reaction(
() => store.settings.language,
(languageSetting) => {
(async () => {
const languageToSet = getLanguage(
languageSetting,
systemLocale,
supportedLanguages,
);
if (i18nInstance.language !== languageToSet) {
await i18nInstance.changeLanguage(languageToSet);
updateSharedStoreLanguage(store, i18nInstance);
}
})().catch((error) => {
log.error('Failed to change language', error);
});
},
{
fireImmediately: true,
},
);
addDisposer(store, disposeChangeLanguage);
}
|