@nerimity/solid-i18lite 1.5.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/LICENSE +21 -0
- package/README.md +223 -0
- package/dist/browser.mjs +142 -0
- package/dist/ssr.js +1 -0
- package/dist/ssr.mjs +142 -0
- package/dist/types/Trans.d.ts +7 -0
- package/dist/types/TransProvider.d.ts +13 -0
- package/dist/types/i18Lite.d.ts +50 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/utils/has-interpolation.d.ts +2 -0
- package/dist/types/utils/replace-elements.d.ts +3 -0
- package/dist/types/utils/translate-jsx.d.ts +10 -0
- package/dist/types/utils/translate-with-interpolation.d.ts +3 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# i18next for Solid
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://codecov.io/gh/nerimity/solid-i18lite)
|
|
5
|
+
[](https://bundlephobia.com/package/@nerimity/solid-i18lite)
|
|
6
|
+
|
|
7
|
+
The purpose of this library is to provide ability to support [i18next](https://www.i18next.com/) library in Solid applications
|
|
8
|
+
with `<TransProvider />` and `<Trans />` components.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
1. [Usage](#usage)
|
|
13
|
+
1. [Simple Example](#simple-example)
|
|
14
|
+
1. [Add Resources](#add-resources)
|
|
15
|
+
1. [Change a Language](#change-a-language)
|
|
16
|
+
1. [T Function](#t-function)
|
|
17
|
+
1. [Interpolation](#interpolation)
|
|
18
|
+
1. [Nested JSX](#nested-jsx)
|
|
19
|
+
1. [API](#api)
|
|
20
|
+
1. [Components](#components)
|
|
21
|
+
1. [Utilities](#utilities)
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Installation:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install @nerimity/solid-i18lite i18next --save
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Simple Example
|
|
32
|
+
|
|
33
|
+
`<TransProvider />` must wrap Solid application's most parent component (e.g. `<App />`). `<Trans />` component's `key` property is mandatory.
|
|
34
|
+
|
|
35
|
+
Default value can be wrapped with `<Trans />` component or set with `options` or `children` property.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// esm
|
|
39
|
+
import { TransProvider, Trans } from '@nerimity/solid-i18lite';
|
|
40
|
+
|
|
41
|
+
// cjs
|
|
42
|
+
const { TransProvider, Trans } = require('@nerimity/solid-i18lite');
|
|
43
|
+
|
|
44
|
+
render(() => (
|
|
45
|
+
<TransProvider>
|
|
46
|
+
<App>
|
|
47
|
+
<Trans key="greeting" />
|
|
48
|
+
{/* or */}
|
|
49
|
+
<Trans key="greeting">Hello!</Trans>
|
|
50
|
+
{/* or */}
|
|
51
|
+
<Trans key="greeting" options={{ defaultValue: 'Hello!' }} />
|
|
52
|
+
{/* or */}
|
|
53
|
+
<Trans key="greeting" options="Hello!" />
|
|
54
|
+
{/* or */}
|
|
55
|
+
<Trans key="greeting" children="Hello!" />
|
|
56
|
+
</App>
|
|
57
|
+
</TransProvider>
|
|
58
|
+
));
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Add Resources
|
|
62
|
+
|
|
63
|
+
Resources can be added on initialization with `options` property in `<TransProvider />` or
|
|
64
|
+
by calling `addResources` method from `TransContext`, which can be got with `useTransContext()`.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { Trans, TransProvider, useTransContext } from '@nerimity/solid-18lite';
|
|
68
|
+
|
|
69
|
+
const resources = {
|
|
70
|
+
lt: {...},
|
|
71
|
+
pl: {...},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
render(() => <TransProvider options={{ resources }} children={<App />} />, container);
|
|
75
|
+
|
|
76
|
+
{/* or */}
|
|
77
|
+
|
|
78
|
+
const Component = () => {
|
|
79
|
+
const [, actions] = useTransContext();
|
|
80
|
+
actions.addResources('lt', 'translation', resources.lt);
|
|
81
|
+
actions.addResources('pl', 'translation', resources.pl);
|
|
82
|
+
|
|
83
|
+
return <Trans key="greeting">Hello!</Trans>;
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Change a Language
|
|
88
|
+
|
|
89
|
+
Default language can be provided to `<TransProvider />` with `lng` or `options` property.
|
|
90
|
+
|
|
91
|
+
`options.lng` overrides `lng` property.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<TransProvider lng="lt" children={...} />
|
|
95
|
+
<TransProvider options={{lng: 'pl'}} children={...} />
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To change a language you need to use `TransContext` and call `changeLanguage`.
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { useTransContext } from '@nerimity/solid-18lite';
|
|
102
|
+
|
|
103
|
+
const Component = () => {
|
|
104
|
+
const [, { changeLanguage }] = useTransContext();
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<article>
|
|
108
|
+
<button type="button" onClick={() => changeLanguage('en')}>
|
|
109
|
+
English
|
|
110
|
+
</button>
|
|
111
|
+
<button type="button" onClick={() => changeLanguage('lt')}>
|
|
112
|
+
Lietuvių
|
|
113
|
+
</button>
|
|
114
|
+
</article>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### T Function
|
|
120
|
+
|
|
121
|
+
**i18next** have `t` function, which is essential and sometimes there is need to use it without `<Trans />` component.
|
|
122
|
+
`TransContext` provides it in case you need it.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
const Component = () => {
|
|
126
|
+
const [t] = useTransContext();
|
|
127
|
+
const messages = {
|
|
128
|
+
get greeting() {
|
|
129
|
+
return t('greeting', 'Hello!');
|
|
130
|
+
},
|
|
131
|
+
get bye() {
|
|
132
|
+
return t('bye', 'Bye!');
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return <>{isLogin() ? messages.greeting : messages.bye}</>;
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Interpolation
|
|
141
|
+
|
|
142
|
+
Default interpolation uses `{{` and `}}` as prefix and suffix. Solid uses `{` and `}` for properties propagation. In that case
|
|
143
|
+
messages with default interpolation must be put as string. Placeholder values should be provided
|
|
144
|
+
through `options` property of `<Trans />` component.
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
<Trans key="greeting" options={{ name: 'John Doe' }}>
|
|
148
|
+
{'Hello {{name}}!'}
|
|
149
|
+
</Trans>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**i18next** also allows to define custom interpolation prefix and suffix.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
const resources = { lt: { greeting: 'Labas, ##name##!' } };
|
|
156
|
+
const interpolation = { prefix: '##', suffix: '##' };
|
|
157
|
+
|
|
158
|
+
<TransProvider options={{ interpolation, resources }}>
|
|
159
|
+
<Trans key="greeting" options={{ name: 'John Doe' }}>
|
|
160
|
+
Hello ##name##!
|
|
161
|
+
</Trans>
|
|
162
|
+
</TransProvider>;
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Nested JSX
|
|
166
|
+
|
|
167
|
+
This library supports nested JSX messages, like [react-i18next](https://react.i18next.com/latest/trans-component). If you want use this feature, you need to install [html-parse-string](https://github.com/ryansolid/html-parse-string) separately:
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
npm i html-parse-string
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Then you can define your translation strings, like described in [How to get the correct translation string?](https://react.i18next.com/latest/trans-component#how-to-get-the-correct-translation-string).
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
const resources = {
|
|
177
|
+
lt: { translation: { greeting_nested: '<0>Sveiki, {{fullName}}! </0><1>Tavo profilis</1>.' } },
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
<TransProvider options={{ interpolation, resources }}>
|
|
181
|
+
<Trans key="greeting_nested" options={{ name: 'John Doe' }}>
|
|
182
|
+
{'Hello {{ name }}! '}
|
|
183
|
+
<a href="/profile">Your Profile</a>.
|
|
184
|
+
</Trans>
|
|
185
|
+
</TransProvider>;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Keep in mind that elements, with interpolation, must be a string, e.g: `'Hello {{name}}!'`.
|
|
189
|
+
|
|
190
|
+
## API
|
|
191
|
+
|
|
192
|
+
### Components
|
|
193
|
+
|
|
194
|
+
#### `<TransProvider />`
|
|
195
|
+
|
|
196
|
+
| Property | Description | Required |
|
|
197
|
+
| -------- | ------------------------------------------------------------------------------------------------ | -------- |
|
|
198
|
+
| instance | i18next instance, see: [i18n](https://www.i18next.com/overview/api) | No |
|
|
199
|
+
| lng | default language, `options.lng` overrides it | No |
|
|
200
|
+
| options | i18next init options, see: [InitOptions](https://www.i18next.com/overview/configuration-options) | No |
|
|
201
|
+
|
|
202
|
+
#### `<Trans />`
|
|
203
|
+
|
|
204
|
+
| Property | Description | Required |
|
|
205
|
+
| -------- | ------------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
206
|
+
| key | translation key or keys [TFunctionKeys](https://www.i18next.com/translation-function/essentials) | Yes |
|
|
207
|
+
| options | t function's options, see: [TOptions \| string](https://www.i18next.com/translation-function/essentials#overview-options) | No |
|
|
208
|
+
|
|
209
|
+
### Utilities
|
|
210
|
+
|
|
211
|
+
#### `useTransContext`
|
|
212
|
+
|
|
213
|
+
`useTransContext` function returns `TransContext` as array: `[TFunction, TransProviderActions]`.
|
|
214
|
+
|
|
215
|
+
The first item is `t` function, second - the list of actions, which are listed below.
|
|
216
|
+
|
|
217
|
+
`TransProviderActions`
|
|
218
|
+
|
|
219
|
+
| Function | Description |
|
|
220
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
221
|
+
| addResources(<br/> lng, <br/> ns, <br/> resources, <br/> bundleOptions?: { deep?; overwrite? }<br/>) | adds translation resources, see [addResourcesBundle](https://www.i18next.com/overview/api#addresourcebundle) |
|
|
222
|
+
| changeLanguage(lng) | changes language and sets new t function |
|
|
223
|
+
| getI18next | returns **i18next** instance, see [i18n](https://www.i18next.com/overview/api) |
|
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createComponent as I, memo as v } from "solid-js/web";
|
|
2
|
+
import { useContext as P, createContext as w, createSignal as L, children as $ } from "solid-js";
|
|
3
|
+
let S = {}, E = "translation", x = "";
|
|
4
|
+
const T = { resources: {}, interpolation: { prefix: "{{", suffix: "}}" } };
|
|
5
|
+
let f = T;
|
|
6
|
+
const R = (t) => t.replace(/[-|\\{}()[\]^$+*?.]/g, (e) => e === "-" ? "\\x2d" : `\\${e}`), m = /* @__PURE__ */ new Map(), M = (t, e) => {
|
|
7
|
+
if (!t) return "";
|
|
8
|
+
const n = f?.interpolation, r = n?.prefix ?? "{{", s = n?.suffix ?? "}}", a = r + "|" + s;
|
|
9
|
+
let o = m.get(a);
|
|
10
|
+
if (!o) {
|
|
11
|
+
const i = R(r), u = R(s);
|
|
12
|
+
o = new RegExp(`${i}\\s*(\\w+)\\s*${u}`, "g"), m.set(a, o);
|
|
13
|
+
}
|
|
14
|
+
return t.replace(o, (i, u) => Object.prototype.hasOwnProperty.call(e, u) ? e[u] : i);
|
|
15
|
+
}, h = (t, e, n) => {
|
|
16
|
+
let r = j(c.language, E, t) ?? (typeof e == "string" ? e : t);
|
|
17
|
+
return n || typeof e == "object" && e !== null ? M(r, n || e) : r;
|
|
18
|
+
}, B = (t, e) => {
|
|
19
|
+
S[t] = e;
|
|
20
|
+
}, F = (t, e) => {
|
|
21
|
+
f = T, t && (f = { ...t, interpolation: t?.interpolation || {} }, f.interpolation.prefix = t.interpolation?.prefix || "{{", f.interpolation.suffix = t.interpolation?.suffix || "}}"), x = t?.lng || "", c.store = { data: f.resources || {} }, f.resources = {}, e?.(null, h);
|
|
22
|
+
}, J = (t) => (x = t, Promise.resolve(h)), b = (t, e, n = !0) => {
|
|
23
|
+
const r = t;
|
|
24
|
+
for (const s in e) {
|
|
25
|
+
const a = r[s], o = e[s];
|
|
26
|
+
o && typeof o == "object" && !Array.isArray(o) ? ((typeof a != "object" || Array.isArray(a)) && (r[s] = {}), b(r[s], o, n)) : (n || a === void 0) && (r[s] = o);
|
|
27
|
+
}
|
|
28
|
+
return t;
|
|
29
|
+
}, V = (t, e, n, r = !0, s = !0) => {
|
|
30
|
+
c.store = c.store || { data: {} }, c.store.data = c.store.data || {}, c.store.data[t] = c.store.data[t] || {}, c.store.data[t][e] = c.store.data[t][e] || {};
|
|
31
|
+
const a = c.store.data[t][e], o = n;
|
|
32
|
+
return r ? b(a, o, s) : c.store.data[t][e] = s ? o : { ...o, ...a }, (S.loaded || (() => {
|
|
33
|
+
}))(t, e), c;
|
|
34
|
+
}, j = (t, e, n, r) => {
|
|
35
|
+
const s = c.store;
|
|
36
|
+
if (!s) return;
|
|
37
|
+
const a = s.data?.[t];
|
|
38
|
+
if (!a) return;
|
|
39
|
+
const o = a[e];
|
|
40
|
+
if (!o || typeof o == "string") return;
|
|
41
|
+
const i = r?.keySeparator ?? c.options?.keySeparator ?? ".";
|
|
42
|
+
if (i === !1) return o[n];
|
|
43
|
+
const u = String(i);
|
|
44
|
+
if (n.indexOf(u) === -1) return o[n];
|
|
45
|
+
let l = o, y = 0;
|
|
46
|
+
for (let d = 0; d <= n.length; d++)
|
|
47
|
+
if (d === n.length || n[d] === u) {
|
|
48
|
+
const C = n.slice(y, d);
|
|
49
|
+
if (l == null || !(C in l)) return;
|
|
50
|
+
l = l[C], y = d + 1;
|
|
51
|
+
}
|
|
52
|
+
return l;
|
|
53
|
+
}, X = () => c, c = {
|
|
54
|
+
get language() {
|
|
55
|
+
return x;
|
|
56
|
+
},
|
|
57
|
+
createInstance: X,
|
|
58
|
+
t: h,
|
|
59
|
+
on: B,
|
|
60
|
+
init: F,
|
|
61
|
+
changeLanguage: J,
|
|
62
|
+
addResourceBundle: V,
|
|
63
|
+
options: f,
|
|
64
|
+
getResource: j
|
|
65
|
+
}, A = w();
|
|
66
|
+
function H(t, e) {
|
|
67
|
+
const [n, r] = L(e.resources ? t.t : () => null);
|
|
68
|
+
t.on("loaded", () => r(() => t.t)), t.init(e, (o, i) => r(() => i));
|
|
69
|
+
async function s(o) {
|
|
70
|
+
const i = await t.changeLanguage(o);
|
|
71
|
+
r(() => i);
|
|
72
|
+
}
|
|
73
|
+
function a(o, i, u, l = {}) {
|
|
74
|
+
return t.addResourceBundle(o, i, u, l.deep, l.overwrite);
|
|
75
|
+
}
|
|
76
|
+
return [((...o) => n().apply(null, o)), {
|
|
77
|
+
addResources: a,
|
|
78
|
+
getI18next: () => t,
|
|
79
|
+
changeLanguage: s
|
|
80
|
+
}];
|
|
81
|
+
}
|
|
82
|
+
const K = () => P(A), Y = (t) => I(A.Provider, {
|
|
83
|
+
get value() {
|
|
84
|
+
return H(t.instance || c, {
|
|
85
|
+
lng: t.lng,
|
|
86
|
+
...t.options
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
get children() {
|
|
90
|
+
return t.children;
|
|
91
|
+
}
|
|
92
|
+
}), g = (t, { prefix: e, suffix: n }) => t.includes(e) && t.includes(n), W = (t, { interpolation: e }) => (n, r) => typeof n == "string" ? g(n, e) ? t.children[r].children?.[0].content : t.children[r].content : (n.textContent = t.children[r].children?.[0].content, n), _ = !globalThis.window, q = (t, e, n) => (r) => {
|
|
93
|
+
const s = typeof r;
|
|
94
|
+
if (s === "string" && g(r, e.interpolation)) return t(r, n.options);
|
|
95
|
+
if (s === "object") {
|
|
96
|
+
const a = r.textContent ?? r.t;
|
|
97
|
+
a && g(a, e.interpolation) && (r[_ ? "t" : "textContent"] = t(a, n.options));
|
|
98
|
+
}
|
|
99
|
+
return r;
|
|
100
|
+
};
|
|
101
|
+
let p;
|
|
102
|
+
(async () => {
|
|
103
|
+
try {
|
|
104
|
+
p = (await import("html-parse-string")).parse;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
const z = () => {
|
|
109
|
+
console.error(
|
|
110
|
+
"In order to use JSX nesting, install %chtml-parse-string",
|
|
111
|
+
"font-weight: 700",
|
|
112
|
+
"https://github.com/ryansolid/html-parse-string."
|
|
113
|
+
);
|
|
114
|
+
}, G = ({ i18n: { options: t }, t: e, props: n }, r) => {
|
|
115
|
+
const s = e(n.key, n.options);
|
|
116
|
+
if (!n.children) return s;
|
|
117
|
+
if (s === n.key) return r.map(q(e, t, n));
|
|
118
|
+
if (!p) {
|
|
119
|
+
z();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const [a] = p(`<0>${s}</0>`);
|
|
124
|
+
return r.map(W(a, t));
|
|
125
|
+
} catch (a) {
|
|
126
|
+
console.error(a);
|
|
127
|
+
}
|
|
128
|
+
}, Z = (t) => {
|
|
129
|
+
const [e, {
|
|
130
|
+
getI18next: n
|
|
131
|
+
}] = K();
|
|
132
|
+
return v(() => v(() => typeof t.children == "string")() ? e(t.key, t.children, t.options) : G({
|
|
133
|
+
i18n: n(),
|
|
134
|
+
t: e,
|
|
135
|
+
props: t
|
|
136
|
+
}, $(() => t.children)()));
|
|
137
|
+
};
|
|
138
|
+
export {
|
|
139
|
+
Z as Trans,
|
|
140
|
+
Y as TransProvider,
|
|
141
|
+
K as useTransContext
|
|
142
|
+
};
|
package/dist/ssr.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var L=Object.create;var T=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var J=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of m(e))!E.call(t,o)&&o!==n&&T(t,o,{get:()=>e[o],enumerable:!(r=$(e,o))||r.enumerable});return t};var q=(t,e,n)=>(n=t!=null?L(M(t)):{},J(e||!t||!t.__esModule?T(n,"default",{value:t,enumerable:!0}):n,t));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("solid-js"),B=require("solid-js/web");let R={},F="translation",h="";const P={resources:{},interpolation:{prefix:"{{",suffix:"}}"}};let f=P;const S=t=>t.replace(/[-|\\{}()[\]^$+*?.]/g,e=>e==="-"?"\\x2d":`\\${e}`),b=new Map,V=(t,e)=>{if(!t)return"";const n=f?.interpolation,r=n?.prefix??"{{",o=n?.suffix??"}}",a=r+"|"+o;let s=b.get(a);if(!s){const i=S(r),u=S(o);s=new RegExp(`${i}\\s*(\\w+)\\s*${u}`,"g"),b.set(a,s)}return t.replace(s,(i,u)=>Object.prototype.hasOwnProperty.call(e,u)?e[u]:i)},y=(t,e,n)=>{let r=w(c.language,F,t)??(typeof e=="string"?e:t);return n||typeof e=="object"&&e!==null?V(r,n||e):r},X=(t,e)=>{R[t]=e},H=(t,e)=>{f=P,t&&(f={...t,interpolation:t?.interpolation||{}},f.interpolation.prefix=t.interpolation?.prefix||"{{",f.interpolation.suffix=t.interpolation?.suffix||"}}"),h=t?.lng||"",c.store={data:f.resources||{}},f.resources={},e?.(null,y)},K=t=>(h=t,Promise.resolve(y)),j=(t,e,n=!0)=>{const r=t;for(const o in e){const a=r[o],s=e[o];s&&typeof s=="object"&&!Array.isArray(s)?((typeof a!="object"||Array.isArray(a))&&(r[o]={}),j(r[o],s,n)):(n||a===void 0)&&(r[o]=s)}return t},W=(t,e,n,r=!0,o=!0)=>{c.store=c.store||{data:{}},c.store.data=c.store.data||{},c.store.data[t]=c.store.data[t]||{},c.store.data[t][e]=c.store.data[t][e]||{};const a=c.store.data[t][e],s=n;return r?j(a,s,o):c.store.data[t][e]=o?s:{...s,...a},(R.loaded||(()=>{}))(t,e),c},w=(t,e,n,r)=>{const o=c.store;if(!o)return;const a=o.data?.[t];if(!a)return;const s=a[e];if(!s||typeof s=="string")return;const i=r?.keySeparator??c.options?.keySeparator??".";if(i===!1)return s[n];const u=String(i);if(n.indexOf(u)===-1)return s[n];let l=s,v=0;for(let d=0;d<=n.length;d++)if(d===n.length||n[d]===u){const C=n.slice(v,d);if(l==null||!(C in l))return;l=l[C],v=d+1}return l},_=()=>c,c={get language(){return h},createInstance:_,t:y,on:X,init:H,changeLanguage:K,addResourceBundle:W,options:f,getResource:w},A=g.createContext();function z(t,e){const[n,r]=g.createSignal(e.resources?t.t:()=>null);t.on("loaded",()=>r(()=>t.t)),t.init(e,(s,i)=>r(()=>i));async function o(s){const i=await t.changeLanguage(s);r(()=>i)}function a(s,i,u,l={}){return t.addResourceBundle(s,i,u,l.deep,l.overwrite)}return[((...s)=>n().apply(null,s)),{addResources:a,getI18next:()=>t,changeLanguage:o}]}const I=()=>g.useContext(A),G=t=>B.createComponent(A.Provider,{get value(){return z(t.instance||c,{lng:t.lng,...t.options})},get children(){return t.children}}),x=(t,{prefix:e,suffix:n})=>t.includes(e)&&t.includes(n),Q=(t,{interpolation:e})=>(n,r)=>typeof n=="string"?x(n,e)?t.children[r].children?.[0].content:t.children[r].content:(n.textContent=t.children[r].children?.[0].content,n),U=!globalThis.window,Y=(t,e,n)=>r=>{const o=typeof r;if(o==="string"&&x(r,e.interpolation))return t(r,n.options);if(o==="object"){const a=r.textContent??r.t;a&&x(a,e.interpolation)&&(r[U?"t":"textContent"]=t(a,n.options))}return r};let p;(async()=>{try{p=(await import("html-parse-string")).parse}catch{}})();const Z=()=>{console.error("In order to use JSX nesting, install %chtml-parse-string","font-weight: 700","https://github.com/ryansolid/html-parse-string.")},k=({i18n:{options:t},t:e,props:n},r)=>{const o=e(n.key,n.options);if(!n.children)return o;if(o===n.key)return r.map(Y(e,t,n));if(!p){Z();return}try{const[a]=p(`<0>${o}</0>`);return r.map(Q(a,t))}catch(a){console.error(a)}},N=t=>{const[e,{getI18next:n}]=I();return typeof t.children=="string"?e(t.key,t.children,t.options):k({i18n:n(),t:e,props:t},g.children(()=>t.children)())};exports.Trans=N;exports.TransProvider=G;exports.useTransContext=I;
|
package/dist/ssr.mjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { useContext as A, createContext as I, createSignal as P, children as w } from "solid-js";
|
|
2
|
+
import { createComponent as L } from "solid-js/web";
|
|
3
|
+
let S = {}, $ = "translation", x = "";
|
|
4
|
+
const T = { resources: {}, interpolation: { prefix: "{{", suffix: "}}" } };
|
|
5
|
+
let f = T;
|
|
6
|
+
const v = (t) => t.replace(/[-|\\{}()[\]^$+*?.]/g, (e) => e === "-" ? "\\x2d" : `\\${e}`), R = /* @__PURE__ */ new Map(), E = (t, e) => {
|
|
7
|
+
if (!t) return "";
|
|
8
|
+
const n = f?.interpolation, r = n?.prefix ?? "{{", s = n?.suffix ?? "}}", a = r + "|" + s;
|
|
9
|
+
let o = R.get(a);
|
|
10
|
+
if (!o) {
|
|
11
|
+
const i = v(r), u = v(s);
|
|
12
|
+
o = new RegExp(`${i}\\s*(\\w+)\\s*${u}`, "g"), R.set(a, o);
|
|
13
|
+
}
|
|
14
|
+
return t.replace(o, (i, u) => Object.prototype.hasOwnProperty.call(e, u) ? e[u] : i);
|
|
15
|
+
}, h = (t, e, n) => {
|
|
16
|
+
let r = m(c.language, $, t) ?? (typeof e == "string" ? e : t);
|
|
17
|
+
return n || typeof e == "object" && e !== null ? E(r, n || e) : r;
|
|
18
|
+
}, M = (t, e) => {
|
|
19
|
+
S[t] = e;
|
|
20
|
+
}, B = (t, e) => {
|
|
21
|
+
f = T, t && (f = { ...t, interpolation: t?.interpolation || {} }, f.interpolation.prefix = t.interpolation?.prefix || "{{", f.interpolation.suffix = t.interpolation?.suffix || "}}"), x = t?.lng || "", c.store = { data: f.resources || {} }, f.resources = {}, e?.(null, h);
|
|
22
|
+
}, F = (t) => (x = t, Promise.resolve(h)), b = (t, e, n = !0) => {
|
|
23
|
+
const r = t;
|
|
24
|
+
for (const s in e) {
|
|
25
|
+
const a = r[s], o = e[s];
|
|
26
|
+
o && typeof o == "object" && !Array.isArray(o) ? ((typeof a != "object" || Array.isArray(a)) && (r[s] = {}), b(r[s], o, n)) : (n || a === void 0) && (r[s] = o);
|
|
27
|
+
}
|
|
28
|
+
return t;
|
|
29
|
+
}, J = (t, e, n, r = !0, s = !0) => {
|
|
30
|
+
c.store = c.store || { data: {} }, c.store.data = c.store.data || {}, c.store.data[t] = c.store.data[t] || {}, c.store.data[t][e] = c.store.data[t][e] || {};
|
|
31
|
+
const a = c.store.data[t][e], o = n;
|
|
32
|
+
return r ? b(a, o, s) : c.store.data[t][e] = s ? o : { ...o, ...a }, (S.loaded || (() => {
|
|
33
|
+
}))(t, e), c;
|
|
34
|
+
}, m = (t, e, n, r) => {
|
|
35
|
+
const s = c.store;
|
|
36
|
+
if (!s) return;
|
|
37
|
+
const a = s.data?.[t];
|
|
38
|
+
if (!a) return;
|
|
39
|
+
const o = a[e];
|
|
40
|
+
if (!o || typeof o == "string") return;
|
|
41
|
+
const i = r?.keySeparator ?? c.options?.keySeparator ?? ".";
|
|
42
|
+
if (i === !1) return o[n];
|
|
43
|
+
const u = String(i);
|
|
44
|
+
if (n.indexOf(u) === -1) return o[n];
|
|
45
|
+
let l = o, y = 0;
|
|
46
|
+
for (let d = 0; d <= n.length; d++)
|
|
47
|
+
if (d === n.length || n[d] === u) {
|
|
48
|
+
const C = n.slice(y, d);
|
|
49
|
+
if (l == null || !(C in l)) return;
|
|
50
|
+
l = l[C], y = d + 1;
|
|
51
|
+
}
|
|
52
|
+
return l;
|
|
53
|
+
}, V = () => c, c = {
|
|
54
|
+
get language() {
|
|
55
|
+
return x;
|
|
56
|
+
},
|
|
57
|
+
createInstance: V,
|
|
58
|
+
t: h,
|
|
59
|
+
on: M,
|
|
60
|
+
init: B,
|
|
61
|
+
changeLanguage: F,
|
|
62
|
+
addResourceBundle: J,
|
|
63
|
+
options: f,
|
|
64
|
+
getResource: m
|
|
65
|
+
}, j = I();
|
|
66
|
+
function X(t, e) {
|
|
67
|
+
const [n, r] = P(e.resources ? t.t : () => null);
|
|
68
|
+
t.on("loaded", () => r(() => t.t)), t.init(e, (o, i) => r(() => i));
|
|
69
|
+
async function s(o) {
|
|
70
|
+
const i = await t.changeLanguage(o);
|
|
71
|
+
r(() => i);
|
|
72
|
+
}
|
|
73
|
+
function a(o, i, u, l = {}) {
|
|
74
|
+
return t.addResourceBundle(o, i, u, l.deep, l.overwrite);
|
|
75
|
+
}
|
|
76
|
+
return [((...o) => n().apply(null, o)), {
|
|
77
|
+
addResources: a,
|
|
78
|
+
getI18next: () => t,
|
|
79
|
+
changeLanguage: s
|
|
80
|
+
}];
|
|
81
|
+
}
|
|
82
|
+
const H = () => A(j), U = (t) => L(j.Provider, {
|
|
83
|
+
get value() {
|
|
84
|
+
return X(t.instance || c, {
|
|
85
|
+
lng: t.lng,
|
|
86
|
+
...t.options
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
get children() {
|
|
90
|
+
return t.children;
|
|
91
|
+
}
|
|
92
|
+
}), g = (t, { prefix: e, suffix: n }) => t.includes(e) && t.includes(n), K = (t, { interpolation: e }) => (n, r) => typeof n == "string" ? g(n, e) ? t.children[r].children?.[0].content : t.children[r].content : (n.textContent = t.children[r].children?.[0].content, n), W = !globalThis.window, _ = (t, e, n) => (r) => {
|
|
93
|
+
const s = typeof r;
|
|
94
|
+
if (s === "string" && g(r, e.interpolation)) return t(r, n.options);
|
|
95
|
+
if (s === "object") {
|
|
96
|
+
const a = r.textContent ?? r.t;
|
|
97
|
+
a && g(a, e.interpolation) && (r[W ? "t" : "textContent"] = t(a, n.options));
|
|
98
|
+
}
|
|
99
|
+
return r;
|
|
100
|
+
};
|
|
101
|
+
let p;
|
|
102
|
+
(async () => {
|
|
103
|
+
try {
|
|
104
|
+
p = (await import("html-parse-string")).parse;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
const q = () => {
|
|
109
|
+
console.error(
|
|
110
|
+
"In order to use JSX nesting, install %chtml-parse-string",
|
|
111
|
+
"font-weight: 700",
|
|
112
|
+
"https://github.com/ryansolid/html-parse-string."
|
|
113
|
+
);
|
|
114
|
+
}, z = ({ i18n: { options: t }, t: e, props: n }, r) => {
|
|
115
|
+
const s = e(n.key, n.options);
|
|
116
|
+
if (!n.children) return s;
|
|
117
|
+
if (s === n.key) return r.map(_(e, t, n));
|
|
118
|
+
if (!p) {
|
|
119
|
+
q();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const [a] = p(`<0>${s}</0>`);
|
|
124
|
+
return r.map(K(a, t));
|
|
125
|
+
} catch (a) {
|
|
126
|
+
console.error(a);
|
|
127
|
+
}
|
|
128
|
+
}, Y = (t) => {
|
|
129
|
+
const [e, {
|
|
130
|
+
getI18next: n
|
|
131
|
+
}] = H();
|
|
132
|
+
return typeof t.children == "string" ? e(t.key, t.children, t.options) : z({
|
|
133
|
+
i18n: n(),
|
|
134
|
+
t: e,
|
|
135
|
+
props: t
|
|
136
|
+
}, w(() => t.children)());
|
|
137
|
+
};
|
|
138
|
+
export {
|
|
139
|
+
Y as Trans,
|
|
140
|
+
U as TransProvider,
|
|
141
|
+
H as useTransContext
|
|
142
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ParentComponent } from 'solid-js';
|
|
2
|
+
import { type InitOptions, type TFunction, type i18n } from './i18Lite';
|
|
3
|
+
export type TransProviderActions = {
|
|
4
|
+
addResources(lng: string, ns: string, resources: any): i18n;
|
|
5
|
+
changeLanguage(lng: string): Promise<void>;
|
|
6
|
+
getI18next(): i18n;
|
|
7
|
+
};
|
|
8
|
+
export declare const useTransContext: () => [TFunction, TransProviderActions];
|
|
9
|
+
export declare const TransProvider: ParentComponent<{
|
|
10
|
+
instance?: i18n;
|
|
11
|
+
lng?: string;
|
|
12
|
+
options?: InitOptions;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type $Dictionary<T = unknown> = {
|
|
2
|
+
[key: string]: T;
|
|
3
|
+
};
|
|
4
|
+
export type ResourceKey = string | {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
export interface ResourceLanguage {
|
|
8
|
+
[namespace: string]: ResourceKey;
|
|
9
|
+
}
|
|
10
|
+
export interface Resource {
|
|
11
|
+
[language: string]: ResourceLanguage;
|
|
12
|
+
}
|
|
13
|
+
export interface InterpolationOptions {
|
|
14
|
+
prefix?: string;
|
|
15
|
+
suffix?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface InitOptions {
|
|
18
|
+
resources: Resource;
|
|
19
|
+
lng?: string;
|
|
20
|
+
interpolation?: InterpolationOptions;
|
|
21
|
+
keySeparator?: false | string;
|
|
22
|
+
nsSeparator?: false | string;
|
|
23
|
+
defaultNS?: string;
|
|
24
|
+
ignoreJSONStructure?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface TOptionsBase {
|
|
27
|
+
lng?: string;
|
|
28
|
+
}
|
|
29
|
+
export type TOptions<TInterpolationMap extends object = $Dictionary> = TOptionsBase & TInterpolationMap;
|
|
30
|
+
export type TFunction = {
|
|
31
|
+
(key: string, options?: {}): string;
|
|
32
|
+
(key: string, defaultValue: string, options?: {}): string;
|
|
33
|
+
(key: string, arg2?: string | {}, arg3?: {}): string;
|
|
34
|
+
};
|
|
35
|
+
export interface i18n {
|
|
36
|
+
language: string;
|
|
37
|
+
getResource: (lng: string, ns: string, key: string, options?: any) => any;
|
|
38
|
+
createInstance: () => i18n;
|
|
39
|
+
t: TFunction;
|
|
40
|
+
on: (...args: any[]) => void;
|
|
41
|
+
init: (options?: InitOptions, callback?: (error: any, t: TFunction) => void) => void;
|
|
42
|
+
changeLanguage: (lng: string) => Promise<TFunction>;
|
|
43
|
+
addResourceBundle(lng: string, ns: string, resources: any, deep?: boolean, overwrite?: boolean): i18n;
|
|
44
|
+
store?: {
|
|
45
|
+
data: Resource;
|
|
46
|
+
};
|
|
47
|
+
options?: InitOptions;
|
|
48
|
+
}
|
|
49
|
+
declare const instance: i18n;
|
|
50
|
+
export default instance;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { parse } from 'html-parse-string';
|
|
2
|
+
import type { ParentProps } from 'solid-js';
|
|
3
|
+
import type { TFunction, i18n } from '../i18Lite';
|
|
4
|
+
import type { TransProps } from '../Trans';
|
|
5
|
+
export declare let parseHTML: typeof parse;
|
|
6
|
+
export declare const translateJSX: ({ i18n: { options }, t, props }: {
|
|
7
|
+
t: TFunction;
|
|
8
|
+
props: ParentProps<TransProps>;
|
|
9
|
+
i18n: i18n;
|
|
10
|
+
}, children: Node[]) => string | any[];
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "SupertigerDev",
|
|
3
|
+
"description": "i18next for SolidJS",
|
|
4
|
+
"devDependencies": {
|
|
5
|
+
"@babel/plugin-transform-runtime": "^7.28.3",
|
|
6
|
+
"@babel/preset-typescript": "^7.27.1",
|
|
7
|
+
"@solidjs/testing-library": "^0.8.10",
|
|
8
|
+
"@types/jest": "^30.0.0",
|
|
9
|
+
"babel-preset-solid": "^1.9.9",
|
|
10
|
+
"html-parse-string": "^0.0.9",
|
|
11
|
+
"i18next-http-backend": "^3.0.2",
|
|
12
|
+
"jest": "^30.2.0",
|
|
13
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
14
|
+
"solid-jest": "^0.2.0",
|
|
15
|
+
"solid-js": "^1.9.9",
|
|
16
|
+
"typescript": "^5.9.3",
|
|
17
|
+
"vite": "^7.1.9",
|
|
18
|
+
"vite-plugin-solid": "^2.11.9"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/types/index.d.ts",
|
|
23
|
+
"browser": {
|
|
24
|
+
"default": "./dist/browser.mjs"
|
|
25
|
+
},
|
|
26
|
+
"import": "./dist/ssr.mjs",
|
|
27
|
+
"require": "./dist/ssr.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"keywords": [
|
|
35
|
+
"i18n",
|
|
36
|
+
"i18next",
|
|
37
|
+
"internationalization",
|
|
38
|
+
"intl",
|
|
39
|
+
"language",
|
|
40
|
+
"localization",
|
|
41
|
+
"solid",
|
|
42
|
+
"solid-js",
|
|
43
|
+
"solidjs",
|
|
44
|
+
"translate",
|
|
45
|
+
"translations"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"main": "./dist/ssr.js",
|
|
49
|
+
"module": "./dist/ssr.mjs",
|
|
50
|
+
"name": "@nerimity/solid-i18lite",
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"html-parse-string": "<=1.x",
|
|
53
|
+
"solid-js": ">=1.8.x"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"html-parse-string": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"repository": "github:nerimity/solid-i18lite",
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build:browser": "vite build --config vite.browser.config.js",
|
|
63
|
+
"build:docs": "vite build --config vite.docs.config.js",
|
|
64
|
+
"build:ssr": "vite build --config vite.ssr.config.js",
|
|
65
|
+
"build:types": "tsc --project tsconfig.types.json",
|
|
66
|
+
"docs": "vite --config vite.docs.config.js",
|
|
67
|
+
"test": "jest --coverage",
|
|
68
|
+
"test:dev": "jest"
|
|
69
|
+
},
|
|
70
|
+
"sideEffects": false,
|
|
71
|
+
"type": "module",
|
|
72
|
+
"types": "./dist/types/index.d.ts",
|
|
73
|
+
"version": "1.5.0"
|
|
74
|
+
}
|