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 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 | 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"` |
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 `src` directory.
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
- │ └── [...locale]/
134
- ├── ...
135
- └── index.jsx
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, locales: string[], prefixDefaultLocale: boolean }` |
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
- options
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
- initImmediate: false,
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 clientLocaleRestorationScript = `
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
- options
104
+ mergedOptions
105
105
  });
106
106
  const serverI18nextInitScript = buildI18nextInitScript({
107
107
  backendType: "fs",
108
108
  basePath: config.publicDir.pathname,
109
- options
109
+ mergedOptions
110
110
  });
111
- const middlewareEntrypoint = config.output === "server" ? `${INTEGRATION_NAME}/middleware/server` : `${INTEGRATION_NAME}/middleware/static`;
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
- injectScript("page", clientLocaleRestorationScript);
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 { defaultLocale, locales, prefixDefaultLocale };
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 { defaultLocale, locales, prefixDefaultLocale };
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 { defaultLocale, locales, prefixDefaultLocale };
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.1.2",
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": "^23.15.1",
36
+ "i18next": "^24.0.2",
33
37
  "i18next-browser-languagedetector": "^8.0.0",
34
- "i18next-fs-backend": "^2.3.2",
35
- "i18next-http-backend": "^2.6.1",
36
- "react-i18next": "^15.0.2"
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.7.4",
40
- "@typescript-eslint/eslint-plugin": "^8.7.0",
41
- "@typescript-eslint/parser": "^8.7.0",
42
- "astro": "^4.15.9",
43
- "astro-eslint-parser": "^1.0.3",
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.2.4",
48
- "eslint-plugin-import": "^2.30.0",
49
- "eslint-plugin-react": "^7.37.0",
50
- "husky": "^9.1.6",
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.3.3",
56
+ "prettier": "^3.4.1",
53
57
  "prettier-plugin-astro": "^0.14.1",
54
- "typescript": "^5.5.4"
58
+ "typescript": "^5.7.2"
55
59
  },
56
60
  "engines": {
57
61
  "node": "^18.17.1 || ^20.3.0 || >=21.0.0"