@onruntime/translations 0.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/README.md +285 -0
- package/dist/chunk-5W5CCQME.cjs +48 -0
- package/dist/chunk-X3HAZ4DT.js +44 -0
- package/dist/index.cjs +33 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +30 -0
- package/dist/next/index.cjs +96 -0
- package/dist/next/index.d.cts +38 -0
- package/dist/next/index.d.ts +38 -0
- package/dist/next/index.js +88 -0
- package/dist/react/index.cjs +72 -0
- package/dist/react/index.d.cts +44 -0
- package/dist/react/index.d.ts +44 -0
- package/dist/react/index.js +57 -0
- package/dist/types-BpDtTtSF.d.cts +11 -0
- package/dist/types-BpDtTtSF.d.ts +11 -0
- package/dist/vite/index.cjs +18 -0
- package/dist/vite/index.d.cts +20 -0
- package/dist/vite/index.d.ts +20 -0
- package/dist/vite/index.js +16 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# @onruntime/translations
|
|
2
|
+
|
|
3
|
+
Lightweight i18n library for React, Next.js, and React Native.
|
|
4
|
+
|
|
5
|
+
## Examples
|
|
6
|
+
|
|
7
|
+
- [Next.js App Router](https://github.com/onRuntime/onruntime/tree/master/examples/translations/next-app)
|
|
8
|
+
- [Next.js Pages Router](https://github.com/onRuntime/onruntime/tree/master/examples/translations/next-pages)
|
|
9
|
+
- [React + Vite](https://github.com/onRuntime/onruntime/tree/master/examples/translations/react)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add @onruntime/translations
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Next.js App Router
|
|
20
|
+
|
|
21
|
+
#### 1. Create your translations config
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// lib/translations.ts
|
|
25
|
+
import {
|
|
26
|
+
getTranslation as getTranslationCore,
|
|
27
|
+
type TranslationLoader,
|
|
28
|
+
} from "@onruntime/translations";
|
|
29
|
+
|
|
30
|
+
export const locales = ["en", "fr"];
|
|
31
|
+
export const defaultLocale = locales[0];
|
|
32
|
+
|
|
33
|
+
export const load: TranslationLoader = (locale, namespace) => {
|
|
34
|
+
try {
|
|
35
|
+
return require(`../locales/${locale}/${namespace}.json`);
|
|
36
|
+
} catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const getTranslation = async (
|
|
42
|
+
params: Promise<{ lang: string }>,
|
|
43
|
+
namespace = "common",
|
|
44
|
+
) => {
|
|
45
|
+
const { lang } = await params;
|
|
46
|
+
return getTranslationCore(load, lang, namespace);
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### 2. Setup middleware
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// middleware.ts
|
|
54
|
+
import { NextResponse } from "next/server";
|
|
55
|
+
import type { NextRequest } from "next/server";
|
|
56
|
+
|
|
57
|
+
import { locales, defaultLocale } from "@/lib/translations";
|
|
58
|
+
|
|
59
|
+
export function middleware(request: NextRequest) {
|
|
60
|
+
const { pathname } = request.nextUrl;
|
|
61
|
+
|
|
62
|
+
const pathnameLocale = locales.find(
|
|
63
|
+
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (pathnameLocale === defaultLocale) {
|
|
67
|
+
const newPathname = pathname.replace(`/${defaultLocale}`, "") || "/";
|
|
68
|
+
return NextResponse.redirect(new URL(newPathname, request.url));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (pathnameLocale) return;
|
|
72
|
+
|
|
73
|
+
request.nextUrl.pathname = `/${defaultLocale}${pathname}`;
|
|
74
|
+
return NextResponse.rewrite(request.nextUrl);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const config = {
|
|
78
|
+
matcher: ["/((?!_next|favicon.ico).*)"],
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### 3. Setup layout with provider
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// app/[lang]/layout.tsx
|
|
86
|
+
import type { ReactNode } from "react";
|
|
87
|
+
import { AppTranslationProvider } from "@onruntime/translations/next";
|
|
88
|
+
|
|
89
|
+
import { load, locales } from "@/lib/translations";
|
|
90
|
+
|
|
91
|
+
export async function generateStaticParams() {
|
|
92
|
+
return locales.map((lang) => ({ lang }));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default async function RootLayout({
|
|
96
|
+
children,
|
|
97
|
+
params,
|
|
98
|
+
}: {
|
|
99
|
+
children: ReactNode;
|
|
100
|
+
params: Promise<{ lang: string }>;
|
|
101
|
+
}) {
|
|
102
|
+
const { lang } = await params;
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<html lang={lang}>
|
|
106
|
+
<body>
|
|
107
|
+
<AppTranslationProvider locale={lang} locales={locales} load={load}>
|
|
108
|
+
{children}
|
|
109
|
+
</AppTranslationProvider>
|
|
110
|
+
</body>
|
|
111
|
+
</html>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### 4. Use in Server Components
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// app/[lang]/page.tsx
|
|
120
|
+
import { Link } from "@onruntime/translations/next";
|
|
121
|
+
|
|
122
|
+
import { getTranslation } from "@/lib/translations";
|
|
123
|
+
|
|
124
|
+
export default async function Home({
|
|
125
|
+
params,
|
|
126
|
+
}: {
|
|
127
|
+
params: Promise<{ lang: string }>;
|
|
128
|
+
}) {
|
|
129
|
+
const { t, locale } = await getTranslation(params);
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<h1>{t("greeting", { name: "John" })}</h1>
|
|
134
|
+
<Link href="/about">{t("nav.about")}</Link>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### 5. Use in Client Components
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// app/[lang]/about/page.tsx
|
|
144
|
+
"use client";
|
|
145
|
+
|
|
146
|
+
import { useTranslation, useLocale } from "@onruntime/translations/react";
|
|
147
|
+
import { Link } from "@onruntime/translations/next";
|
|
148
|
+
|
|
149
|
+
export default function About() {
|
|
150
|
+
const { t } = useTranslation();
|
|
151
|
+
const { locale } = useLocale();
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div>
|
|
155
|
+
<h1>{t("about.title")}</h1>
|
|
156
|
+
<p>Current locale: {locale}</p>
|
|
157
|
+
<Link href="/">{t("nav.home")}</Link>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Next.js Pages Router
|
|
164
|
+
|
|
165
|
+
#### 1. Configure i18n in next.config.js
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// next.config.js
|
|
169
|
+
module.exports = {
|
|
170
|
+
i18n: {
|
|
171
|
+
locales: ["en", "fr"],
|
|
172
|
+
defaultLocale: "en",
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### 2. Setup provider in _app.tsx
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// pages/_app.tsx
|
|
181
|
+
import type { AppProps } from "next/app";
|
|
182
|
+
import { TranslationProvider } from "@onruntime/translations/next";
|
|
183
|
+
|
|
184
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
185
|
+
return (
|
|
186
|
+
<TranslationProvider
|
|
187
|
+
load={(locale, ns) => {
|
|
188
|
+
try {
|
|
189
|
+
return require(`@/locales/${locale}/${ns}.json`);
|
|
190
|
+
} catch {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
}}
|
|
194
|
+
>
|
|
195
|
+
<Component {...pageProps} />
|
|
196
|
+
</TranslationProvider>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### 3. Use in pages
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// pages/index.tsx
|
|
205
|
+
import Link from "next/link";
|
|
206
|
+
import { useTranslation } from "@onruntime/translations/react";
|
|
207
|
+
|
|
208
|
+
export default function Home() {
|
|
209
|
+
const { t, locale } = useTranslation();
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<div>
|
|
213
|
+
<h1>{t("greeting", { name: "John" })}</h1>
|
|
214
|
+
<Link href="/about" locale="fr">
|
|
215
|
+
Switch to French
|
|
216
|
+
</Link>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### React + Vite
|
|
223
|
+
|
|
224
|
+
#### 1. Setup provider with Vite loader
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// src/app.tsx
|
|
228
|
+
import { TranslationProvider } from "@onruntime/translations/react";
|
|
229
|
+
import { createViteLoader } from "@onruntime/translations/vite";
|
|
230
|
+
|
|
231
|
+
const modules = import.meta.glob("./locales/**/*.json", { eager: true });
|
|
232
|
+
const load = createViteLoader(modules);
|
|
233
|
+
|
|
234
|
+
const App = () => {
|
|
235
|
+
return (
|
|
236
|
+
<TranslationProvider defaultLocale="en" locales={["en", "fr"]} load={load}>
|
|
237
|
+
<Demo />
|
|
238
|
+
</TranslationProvider>
|
|
239
|
+
);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export default App;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### 2. Use translations
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// src/components/demo.tsx
|
|
249
|
+
import { useTranslation, useLocale } from "@onruntime/translations/react";
|
|
250
|
+
|
|
251
|
+
export const Demo = () => {
|
|
252
|
+
const { t, locale } = useTranslation();
|
|
253
|
+
const { setLocale } = useLocale();
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div>
|
|
257
|
+
<h1>{t("greeting", { name: "John" })}</h1>
|
|
258
|
+
<p>Current locale: {locale}</p>
|
|
259
|
+
<button onClick={() => setLocale(locale === "en" ? "fr" : "en")}>
|
|
260
|
+
Switch language
|
|
261
|
+
</button>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Translation files
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
// locales/en/common.json
|
|
271
|
+
{
|
|
272
|
+
"greeting": "Hello, {name}!",
|
|
273
|
+
"nav": {
|
|
274
|
+
"home": "Home",
|
|
275
|
+
"about": "About"
|
|
276
|
+
},
|
|
277
|
+
"about": {
|
|
278
|
+
"title": "About Us"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/react/contexts/translation-context.tsx
|
|
8
|
+
var TranslationContext = react.createContext(
|
|
9
|
+
null
|
|
10
|
+
);
|
|
11
|
+
var TranslationProvider = ({
|
|
12
|
+
children,
|
|
13
|
+
locales,
|
|
14
|
+
defaultLocale,
|
|
15
|
+
load,
|
|
16
|
+
keySplit = true
|
|
17
|
+
}) => {
|
|
18
|
+
if (locales.length === 0) {
|
|
19
|
+
throw new Error("TranslationProvider: locales array must not be empty");
|
|
20
|
+
}
|
|
21
|
+
const resolvedDefaultLocale = defaultLocale ?? locales[0];
|
|
22
|
+
const [locale, setLocale] = react.useState(resolvedDefaultLocale);
|
|
23
|
+
const value = react.useMemo(
|
|
24
|
+
() => ({
|
|
25
|
+
locale,
|
|
26
|
+
locales,
|
|
27
|
+
defaultLocale: resolvedDefaultLocale,
|
|
28
|
+
setLocale,
|
|
29
|
+
load,
|
|
30
|
+
keySplit
|
|
31
|
+
}),
|
|
32
|
+
[locale, locales, resolvedDefaultLocale, load, keySplit]
|
|
33
|
+
);
|
|
34
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TranslationContext.Provider, { value, children });
|
|
35
|
+
};
|
|
36
|
+
var useTranslationContext = () => {
|
|
37
|
+
const context = react.useContext(TranslationContext);
|
|
38
|
+
if (!context) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"useTranslationContext must be used within a TranslationProvider"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return context;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
exports.TranslationContext = TranslationContext;
|
|
47
|
+
exports.TranslationProvider = TranslationProvider;
|
|
48
|
+
exports.useTranslationContext = useTranslationContext;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useState, useMemo, useContext } from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/react/contexts/translation-context.tsx
|
|
6
|
+
var TranslationContext = createContext(
|
|
7
|
+
null
|
|
8
|
+
);
|
|
9
|
+
var TranslationProvider = ({
|
|
10
|
+
children,
|
|
11
|
+
locales,
|
|
12
|
+
defaultLocale,
|
|
13
|
+
load,
|
|
14
|
+
keySplit = true
|
|
15
|
+
}) => {
|
|
16
|
+
if (locales.length === 0) {
|
|
17
|
+
throw new Error("TranslationProvider: locales array must not be empty");
|
|
18
|
+
}
|
|
19
|
+
const resolvedDefaultLocale = defaultLocale ?? locales[0];
|
|
20
|
+
const [locale, setLocale] = useState(resolvedDefaultLocale);
|
|
21
|
+
const value = useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
locale,
|
|
24
|
+
locales,
|
|
25
|
+
defaultLocale: resolvedDefaultLocale,
|
|
26
|
+
setLocale,
|
|
27
|
+
load,
|
|
28
|
+
keySplit
|
|
29
|
+
}),
|
|
30
|
+
[locale, locales, resolvedDefaultLocale, load, keySplit]
|
|
31
|
+
);
|
|
32
|
+
return /* @__PURE__ */ jsx(TranslationContext.Provider, { value, children });
|
|
33
|
+
};
|
|
34
|
+
var useTranslationContext = () => {
|
|
35
|
+
const context = useContext(TranslationContext);
|
|
36
|
+
if (!context) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"useTranslationContext must be used within a TranslationProvider"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return context;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { TranslationContext, TranslationProvider, useTranslationContext };
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/translate.ts
|
|
4
|
+
var createTranslate = (translation, keySplit = true) => {
|
|
5
|
+
return (key, variables) => {
|
|
6
|
+
const keyList = keySplit ? key.split(".") : [key];
|
|
7
|
+
let parent = translation;
|
|
8
|
+
for (const k of keyList) {
|
|
9
|
+
if (parent && typeof parent === "object" && k in parent) {
|
|
10
|
+
parent = parent[k];
|
|
11
|
+
} else {
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (typeof parent === "string" && variables) {
|
|
16
|
+
return parent.replace(
|
|
17
|
+
/\{(\w+)\}/g,
|
|
18
|
+
(_, name) => String(variables[name] ?? `{${name}}`)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return typeof parent === "string" ? parent : key;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/core/loader.ts
|
|
26
|
+
var getTranslation = (load, locale, namespace = "common") => {
|
|
27
|
+
const dictionary = load(locale, namespace);
|
|
28
|
+
const t = createTranslate(dictionary);
|
|
29
|
+
return { t, locale };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
exports.createTranslate = createTranslate;
|
|
33
|
+
exports.getTranslation = getTranslation;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationVariables = Record<string, string | number>;
|
|
8
|
+
type TranslateFunction = (key: string, variables?: TranslationVariables) => string;
|
|
9
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
10
|
+
type TranslationConfig = {
|
|
11
|
+
locale: string;
|
|
12
|
+
fallbackLocale?: string;
|
|
13
|
+
keySplit?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a translation function for a given dictionary
|
|
18
|
+
*/
|
|
19
|
+
declare const createTranslate: (translation: TranslationDictionary | undefined, keySplit?: boolean) => TranslateFunction;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get translation function for server components or static usage
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Server Component
|
|
27
|
+
* const { t } = getTranslation(load, "en");
|
|
28
|
+
* return <h1>{t("greeting", { name: "John" })}</h1>;
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare const getTranslation: (load: TranslationLoader, locale: string, namespace?: string) => {
|
|
32
|
+
t: TranslateFunction;
|
|
33
|
+
locale: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { type TranslateFunction, type TranslationConfig, type TranslationDictionary, type TranslationLoader, type TranslationValue, type TranslationVariables, createTranslate, getTranslation };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationVariables = Record<string, string | number>;
|
|
8
|
+
type TranslateFunction = (key: string, variables?: TranslationVariables) => string;
|
|
9
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
10
|
+
type TranslationConfig = {
|
|
11
|
+
locale: string;
|
|
12
|
+
fallbackLocale?: string;
|
|
13
|
+
keySplit?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a translation function for a given dictionary
|
|
18
|
+
*/
|
|
19
|
+
declare const createTranslate: (translation: TranslationDictionary | undefined, keySplit?: boolean) => TranslateFunction;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get translation function for server components or static usage
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Server Component
|
|
27
|
+
* const { t } = getTranslation(load, "en");
|
|
28
|
+
* return <h1>{t("greeting", { name: "John" })}</h1>;
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare const getTranslation: (load: TranslationLoader, locale: string, namespace?: string) => {
|
|
32
|
+
t: TranslateFunction;
|
|
33
|
+
locale: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { type TranslateFunction, type TranslationConfig, type TranslationDictionary, type TranslationLoader, type TranslationValue, type TranslationVariables, createTranslate, getTranslation };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/core/translate.ts
|
|
2
|
+
var createTranslate = (translation, keySplit = true) => {
|
|
3
|
+
return (key, variables) => {
|
|
4
|
+
const keyList = keySplit ? key.split(".") : [key];
|
|
5
|
+
let parent = translation;
|
|
6
|
+
for (const k of keyList) {
|
|
7
|
+
if (parent && typeof parent === "object" && k in parent) {
|
|
8
|
+
parent = parent[k];
|
|
9
|
+
} else {
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (typeof parent === "string" && variables) {
|
|
14
|
+
return parent.replace(
|
|
15
|
+
/\{(\w+)\}/g,
|
|
16
|
+
(_, name) => String(variables[name] ?? `{${name}}`)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return typeof parent === "string" ? parent : key;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// src/core/loader.ts
|
|
24
|
+
var getTranslation = (load, locale, namespace = "common") => {
|
|
25
|
+
const dictionary = load(locale, namespace);
|
|
26
|
+
const t = createTranslate(dictionary);
|
|
27
|
+
return { t, locale };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { createTranslate, getTranslation };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk5W5CCQME_cjs = require('../chunk-5W5CCQME.cjs');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var router = require('next/router');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var navigation = require('next/navigation');
|
|
9
|
+
var NextLink = require('next/link');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var NextLink__default = /*#__PURE__*/_interopDefault(NextLink);
|
|
14
|
+
|
|
15
|
+
var NextTranslationProvider = ({
|
|
16
|
+
children,
|
|
17
|
+
load,
|
|
18
|
+
keySplit = true
|
|
19
|
+
}) => {
|
|
20
|
+
const router$1 = router.useRouter();
|
|
21
|
+
const locale = router$1.locale ?? "en";
|
|
22
|
+
const locales = router$1.locales ?? ["en"];
|
|
23
|
+
const defaultLocale = router$1.defaultLocale ?? "en";
|
|
24
|
+
const value = react.useMemo(
|
|
25
|
+
() => ({
|
|
26
|
+
locale,
|
|
27
|
+
locales,
|
|
28
|
+
defaultLocale,
|
|
29
|
+
setLocale: (newLocale) => {
|
|
30
|
+
router$1.push(router$1.pathname, router$1.asPath, { locale: newLocale });
|
|
31
|
+
},
|
|
32
|
+
load,
|
|
33
|
+
keySplit
|
|
34
|
+
}),
|
|
35
|
+
[locale, locales, defaultLocale, router$1, load, keySplit]
|
|
36
|
+
);
|
|
37
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk5W5CCQME_cjs.TranslationContext.Provider, { value, children });
|
|
38
|
+
};
|
|
39
|
+
var AppTranslationProvider = ({
|
|
40
|
+
children,
|
|
41
|
+
locale,
|
|
42
|
+
locales,
|
|
43
|
+
defaultLocale,
|
|
44
|
+
load,
|
|
45
|
+
keySplit = true
|
|
46
|
+
}) => {
|
|
47
|
+
if (locales.length === 0) {
|
|
48
|
+
throw new Error("AppTranslationProvider: locales array must not be empty");
|
|
49
|
+
}
|
|
50
|
+
const router = navigation.useRouter();
|
|
51
|
+
const pathname = navigation.usePathname();
|
|
52
|
+
const value = react.useMemo(
|
|
53
|
+
() => ({
|
|
54
|
+
locale,
|
|
55
|
+
locales,
|
|
56
|
+
defaultLocale: defaultLocale ?? locales[0],
|
|
57
|
+
setLocale: (newLocale) => {
|
|
58
|
+
const segments = pathname.split("/");
|
|
59
|
+
segments[1] = newLocale;
|
|
60
|
+
router.push(segments.join("/"));
|
|
61
|
+
},
|
|
62
|
+
load,
|
|
63
|
+
keySplit
|
|
64
|
+
}),
|
|
65
|
+
[locale, locales, defaultLocale, pathname, router, load, keySplit]
|
|
66
|
+
);
|
|
67
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk5W5CCQME_cjs.TranslationContext.Provider, { value, children });
|
|
68
|
+
};
|
|
69
|
+
var Link = ({ href, locale, ...props }) => {
|
|
70
|
+
const { locale: currentLocale, defaultLocale } = chunk5W5CCQME_cjs.useTranslationContext();
|
|
71
|
+
const targetLocale = locale ?? currentLocale;
|
|
72
|
+
if (typeof href === "string") {
|
|
73
|
+
if (href.startsWith("http") || href.startsWith("//")) {
|
|
74
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { href, ...props });
|
|
75
|
+
}
|
|
76
|
+
if (targetLocale === defaultLocale) {
|
|
77
|
+
const cleanHref = href.startsWith("/") ? href : `/${href}`;
|
|
78
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { href: cleanHref, ...props });
|
|
79
|
+
}
|
|
80
|
+
const localizedHref2 = href.startsWith("/") ? `/${targetLocale}${href}` : `/${targetLocale}/${href}`;
|
|
81
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { href: localizedHref2, ...props });
|
|
82
|
+
}
|
|
83
|
+
const pathname = href.pathname ?? "/";
|
|
84
|
+
if (targetLocale === defaultLocale) {
|
|
85
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { href, ...props });
|
|
86
|
+
}
|
|
87
|
+
const localizedHref = {
|
|
88
|
+
...href,
|
|
89
|
+
pathname: pathname.startsWith("/") ? `/${targetLocale}${pathname}` : `/${targetLocale}/${pathname}`
|
|
90
|
+
};
|
|
91
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { href: localizedHref, ...props });
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
exports.AppTranslationProvider = AppTranslationProvider;
|
|
95
|
+
exports.Link = Link;
|
|
96
|
+
exports.TranslationProvider = NextTranslationProvider;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentProps } from 'react';
|
|
3
|
+
import { T as TranslationLoader } from '../types-BpDtTtSF.cjs';
|
|
4
|
+
import NextLink from 'next/link';
|
|
5
|
+
|
|
6
|
+
type NextTranslationProviderProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
load: TranslationLoader;
|
|
9
|
+
keySplit?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Translation provider for Next.js applications
|
|
13
|
+
* Automatically uses locale info from Next.js router
|
|
14
|
+
*/
|
|
15
|
+
declare const NextTranslationProvider: ({ children, load, keySplit, }: NextTranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
16
|
+
|
|
17
|
+
type AppTranslationProviderProps = {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
locale: string;
|
|
20
|
+
locales: readonly string[];
|
|
21
|
+
defaultLocale?: string;
|
|
22
|
+
load: TranslationLoader;
|
|
23
|
+
keySplit?: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Translation provider for Next.js App Router
|
|
27
|
+
* Locale is passed from route params [lang]
|
|
28
|
+
*/
|
|
29
|
+
declare const AppTranslationProvider: ({ children, locale, locales, defaultLocale, load, keySplit, }: AppTranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
30
|
+
|
|
31
|
+
type LinkProps = ComponentProps<typeof NextLink>;
|
|
32
|
+
/**
|
|
33
|
+
* Link component that automatically prefixes href with the current locale.
|
|
34
|
+
* For the default locale, no prefix is added (Pages Router behavior).
|
|
35
|
+
*/
|
|
36
|
+
declare const Link: ({ href, locale, ...props }: LinkProps) => react_jsx_runtime.JSX.Element;
|
|
37
|
+
|
|
38
|
+
export { AppTranslationProvider, type AppTranslationProviderProps, Link, type LinkProps, NextTranslationProvider as TranslationProvider, type NextTranslationProviderProps as TranslationProviderProps };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentProps } from 'react';
|
|
3
|
+
import { T as TranslationLoader } from '../types-BpDtTtSF.js';
|
|
4
|
+
import NextLink from 'next/link';
|
|
5
|
+
|
|
6
|
+
type NextTranslationProviderProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
load: TranslationLoader;
|
|
9
|
+
keySplit?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Translation provider for Next.js applications
|
|
13
|
+
* Automatically uses locale info from Next.js router
|
|
14
|
+
*/
|
|
15
|
+
declare const NextTranslationProvider: ({ children, load, keySplit, }: NextTranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
16
|
+
|
|
17
|
+
type AppTranslationProviderProps = {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
locale: string;
|
|
20
|
+
locales: readonly string[];
|
|
21
|
+
defaultLocale?: string;
|
|
22
|
+
load: TranslationLoader;
|
|
23
|
+
keySplit?: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Translation provider for Next.js App Router
|
|
27
|
+
* Locale is passed from route params [lang]
|
|
28
|
+
*/
|
|
29
|
+
declare const AppTranslationProvider: ({ children, locale, locales, defaultLocale, load, keySplit, }: AppTranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
30
|
+
|
|
31
|
+
type LinkProps = ComponentProps<typeof NextLink>;
|
|
32
|
+
/**
|
|
33
|
+
* Link component that automatically prefixes href with the current locale.
|
|
34
|
+
* For the default locale, no prefix is added (Pages Router behavior).
|
|
35
|
+
*/
|
|
36
|
+
declare const Link: ({ href, locale, ...props }: LinkProps) => react_jsx_runtime.JSX.Element;
|
|
37
|
+
|
|
38
|
+
export { AppTranslationProvider, type AppTranslationProviderProps, Link, type LinkProps, NextTranslationProvider as TranslationProvider, type NextTranslationProviderProps as TranslationProviderProps };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { TranslationContext, useTranslationContext } from '../chunk-X3HAZ4DT.js';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useRouter } from 'next/router';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
import { useRouter as useRouter$1, usePathname } from 'next/navigation';
|
|
7
|
+
import NextLink from 'next/link';
|
|
8
|
+
|
|
9
|
+
var NextTranslationProvider = ({
|
|
10
|
+
children,
|
|
11
|
+
load,
|
|
12
|
+
keySplit = true
|
|
13
|
+
}) => {
|
|
14
|
+
const router = useRouter();
|
|
15
|
+
const locale = router.locale ?? "en";
|
|
16
|
+
const locales = router.locales ?? ["en"];
|
|
17
|
+
const defaultLocale = router.defaultLocale ?? "en";
|
|
18
|
+
const value = useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
locale,
|
|
21
|
+
locales,
|
|
22
|
+
defaultLocale,
|
|
23
|
+
setLocale: (newLocale) => {
|
|
24
|
+
router.push(router.pathname, router.asPath, { locale: newLocale });
|
|
25
|
+
},
|
|
26
|
+
load,
|
|
27
|
+
keySplit
|
|
28
|
+
}),
|
|
29
|
+
[locale, locales, defaultLocale, router, load, keySplit]
|
|
30
|
+
);
|
|
31
|
+
return /* @__PURE__ */ jsx(TranslationContext.Provider, { value, children });
|
|
32
|
+
};
|
|
33
|
+
var AppTranslationProvider = ({
|
|
34
|
+
children,
|
|
35
|
+
locale,
|
|
36
|
+
locales,
|
|
37
|
+
defaultLocale,
|
|
38
|
+
load,
|
|
39
|
+
keySplit = true
|
|
40
|
+
}) => {
|
|
41
|
+
if (locales.length === 0) {
|
|
42
|
+
throw new Error("AppTranslationProvider: locales array must not be empty");
|
|
43
|
+
}
|
|
44
|
+
const router = useRouter$1();
|
|
45
|
+
const pathname = usePathname();
|
|
46
|
+
const value = useMemo(
|
|
47
|
+
() => ({
|
|
48
|
+
locale,
|
|
49
|
+
locales,
|
|
50
|
+
defaultLocale: defaultLocale ?? locales[0],
|
|
51
|
+
setLocale: (newLocale) => {
|
|
52
|
+
const segments = pathname.split("/");
|
|
53
|
+
segments[1] = newLocale;
|
|
54
|
+
router.push(segments.join("/"));
|
|
55
|
+
},
|
|
56
|
+
load,
|
|
57
|
+
keySplit
|
|
58
|
+
}),
|
|
59
|
+
[locale, locales, defaultLocale, pathname, router, load, keySplit]
|
|
60
|
+
);
|
|
61
|
+
return /* @__PURE__ */ jsx(TranslationContext.Provider, { value, children });
|
|
62
|
+
};
|
|
63
|
+
var Link = ({ href, locale, ...props }) => {
|
|
64
|
+
const { locale: currentLocale, defaultLocale } = useTranslationContext();
|
|
65
|
+
const targetLocale = locale ?? currentLocale;
|
|
66
|
+
if (typeof href === "string") {
|
|
67
|
+
if (href.startsWith("http") || href.startsWith("//")) {
|
|
68
|
+
return /* @__PURE__ */ jsx(NextLink, { href, ...props });
|
|
69
|
+
}
|
|
70
|
+
if (targetLocale === defaultLocale) {
|
|
71
|
+
const cleanHref = href.startsWith("/") ? href : `/${href}`;
|
|
72
|
+
return /* @__PURE__ */ jsx(NextLink, { href: cleanHref, ...props });
|
|
73
|
+
}
|
|
74
|
+
const localizedHref2 = href.startsWith("/") ? `/${targetLocale}${href}` : `/${targetLocale}/${href}`;
|
|
75
|
+
return /* @__PURE__ */ jsx(NextLink, { href: localizedHref2, ...props });
|
|
76
|
+
}
|
|
77
|
+
const pathname = href.pathname ?? "/";
|
|
78
|
+
if (targetLocale === defaultLocale) {
|
|
79
|
+
return /* @__PURE__ */ jsx(NextLink, { href, ...props });
|
|
80
|
+
}
|
|
81
|
+
const localizedHref = {
|
|
82
|
+
...href,
|
|
83
|
+
pathname: pathname.startsWith("/") ? `/${targetLocale}${pathname}` : `/${targetLocale}/${pathname}`
|
|
84
|
+
};
|
|
85
|
+
return /* @__PURE__ */ jsx(NextLink, { href: localizedHref, ...props });
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export { AppTranslationProvider, Link, NextTranslationProvider as TranslationProvider };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk5W5CCQME_cjs = require('../chunk-5W5CCQME.cjs');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
|
|
7
|
+
// src/react/hooks/use-locale.ts
|
|
8
|
+
var useLocale = () => {
|
|
9
|
+
const { locale, locales, setLocale } = chunk5W5CCQME_cjs.useTranslationContext();
|
|
10
|
+
return { locale, locales, setLocale };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/core/translate.ts
|
|
14
|
+
var createTranslate = (translation, keySplit = true) => {
|
|
15
|
+
return (key, variables) => {
|
|
16
|
+
const keyList = keySplit ? key.split(".") : [key];
|
|
17
|
+
let parent = translation;
|
|
18
|
+
for (const k of keyList) {
|
|
19
|
+
if (parent && typeof parent === "object" && k in parent) {
|
|
20
|
+
parent = parent[k];
|
|
21
|
+
} else {
|
|
22
|
+
return key;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (typeof parent === "string" && variables) {
|
|
26
|
+
return parent.replace(
|
|
27
|
+
/\{(\w+)\}/g,
|
|
28
|
+
(_, name) => String(variables[name] ?? `{${name}}`)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return typeof parent === "string" ? parent : key;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/react/hooks/use-translation-loader.ts
|
|
36
|
+
var useTranslationLoader = (namespace) => {
|
|
37
|
+
const { locale, defaultLocale, load, keySplit } = chunk5W5CCQME_cjs.useTranslationContext();
|
|
38
|
+
const translation = react.useMemo(() => {
|
|
39
|
+
let dict = load(locale, namespace);
|
|
40
|
+
if (!dict && defaultLocale !== locale) {
|
|
41
|
+
dict = load(defaultLocale, namespace);
|
|
42
|
+
}
|
|
43
|
+
return dict;
|
|
44
|
+
}, [locale, defaultLocale, namespace, load]);
|
|
45
|
+
const t = react.useMemo(
|
|
46
|
+
() => createTranslate(translation, keySplit),
|
|
47
|
+
[translation, keySplit]
|
|
48
|
+
);
|
|
49
|
+
return { translation, t, locale };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/react/hooks/use-translation.ts
|
|
53
|
+
var useTranslation = (namespace = "common") => {
|
|
54
|
+
const { t, locale } = useTranslationLoader(namespace);
|
|
55
|
+
return { t, locale };
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
Object.defineProperty(exports, "TranslationContext", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function () { return chunk5W5CCQME_cjs.TranslationContext; }
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(exports, "TranslationProvider", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
get: function () { return chunk5W5CCQME_cjs.TranslationProvider; }
|
|
65
|
+
});
|
|
66
|
+
Object.defineProperty(exports, "useTranslationContext", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
get: function () { return chunk5W5CCQME_cjs.useTranslationContext; }
|
|
69
|
+
});
|
|
70
|
+
exports.useLocale = useLocale;
|
|
71
|
+
exports.useTranslation = useTranslation;
|
|
72
|
+
exports.useTranslationLoader = useTranslationLoader;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { T as TranslationLoader, a as TranslationDictionary, b as TranslateFunction } from '../types-BpDtTtSF.cjs';
|
|
5
|
+
|
|
6
|
+
type TranslationContextValue = {
|
|
7
|
+
locale: string;
|
|
8
|
+
locales: readonly string[];
|
|
9
|
+
defaultLocale: string;
|
|
10
|
+
setLocale: (locale: string) => void;
|
|
11
|
+
load: TranslationLoader;
|
|
12
|
+
keySplit?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare const TranslationContext: react.Context<TranslationContextValue | null>;
|
|
15
|
+
type TranslationProviderProps = {
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
locales: readonly string[];
|
|
18
|
+
defaultLocale?: string;
|
|
19
|
+
load: TranslationLoader;
|
|
20
|
+
keySplit?: boolean;
|
|
21
|
+
};
|
|
22
|
+
declare const TranslationProvider: ({ children, locales, defaultLocale, load, keySplit, }: TranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
|
|
24
|
+
declare const useTranslationContext: () => TranslationContextValue;
|
|
25
|
+
|
|
26
|
+
declare const useLocale: () => {
|
|
27
|
+
locale: string;
|
|
28
|
+
locales: readonly string[];
|
|
29
|
+
setLocale: (locale: string) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
declare const useTranslationLoader: (namespace: string) => {
|
|
33
|
+
translation: TranslationDictionary | undefined;
|
|
34
|
+
t: TranslateFunction;
|
|
35
|
+
locale: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type UseTranslationResult = {
|
|
39
|
+
t: TranslateFunction;
|
|
40
|
+
locale: string;
|
|
41
|
+
};
|
|
42
|
+
declare const useTranslation: (namespace?: string) => UseTranslationResult;
|
|
43
|
+
|
|
44
|
+
export { TranslationContext, type TranslationContextValue, TranslationProvider, type TranslationProviderProps, type UseTranslationResult, useLocale, useTranslation, useTranslationContext, useTranslationLoader };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { T as TranslationLoader, a as TranslationDictionary, b as TranslateFunction } from '../types-BpDtTtSF.js';
|
|
5
|
+
|
|
6
|
+
type TranslationContextValue = {
|
|
7
|
+
locale: string;
|
|
8
|
+
locales: readonly string[];
|
|
9
|
+
defaultLocale: string;
|
|
10
|
+
setLocale: (locale: string) => void;
|
|
11
|
+
load: TranslationLoader;
|
|
12
|
+
keySplit?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare const TranslationContext: react.Context<TranslationContextValue | null>;
|
|
15
|
+
type TranslationProviderProps = {
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
locales: readonly string[];
|
|
18
|
+
defaultLocale?: string;
|
|
19
|
+
load: TranslationLoader;
|
|
20
|
+
keySplit?: boolean;
|
|
21
|
+
};
|
|
22
|
+
declare const TranslationProvider: ({ children, locales, defaultLocale, load, keySplit, }: TranslationProviderProps) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
|
|
24
|
+
declare const useTranslationContext: () => TranslationContextValue;
|
|
25
|
+
|
|
26
|
+
declare const useLocale: () => {
|
|
27
|
+
locale: string;
|
|
28
|
+
locales: readonly string[];
|
|
29
|
+
setLocale: (locale: string) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
declare const useTranslationLoader: (namespace: string) => {
|
|
33
|
+
translation: TranslationDictionary | undefined;
|
|
34
|
+
t: TranslateFunction;
|
|
35
|
+
locale: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type UseTranslationResult = {
|
|
39
|
+
t: TranslateFunction;
|
|
40
|
+
locale: string;
|
|
41
|
+
};
|
|
42
|
+
declare const useTranslation: (namespace?: string) => UseTranslationResult;
|
|
43
|
+
|
|
44
|
+
export { TranslationContext, type TranslationContextValue, TranslationProvider, type TranslationProviderProps, type UseTranslationResult, useLocale, useTranslation, useTranslationContext, useTranslationLoader };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useTranslationContext } from '../chunk-X3HAZ4DT.js';
|
|
3
|
+
export { TranslationContext, TranslationProvider, useTranslationContext } from '../chunk-X3HAZ4DT.js';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
|
|
6
|
+
// src/react/hooks/use-locale.ts
|
|
7
|
+
var useLocale = () => {
|
|
8
|
+
const { locale, locales, setLocale } = useTranslationContext();
|
|
9
|
+
return { locale, locales, setLocale };
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/core/translate.ts
|
|
13
|
+
var createTranslate = (translation, keySplit = true) => {
|
|
14
|
+
return (key, variables) => {
|
|
15
|
+
const keyList = keySplit ? key.split(".") : [key];
|
|
16
|
+
let parent = translation;
|
|
17
|
+
for (const k of keyList) {
|
|
18
|
+
if (parent && typeof parent === "object" && k in parent) {
|
|
19
|
+
parent = parent[k];
|
|
20
|
+
} else {
|
|
21
|
+
return key;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (typeof parent === "string" && variables) {
|
|
25
|
+
return parent.replace(
|
|
26
|
+
/\{(\w+)\}/g,
|
|
27
|
+
(_, name) => String(variables[name] ?? `{${name}}`)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return typeof parent === "string" ? parent : key;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/react/hooks/use-translation-loader.ts
|
|
35
|
+
var useTranslationLoader = (namespace) => {
|
|
36
|
+
const { locale, defaultLocale, load, keySplit } = useTranslationContext();
|
|
37
|
+
const translation = useMemo(() => {
|
|
38
|
+
let dict = load(locale, namespace);
|
|
39
|
+
if (!dict && defaultLocale !== locale) {
|
|
40
|
+
dict = load(defaultLocale, namespace);
|
|
41
|
+
}
|
|
42
|
+
return dict;
|
|
43
|
+
}, [locale, defaultLocale, namespace, load]);
|
|
44
|
+
const t = useMemo(
|
|
45
|
+
() => createTranslate(translation, keySplit),
|
|
46
|
+
[translation, keySplit]
|
|
47
|
+
);
|
|
48
|
+
return { translation, t, locale };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/react/hooks/use-translation.ts
|
|
52
|
+
var useTranslation = (namespace = "common") => {
|
|
53
|
+
const { t, locale } = useTranslationLoader(namespace);
|
|
54
|
+
return { t, locale };
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export { useLocale, useTranslation, useTranslationLoader };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationVariables = Record<string, string | number>;
|
|
8
|
+
type TranslateFunction = (key: string, variables?: TranslationVariables) => string;
|
|
9
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
10
|
+
|
|
11
|
+
export type { TranslationLoader as T, TranslationDictionary as a, TranslateFunction as b };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationVariables = Record<string, string | number>;
|
|
8
|
+
type TranslateFunction = (key: string, variables?: TranslationVariables) => string;
|
|
9
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
10
|
+
|
|
11
|
+
export type { TranslationLoader as T, TranslationDictionary as a, TranslateFunction as b };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/vite/loader.ts
|
|
4
|
+
var createViteLoader = (modules, basePath = "./locales") => {
|
|
5
|
+
return (locale, namespace) => {
|
|
6
|
+
const path = `${basePath}/${locale}/${namespace}.json`;
|
|
7
|
+
const module = modules[path];
|
|
8
|
+
if (!module) {
|
|
9
|
+
return void 0;
|
|
10
|
+
}
|
|
11
|
+
if (typeof module === "object" && "default" in module) {
|
|
12
|
+
return module.default;
|
|
13
|
+
}
|
|
14
|
+
return module;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
exports.createViteLoader = createViteLoader;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a translation loader from Vite's import.meta.glob result
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const modules = import.meta.glob('./locales/*.json', { eager: true });
|
|
15
|
+
* const load = createViteLoader(modules);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare const createViteLoader: (modules: Record<string, unknown>, basePath?: string) => TranslationLoader;
|
|
19
|
+
|
|
20
|
+
export { createViteLoader };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type TranslationValue = string | {
|
|
2
|
+
[key: string]: TranslationValue;
|
|
3
|
+
};
|
|
4
|
+
type TranslationDictionary = {
|
|
5
|
+
[key: string]: TranslationValue;
|
|
6
|
+
};
|
|
7
|
+
type TranslationLoader = (locale: string, namespace: string) => TranslationDictionary | undefined;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a translation loader from Vite's import.meta.glob result
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const modules = import.meta.glob('./locales/*.json', { eager: true });
|
|
15
|
+
* const load = createViteLoader(modules);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare const createViteLoader: (modules: Record<string, unknown>, basePath?: string) => TranslationLoader;
|
|
19
|
+
|
|
20
|
+
export { createViteLoader };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/vite/loader.ts
|
|
2
|
+
var createViteLoader = (modules, basePath = "./locales") => {
|
|
3
|
+
return (locale, namespace) => {
|
|
4
|
+
const path = `${basePath}/${locale}/${namespace}.json`;
|
|
5
|
+
const module = modules[path];
|
|
6
|
+
if (!module) {
|
|
7
|
+
return void 0;
|
|
8
|
+
}
|
|
9
|
+
if (typeof module === "object" && "default" in module) {
|
|
10
|
+
return module.default;
|
|
11
|
+
}
|
|
12
|
+
return module;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { createViteLoader };
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@onruntime/translations",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight i18n library for React, Next.js, and React Native",
|
|
5
|
+
"author": "onRuntime Studio <contact@onruntime.com>",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/onRuntime/onruntime.git",
|
|
9
|
+
"directory": "packages/translations"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/onRuntime/onruntime/tree/master/packages/translations#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/onRuntime/onruntime/issues"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/index.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./react": {
|
|
28
|
+
"types": "./dist/react/index.d.ts",
|
|
29
|
+
"import": "./dist/react/index.js",
|
|
30
|
+
"require": "./dist/react/index.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./next": {
|
|
33
|
+
"types": "./dist/next/index.d.ts",
|
|
34
|
+
"import": "./dist/next/index.js",
|
|
35
|
+
"require": "./dist/next/index.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./vite": {
|
|
38
|
+
"types": "./dist/vite/index.d.ts",
|
|
39
|
+
"import": "./dist/vite/index.js",
|
|
40
|
+
"require": "./dist/vite/index.cjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"dev": "tsup --watch",
|
|
49
|
+
"type-check": "tsc --noEmit"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": ">=18.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"next": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"react-native": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^25.0.3",
|
|
64
|
+
"@types/react": "^19",
|
|
65
|
+
"next": "^16.1.1",
|
|
66
|
+
"react": "^19.2.3",
|
|
67
|
+
"tsup": "^8",
|
|
68
|
+
"typescript": "^5"
|
|
69
|
+
},
|
|
70
|
+
"keywords": [
|
|
71
|
+
"i18n",
|
|
72
|
+
"translations",
|
|
73
|
+
"react",
|
|
74
|
+
"nextjs",
|
|
75
|
+
"react-native",
|
|
76
|
+
"internationalization"
|
|
77
|
+
],
|
|
78
|
+
"license": "MIT"
|
|
79
|
+
}
|