@umituz/react-native-localization 2.3.0 → 2.4.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/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n Initializer
|
|
3
3
|
*
|
|
4
|
-
* Handles i18n configuration
|
|
5
|
-
* -
|
|
4
|
+
* Handles i18n configuration with namespace support
|
|
5
|
+
* - Loads package translations
|
|
6
|
+
* - Loads app translations (merges with package)
|
|
6
7
|
* - Namespace-based organization (common, auth, etc.)
|
|
7
|
-
* - React i18next integration
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import i18n from 'i18next';
|
|
@@ -18,46 +18,55 @@ export class I18nInitializer {
|
|
|
18
18
|
private static reactI18nextInitialized = false;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Build resources
|
|
21
|
+
* Build resources with package + app translations merged
|
|
22
22
|
*/
|
|
23
23
|
private static buildResources(): Record<string, Record<string, any>> {
|
|
24
24
|
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
25
|
+
const appTranslations = TranslationLoader.loadAppTranslations();
|
|
25
26
|
|
|
26
|
-
// Create namespace-based resources structure
|
|
27
27
|
const resources: Record<string, Record<string, any>> = {
|
|
28
28
|
'en-US': {},
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
// Package translations are already in namespace format (alerts, auth, etc.)
|
|
32
31
|
const enUSPackage = packageTranslations['en-US'] || {};
|
|
33
32
|
|
|
34
|
-
//
|
|
33
|
+
// Add package namespaces
|
|
35
34
|
for (const [namespace, translations] of Object.entries(enUSPackage)) {
|
|
36
35
|
resources['en-US'][namespace] = translations;
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
// Merge app namespaces (app overrides package)
|
|
39
|
+
for (const [namespace, translations] of Object.entries(appTranslations)) {
|
|
40
|
+
if (resources['en-US'][namespace]) {
|
|
41
|
+
resources['en-US'][namespace] = TranslationLoader.mergeTranslations(
|
|
42
|
+
resources['en-US'][namespace],
|
|
43
|
+
translations
|
|
44
|
+
);
|
|
45
|
+
} else {
|
|
46
|
+
resources['en-US'][namespace] = translations;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
39
50
|
return resources;
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
/**
|
|
43
|
-
* Get all available namespaces from package translations
|
|
44
|
-
*/
|
|
45
53
|
private static getNamespaces(): string[] {
|
|
46
54
|
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
55
|
+
const appTranslations = TranslationLoader.loadAppTranslations();
|
|
56
|
+
|
|
47
57
|
const enUSPackage = packageTranslations['en-US'] || {};
|
|
48
|
-
const namespaces =
|
|
58
|
+
const namespaces = new Set([
|
|
59
|
+
...Object.keys(enUSPackage),
|
|
60
|
+
...Object.keys(appTranslations),
|
|
61
|
+
]);
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
namespaces.unshift(DEFAULT_NAMESPACE);
|
|
63
|
+
if (!namespaces.has(DEFAULT_NAMESPACE)) {
|
|
64
|
+
namespaces.add(DEFAULT_NAMESPACE);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
|
-
return namespaces;
|
|
67
|
+
return Array.from(namespaces);
|
|
56
68
|
}
|
|
57
69
|
|
|
58
|
-
/**
|
|
59
|
-
* Initialize i18next with namespace support
|
|
60
|
-
*/
|
|
61
70
|
static initialize(): void {
|
|
62
71
|
if (i18n.isInitialized) {
|
|
63
72
|
return;
|
|
@@ -79,37 +88,25 @@ export class I18nInitializer {
|
|
|
79
88
|
ns: namespaces,
|
|
80
89
|
defaultNS: DEFAULT_NAMESPACE,
|
|
81
90
|
fallbackNS: DEFAULT_NAMESPACE,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
escapeValue: false,
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
react: {
|
|
88
|
-
useSuspense: false,
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
+
interpolation: { escapeValue: false },
|
|
92
|
+
react: { useSuspense: false },
|
|
91
93
|
compatibilityJSON: 'v3',
|
|
92
94
|
pluralSeparator: '_',
|
|
93
95
|
keySeparator: '.',
|
|
94
96
|
nsSeparator: ':',
|
|
95
|
-
|
|
96
97
|
saveMissing: false,
|
|
97
98
|
missingKeyHandler: false,
|
|
98
|
-
|
|
99
99
|
debug: false,
|
|
100
100
|
});
|
|
101
|
-
|
|
102
101
|
} catch (error) {
|
|
103
102
|
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
104
|
-
console.error('[Localization]
|
|
103
|
+
console.error('[Localization] init error:', error);
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
/**
|
|
110
|
-
* Add
|
|
111
|
-
* @param languageCode - Language code (e.g., 'en-US')
|
|
112
|
-
* @param namespaceResources - Object with namespace keys and translation objects
|
|
109
|
+
* Add translation resources at runtime
|
|
113
110
|
*/
|
|
114
111
|
static addTranslationResources(
|
|
115
112
|
languageCode: string,
|
|
@@ -1,58 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Translation Loader
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Loads translations from package and app
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export class TranslationLoader {
|
|
8
8
|
/**
|
|
9
|
-
* Load package translations (en-US
|
|
9
|
+
* Load package translations (en-US)
|
|
10
10
|
*/
|
|
11
11
|
static loadPackageTranslations(): Record<string, any> {
|
|
12
12
|
try {
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
14
14
|
const translations = require('../locales/en-US');
|
|
15
15
|
return { 'en-US': translations.default || translations };
|
|
16
|
-
} catch
|
|
16
|
+
} catch {
|
|
17
17
|
return { 'en-US': {} };
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Load app translations from common paths
|
|
23
23
|
*/
|
|
24
|
-
static
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
static loadAppTranslations(): Record<string, any> {
|
|
25
|
+
const paths = [
|
|
26
|
+
'@/domains/localization/infrastructure/locales/en-US',
|
|
27
|
+
'./src/domains/localization/infrastructure/locales/en-US',
|
|
28
|
+
'../../../src/domains/localization/infrastructure/locales/en-US',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
for (const path of paths) {
|
|
32
|
+
try {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
34
|
+
const translations = require(path);
|
|
35
|
+
return translations.default || translations;
|
|
36
|
+
} catch {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Deep merge translations (app overrides package)
|
|
46
|
+
*/
|
|
47
|
+
static mergeTranslations(base: any, override: any): any {
|
|
48
|
+
if (!override || Object.keys(override).length === 0) {
|
|
49
|
+
return base;
|
|
30
50
|
}
|
|
31
51
|
|
|
32
|
-
const merged = { ...
|
|
33
|
-
|
|
34
|
-
for (const key in
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
packageTranslations[key] !== null &&
|
|
42
|
-
!Array.isArray(packageTranslations[key])
|
|
43
|
-
) {
|
|
44
|
-
// Deep merge nested objects
|
|
45
|
-
merged[key] = this.mergeTranslations(
|
|
46
|
-
packageTranslations[key],
|
|
47
|
-
projectTranslations[key]
|
|
48
|
-
);
|
|
52
|
+
const merged = { ...base };
|
|
53
|
+
|
|
54
|
+
for (const key in override) {
|
|
55
|
+
if (Object.prototype.hasOwnProperty.call(override, key)) {
|
|
56
|
+
const baseVal = base[key];
|
|
57
|
+
const overrideVal = override[key];
|
|
58
|
+
|
|
59
|
+
if (this.isObject(baseVal) && this.isObject(overrideVal)) {
|
|
60
|
+
merged[key] = this.mergeTranslations(baseVal, overrideVal);
|
|
49
61
|
} else {
|
|
50
|
-
|
|
51
|
-
merged[key] = projectTranslations[key];
|
|
62
|
+
merged[key] = overrideVal;
|
|
52
63
|
}
|
|
53
64
|
}
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
return merged;
|
|
57
68
|
}
|
|
69
|
+
|
|
70
|
+
private static isObject(val: any): boolean {
|
|
71
|
+
return val !== null && typeof val === 'object' && !Array.isArray(val);
|
|
72
|
+
}
|
|
58
73
|
}
|