@stamhoofd/backend-i18n 2.49.1 → 2.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/I18n.d.ts.map +1 -1
- package/dist/I18n.js +26 -23
- package/dist/I18n.js.map +1 -1
- package/package.json +2 -2
- package/src/I18n.ts +88 -81
package/dist/I18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18n.d.ts","sourceRoot":"","sources":["../src/I18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIhD,qBAAa,IAAI;IACb,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"I18n.d.ts","sourceRoot":"","sources":["../src/I18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIhD,qBAAa,IAAI;IACb,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAa;IACnE,MAAM,CAAC,eAAe,SAAQ;IAC9B,MAAM,CAAC,cAAc,UAAmB;WAE3B,IAAI;IA4BjB,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAetF,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM;IAUnC,QAAQ,SAAM;IACd,OAAO,SAAM;IAGb,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE9B,IAAI,MAAM,WAET;gBAEW,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAa7C,iCAAiC;IA8BjC,cAAc,CAAC,OAAO,EAAE;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB;IAaD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI;IAsD1E,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhD,WAAW,CAAC,MAAM,KAAA;IAIlB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAatD,SAAS,CAAC,eAAe,EAAE,eAAe,GAAG,MAAM;IAInD,gBAAgB;yBACG,MAAM;yCACU,MAAM;qCACV,MAAM;MACnC;CACL"}
|
package/dist/I18n.js
CHANGED
|
@@ -9,55 +9,58 @@ const fs_1 = require("fs");
|
|
|
9
9
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
10
10
|
class I18n {
|
|
11
11
|
static loadedLocales = new Map();
|
|
12
|
-
static defaultLanguage =
|
|
12
|
+
static defaultLanguage = 'nl';
|
|
13
13
|
static defaultCountry = structures_1.Country.Belgium;
|
|
14
14
|
static async load() {
|
|
15
15
|
await simple_logging_1.logger.setContext({
|
|
16
16
|
prefixes: [
|
|
17
|
-
new simple_logging_1.StyledText('[I18n] ').addClass('i18n', 'tag')
|
|
17
|
+
new simple_logging_1.StyledText('[I18n] ').addClass('i18n', 'tag'),
|
|
18
18
|
],
|
|
19
|
-
tags: ['i18n']
|
|
19
|
+
tags: ['i18n'],
|
|
20
20
|
}, async () => {
|
|
21
|
-
console.log(
|
|
22
|
-
|
|
21
|
+
console.log('Loading locales...');
|
|
22
|
+
if (!STAMHOOFD.translationNamespace) {
|
|
23
|
+
throw new Error('STAMHOOFD.translationNamespace is not set');
|
|
24
|
+
}
|
|
25
|
+
const directory = path_1.default.dirname(require.resolve('@stamhoofd/locales')) + '/' + STAMHOOFD.translationNamespace;
|
|
23
26
|
const files = (await fs_1.promises.readdir(directory, { withFileTypes: true }))
|
|
24
|
-
.filter(
|
|
27
|
+
.filter(dirent => !dirent.isDirectory());
|
|
25
28
|
for (const file of files) {
|
|
26
29
|
const locale = file.name.substr(0, file.name.length - 5);
|
|
27
|
-
|
|
28
|
-
const messages = await Promise.resolve(`${directory + "/" + file.name}`).then(s => tslib_1.__importStar(require(s)));
|
|
30
|
+
const messages = await Promise.resolve(`${directory + '/' + file.name}`).then(s => tslib_1.__importStar(require(s)));
|
|
29
31
|
this.loadedLocales.set(locale, this.loadRecursive(messages.default));
|
|
30
32
|
}
|
|
33
|
+
console.log('Loaded all locales');
|
|
31
34
|
});
|
|
32
35
|
}
|
|
33
36
|
static loadRecursive(messages, prefix = null) {
|
|
34
37
|
const map = new Map();
|
|
35
38
|
for (const key in messages) {
|
|
36
39
|
const element = messages[key];
|
|
37
|
-
if (typeof (element) !==
|
|
38
|
-
const map2 = this.loadRecursive(element, (prefix ? prefix +
|
|
40
|
+
if (typeof (element) !== 'string') {
|
|
41
|
+
const map2 = this.loadRecursive(element, (prefix ? prefix + '.' : '') + key);
|
|
39
42
|
map2.forEach((val, key) => map.set(key, val));
|
|
40
43
|
}
|
|
41
44
|
else {
|
|
42
|
-
map.set((prefix ? prefix +
|
|
45
|
+
map.set((prefix ? prefix + '.' : '') + key, element);
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
return map;
|
|
46
49
|
}
|
|
47
50
|
static isValidLocale(locale) {
|
|
48
|
-
if (locale.length == 5 && locale.substr(2, 1) ==
|
|
51
|
+
if (locale.length == 5 && locale.substr(2, 1) == '-') {
|
|
49
52
|
const l = locale.substr(0, 2).toLowerCase();
|
|
50
53
|
const c = locale.substr(3, 2).toUpperCase();
|
|
51
54
|
return locales_1.languages.includes(l) && locales_1.countries.includes(c);
|
|
52
55
|
}
|
|
53
56
|
return false;
|
|
54
57
|
}
|
|
55
|
-
language =
|
|
56
|
-
country =
|
|
58
|
+
language = '';
|
|
59
|
+
country = '';
|
|
57
60
|
// Reference to messages in loadedLocales
|
|
58
61
|
messages;
|
|
59
62
|
get locale() {
|
|
60
|
-
return this.language +
|
|
63
|
+
return this.language + '-' + this.country;
|
|
61
64
|
}
|
|
62
65
|
constructor(language, country) {
|
|
63
66
|
this.language = language;
|
|
@@ -65,7 +68,7 @@ class I18n {
|
|
|
65
68
|
this.correctLanguageCountryCombination();
|
|
66
69
|
const m = I18n.loadedLocales.get(this.locale);
|
|
67
70
|
if (!m) {
|
|
68
|
-
throw new Error(
|
|
71
|
+
throw new Error('Locale not loaded when creating I18n for ' + language + '-' + country);
|
|
69
72
|
}
|
|
70
73
|
this.messages = m;
|
|
71
74
|
}
|
|
@@ -101,7 +104,7 @@ class I18n {
|
|
|
101
104
|
this.correctLanguageCountryCombination();
|
|
102
105
|
const m = I18n.loadedLocales.get(this.locale);
|
|
103
106
|
if (!m) {
|
|
104
|
-
throw new Error(
|
|
107
|
+
throw new Error('Locale not loaded, when switching to locale ' + this.language + '-' + this.country);
|
|
105
108
|
}
|
|
106
109
|
this.messages = m;
|
|
107
110
|
}
|
|
@@ -110,8 +113,8 @@ class I18n {
|
|
|
110
113
|
return request._cached_i18n;
|
|
111
114
|
}
|
|
112
115
|
// Try using custom property
|
|
113
|
-
const localeHeader = request.headers[
|
|
114
|
-
if (localeHeader && typeof localeHeader ===
|
|
116
|
+
const localeHeader = request.headers['x-locale'];
|
|
117
|
+
if (localeHeader && typeof localeHeader === 'string' && this.isValidLocale(localeHeader)) {
|
|
115
118
|
const l = localeHeader.substr(0, 2).toLowerCase();
|
|
116
119
|
const c = localeHeader.substr(3, 2).toUpperCase();
|
|
117
120
|
const i18n = new I18n(l, c);
|
|
@@ -119,13 +122,13 @@ class I18n {
|
|
|
119
122
|
return i18n;
|
|
120
123
|
}
|
|
121
124
|
// Try using accept-language defaults
|
|
122
|
-
const acceptLanguage = request.headers[
|
|
125
|
+
const acceptLanguage = request.headers['accept-language'];
|
|
123
126
|
if (acceptLanguage) {
|
|
124
|
-
const splitted = acceptLanguage.split(
|
|
127
|
+
const splitted = acceptLanguage.split(',');
|
|
125
128
|
// Loop all countries and languages in the header, until we find a valid one
|
|
126
129
|
for (const item of splitted) {
|
|
127
130
|
const trimmed = item.trim();
|
|
128
|
-
const localeSplit = trimmed.split(
|
|
131
|
+
const localeSplit = trimmed.split(';');
|
|
129
132
|
const locale = localeSplit[0];
|
|
130
133
|
if (locale.length == 2) {
|
|
131
134
|
// Language
|
|
@@ -168,7 +171,7 @@ class I18n {
|
|
|
168
171
|
for (const key in replace) {
|
|
169
172
|
if (replace.hasOwnProperty(key)) {
|
|
170
173
|
const value = replace[key];
|
|
171
|
-
text = text.replace(new RegExp(
|
|
174
|
+
text = text.replace(new RegExp('{' + this.escapeRegex(key) + '}', 'g'), value);
|
|
172
175
|
}
|
|
173
176
|
}
|
|
174
177
|
return text;
|
package/dist/I18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18n.js","sourceRoot":"","sources":["../src/I18n.ts"],"names":[],"mappings":";;;;AACA,+DAAgE;AAChE,gDAA0D;AAC1D,sDAAgD;AAChD,2BAAoC;AACpC,wDAAwB;AAExB,MAAa,IAAI;IACb,MAAM,CAAC,aAAa,GAAqC,IAAI,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"I18n.js","sourceRoot":"","sources":["../src/I18n.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/backend-i18n",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.50.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"license": "UNLICENCED",
|
|
@@ -18,5 +18,5 @@
|
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "809b483cc6e98291fca589b1ac39aaa3a7fcf6f2"
|
|
22
22
|
}
|
package/src/I18n.ts
CHANGED
|
@@ -1,155 +1,162 @@
|
|
|
1
1
|
import { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
2
|
-
import { logger, StyledText } from
|
|
3
|
-
import { countries, languages } from
|
|
2
|
+
import { logger, StyledText } from '@simonbackx/simple-logging';
|
|
3
|
+
import { countries, languages } from '@stamhoofd/locales';
|
|
4
4
|
import { Country } from '@stamhoofd/structures';
|
|
5
|
-
import { promises as fs } from
|
|
6
|
-
import path from
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
7
|
|
|
8
8
|
export class I18n {
|
|
9
|
-
static loadedLocales: Map<string, Map<string, string>> = new Map()
|
|
10
|
-
static defaultLanguage =
|
|
11
|
-
static defaultCountry = Country.Belgium
|
|
9
|
+
static loadedLocales: Map<string, Map<string, string>> = new Map();
|
|
10
|
+
static defaultLanguage = 'nl';
|
|
11
|
+
static defaultCountry = Country.Belgium;
|
|
12
12
|
|
|
13
13
|
static async load() {
|
|
14
14
|
await logger.setContext({
|
|
15
15
|
prefixes: [
|
|
16
|
-
new StyledText('[I18n] ').addClass('i18n', 'tag')
|
|
16
|
+
new StyledText('[I18n] ').addClass('i18n', 'tag'),
|
|
17
17
|
],
|
|
18
|
-
tags: ['i18n']
|
|
18
|
+
tags: ['i18n'],
|
|
19
19
|
}, async () => {
|
|
20
|
-
console.log(
|
|
21
|
-
|
|
20
|
+
console.log('Loading locales...');
|
|
21
|
+
|
|
22
|
+
if (!STAMHOOFD.translationNamespace) {
|
|
23
|
+
throw new Error('STAMHOOFD.translationNamespace is not set');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const directory = path.dirname(require.resolve('@stamhoofd/locales')) + '/' + STAMHOOFD.translationNamespace;
|
|
22
27
|
const files = (await fs.readdir(directory, { withFileTypes: true }))
|
|
23
|
-
.filter(
|
|
28
|
+
.filter(dirent => !dirent.isDirectory());
|
|
24
29
|
|
|
25
|
-
for (const file of files
|
|
30
|
+
for (const file of files) {
|
|
26
31
|
const locale = file.name.substr(0, file.name.length - 5);
|
|
27
|
-
console.log("Loaded:" + locale)
|
|
28
32
|
|
|
29
|
-
const messages = await import(directory+
|
|
30
|
-
this.loadedLocales.set(locale, this.loadRecursive(messages.default))
|
|
33
|
+
const messages = await import(directory + '/' + file.name);
|
|
34
|
+
this.loadedLocales.set(locale, this.loadRecursive(messages.default));
|
|
31
35
|
}
|
|
32
|
-
|
|
36
|
+
|
|
37
|
+
console.log('Loaded all locales');
|
|
38
|
+
});
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
static loadRecursive(messages: any, prefix: string | null =
|
|
36
|
-
const map = new Map()
|
|
41
|
+
static loadRecursive(messages: any, prefix: string | null = null): Map<string, string> {
|
|
42
|
+
const map = new Map();
|
|
37
43
|
for (const key in messages) {
|
|
38
44
|
const element = messages[key];
|
|
39
|
-
if (typeof (element) !==
|
|
40
|
-
const map2 = this.loadRecursive(element, (prefix ? prefix +
|
|
45
|
+
if (typeof (element) !== 'string') {
|
|
46
|
+
const map2 = this.loadRecursive(element, (prefix ? prefix + '.' : '') + key);
|
|
41
47
|
map2.forEach((val, key) => map.set(key, val));
|
|
42
|
-
}
|
|
43
|
-
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
map.set((prefix ? prefix + '.' : '') + key, element);
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
return map;
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
static isValidLocale(locale: string) {
|
|
50
|
-
if (locale.length == 5 && locale.substr(2, 1) ==
|
|
51
|
-
const l = locale.substr(0, 2).toLowerCase()
|
|
52
|
-
const c = locale.substr(3, 2).toUpperCase()
|
|
57
|
+
if (locale.length == 5 && locale.substr(2, 1) == '-') {
|
|
58
|
+
const l = locale.substr(0, 2).toLowerCase();
|
|
59
|
+
const c = locale.substr(3, 2).toUpperCase();
|
|
53
60
|
|
|
54
|
-
return languages.includes(l) && countries.includes(c)
|
|
61
|
+
return languages.includes(l) && countries.includes(c);
|
|
55
62
|
}
|
|
56
|
-
return false
|
|
63
|
+
return false;
|
|
57
64
|
}
|
|
58
|
-
|
|
59
|
-
language =
|
|
60
|
-
country =
|
|
65
|
+
|
|
66
|
+
language = '';
|
|
67
|
+
country = '';
|
|
61
68
|
|
|
62
69
|
// Reference to messages in loadedLocales
|
|
63
|
-
messages: Map<string, string
|
|
70
|
+
messages: Map<string, string>;
|
|
64
71
|
|
|
65
72
|
get locale() {
|
|
66
|
-
return this.language+
|
|
73
|
+
return this.language + '-' + this.country;
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
constructor(language: string, country: string) {
|
|
70
|
-
this.language = language
|
|
71
|
-
this.country = country
|
|
72
|
-
this.correctLanguageCountryCombination()
|
|
77
|
+
this.language = language;
|
|
78
|
+
this.country = country;
|
|
79
|
+
this.correctLanguageCountryCombination();
|
|
73
80
|
|
|
74
|
-
const m = I18n.loadedLocales.get(this.locale)
|
|
81
|
+
const m = I18n.loadedLocales.get(this.locale);
|
|
75
82
|
if (!m) {
|
|
76
|
-
throw new Error(
|
|
83
|
+
throw new Error('Locale not loaded when creating I18n for ' + language + '-' + country);
|
|
77
84
|
}
|
|
78
85
|
|
|
79
|
-
this.messages = m
|
|
86
|
+
this.messages = m;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
correctLanguageCountryCombination() {
|
|
83
|
-
|
|
90
|
+
if (I18n.isValidLocale(this.locale)) {
|
|
84
91
|
return;
|
|
85
|
-
|
|
92
|
+
}
|
|
86
93
|
|
|
87
94
|
// Check language is valid
|
|
88
95
|
if (!languages.includes(this.language)) {
|
|
89
|
-
this.language = I18n.defaultLanguage
|
|
96
|
+
this.language = I18n.defaultLanguage;
|
|
90
97
|
|
|
91
98
|
if (I18n.isValidLocale(this.locale)) {
|
|
92
99
|
return;
|
|
93
100
|
}
|
|
94
|
-
this.country = I18n.defaultCountry
|
|
101
|
+
this.country = I18n.defaultCountry;
|
|
95
102
|
return;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
// Loop countries until valid
|
|
99
|
-
this.country = I18n.defaultCountry
|
|
106
|
+
this.country = I18n.defaultCountry;
|
|
100
107
|
while (!I18n.isValidLocale(this.locale)) {
|
|
101
|
-
const index = countries.indexOf(this.country)
|
|
108
|
+
const index = countries.indexOf(this.country);
|
|
102
109
|
if (index == countries.length - 1) {
|
|
103
110
|
// Last country
|
|
104
|
-
this.language = I18n.defaultLanguage
|
|
105
|
-
this.country = I18n.defaultCountry
|
|
111
|
+
this.language = I18n.defaultLanguage;
|
|
112
|
+
this.country = I18n.defaultCountry;
|
|
106
113
|
return;
|
|
107
114
|
}
|
|
108
|
-
this.country = countries[index + 1]
|
|
115
|
+
this.country = countries[index + 1];
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
switchToLocale(options: {
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
language?: string;
|
|
121
|
+
country?: string;
|
|
115
122
|
}) {
|
|
116
|
-
this.country = options.country ?? this.country
|
|
117
|
-
this.language = options.language ?? this.language
|
|
118
|
-
this.correctLanguageCountryCombination()
|
|
119
|
-
|
|
120
|
-
const m = I18n.loadedLocales.get(this.locale)
|
|
123
|
+
this.country = options.country ?? this.country;
|
|
124
|
+
this.language = options.language ?? this.language;
|
|
125
|
+
this.correctLanguageCountryCombination();
|
|
126
|
+
|
|
127
|
+
const m = I18n.loadedLocales.get(this.locale);
|
|
121
128
|
if (!m) {
|
|
122
|
-
throw new Error(
|
|
129
|
+
throw new Error('Locale not loaded, when switching to locale ' + this.language + '-' + this.country);
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
this.messages = m
|
|
132
|
+
this.messages = m;
|
|
126
133
|
}
|
|
127
134
|
|
|
128
|
-
static fromRequest(request: Request|DecodedRequest<any, any, any>): I18n {
|
|
135
|
+
static fromRequest(request: Request | DecodedRequest<any, any, any>): I18n {
|
|
129
136
|
if ((request as any)._cached_i18n) {
|
|
130
|
-
return (request as any)._cached_i18n
|
|
137
|
+
return (request as any)._cached_i18n;
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
// Try using custom property
|
|
134
|
-
const localeHeader = request.headers[
|
|
135
|
-
if (localeHeader && typeof localeHeader ===
|
|
136
|
-
const l = localeHeader.substr(0, 2).toLowerCase()
|
|
137
|
-
const c = localeHeader.substr(3, 2).toUpperCase()
|
|
138
|
-
|
|
141
|
+
const localeHeader = request.headers['x-locale'];
|
|
142
|
+
if (localeHeader && typeof localeHeader === 'string' && this.isValidLocale(localeHeader)) {
|
|
143
|
+
const l = localeHeader.substr(0, 2).toLowerCase();
|
|
144
|
+
const c = localeHeader.substr(3, 2).toUpperCase();
|
|
145
|
+
|
|
139
146
|
const i18n = new I18n(l, c);
|
|
140
147
|
(request as any)._cached_i18n = i18n;
|
|
141
148
|
return i18n;
|
|
142
149
|
}
|
|
143
150
|
|
|
144
151
|
// Try using accept-language defaults
|
|
145
|
-
const acceptLanguage = request.headers[
|
|
152
|
+
const acceptLanguage = request.headers['accept-language'];
|
|
146
153
|
if (acceptLanguage) {
|
|
147
|
-
const splitted = acceptLanguage.split(
|
|
154
|
+
const splitted = acceptLanguage.split(',');
|
|
148
155
|
|
|
149
156
|
// Loop all countries and languages in the header, until we find a valid one
|
|
150
157
|
for (const item of splitted) {
|
|
151
158
|
const trimmed = item.trim();
|
|
152
|
-
const localeSplit = trimmed.split(
|
|
159
|
+
const localeSplit = trimmed.split(';');
|
|
153
160
|
const locale = localeSplit[0];
|
|
154
161
|
|
|
155
162
|
if (locale.length == 2) {
|
|
@@ -160,18 +167,18 @@ export class I18n {
|
|
|
160
167
|
// using .setCountry(country) method
|
|
161
168
|
const i18n = new I18n(locale, Country.Belgium);
|
|
162
169
|
(request as any)._cached_i18n = i18n;
|
|
163
|
-
return i18n
|
|
170
|
+
return i18n;
|
|
164
171
|
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const
|
|
172
|
+
}
|
|
173
|
+
else if (locale.length === 5 && this.isValidLocale(locale)) {
|
|
174
|
+
const l = locale.substr(0, 2).toLowerCase();
|
|
175
|
+
const c = locale.substr(3, 2).toUpperCase();
|
|
168
176
|
|
|
169
177
|
// Lang + country
|
|
170
178
|
const i18n = new I18n(l, c);
|
|
171
179
|
(request as any)._cached_i18n = i18n;
|
|
172
|
-
return i18n
|
|
180
|
+
return i18n;
|
|
173
181
|
}
|
|
174
|
-
|
|
175
182
|
}
|
|
176
183
|
}
|
|
177
184
|
const i18n = new I18n(this.defaultLanguage, this.defaultCountry);
|
|
@@ -180,11 +187,11 @@ export class I18n {
|
|
|
180
187
|
}
|
|
181
188
|
|
|
182
189
|
t(key: string, replace?: Record<string, string>) {
|
|
183
|
-
return this.$t(key, replace)
|
|
190
|
+
return this.$t(key, replace);
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
$t(key: string, replace?: Record<string, string>) {
|
|
187
|
-
return this.replace(this.messages.get(key) ?? key, replace)
|
|
194
|
+
return this.replace(this.messages.get(key) ?? key, replace);
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
escapeRegex(string) {
|
|
@@ -193,15 +200,15 @@ export class I18n {
|
|
|
193
200
|
|
|
194
201
|
replace(text: string, replace?: Record<string, string>) {
|
|
195
202
|
if (!replace) {
|
|
196
|
-
return text
|
|
203
|
+
return text;
|
|
197
204
|
}
|
|
198
205
|
for (const key in replace) {
|
|
199
206
|
if (replace.hasOwnProperty(key)) {
|
|
200
207
|
const value = replace[key];
|
|
201
|
-
text = text.replace(new RegExp(
|
|
208
|
+
text = text.replace(new RegExp('{' + this.escapeRegex(key) + '}', 'g'), value);
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
|
-
return text
|
|
211
|
+
return text;
|
|
205
212
|
}
|
|
206
213
|
|
|
207
214
|
getDomain(localizedDomain: LocalizedDomain): string {
|
|
@@ -210,7 +217,7 @@ export class I18n {
|
|
|
210
217
|
|
|
211
218
|
localizedDomains = {
|
|
212
219
|
marketing: (): string => this.getDomain(STAMHOOFD.domains.marketing),
|
|
213
|
-
defaultTransactionalEmail: (): string => this.getDomain(STAMHOOFD.domains.defaultTransactionalEmail ?? {['']: 'stamhoofd.be'}),
|
|
214
|
-
defaultBroadcastEmail: (): string => this.getDomain(STAMHOOFD.domains.defaultBroadcastEmail?? {['']: 'stamhoofd.email'}),
|
|
215
|
-
}
|
|
220
|
+
defaultTransactionalEmail: (): string => this.getDomain(STAMHOOFD.domains.defaultTransactionalEmail ?? { ['']: 'stamhoofd.be' }),
|
|
221
|
+
defaultBroadcastEmail: (): string => this.getDomain(STAMHOOFD.domains.defaultBroadcastEmail ?? { ['']: 'stamhoofd.email' }),
|
|
222
|
+
};
|
|
216
223
|
}
|