react-localization 2.0.5 → 2.1.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/CHANGELOG.md +69 -0
- package/README.md +10 -0
- package/lib/react-localization.d.ts +5 -1
- package/lib/react-localization.es.js +150 -183
- package/lib/react-localization.umd.cjs +1 -0
- package/package.json +21 -17
- package/lib/react-localization.umd.js +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [2.1.0] - 2026-10-04
|
|
9
|
+
|
|
10
|
+
Behaviour of `formatString` is now aligned with the
|
|
11
|
+
[`localized-strings`](https://github.com/stefalda/localized-strings) package,
|
|
12
|
+
which this library builds upon. The override still exists only to add React
|
|
13
|
+
(JSX) interpolation, but it no longer drops the base package features.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `formatString` now expands `$ref{key}` references, e.g.
|
|
18
|
+
`strings.formatString(strings.questionWithReferences)`.
|
|
19
|
+
- `formatString` accepts a string key directly, with dot-notation support, e.g.
|
|
20
|
+
`strings.formatString("fridge.bread")`.
|
|
21
|
+
- `getContent()` added to the public TypeScript types (aligned with
|
|
22
|
+
`localized-strings` 2.1.x).
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `$ref{key}` placeholders are no longer silently dropped. Previously the inner
|
|
27
|
+
`{key}` was treated as an unknown named placeholder and removed from the
|
|
28
|
+
output.
|
|
29
|
+
- `require("react-localization")` now returns the library instead of an empty
|
|
30
|
+
object. The UMD bundle is emitted as `.cjs` and `main`/`exports.require` point
|
|
31
|
+
to it; previously the `require` entry resolved to an ES module that could not
|
|
32
|
+
be loaded as CommonJS.
|
|
33
|
+
- `getString()` is now correctly typed as returning `string | null`.
|
|
34
|
+
- The placeholder regular expression no longer contains a literal `|`
|
|
35
|
+
(`/(\{[\d|\w]+\})/` → `/(\{\w+\})/`).
|
|
36
|
+
- Tests work again with jsdom 30, where `navigator` is a getter-only property
|
|
37
|
+
(`vi.stubGlobal` is used instead of direct assignment).
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- React element interpolation now uses `React.cloneElement` to assign keys
|
|
42
|
+
instead of spreading the element object, which is discouraged in React 19.
|
|
43
|
+
- The test suite runs against `src/` through a Vitest alias instead of the
|
|
44
|
+
built `lib/` artifact, so a stale build can no longer make the suite pass or
|
|
45
|
+
fail incorrectly.
|
|
46
|
+
- `npm test` runs the suite once (`vitest run`); `npm run test:watch` is
|
|
47
|
+
available for watch mode.
|
|
48
|
+
- The library instance's `formatString` is now a regular method (previously an
|
|
49
|
+
arrow function) so it can access the instance for `$ref`/key resolution.
|
|
50
|
+
|
|
51
|
+
### Dependencies
|
|
52
|
+
|
|
53
|
+
- `localized-strings`: `^2.0.3` → `^2.1.2`
|
|
54
|
+
- `typescript`: `^5.7.3` → `^6.0.3`
|
|
55
|
+
- `react` / `react-dom`: `^19.0.0` → `^19.3.0`
|
|
56
|
+
- `@types/react` / `@types/react-dom`: `^19.0.4` / `^19.0.2` → `^19.3.0`
|
|
57
|
+
- `@types/node`: `^22.10.5` → `^26.6.4`
|
|
58
|
+
- `vite`: `^6.0.7` → `^8.3.2`
|
|
59
|
+
- `vitest`: `^2.1.8` → `^5.0.3`
|
|
60
|
+
- `@vitejs/plugin-react`: `^4.3.4` → `^6.1.1`
|
|
61
|
+
- `jsdom`: `^26.0.0` → `^30.1.1`
|
|
62
|
+
- `@testing-library/react`: `^16.1.0` → `^16.3.3`
|
|
63
|
+
|
|
64
|
+
### Notes
|
|
65
|
+
|
|
66
|
+
- TypeScript 6 requires an explicit `rootDir` when `declarationDir` is used.
|
|
67
|
+
- The Vite config now uses `import.meta.dirname` instead of `__dirname`.
|
|
68
|
+
|
|
69
|
+
[2.1.0]: https://github.com/stefalda/react-localization/compare/v2.0.6...v2.1.0
|
package/README.md
CHANGED
|
@@ -126,6 +126,13 @@ strings.setContent({
|
|
|
126
126
|
day: 12,
|
|
127
127
|
year: 2018
|
|
128
128
|
})
|
|
129
|
+
|
|
130
|
+
// A key can also be passed directly (dot-notation is supported)
|
|
131
|
+
strings.formatString('fridge.bread')
|
|
132
|
+
|
|
133
|
+
// Other localized strings can be referenced with $ref{key}
|
|
134
|
+
// en: { bread: 'bread', questionWithReferences: 'I\'d like $ref{bread}' }
|
|
135
|
+
strings.formatString(strings.questionWithReferences)
|
|
129
136
|
```
|
|
130
137
|
|
|
131
138
|
Typical usage is to render it in a JSX with `formatString` calls inlined:
|
|
@@ -149,6 +156,9 @@ Typical usage is to render it in a JSX with `formatString` calls inlined:
|
|
|
149
156
|
**Beware: do not define a string key as formatString!**
|
|
150
157
|
|
|
151
158
|
- setContent(props) - to dynamically load another set of strings
|
|
159
|
+
- getContent() - to get the whole content object (all languages/strings)
|
|
160
|
+
- getString(key, language?, omitWarning?) - to get a single string, dot-notation
|
|
161
|
+
supported
|
|
152
162
|
- getAvailableLanguages() - to get an array of the languages passed in the
|
|
153
163
|
constructor
|
|
154
164
|
|
|
@@ -39,12 +39,16 @@ declare module 'react-localization' {
|
|
|
39
39
|
* @param key
|
|
40
40
|
* @param language
|
|
41
41
|
*/
|
|
42
|
-
getString(key: string, language?: string, omitWarning?: boolean): string;
|
|
42
|
+
getString(key: string, language?: string | null, omitWarning?: boolean): string | null;
|
|
43
43
|
/**
|
|
44
44
|
* Replace the NamedLocalization object without reinstantiating the object
|
|
45
45
|
* @param props
|
|
46
46
|
*/
|
|
47
47
|
setContent(props: any): void;
|
|
48
|
+
/**
|
|
49
|
+
* Return the whole content object (all the languages/strings)
|
|
50
|
+
*/
|
|
51
|
+
getContent(): GlobalStrings<any>;
|
|
48
52
|
}
|
|
49
53
|
export type LocalizedStrings<T> = LocalizedStringsMethods & T;
|
|
50
54
|
type GetInterfaceLanguageCallback = () => string;
|
|
@@ -1,188 +1,155 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return e.userLanguage;
|
|
15
|
-
if ("browserLanguage" in e)
|
|
16
|
-
return e.browserLanguage;
|
|
17
|
-
}
|
|
18
|
-
return n;
|
|
1
|
+
import e from "react";
|
|
2
|
+
//#region node_modules/localized-strings/lib/LocalizedStrings.es.js
|
|
3
|
+
function t() {
|
|
4
|
+
let e = "en-US";
|
|
5
|
+
if (typeof navigator > "u") return e;
|
|
6
|
+
let t = navigator;
|
|
7
|
+
if (t) {
|
|
8
|
+
if (t.language) return t.language;
|
|
9
|
+
if (t.languages && t.languages[0]) return t.languages[0];
|
|
10
|
+
if ("userLanguage" in t) return t.userLanguage;
|
|
11
|
+
if ("browserLanguage" in t) return t.browserLanguage;
|
|
12
|
+
}
|
|
13
|
+
return e;
|
|
19
14
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
function n(e, t) {
|
|
16
|
+
if (t[e]) return e;
|
|
17
|
+
let n = e.indexOf("-"), r = n >= 0 ? e.substring(0, n) : e;
|
|
18
|
+
return t[r] ? r : Object.keys(t)[0];
|
|
24
19
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
20
|
+
function r(e) {
|
|
21
|
+
let t = [
|
|
22
|
+
"_interfaceLanguage",
|
|
23
|
+
"_language",
|
|
24
|
+
"_defaultLanguage",
|
|
25
|
+
"_defaultLanguageFirstLevelKeys",
|
|
26
|
+
"_props"
|
|
27
|
+
];
|
|
28
|
+
e.forEach((e) => {
|
|
29
|
+
if (t.indexOf(e) !== -1) throw Error(`${e} cannot be used as a key. It is a reserved word.`);
|
|
30
|
+
});
|
|
37
31
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
e += t.charAt(Math.floor(Math.random() * t.length));
|
|
43
|
-
return e;
|
|
32
|
+
function i(e) {
|
|
33
|
+
let t = "";
|
|
34
|
+
for (let n = 0; n < e; n += 1) t += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(Math.random() * 62));
|
|
35
|
+
return t;
|
|
44
36
|
}
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
getContent() {
|
|
163
|
-
return this._props;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const h = /(\{[\d|\w]+\})/;
|
|
167
|
-
m.prototype.formatString = (n, ...e) => {
|
|
168
|
-
let t = !1;
|
|
169
|
-
const a = (n || "").split(h).filter((s) => !!s).map((s, r) => {
|
|
170
|
-
if (s.match(h)) {
|
|
171
|
-
const i = s.slice(1, -1);
|
|
172
|
-
let u = e[i];
|
|
173
|
-
if (u == null) {
|
|
174
|
-
const g = e[0] ? e[0][i] : void 0;
|
|
175
|
-
if (g !== void 0)
|
|
176
|
-
u = g;
|
|
177
|
-
else
|
|
178
|
-
return u;
|
|
179
|
-
}
|
|
180
|
-
return c.isValidElement(u) ? (t = !0, c.Children.toArray(u).map((g) => ({ ...g, key: r.toString() }))) : u;
|
|
181
|
-
}
|
|
182
|
-
return s;
|
|
183
|
-
});
|
|
184
|
-
return t ? a : a.join("");
|
|
185
|
-
};
|
|
186
|
-
export {
|
|
187
|
-
m as default
|
|
37
|
+
var a = /(\{[\d|\w]+\})/, o = /(\$ref\{[\w|.]+\})/, s = class {
|
|
38
|
+
_opts;
|
|
39
|
+
_interfaceLanguage;
|
|
40
|
+
_language;
|
|
41
|
+
_defaultLanguage;
|
|
42
|
+
_defaultLanguageFirstLevelKeys;
|
|
43
|
+
_props;
|
|
44
|
+
_availableLanguages;
|
|
45
|
+
constructor(e, n) {
|
|
46
|
+
typeof n == "function" && (n = { customLanguageInterface: n }), this._opts = {
|
|
47
|
+
customLanguageInterface: t,
|
|
48
|
+
pseudo: !1,
|
|
49
|
+
pseudoMultipleLanguages: !1,
|
|
50
|
+
logsEnabled: !0,
|
|
51
|
+
...n
|
|
52
|
+
}, this._interfaceLanguage = this._opts.customLanguageInterface(), this._language = this._interfaceLanguage, this.setContent(e);
|
|
53
|
+
}
|
|
54
|
+
setContent(e) {
|
|
55
|
+
let [t] = Object.keys(e);
|
|
56
|
+
this._defaultLanguage = t, this._defaultLanguageFirstLevelKeys = [], this._props = e, r(Object.keys(e[this._defaultLanguage])), Object.keys(this._props[this._defaultLanguage]).forEach((e) => {
|
|
57
|
+
typeof this._props[this._defaultLanguage][e] == "string" && this._defaultLanguageFirstLevelKeys.push(e);
|
|
58
|
+
}), this.setLanguage(this._interfaceLanguage), this._opts.pseudo && this._pseudoAllValues(this._props);
|
|
59
|
+
}
|
|
60
|
+
_pseudoAllValues(e) {
|
|
61
|
+
Object.keys(e).forEach((t) => {
|
|
62
|
+
if (typeof e[t] == "object") this._pseudoAllValues(e[t]);
|
|
63
|
+
else if (typeof e[t] == "string") {
|
|
64
|
+
if (e[t].indexOf("[") === 0 && e[t].lastIndexOf("]") === e[t].length - 1) return;
|
|
65
|
+
let n = e[t].split(" ");
|
|
66
|
+
for (let e = 0; e < n.length; e += 1) {
|
|
67
|
+
if (n[e].match(a) || n[e].match(o)) continue;
|
|
68
|
+
let t = n[e].length;
|
|
69
|
+
this._opts.pseudoMultipleLanguages && (t = Math.floor(t * 1.4)), n[e] = i(t);
|
|
70
|
+
}
|
|
71
|
+
e[t] = `[${n.join(" ")}]`;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
setLanguage(e) {
|
|
76
|
+
let t = n(e, this._props), r = Object.keys(this._props)[0];
|
|
77
|
+
if (this._language = t, this._props[t]) {
|
|
78
|
+
for (let e of this._defaultLanguageFirstLevelKeys) delete this[e];
|
|
79
|
+
let e = { ...this._props[this._language] };
|
|
80
|
+
Object.keys(e).forEach((t) => {
|
|
81
|
+
this[t] = e[t];
|
|
82
|
+
}), r !== this._language && (e = this._props[r], this._fallbackValues(e, this));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
_fallbackValues(e, t) {
|
|
86
|
+
Object.keys(e).forEach((n) => {
|
|
87
|
+
Object.prototype.hasOwnProperty.call(e, n) && !t[n] && t[n] !== "" ? (t[n] = e[n], this._opts.logsEnabled && console.log(`🚧 👷 key '${n}' not found in localizedStrings for language ${this._language} 🚧`)) : typeof t[n] != "string" && this._fallbackValues(e[n], t[n]);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
getLanguage() {
|
|
91
|
+
return this._language;
|
|
92
|
+
}
|
|
93
|
+
getInterfaceLanguage() {
|
|
94
|
+
return this._interfaceLanguage;
|
|
95
|
+
}
|
|
96
|
+
getAvailableLanguages() {
|
|
97
|
+
return this._availableLanguages ||= Object.keys(this._props), this._availableLanguages;
|
|
98
|
+
}
|
|
99
|
+
formatString(e, ...t) {
|
|
100
|
+
let n = e || "";
|
|
101
|
+
return typeof n == "string" && (n = this.getString(e, null, !0) || n), n.split(o).filter(Boolean).map((t) => {
|
|
102
|
+
if (t.match(o)) {
|
|
103
|
+
let n = t.slice(5, -1);
|
|
104
|
+
return this.getString(n) || (this._opts.logsEnabled && console.log(`No Localization ref found for '${t}' in string '${e}'`), `$ref(id:${n})`);
|
|
105
|
+
}
|
|
106
|
+
return t;
|
|
107
|
+
}).join("").split(a).filter(Boolean).map((e) => {
|
|
108
|
+
if (e.match(a)) {
|
|
109
|
+
let n = e.slice(1, -1), r = t[n];
|
|
110
|
+
return r === void 0 && t[0] && (r = t[0][n]), r;
|
|
111
|
+
}
|
|
112
|
+
return e;
|
|
113
|
+
}).join("");
|
|
114
|
+
}
|
|
115
|
+
getString(e, t, n = !1) {
|
|
116
|
+
try {
|
|
117
|
+
let n = this._props[t || this._language], r = e.split(".");
|
|
118
|
+
for (let e of r) {
|
|
119
|
+
if (n[e] === void 0) throw Error(e);
|
|
120
|
+
n = n[e];
|
|
121
|
+
}
|
|
122
|
+
return n;
|
|
123
|
+
} catch (r) {
|
|
124
|
+
!n && this._opts.logsEnabled && console.log(`No localization found for key '${e}' and language '${t}', failed on ${r.message}`);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
getContent() {
|
|
129
|
+
return this._props;
|
|
130
|
+
}
|
|
131
|
+
}, c = /(\{\w+\})/, l = /(\$ref\{[\w|.]+\})/;
|
|
132
|
+
s.prototype.formatString = function(t, ...n) {
|
|
133
|
+
let r = (t ? this.getString(t, null, !0) || t : "").split(l).filter((e) => !!e).map((e) => {
|
|
134
|
+
if (e.match(l)) {
|
|
135
|
+
let t = e.slice(5, -1);
|
|
136
|
+
return this.getString(t) || `$ref(id:${t})`;
|
|
137
|
+
}
|
|
138
|
+
return e;
|
|
139
|
+
}).join(""), i = !1, a = r.split(c).filter((e) => !!e).map((t, r) => {
|
|
140
|
+
if (t.match(c)) {
|
|
141
|
+
let a = t.slice(1, -1), o = n[a];
|
|
142
|
+
if (o == null) {
|
|
143
|
+
let e = n[0] ? n[0][a] : void 0;
|
|
144
|
+
if (e !== void 0) o = e;
|
|
145
|
+
else return o;
|
|
146
|
+
}
|
|
147
|
+
return e.isValidElement(o) ? (i = !0, e.Children.toArray(o).map((t) => e.cloneElement(t, { key: r.toString() }))) : o;
|
|
148
|
+
}
|
|
149
|
+
return t;
|
|
150
|
+
});
|
|
151
|
+
return i ? a : a.join("");
|
|
188
152
|
};
|
|
153
|
+
var u = s;
|
|
154
|
+
//#endregion
|
|
155
|
+
export { u as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t(require("react")):typeof define==`function`&&define.amd?define([`react`],t):(e=typeof globalThis<`u`?globalThis:e||self,e.ReactLocalization=t(e.React))})(this,function(e){var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;l<u;l++)d=c[l],!o.call(e,d)&&d!==a&&n(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e};e=((e,r,i)=>(i=e==null?{}:t(a(e)),s(r||!e||!e.__esModule||!o.call(e,`default`)?n(i,`default`,{value:e,enumerable:!0}):i,e)))(e,1);function c(){let e=`en-US`;if(typeof navigator>`u`)return e;let t=navigator;if(t){if(t.language)return t.language;if(t.languages&&t.languages[0])return t.languages[0];if(`userLanguage`in t)return t.userLanguage;if(`browserLanguage`in t)return t.browserLanguage}return e}function l(e,t){if(t[e])return e;let n=e.indexOf(`-`),r=n>=0?e.substring(0,n):e;return t[r]?r:Object.keys(t)[0]}function u(e){let t=[`_interfaceLanguage`,`_language`,`_defaultLanguage`,`_defaultLanguageFirstLevelKeys`,`_props`];e.forEach(e=>{if(t.indexOf(e)!==-1)throw Error(`${e} cannot be used as a key. It is a reserved word.`)})}function d(e){let t=``;for(let n=0;n<e;n+=1)t+=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`.charAt(Math.floor(Math.random()*62));return t}var f=/(\{[\d|\w]+\})/,p=/(\$ref\{[\w|.]+\})/,m=class{_opts;_interfaceLanguage;_language;_defaultLanguage;_defaultLanguageFirstLevelKeys;_props;_availableLanguages;constructor(e,t){typeof t==`function`&&(t={customLanguageInterface:t}),this._opts={customLanguageInterface:c,pseudo:!1,pseudoMultipleLanguages:!1,logsEnabled:!0,...t},this._interfaceLanguage=this._opts.customLanguageInterface(),this._language=this._interfaceLanguage,this.setContent(e)}setContent(e){let[t]=Object.keys(e);this._defaultLanguage=t,this._defaultLanguageFirstLevelKeys=[],this._props=e,u(Object.keys(e[this._defaultLanguage])),Object.keys(this._props[this._defaultLanguage]).forEach(e=>{typeof this._props[this._defaultLanguage][e]==`string`&&this._defaultLanguageFirstLevelKeys.push(e)}),this.setLanguage(this._interfaceLanguage),this._opts.pseudo&&this._pseudoAllValues(this._props)}_pseudoAllValues(e){Object.keys(e).forEach(t=>{if(typeof e[t]==`object`)this._pseudoAllValues(e[t]);else if(typeof e[t]==`string`){if(e[t].indexOf(`[`)===0&&e[t].lastIndexOf(`]`)===e[t].length-1)return;let n=e[t].split(` `);for(let e=0;e<n.length;e+=1){if(n[e].match(f)||n[e].match(p))continue;let t=n[e].length;this._opts.pseudoMultipleLanguages&&(t=Math.floor(t*1.4)),n[e]=d(t)}e[t]=`[${n.join(` `)}]`}})}setLanguage(e){let t=l(e,this._props),n=Object.keys(this._props)[0];if(this._language=t,this._props[t]){for(let e of this._defaultLanguageFirstLevelKeys)delete this[e];let e={...this._props[this._language]};Object.keys(e).forEach(t=>{this[t]=e[t]}),n!==this._language&&(e=this._props[n],this._fallbackValues(e,this))}}_fallbackValues(e,t){Object.keys(e).forEach(n=>{Object.prototype.hasOwnProperty.call(e,n)&&!t[n]&&t[n]!==``?(t[n]=e[n],this._opts.logsEnabled&&console.log(`🚧 👷 key '${n}' not found in localizedStrings for language ${this._language} 🚧`)):typeof t[n]!=`string`&&this._fallbackValues(e[n],t[n])})}getLanguage(){return this._language}getInterfaceLanguage(){return this._interfaceLanguage}getAvailableLanguages(){return this._availableLanguages||=Object.keys(this._props),this._availableLanguages}formatString(e,...t){let n=e||``;return typeof n==`string`&&(n=this.getString(e,null,!0)||n),n.split(p).filter(Boolean).map(t=>{if(t.match(p)){let n=t.slice(5,-1);return this.getString(n)||(this._opts.logsEnabled&&console.log(`No Localization ref found for '${t}' in string '${e}'`),`$ref(id:${n})`)}return t}).join(``).split(f).filter(Boolean).map(e=>{if(e.match(f)){let n=e.slice(1,-1),r=t[n];return r===void 0&&t[0]&&(r=t[0][n]),r}return e}).join(``)}getString(e,t,n=!1){try{let n=this._props[t||this._language],r=e.split(`.`);for(let e of r){if(n[e]===void 0)throw Error(e);n=n[e]}return n}catch(r){!n&&this._opts.logsEnabled&&console.log(`No localization found for key '${e}' and language '${t}', failed on ${r.message}`)}return null}getContent(){return this._props}},h=/(\{\w+\})/,g=/(\$ref\{[\w|.]+\})/;return m.prototype.formatString=function(t,...n){let r=(t?this.getString(t,null,!0)||t:``).split(g).filter(e=>!!e).map(e=>{if(e.match(g)){let t=e.slice(5,-1);return this.getString(t)||`$ref(id:${t})`}return e}).join(``),i=!1,a=r.split(h).filter(e=>!!e).map((t,r)=>{if(t.match(h)){let a=t.slice(1,-1),o=n[a];if(o==null){let e=n[0]?n[0][a]:void 0;if(e!==void 0)o=e;else return o}return e.default.isValidElement(o)?(i=!0,e.default.Children.toArray(o).map(t=>e.default.cloneElement(t,{key:r.toString()}))):o}return t});return i?a:a.join(``)},m});
|
package/package.json
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-localization",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Simple module to localize the React interface using the same syntax used in the ReactNativeLocalization module",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./lib/react-localization.umd.
|
|
6
|
+
"main": "./lib/react-localization.umd.cjs",
|
|
7
7
|
"module": "./lib/react-localization.es.js",
|
|
8
8
|
"types": "./lib/react-localization.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"
|
|
11
|
+
"types": "./lib/react-localization.d.ts",
|
|
12
|
+
"import": "./lib/react-localization.es.js",
|
|
13
|
+
"require": "./lib/react-localization.umd.cjs"
|
|
12
14
|
}
|
|
13
15
|
},
|
|
14
16
|
"files": [
|
|
15
|
-
"lib"
|
|
17
|
+
"lib",
|
|
18
|
+
"CHANGELOG.md"
|
|
16
19
|
],
|
|
17
20
|
"scripts": {
|
|
18
21
|
"dev": "vite",
|
|
19
|
-
"test": "vitest",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
20
24
|
"prepare": "npm run build",
|
|
21
25
|
"build:vite": "vite build",
|
|
22
26
|
"build:types": "tsc --emitDeclarationOnly",
|
|
@@ -45,20 +49,20 @@
|
|
|
45
49
|
"react-dom": ">=19.0.0"
|
|
46
50
|
},
|
|
47
51
|
"devDependencies": {
|
|
48
|
-
"@testing-library/react": "^16.
|
|
49
|
-
"@types/node": "^
|
|
50
|
-
"@types/react": "^19.0
|
|
51
|
-
"@types/react-dom": "^19.0
|
|
52
|
-
"@vitejs/plugin-react": "^
|
|
53
|
-
"react": "^19.
|
|
54
|
-
"react-dom": "^19.
|
|
55
|
-
"typescript": "^
|
|
56
|
-
"vite": "^
|
|
57
|
-
"vitest": "^
|
|
58
|
-
"jsdom": "^
|
|
52
|
+
"@testing-library/react": "^16.3.3",
|
|
53
|
+
"@types/node": "^26.6.4",
|
|
54
|
+
"@types/react": "^19.3.0",
|
|
55
|
+
"@types/react-dom": "^19.3.0",
|
|
56
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
57
|
+
"react": "^19.3.0",
|
|
58
|
+
"react-dom": "^19.3.0",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vite": "^8.3.2",
|
|
61
|
+
"vitest": "^5.0.3",
|
|
62
|
+
"jsdom": "^30.1.1"
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
61
|
-
"localized-strings": "^2.
|
|
65
|
+
"localized-strings": "^2.1.2"
|
|
62
66
|
},
|
|
63
67
|
"peerDependenciesMeta": {
|
|
64
68
|
"react": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(o,g){typeof exports=="object"&&typeof module<"u"?module.exports=g(require("react")):typeof define=="function"&&define.amd?define(["react"],g):(o=typeof globalThis<"u"?globalThis:o||self,o.ReactLocalization=g(o.React))})(this,function(o){"use strict";var g=Object.defineProperty,_=(s,e,t)=>e in s?g(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,u=(s,e,t)=>_(s,typeof e!="symbol"?e+"":e,t);function L(){const s="en-US";if(typeof navigator>"u")return s;const e=navigator;if(e){if(e.language)return e.language;if(e.languages&&e.languages[0])return e.languages[0];if("userLanguage"in e)return e.userLanguage;if("browserLanguage"in e)return e.browserLanguage}return s}function y(s,e){if(e[s])return s;const t=s.indexOf("-"),a=t>=0?s.substring(0,t):s;return e[a]?a:Object.keys(e)[0]}function b(s){const e=["_interfaceLanguage","_language","_defaultLanguage","_defaultLanguageFirstLevelKeys","_props"];s.forEach(t=>{if(e.indexOf(t)!==-1)throw new Error(`${t} cannot be used as a key. It is a reserved word.`)})}function m(s){let e="";const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let a=0;a<s;a+=1)e+=t.charAt(Math.floor(Math.random()*t.length));return e}const c=/(\{[\d|\w]+\})/,h=/(\$ref\{[\w|.]+\})/;class p{constructor(e,t){u(this,"_opts"),u(this,"_interfaceLanguage"),u(this,"_language"),u(this,"_defaultLanguage"),u(this,"_defaultLanguageFirstLevelKeys"),u(this,"_props"),u(this,"_availableLanguages"),typeof t=="function"&&(t={customLanguageInterface:t}),this._opts={customLanguageInterface:L,pseudo:!1,pseudoMultipleLanguages:!1,logsEnabled:!0,...t},this._interfaceLanguage=this._opts.customLanguageInterface(),this._language=this._interfaceLanguage,this.setContent(e)}setContent(e){const[t]=Object.keys(e);this._defaultLanguage=t,this._defaultLanguageFirstLevelKeys=[],this._props=e,b(Object.keys(e[this._defaultLanguage])),Object.keys(this._props[this._defaultLanguage]).forEach(a=>{typeof this._props[this._defaultLanguage][a]=="string"&&this._defaultLanguageFirstLevelKeys.push(a)}),this.setLanguage(this._interfaceLanguage),this._opts.pseudo&&this._pseudoAllValues(this._props)}_pseudoAllValues(e){Object.keys(e).forEach(t=>{if(typeof e[t]=="object")this._pseudoAllValues(e[t]);else if(typeof e[t]=="string"){if(e[t].indexOf("[")===0&&e[t].lastIndexOf("]")===e[t].length-1)return;const a=e[t].split(" ");for(let n=0;n<a.length;n+=1){if(a[n].match(c)||a[n].match(h))continue;let i=a[n].length;this._opts.pseudoMultipleLanguages&&(i=Math.floor(i*1.4)),a[n]=m(i)}e[t]=`[${a.join(" ")}]`}})}setLanguage(e){const t=y(e,this._props),a=Object.keys(this._props)[0];if(this._language=t,this._props[t]){for(const i of this._defaultLanguageFirstLevelKeys)delete this[i];let n={...this._props[this._language]};Object.keys(n).forEach(i=>{this[i]=n[i]}),a!==this._language&&(n=this._props[a],this._fallbackValues(n,this))}}_fallbackValues(e,t){Object.keys(e).forEach(a=>{Object.prototype.hasOwnProperty.call(e,a)&&!t[a]&&t[a]!==""?(t[a]=e[a],this._opts.logsEnabled&&console.log(`🚧 👷 key '${a}' not found in localizedStrings for language ${this._language} 🚧`)):typeof t[a]!="string"&&this._fallbackValues(e[a],t[a])})}getLanguage(){return this._language}getInterfaceLanguage(){return this._interfaceLanguage}getAvailableLanguages(){return this._availableLanguages||(this._availableLanguages=Object.keys(this._props)),this._availableLanguages}formatString(e,...t){let a=e||"";return typeof a=="string"&&(a=this.getString(e,null,!0)||a),a.split(h).filter(Boolean).map(n=>{if(n.match(h)){const i=n.slice(5,-1);return this.getString(i)||(this._opts.logsEnabled&&console.log(`No Localization ref found for '${n}' in string '${e}'`),`$ref(id:${i})`)}return n}).join("").split(c).filter(Boolean).map(n=>{if(n.match(c)){const i=n.slice(1,-1);let r=t[i];return r===void 0&&t[0]&&(r=t[0][i]),r}return n}).join("")}getString(e,t,a=!1){try{let n=this._props[t||this._language];const i=e.split(".");for(const r of i){if(n[r]===void 0)throw new Error(r);n=n[r]}return n}catch(n){!a&&this._opts.logsEnabled&&console.log(`No localization found for key '${e}' and language '${t}', failed on ${n.message}`)}return null}getContent(){return this._props}}const d=/(\{[\d|\w]+\})/;return p.prototype.formatString=(s,...e)=>{let t=!1;const a=(s||"").split(d).filter(n=>!!n).map((n,i)=>{if(n.match(d)){const r=n.slice(1,-1);let l=e[r];if(l==null){const f=e[0]?e[0][r]:void 0;if(f!==void 0)l=f;else return l}return o.isValidElement(l)?(t=!0,o.Children.toArray(l).map(f=>({...f,key:i.toString()}))):l}return n});return t?a:a.join("")},p});
|