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
126
127
128
129
130
131
132
133
134
135
136
137
138
|
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Qt.labs.folderlistmodel
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string _resolvedLocale: "en"
readonly property string _rawLocale: SessionData.locale === "" ? Qt.locale().name : SessionData.locale
readonly property string _lang: _rawLocale.split(/[_-]/)[0]
readonly property var _candidates: {
const fullUnderscore = _rawLocale;
const fullHyphen = _rawLocale.replace("_", "-");
return [fullUnderscore, fullHyphen, _lang].filter(c => c && c !== "en");
}
readonly property var _rtlLanguages: ["ar", "he", "iw", "fa", "ur", "ps", "sd", "dv", "yi", "ku"]
readonly property bool isRtl: _rtlLanguages.includes(_lang)
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
readonly property alias folder: dir.folder
property var presentLocales: ({
"en": Qt.locale("en")
})
property var translations: ({})
property bool translationsLoaded: false
property url _selectedPath: ""
FolderListModel {
id: dir
folder: root.translationsFolder
nameFilters: ["*.json"]
showDirs: false
showDotAndDotDot: false
onStatusChanged: if (status === FolderListModel.Ready) {
root._loadPresentLocales();
root._pickTranslation();
}
}
FileView {
id: translationLoader
path: root._selectedPath
onLoaded: {
try {
root.translations = JSON.parse(text());
root.translationsLoaded = true;
console.info(`I18n: Loaded translations for '${root._resolvedLocale}' (${Object.keys(root.translations).length} contexts)`);
} catch (e) {
console.warn(`I18n: Error parsing '${root._resolvedLocale}':`, e, "- falling back to English");
root._fallbackToEnglish();
}
}
onLoadFailed: error => {
console.warn(`I18n: Failed to load '${root._resolvedLocale}' (${error}), ` + "falling back to English");
root._fallbackToEnglish();
}
}
function locale() {
if (SessionData.timeLocale)
return Qt.locale(SessionData.timeLocale);
return Qt.locale();
}
function _loadPresentLocales() {
if (Object.keys(presentLocales).length > 1) {
return; // already loaded
}
for (let i = 0; i < dir.count; i++) {
const name = dir.get(i, "fileName"); // e.g. "zh_CN.json"
if (name && name.endsWith(".json")) {
const shortName = name.slice(0, -5);
presentLocales[shortName] = Qt.locale(shortName);
}
}
}
function _pickTranslation() {
for (let i = 0; i < _candidates.length; i++) {
const cand = _candidates[i];
if (presentLocales[cand] === undefined)
continue;
_resolvedLocale = cand;
useLocale(cand, cand.startsWith("en") ? "" : translationsFolder + "/" + cand + ".json");
return;
}
_resolvedLocale = "en";
_fallbackToEnglish();
}
function useLocale(localeTag, fileUrl) {
_resolvedLocale = localeTag || "en";
_selectedPath = fileUrl;
translationsLoaded = false;
translations = ({});
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`);
}
function _fallbackToEnglish() {
_selectedPath = "";
translationsLoaded = false;
translations = ({});
console.warn("I18n: Falling back to built-in English strings");
}
function tr(term, context) {
if (!translationsLoaded || !translations)
return term;
const ctx = context || term;
if (translations[ctx] && translations[ctx][term])
return translations[ctx][term];
for (const c in translations) {
if (translations[c] && translations[c][term])
return translations[c][term];
}
return term;
}
function trContext(context, term) {
if (!translationsLoaded || !translations)
return term;
if (translations[context] && translations[context][term])
return translations[context][term];
return term;
}
}
|