cloudflare-next-intl-intl 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +279 -2
- package/dist/package.json +3 -0
- package/dist/src/client/components/client_provider.d.ts +8 -0
- package/dist/src/client/components/client_provider.js +12 -0
- package/dist/src/client/components/client_provider_static.d.ts +8 -0
- package/dist/src/client/components/client_provider_static.js +12 -0
- package/dist/src/client/components/locale_link.d.ts +8 -0
- package/dist/src/client/components/locale_link.js +8 -0
- package/dist/src/client/components/locale_link_client.d.ts +3 -0
- package/dist/src/client/components/locale_link_client.js +30 -0
- package/dist/src/client/components/locale_provider.d.ts +13 -0
- package/dist/src/client/components/locale_provider.js +8 -0
- package/dist/src/client/functions/get_cookie.d.ts +1 -0
- package/dist/src/client/functions/get_cookie.js +27 -0
- package/dist/src/client/functions/set_cookie.d.ts +5 -0
- package/dist/src/client/functions/set_cookie.js +12 -0
- package/dist/src/client/hooks/client_hooks.d.ts +3 -0
- package/dist/src/client/hooks/client_hooks.js +19 -0
- package/dist/src/client/hooks/use_path_name.d.ts +2 -0
- package/dist/src/client/hooks/use_path_name.js +18 -0
- package/dist/src/client/index.d.ts +4 -0
- package/dist/src/client/index.js +4 -0
- package/dist/src/client_messages_scan/index.d.ts +3 -0
- package/dist/src/client_messages_scan/index.js +3 -0
- package/dist/src/client_messages_scan/match_namespace.d.ts +1 -0
- package/dist/src/client_messages_scan/match_namespace.js +3 -0
- package/dist/src/client_messages_scan/scan_file.d.ts +16 -0
- package/dist/src/client_messages_scan/scan_file.js +182 -0
- package/dist/src/client_messages_scan/scan_project.d.ts +16 -0
- package/dist/src/client_messages_scan/scan_project.js +67 -0
- package/dist/src/config/cookie_key.d.ts +4 -0
- package/dist/src/config/cookie_key.js +4 -0
- package/dist/src/config/create_intl_middleware.d.ts +16 -0
- package/dist/src/config/create_intl_middleware.js +174 -0
- package/dist/src/config/index.d.ts +4 -0
- package/dist/src/config/index.js +4 -0
- package/dist/src/config/init_config.d.ts +2 -0
- package/dist/src/config/init_config.js +3 -0
- package/dist/src/config/intl_config.d.ts +3 -0
- package/dist/src/config/intl_config.js +22 -0
- package/dist/src/config/intl_sitemap.d.ts +8 -0
- package/dist/src/config/intl_sitemap.js +28 -0
- package/dist/src/config/middleware.d.ts +7 -0
- package/dist/src/config/middleware.js +4 -0
- package/dist/src/general/cache_variables.d.ts +10 -0
- package/dist/src/general/cache_variables.js +25 -0
- package/dist/src/general/general_functions.d.ts +2 -0
- package/dist/src/general/general_functions.js +106 -0
- package/dist/src/general/index.d.ts +2 -0
- package/dist/src/general/index.js +2 -0
- package/dist/src/general/metadata.d.ts +13 -0
- package/dist/src/general/metadata.js +25 -0
- package/dist/src/general/pick_client_messages.d.ts +2 -0
- package/dist/src/general/pick_client_messages.js +17 -0
- package/dist/src/general/report_intl_error.d.ts +1 -0
- package/dist/src/general/report_intl_error.js +15 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +5 -0
- package/dist/src/server/components/helper_script.d.ts +6 -0
- package/dist/src/server/components/helper_script.js +39 -0
- package/dist/src/server/components/link.d.ts +10 -0
- package/dist/src/server/components/link.js +143 -0
- package/dist/src/server/components/server_provider.d.ts +8 -0
- package/dist/src/server/components/server_provider.js +24 -0
- package/dist/src/server/components/server_provider_static.d.ts +6 -0
- package/dist/src/server/components/server_provider_static.js +23 -0
- package/dist/src/server/functions/geo.d.ts +8 -0
- package/dist/src/server/functions/geo.js +223 -0
- package/dist/src/server/functions/get_user_locale.d.ts +3 -0
- package/dist/src/server/functions/get_user_locale.js +34 -0
- package/dist/src/server/functions/locale_static_params.d.ts +3 -0
- package/dist/src/server/functions/locale_static_params.js +4 -0
- package/dist/src/server/functions/server.d.ts +8 -0
- package/dist/src/server/functions/server.js +64 -0
- package/dist/src/server/functions/use_functions.d.ts +6 -0
- package/dist/src/server/functions/use_functions.js +30 -0
- package/dist/src/server/index.d.ts +6 -0
- package/dist/src/server/index.js +6 -0
- package/dist/src/types/index.d.ts +1 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/types.d.ts +94 -0
- package/dist/src/types/types.js +3 -0
- package/llms.txt +17 -0
- package/package.json +282 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Demian
|
|
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
CHANGED
|
@@ -1,3 +1,280 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cloudflare-next-intl-intl
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/cloudflare-next-intl-intl)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
Lightweight internationalization (i18n) for the **Next.js App Router**, built for
|
|
7
|
+
**Cloudflare Workers / Pages** (OpenNext and Vinext).
|
|
8
|
+
|
|
9
|
+
This is the core i18n engine of [`cloudflare-next-intl`](https://www.npmjs.com/package/cloudflare-next-intl),
|
|
10
|
+
published on its own with **zero runtime dependencies** and no auth, cookie-consent,
|
|
11
|
+
image or database code. Use it when you only need routing + translations; use
|
|
12
|
+
`cloudflare-next-intl` when you also want those extras auto-wired.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- Locale routing middleware (prefix redirects/rewrites, cookie + `Accept-Language` detection).
|
|
17
|
+
- Translations in Server Components (`getTranslations`) and Client Components (`useTranslations`).
|
|
18
|
+
- Ships only the message namespaces your client components need (`clientMessages`).
|
|
19
|
+
- Locale-aware `Link` / `LocaleLink`, `usePathname`, `getLocale`, `useLocale`.
|
|
20
|
+
- Cloudflare geo helpers: `getCountry`, `getTimezone`.
|
|
21
|
+
- SEO helpers: `hreflang` / canonical alternates via `alternatesLinks`.
|
|
22
|
+
- One subpath export per feature, so unused code is tree-shaken away.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install cloudflare-next-intl-intl
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Peer dependencies: `next` (>= 12) and `react` (>= 16.8).
|
|
31
|
+
|
|
32
|
+
## Setup
|
|
33
|
+
|
|
34
|
+
The package finds your config through the `@intl-config` module alias and your
|
|
35
|
+
message files through `@locale-file`.
|
|
36
|
+
|
|
37
|
+
### 1. Create the config file
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// src/i18n/intl_config.ts
|
|
41
|
+
import { setIntlConfig } from "cloudflare-next-intl-intl/setIntlConfig";
|
|
42
|
+
|
|
43
|
+
export default setIntlConfig({
|
|
44
|
+
locales: ["en", "de"],
|
|
45
|
+
defaultLocale: "en",
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Add message files
|
|
50
|
+
|
|
51
|
+
One JSON file per locale, named `<locale>.json`:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/i18n/messages/en.json
|
|
55
|
+
src/i18n/messages/de.json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"Index": {
|
|
61
|
+
"title": "Hello world",
|
|
62
|
+
"items": ["One", "Two"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Add the aliases in `next.config`
|
|
68
|
+
|
|
69
|
+
Set them for both Turbopack and webpack. If one is missing, the build that uses
|
|
70
|
+
that bundler fails.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// next.config.ts
|
|
74
|
+
import type { NextConfig } from "next";
|
|
75
|
+
import path from "path";
|
|
76
|
+
|
|
77
|
+
const nextConfig: NextConfig = {
|
|
78
|
+
turbopack: {
|
|
79
|
+
resolveAlias: {
|
|
80
|
+
"@intl-config": "./src/i18n/intl_config.ts",
|
|
81
|
+
"@locale-file": "./src/i18n/messages",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
webpack(config) {
|
|
85
|
+
config.resolve.alias = {
|
|
86
|
+
...config.resolve.alias,
|
|
87
|
+
"@intl-config": path.resolve(__dirname, "src/i18n/intl_config"),
|
|
88
|
+
"@locale-file": path.resolve(__dirname, "src/i18n/messages"),
|
|
89
|
+
};
|
|
90
|
+
return config;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default nextConfig;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If you deploy to Cloudflare Workers with Wrangler, add the same aliases to `wrangler.toml`:
|
|
98
|
+
|
|
99
|
+
```toml
|
|
100
|
+
[alias]
|
|
101
|
+
"@intl-config" = "./src/i18n/intl_config.ts"
|
|
102
|
+
"@locale-file" = "./src/i18n/messages"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. Add the middleware
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// src/middleware.ts
|
|
109
|
+
import intlMiddleware from "cloudflare-next-intl-intl/middleware";
|
|
110
|
+
|
|
111
|
+
export const middleware = intlMiddleware;
|
|
112
|
+
|
|
113
|
+
export const config = {
|
|
114
|
+
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
|
|
115
|
+
};
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
To run your own logic (auth, feature flags, A/B tests) on each request, pass a `middlewareHandler`:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
export function middleware(request: NextRequest) {
|
|
122
|
+
return intlMiddleware(request, {
|
|
123
|
+
middlewareHandler: (locale, rewriteUrl, redirectUrl) => {
|
|
124
|
+
return null; // return a NextResponse to override, or null to keep the default
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If you need the final response, for example to update session cookies, build
|
|
131
|
+
your own middleware with `createIntlMiddleware({ afterResponse })`.
|
|
132
|
+
|
|
133
|
+
### 5. Set up the root layout
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// src/app/[locale]/layout.tsx
|
|
137
|
+
import { IntlProvider, IntlHelperScript, getLocaleStaticParams } from "cloudflare-next-intl-intl/server";
|
|
138
|
+
|
|
139
|
+
export const generateStaticParams = getLocaleStaticParams;
|
|
140
|
+
|
|
141
|
+
export default async function RootLayout({ children, params }) {
|
|
142
|
+
const { locale } = await params;
|
|
143
|
+
return (
|
|
144
|
+
<html lang={locale}>
|
|
145
|
+
<head>
|
|
146
|
+
<IntlHelperScript locale={locale} />
|
|
147
|
+
</head>
|
|
148
|
+
<body>
|
|
149
|
+
<IntlProvider language={locale}>{children}</IntlProvider>
|
|
150
|
+
</body>
|
|
151
|
+
</html>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
If you build with `output: "export"`, import `IntlProvider` from
|
|
157
|
+
`cloudflare-next-intl-intl/serverProviderStatic` instead.
|
|
158
|
+
|
|
159
|
+
## Usage
|
|
160
|
+
|
|
161
|
+
### Server Components
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { getTranslations, getLocale } from "cloudflare-next-intl-intl/server";
|
|
165
|
+
|
|
166
|
+
export default async function Page() {
|
|
167
|
+
const t = await getTranslations("Index");
|
|
168
|
+
const locale = await getLocale();
|
|
169
|
+
const items = t.raw("items") as string[];
|
|
170
|
+
|
|
171
|
+
return <h1>{t("title")} ({locale})</h1>;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`t(key)` always returns a string. For arrays or nested objects, use `t.raw(key)`.
|
|
176
|
+
|
|
177
|
+
### Client Components
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
"use client";
|
|
181
|
+
|
|
182
|
+
import { useTranslations, useLocale } from "cloudflare-next-intl-intl/use";
|
|
183
|
+
|
|
184
|
+
export function Title() {
|
|
185
|
+
const t = useTranslations("Index");
|
|
186
|
+
const locale = useLocale();
|
|
187
|
+
return <h1>{t("title")} ({locale})</h1>;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`cloudflare-next-intl-intl/use` works in both Server and Client Components and
|
|
192
|
+
picks the right implementation automatically.
|
|
193
|
+
|
|
194
|
+
By default (`clientMessages: "auto"`), only the namespaces your client
|
|
195
|
+
components use are sent to the browser. You can set this in `setIntlConfig`:
|
|
196
|
+
|
|
197
|
+
- `clientMessages: false`: send no messages to the browser.
|
|
198
|
+
- `clientMessages: true`: send all messages.
|
|
199
|
+
- `clientMessages: ["Common", "Auth*"]`: send only the listed namespaces (prefix wildcards allowed).
|
|
200
|
+
|
|
201
|
+
### Links
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import Link from "cloudflare-next-intl-intl/Link";
|
|
205
|
+
import LocaleLink from "cloudflare-next-intl-intl/LocaleLink";
|
|
206
|
+
|
|
207
|
+
<Link href="/about">About</Link> // stays on the current locale: "/about" or "/de/about"
|
|
208
|
+
<LocaleLink href="/" locale="de">Deutsch</LocaleLink> // client-only, switches the locale
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`usePathname` (`cloudflare-next-intl-intl/usePathname`) returns the current path
|
|
212
|
+
without the locale prefix.
|
|
213
|
+
|
|
214
|
+
### Geo & timezone (Cloudflare)
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import { getCountry, getTimezone } from "cloudflare-next-intl-intl/geo";
|
|
218
|
+
|
|
219
|
+
const country = await getCountry(); // "US", "DE", "UA", ...
|
|
220
|
+
const timezone = await getTimezone(undefined, "UTC");
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
These work in Server Components, Server Actions, Route Handlers, and middleware
|
|
224
|
+
(pass `request` there). The middleware forwards the Cloudflare
|
|
225
|
+
`x-cf-country` / `x-cf-timezone` headers, so these values are also available
|
|
226
|
+
further down the request. You can change the header names with
|
|
227
|
+
`generate.countryHeaderNames` / `generate.timezoneHeaderNames`.
|
|
228
|
+
|
|
229
|
+
### SEO metadata
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
import { alternatesLinks } from "cloudflare-next-intl-intl/metadata";
|
|
233
|
+
|
|
234
|
+
export async function generateMetadata({ params }) {
|
|
235
|
+
const { locale } = await params;
|
|
236
|
+
return {
|
|
237
|
+
alternates: alternatesLinks({ url: "https://example.com", locale, linkPart: "/about" }),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Cookies
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import setCookie from "cloudflare-next-intl-intl/setCookie";
|
|
246
|
+
import getCookie from "cloudflare-next-intl-intl/getCookie";
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Public subpath exports
|
|
250
|
+
|
|
251
|
+
| Subpath | Contents |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `.` | Everything below (prefer the specific subpaths for tree-shaking) |
|
|
254
|
+
| `./setIntlConfig` | `setIntlConfig` |
|
|
255
|
+
| `./middleware` | default `intlMiddleware`, `createIntlMiddleware` |
|
|
256
|
+
| `./server` | `getTranslations`, `getLocale`, `getMessage`, `IntlProvider`, `Link`, `IntlHelperScript`, `getLocaleStaticParams`, `getCountry`, `getTimezone` |
|
|
257
|
+
| `./client` | `LocaleLink`, `usePathname`, `setCookieClient`, `getCookieClient` |
|
|
258
|
+
| `./use` | `useTranslations`, `useLocale` (works in Server and Client Components) |
|
|
259
|
+
| `./serverProvider`, `./serverProviderStatic` | `IntlProvider` variants |
|
|
260
|
+
| `./Link`, `./LocaleLink`, `./usePathname`, `./IntlHelperScript` | Single components / hooks |
|
|
261
|
+
| `./geo`, `./getCountry`, `./getTimezone` | Geo helpers |
|
|
262
|
+
| `./metadata` | `alternatesLinks`, `languages` |
|
|
263
|
+
| `./localeStaticParams` | `getLocaleStaticParams` |
|
|
264
|
+
| `./setCookie`, `./getCookie`, `./setCookieClient`, `./getCookieClient` | Cookie helpers |
|
|
265
|
+
| `./types` | TypeScript types (`IntlRoutingConfig`, `RoutingConfig`, ...) |
|
|
266
|
+
|
|
267
|
+
`./internal/*` subpaths are only for wrapper packages such as
|
|
268
|
+
`cloudflare-next-intl` and `cloudflare-next-intl-auth`. Don't import them in
|
|
269
|
+
your app; they can change in any release.
|
|
270
|
+
|
|
271
|
+
## Related packages
|
|
272
|
+
|
|
273
|
+
- [`cloudflare-next-intl`](https://www.npmjs.com/package/cloudflare-next-intl): all-in-one package (i18n + auth + cookie consent + theme + errors + images + DB), auto-wired.
|
|
274
|
+
- [`cloudflare-next-intl-errors`](https://www.npmjs.com/package/cloudflare-next-intl-errors): Error reporting, overrides, and stale-deploy recovery.
|
|
275
|
+
- [`cloudflare-next-intl-theme`](https://www.npmjs.com/package/cloudflare-next-intl-theme): Theme switcher and dark mode cookies.
|
|
276
|
+
- [`cloudflare-next-intl-auth`](https://www.npmjs.com/package/cloudflare-next-intl-auth): Firebase Auth & App Check built on this package.
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TranslationObject } from "../../types/types.js";
|
|
2
|
+
import { LocaleContext } from "./locale_provider.js";
|
|
3
|
+
export { LocaleContext };
|
|
4
|
+
export default function LocationzationClientProvider({ language, messages, children, }: {
|
|
5
|
+
language: string;
|
|
6
|
+
messages: TranslationObject;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { setLocaleCache, setMessageForLocaleCache } from "../../general/cache_variables.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { LocaleContext } from "./locale_provider.js";
|
|
6
|
+
export { LocaleContext };
|
|
7
|
+
export default function LocationzationClientProvider({ language, messages, children, }) {
|
|
8
|
+
setLocaleCache(language);
|
|
9
|
+
setMessageForLocaleCache(language, messages);
|
|
10
|
+
const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
|
|
11
|
+
return (_jsx(LocaleContext.Provider, { value: contextValue, children: children }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TranslationObject } from "../../types/types.js";
|
|
2
|
+
import { LocaleContext } from "./locale_provider.js";
|
|
3
|
+
export { LocaleContext };
|
|
4
|
+
export default function LocationzationClientProvider({ language, messages, children, }: {
|
|
5
|
+
language: string;
|
|
6
|
+
messages: TranslationObject;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { setLocaleCache, setMessageForLocaleCache } from "../../general/cache_variables.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { LocaleContext } from "./locale_provider.js";
|
|
6
|
+
export { LocaleContext };
|
|
7
|
+
export default function LocationzationClientProvider({ language, messages, children, }) {
|
|
8
|
+
setLocaleCache(language);
|
|
9
|
+
setMessageForLocaleCache(language, messages);
|
|
10
|
+
const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
|
|
11
|
+
return (_jsx(LocaleContext.Provider, { value: contextValue, children: children }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type LinkProps } from 'next/link.js';
|
|
2
|
+
import { type ComponentProps } from 'react';
|
|
3
|
+
type NextLinkProps = Omit<ComponentProps<'a'>, keyof LinkProps> & Omit<LinkProps, 'locale' | 'href' | 'prefetch' | 'onNavigate' | 'hrefLang' | 'replace' | 'scroll'>;
|
|
4
|
+
export type LocaleLinkProps = NextLinkProps & {
|
|
5
|
+
locale: string;
|
|
6
|
+
};
|
|
7
|
+
declare const LocaleLink: import("react").ForwardRefExoticComponent<Omit<LocaleLinkProps, "ref"> & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
8
|
+
export default LocaleLink;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, Suspense, } from 'react';
|
|
3
|
+
import LocaleLinkClient from './locale_link_client.js';
|
|
4
|
+
function LocaleLinkComponent(params, ref) {
|
|
5
|
+
return _jsx(Suspense, { fallback: _jsx("a", { ...params, ref: ref, className: params.className + ' pointer-events-none' }), children: _jsx(LocaleLinkClient, { ref: ref, ...params }) });
|
|
6
|
+
}
|
|
7
|
+
const LocaleLink = forwardRef(LocaleLinkComponent);
|
|
8
|
+
export default LocaleLink;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useEffect, useState, } from 'react';
|
|
4
|
+
import config from '../../config/intl_config.js';
|
|
5
|
+
import usePathname from '../hooks/use_path_name.js';
|
|
6
|
+
import { localeCookieName } from '../../config/cookie_key.js';
|
|
7
|
+
import setCookie from '../functions/set_cookie.js';
|
|
8
|
+
import { useSearchParams } from 'next/navigation.js';
|
|
9
|
+
function ClientLocaleLinkComponent({ locale, className, ...rest }, ref) {
|
|
10
|
+
const pathname = usePathname();
|
|
11
|
+
const searchParams = useSearchParams();
|
|
12
|
+
const [hash, setHash] = useState('');
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setHash(window.location.hash);
|
|
15
|
+
}, [pathname, searchParams]);
|
|
16
|
+
const isDefaultLocale = locale === config.defaultLocale;
|
|
17
|
+
const localePrefix = isDefaultLocale ? '' : `/${locale}`;
|
|
18
|
+
const search = searchParams.toString();
|
|
19
|
+
const newPathname = pathname === '/' && (localePrefix) ? '' : pathname;
|
|
20
|
+
const href = `${localePrefix}${newPathname}${search ? `?${search}` : ''}${hash}`;
|
|
21
|
+
function handleNavigate(e) {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
setCookie({ name: localeCookieName, value: locale });
|
|
24
|
+
window.location.replace(href);
|
|
25
|
+
}
|
|
26
|
+
;
|
|
27
|
+
return _jsx("a", { ref: ref, hrefLang: locale, className: className, ...rest, href: href, onClick: handleNavigate });
|
|
28
|
+
}
|
|
29
|
+
const LocaleLinkClient = forwardRef(ClientLocaleLinkComponent);
|
|
30
|
+
export default LocaleLinkClient;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { TranslationObject } from "../../types/types.js";
|
|
3
|
+
interface LocaleContextType {
|
|
4
|
+
language: string;
|
|
5
|
+
messages: TranslationObject;
|
|
6
|
+
}
|
|
7
|
+
export declare const LocaleContext: import("react").Context<LocaleContextType | undefined>;
|
|
8
|
+
export default function LocaleProvider({ language, messages, children }: {
|
|
9
|
+
language: string;
|
|
10
|
+
messages: TranslationObject;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useMemo } from "react";
|
|
4
|
+
export const LocaleContext = createContext(undefined);
|
|
5
|
+
export default function LocaleProvider({ language, messages, children }) {
|
|
6
|
+
const value = useMemo(() => ({ language, messages }), [language, messages]);
|
|
7
|
+
return _jsx(LocaleContext.Provider, { value: value, children: children });
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function getCookie(name: string): string | null;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import reportIntlError from "../../general/report_intl_error.js";
|
|
3
|
+
export default function getCookie(name) {
|
|
4
|
+
try {
|
|
5
|
+
const cookie = document.cookie;
|
|
6
|
+
const prefix = `${name}=`;
|
|
7
|
+
let start = -1;
|
|
8
|
+
if (cookie.startsWith(prefix)) {
|
|
9
|
+
start = prefix.length;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const idx = cookie.indexOf(`; ${prefix}`);
|
|
13
|
+
if (idx !== -1)
|
|
14
|
+
start = idx + 2 + prefix.length;
|
|
15
|
+
}
|
|
16
|
+
if (start === -1)
|
|
17
|
+
return null;
|
|
18
|
+
const end = cookie.indexOf(';', start);
|
|
19
|
+
const value = end === -1 ? cookie.slice(start) : cookie.slice(start, end);
|
|
20
|
+
return decodeURIComponent(value);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
reportIntlError(e, 'getCookie');
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import reportIntlError from "../../general/report_intl_error.js";
|
|
3
|
+
export default function setCookie({ name, value, maxAge }) {
|
|
4
|
+
try {
|
|
5
|
+
const cookieString = `${name}=${value}; path=/; max-age=${maxAge ?? 31536000}; SameSite=Lax;`;
|
|
6
|
+
document.cookie = cookieString;
|
|
7
|
+
}
|
|
8
|
+
catch (e) {
|
|
9
|
+
reportIntlError(e, 'setCookie');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useContext, useMemo } from "react";
|
|
3
|
+
import { LocaleContext } from "../components/client_provider.js";
|
|
4
|
+
import { getTranslationsImpl } from "../../general/general_functions.js";
|
|
5
|
+
export function useLocale() {
|
|
6
|
+
const context = useContext(LocaleContext);
|
|
7
|
+
if (context === undefined) {
|
|
8
|
+
throw new Error('useLocale must be used within an IntlProvider');
|
|
9
|
+
}
|
|
10
|
+
return context.language;
|
|
11
|
+
}
|
|
12
|
+
export function useTranslations(namespace) {
|
|
13
|
+
const context = useContext(LocaleContext);
|
|
14
|
+
if (context === undefined) {
|
|
15
|
+
throw new Error('useTranslations must be used within an IntlProvider');
|
|
16
|
+
}
|
|
17
|
+
const { language, messages } = context;
|
|
18
|
+
return useMemo(() => getTranslationsImpl(language, messages, namespace), [language, messages, namespace]);
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { usePathname as nextUsePathname } from "next/navigation.js";
|
|
3
|
+
import { useLocale } from "./client_hooks.js";
|
|
4
|
+
export default function usePathname() {
|
|
5
|
+
const pathname = nextUsePathname();
|
|
6
|
+
const locale = useLocale();
|
|
7
|
+
if (!pathname) {
|
|
8
|
+
return '/';
|
|
9
|
+
}
|
|
10
|
+
const path = pathname.replace(`/${locale}`, '');
|
|
11
|
+
if (path) {
|
|
12
|
+
return path;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return '/';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export { usePathname };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as LocaleLink } from './components/locale_link.js';
|
|
2
|
+
export { default as usePathname } from './hooks/use_path_name.js';
|
|
3
|
+
export { default as setCookieClient } from './functions/set_cookie.js';
|
|
4
|
+
export { default as getCookieClient } from './functions/get_cookie.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as LocaleLink } from './components/locale_link.js';
|
|
2
|
+
export { default as usePathname } from './hooks/use_path_name.js';
|
|
3
|
+
export { default as setCookieClient } from './functions/set_cookie.js';
|
|
4
|
+
export { default as getCookieClient } from './functions/get_cookie.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function matchesNamespacePattern(ns: string, pattern: string): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface DynamicCall {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
text: string;
|
|
5
|
+
prop?: {
|
|
6
|
+
component: string;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface FileScanResult {
|
|
11
|
+
namespaces: string[];
|
|
12
|
+
dynamicCalls: DynamicCall[];
|
|
13
|
+
usesRoot: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function findJsxPropValues(file: string, code: string, component: string, prop: string): string[] | null;
|
|
16
|
+
export declare function scanFile(file: string, code: string): FileScanResult;
|