astro-react-i18next 0.1.2 → 0.2.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 +42 -18
- package/dist/index.d.ts +4 -0
- package/dist/index.js +28 -26
- package/dist/middleware-server.js +14 -4
- package/dist/middleware-static.js +7 -2
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +7 -2
- package/package.json +22 -18
package/README.md
CHANGED
|
@@ -39,14 +39,15 @@ export default defineConfig({
|
|
|
39
39
|
|
|
40
40
|
The initialization function accepts an optional configuration object with the following options:
|
|
41
41
|
|
|
42
|
-
| Option | Type
|
|
43
|
-
| --------------------- |
|
|
44
|
-
| `defaultLocale` | `string`
|
|
45
|
-
| `locales` | `string[]`
|
|
46
|
-
| `defaultNamespace` | `string`
|
|
47
|
-
| `namespaces` | `string[]`
|
|
48
|
-
| `prefixDefaultLocale` | `boolean`
|
|
49
|
-
| `localesDir` | `string`
|
|
42
|
+
| Option | Type | Description | Default |
|
|
43
|
+
| --------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------- | ------------ |
|
|
44
|
+
| `defaultLocale` | `string` | The default locale to use when no locale is specified. | `"en-US"` |
|
|
45
|
+
| `locales` | `string[]` | An array of locales to support. | `["en-US"]` |
|
|
46
|
+
| `defaultNamespace` | `string` | The default namespace to use when no namespace is specified. | `"common"` |
|
|
47
|
+
| `namespaces` | `string[]` | An array of namespaces to support. | `["common"]` |
|
|
48
|
+
| `prefixDefaultLocale` | `boolean` | Whether to prefix the default locale with the locale code. | `false` |
|
|
49
|
+
| `localesDir` | `string` | The directory where the locale files are stored, relative to the public directory. | `"locales"` |
|
|
50
|
+
| `domains` | `{ domain: string; defaultLocale: string; }[]` | An array of domains for language selection. | `[]` |
|
|
50
51
|
|
|
51
52
|
Here is an example of how to configure the integration:
|
|
52
53
|
|
|
@@ -124,15 +125,17 @@ The content of the `locales/en-US/common.json` file should look like this:
|
|
|
124
125
|
|
|
125
126
|
## Dynamic Routes for Locales
|
|
126
127
|
|
|
127
|
-
To manage dynamic routes for each locale, create a root route named `[...locale]` in the `
|
|
128
|
+
To manage dynamic routes for each locale, create a root route named `[...locale]` in the `pages` directory.
|
|
128
129
|
|
|
129
130
|
```text
|
|
130
131
|
/
|
|
131
132
|
├── public/
|
|
132
133
|
├── src/
|
|
133
|
-
│ └──
|
|
134
|
-
│
|
|
135
|
-
│
|
|
134
|
+
│ └── pages/
|
|
135
|
+
│ └── [...locale]/
|
|
136
|
+
│ ├── index.astro
|
|
137
|
+
│ ├── page-a.astro
|
|
138
|
+
│ └── page-b.astro
|
|
136
139
|
└── package.json
|
|
137
140
|
```
|
|
138
141
|
|
|
@@ -187,12 +190,33 @@ The integration provides utility functions to help manage locales and translatio
|
|
|
187
190
|
|
|
188
191
|
All utility functions are available in the `astro-react-i18next/utils` module.
|
|
189
192
|
|
|
190
|
-
| Function | Description | Returns
|
|
191
|
-
| -------------------------------------------------- | -------------------------------------------------------- |
|
|
192
|
-
| `getLocaleConfig()` | Returns the locale configuration object. | `{ defaultLocale: string
|
|
193
|
-
| `getLocalizedPathname(pathname = "", locale = "")` | Returns the localized pathname for the specified locale. | string
|
|
194
|
-
| `buildStaticPaths()` | Generates static paths for each locale. | `{ params: { locale: string \| undefined; }; }[]`
|
|
195
|
-
| `changeLocale(nextLocale = "", shallow = true)` | Changes the current locale. |
|
|
193
|
+
| Function | Description | Returns |
|
|
194
|
+
| -------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
195
|
+
| `getLocaleConfig()` | Returns the locale configuration object. | `{ defaultLocale: string; locales: string[]; prefixDefaultLocale: boolean; domains: { domain: string; defaultLocale: string; }[]; }` |
|
|
196
|
+
| `getLocalizedPathname(pathname = "", locale = "")` | Returns the localized pathname for the specified locale. | `string` |
|
|
197
|
+
| `buildStaticPaths()` | Generates static paths for each locale. | `{ params: { locale: string \| undefined; }; }[]` |
|
|
198
|
+
| `changeLocale(nextLocale = "", shallow = true)` | Changes the current locale. | |
|
|
199
|
+
|
|
200
|
+
## Developing locally
|
|
201
|
+
|
|
202
|
+
Clone the repository:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
git clone https://github.com/jeremyxgo/astro-react-i18next.git
|
|
206
|
+
cd astro-react-i18next
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Build the package:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
npm run build
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Install the package in your project:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
npm install $(npm pack /path/to/astro-react-i18next | tail -1)
|
|
219
|
+
```
|
|
196
220
|
|
|
197
221
|
## License
|
|
198
222
|
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ interface AstroReactI18nextOptions {
|
|
|
6
6
|
namespaces?: string[];
|
|
7
7
|
prefixDefaultLocale?: boolean;
|
|
8
8
|
localesDir?: string;
|
|
9
|
+
domains?: {
|
|
10
|
+
domain: string;
|
|
11
|
+
defaultLocale: string;
|
|
12
|
+
}[];
|
|
9
13
|
}
|
|
10
14
|
type MergedAstroReactI18nextOptions = {
|
|
11
15
|
[key in keyof AstroReactI18nextOptions]-?: AstroReactI18nextOptions[key];
|
package/dist/index.js
CHANGED
|
@@ -7,17 +7,14 @@ var DEFAULT_OPTIONS = {
|
|
|
7
7
|
defaultNamespace: "common",
|
|
8
8
|
namespaces: ["common"],
|
|
9
9
|
prefixDefaultLocale: false,
|
|
10
|
-
localesDir: "locales"
|
|
10
|
+
localesDir: "locales",
|
|
11
|
+
domains: []
|
|
11
12
|
};
|
|
12
13
|
function buildI18nextInitScript({
|
|
13
14
|
backendType,
|
|
14
15
|
basePath,
|
|
15
|
-
|
|
16
|
+
mergedOptions
|
|
16
17
|
}) {
|
|
17
|
-
const mergedOptions = {
|
|
18
|
-
...DEFAULT_OPTIONS,
|
|
19
|
-
...options
|
|
20
|
-
};
|
|
21
18
|
let imports = "";
|
|
22
19
|
let i18nextPlugins = "";
|
|
23
20
|
let i18nextOptions = "";
|
|
@@ -26,7 +23,7 @@ function buildI18nextInitScript({
|
|
|
26
23
|
import Backend from "i18next-fs-backend";
|
|
27
24
|
`;
|
|
28
25
|
i18nextOptions = `
|
|
29
|
-
|
|
26
|
+
initAsync: false,
|
|
30
27
|
`;
|
|
31
28
|
}
|
|
32
29
|
if (backendType === "http") {
|
|
@@ -64,13 +61,28 @@ function buildI18nextInitScript({
|
|
|
64
61
|
escapeValue: false,
|
|
65
62
|
},
|
|
66
63
|
backend: {
|
|
67
|
-
loadPath: "${path.join(basePath, mergedOptions.localesDir)}/{{lng}}/{{ns}}.json",
|
|
64
|
+
loadPath: "${path.join(basePath, mergedOptions.localesDir || "")}/{{lng}}/{{ns}}.json",
|
|
68
65
|
},
|
|
69
66
|
astroReactI18next: ${JSON.stringify(mergedOptions)},
|
|
70
67
|
${i18nextOptions}
|
|
71
68
|
});
|
|
72
69
|
`;
|
|
73
70
|
}
|
|
71
|
+
function buildLocaleRestorationScript(mergedOptions) {
|
|
72
|
+
return `
|
|
73
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
74
|
+
const defaultLocale = "${mergedOptions.defaultLocale}";
|
|
75
|
+
const locales = ${JSON.stringify(mergedOptions.locales)};
|
|
76
|
+
let detectedLocale = window.location.pathname.split("/")[1];
|
|
77
|
+
|
|
78
|
+
if (!locales.includes(detectedLocale)) {
|
|
79
|
+
detectedLocale = defaultLocale;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
i18n.changeLanguage(detectedLocale);
|
|
83
|
+
});
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
74
86
|
function AstroReactI18nextIntegration(options) {
|
|
75
87
|
const mergedOptions = {
|
|
76
88
|
...DEFAULT_OPTIONS,
|
|
@@ -85,39 +97,29 @@ function AstroReactI18nextIntegration(options) {
|
|
|
85
97
|
injectScript,
|
|
86
98
|
updateConfig
|
|
87
99
|
}) => {
|
|
88
|
-
const
|
|
89
|
-
window.addEventListener("DOMContentLoaded", () => {
|
|
90
|
-
const defaultLocale = "${mergedOptions.defaultLocale}";
|
|
91
|
-
const locales = ${JSON.stringify(mergedOptions.locales)};
|
|
92
|
-
let detectedLocale = window.location.pathname.split("/")[1];
|
|
93
|
-
|
|
94
|
-
if (!locales.includes(detectedLocale)) {
|
|
95
|
-
detectedLocale = defaultLocale;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
i18n.changeLanguage(detectedLocale);
|
|
99
|
-
});
|
|
100
|
-
`;
|
|
100
|
+
const middlewareEntrypoint = config.output === "server" ? `${INTEGRATION_NAME}/middleware/server` : `${INTEGRATION_NAME}/middleware/static`;
|
|
101
101
|
const clientI18nextInitScript = buildI18nextInitScript({
|
|
102
102
|
backendType: "http",
|
|
103
103
|
basePath: "/",
|
|
104
|
-
|
|
104
|
+
mergedOptions
|
|
105
105
|
});
|
|
106
106
|
const serverI18nextInitScript = buildI18nextInitScript({
|
|
107
107
|
backendType: "fs",
|
|
108
108
|
basePath: config.publicDir.pathname,
|
|
109
|
-
|
|
109
|
+
mergedOptions
|
|
110
110
|
});
|
|
111
|
-
const
|
|
111
|
+
const localeRestorationScript = buildLocaleRestorationScript(mergedOptions);
|
|
112
112
|
addMiddleware({
|
|
113
113
|
entrypoint: middlewareEntrypoint,
|
|
114
114
|
order: "post"
|
|
115
115
|
});
|
|
116
116
|
injectScript("page-ssr", serverI18nextInitScript);
|
|
117
117
|
injectScript("before-hydration", clientI18nextInitScript);
|
|
118
|
-
injectScript("before-hydration", clientLocaleRestorationScript);
|
|
119
118
|
injectScript("page", clientI18nextInitScript);
|
|
120
|
-
|
|
119
|
+
if (mergedOptions.domains.length === 0) {
|
|
120
|
+
injectScript("before-hydration", localeRestorationScript);
|
|
121
|
+
injectScript("page", localeRestorationScript);
|
|
122
|
+
}
|
|
121
123
|
updateConfig({
|
|
122
124
|
i18n: {
|
|
123
125
|
locales: mergedOptions.locales,
|
|
@@ -4,8 +4,13 @@ import i18n2 from "i18next";
|
|
|
4
4
|
// src/utils.ts
|
|
5
5
|
import i18n from "i18next";
|
|
6
6
|
function getLocaleConfig() {
|
|
7
|
-
const { defaultLocale, locales, prefixDefaultLocale } = i18n.options.astroReactI18next;
|
|
8
|
-
return {
|
|
7
|
+
const { defaultLocale, locales, prefixDefaultLocale, domains } = i18n.options.astroReactI18next;
|
|
8
|
+
return {
|
|
9
|
+
defaultLocale,
|
|
10
|
+
locales,
|
|
11
|
+
prefixDefaultLocale,
|
|
12
|
+
domains
|
|
13
|
+
};
|
|
9
14
|
}
|
|
10
15
|
function getLocalizedPathname(pathname = "", locale = "") {
|
|
11
16
|
const { defaultLocale, locales, prefixDefaultLocale } = getLocaleConfig();
|
|
@@ -22,11 +27,16 @@ function getLocalizedPathname(pathname = "", locale = "") {
|
|
|
22
27
|
|
|
23
28
|
// src/middleware-server.ts
|
|
24
29
|
async function onRequest(context, next) {
|
|
25
|
-
const { defaultLocale, locales } = getLocaleConfig();
|
|
30
|
+
const { defaultLocale, locales, domains } = getLocaleConfig();
|
|
31
|
+
const localesByDomain = Object.fromEntries(
|
|
32
|
+
domains.map((domain) => [domain.domain, domain.defaultLocale])
|
|
33
|
+
);
|
|
34
|
+
const localeFromDomain = localesByDomain[context.url.host];
|
|
26
35
|
const localeFromPathname = context.url.pathname.split("/")[1];
|
|
27
36
|
const localeFromCookie = context.cookies.get("i18next")?.value;
|
|
28
37
|
const localeFromHeader = context.preferredLocale;
|
|
29
38
|
const nextLocale = [
|
|
39
|
+
localeFromDomain,
|
|
30
40
|
localeFromPathname,
|
|
31
41
|
localeFromCookie,
|
|
32
42
|
localeFromHeader,
|
|
@@ -36,7 +46,7 @@ async function onRequest(context, next) {
|
|
|
36
46
|
context.cookies.set("i18next", nextLocale || "", { path: "/" });
|
|
37
47
|
const { hash, pathname, search } = context.url;
|
|
38
48
|
const nextPathname = getLocalizedPathname(pathname, nextLocale);
|
|
39
|
-
if (nextPathname !== pathname) {
|
|
49
|
+
if (nextPathname !== pathname && domains.length === 0) {
|
|
40
50
|
const nextUrl = nextPathname + search + hash;
|
|
41
51
|
return context.redirect(nextUrl);
|
|
42
52
|
}
|
|
@@ -4,8 +4,13 @@ import i18n2 from "i18next";
|
|
|
4
4
|
// src/utils.ts
|
|
5
5
|
import i18n from "i18next";
|
|
6
6
|
function getLocaleConfig() {
|
|
7
|
-
const { defaultLocale, locales, prefixDefaultLocale } = i18n.options.astroReactI18next;
|
|
8
|
-
return {
|
|
7
|
+
const { defaultLocale, locales, prefixDefaultLocale, domains } = i18n.options.astroReactI18next;
|
|
8
|
+
return {
|
|
9
|
+
defaultLocale,
|
|
10
|
+
locales,
|
|
11
|
+
prefixDefaultLocale,
|
|
12
|
+
domains
|
|
13
|
+
};
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
// src/middleware-static.ts
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ export declare function getLocaleConfig(): {
|
|
|
2
2
|
defaultLocale: string;
|
|
3
3
|
locales: string[];
|
|
4
4
|
prefixDefaultLocale: boolean;
|
|
5
|
+
domains: {
|
|
6
|
+
domain: string;
|
|
7
|
+
defaultLocale: string;
|
|
8
|
+
}[];
|
|
5
9
|
};
|
|
6
10
|
export declare function getLocalizedPathname(pathname?: string, locale?: string): string;
|
|
7
11
|
export declare function buildStaticPaths(): {
|
package/dist/utils.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// src/utils.ts
|
|
2
2
|
import i18n from "i18next";
|
|
3
3
|
function getLocaleConfig() {
|
|
4
|
-
const { defaultLocale, locales, prefixDefaultLocale } = i18n.options.astroReactI18next;
|
|
5
|
-
return {
|
|
4
|
+
const { defaultLocale, locales, prefixDefaultLocale, domains } = i18n.options.astroReactI18next;
|
|
5
|
+
return {
|
|
6
|
+
defaultLocale,
|
|
7
|
+
locales,
|
|
8
|
+
prefixDefaultLocale,
|
|
9
|
+
domains
|
|
10
|
+
};
|
|
6
11
|
}
|
|
7
12
|
function getLocalizedPathname(pathname = "", locale = "") {
|
|
8
13
|
const { defaultLocale, locales, prefixDefaultLocale } = getLocaleConfig();
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-react-i18next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Integrates i18next and react-i18next seamlessly into your Astro website to provide robust i18n support for React components.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro-integration",
|
|
7
|
-
"withastro"
|
|
7
|
+
"withastro",
|
|
8
|
+
"i18n",
|
|
9
|
+
"i18next",
|
|
10
|
+
"react"
|
|
8
11
|
],
|
|
9
12
|
"author": "jeremyxgo",
|
|
10
13
|
"license": "MIT",
|
|
@@ -12,10 +15,11 @@
|
|
|
12
15
|
"type": "git",
|
|
13
16
|
"url": "https://github.com/jeremyxgo/astro-react-i18next.git"
|
|
14
17
|
},
|
|
15
|
-
"type": "module",
|
|
16
18
|
"files": [
|
|
17
19
|
"dist"
|
|
18
20
|
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
19
23
|
"exports": {
|
|
20
24
|
".": "./dist/index.js",
|
|
21
25
|
"./middleware/server": "./dist/middleware-server.js",
|
|
@@ -29,29 +33,29 @@
|
|
|
29
33
|
"prepare": "husky"
|
|
30
34
|
},
|
|
31
35
|
"dependencies": {
|
|
32
|
-
"i18next": "^
|
|
36
|
+
"i18next": "^24.0.2",
|
|
33
37
|
"i18next-browser-languagedetector": "^8.0.0",
|
|
34
|
-
"i18next-fs-backend": "^2.
|
|
35
|
-
"i18next-http-backend": "^
|
|
36
|
-
"react-i18next": "^15.
|
|
38
|
+
"i18next-fs-backend": "^2.6.0",
|
|
39
|
+
"i18next-http-backend": "^3.0.1",
|
|
40
|
+
"react-i18next": "^15.1.2"
|
|
37
41
|
},
|
|
38
42
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^22.
|
|
40
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
41
|
-
"@typescript-eslint/parser": "^8.
|
|
42
|
-
"astro": "^4.
|
|
43
|
-
"astro-eslint-parser": "^1.0
|
|
43
|
+
"@types/node": "^22.10.1",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^8.16.0",
|
|
45
|
+
"@typescript-eslint/parser": "^8.16.0",
|
|
46
|
+
"astro": "^4.16.16",
|
|
47
|
+
"astro-eslint-parser": "^1.1.0",
|
|
44
48
|
"esbuild": "^0.24.0",
|
|
45
49
|
"eslint": "^8.57.1",
|
|
46
50
|
"eslint-config-prettier": "^9.1.0",
|
|
47
|
-
"eslint-plugin-astro": "^1.
|
|
48
|
-
"eslint-plugin-import": "^2.
|
|
49
|
-
"eslint-plugin-react": "^7.37.
|
|
50
|
-
"husky": "^9.1.
|
|
51
|
+
"eslint-plugin-astro": "^1.3.1",
|
|
52
|
+
"eslint-plugin-import": "^2.31.0",
|
|
53
|
+
"eslint-plugin-react": "^7.37.2",
|
|
54
|
+
"husky": "^9.1.7",
|
|
51
55
|
"lint-staged": "^15.2.10",
|
|
52
|
-
"prettier": "^3.
|
|
56
|
+
"prettier": "^3.4.1",
|
|
53
57
|
"prettier-plugin-astro": "^0.14.1",
|
|
54
|
-
"typescript": "^5.
|
|
58
|
+
"typescript": "^5.7.2"
|
|
55
59
|
},
|
|
56
60
|
"engines": {
|
|
57
61
|
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|