cloudflare-next-intl 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 +129 -4
- package/dist/src/client/components/locale_link.d.ts +22 -0
- package/dist/src/client/components/locale_link.js +22 -0
- package/dist/src/client/functions/get_cookie.d.ts +9 -0
- package/dist/src/client/functions/get_cookie.js +9 -0
- package/dist/src/client/functions/set_cookie.d.ts +14 -0
- package/dist/src/client/functions/set_cookie.js +14 -0
- package/dist/src/client/hooks/client_hooks.d.ts +20 -0
- package/dist/src/client/hooks/client_hooks.js +20 -0
- package/dist/src/client/hooks/use_path_name.d.ts +9 -0
- package/dist/src/client/hooks/use_path_name.js +9 -0
- package/dist/src/config/init_config.d.ts +16 -0
- package/dist/src/config/init_config.js +16 -0
- package/dist/src/config/middleware.d.ts +13 -0
- package/dist/src/config/middleware.js +13 -1
- package/dist/src/general/get_layout_states.js +4 -0
- package/dist/src/general/metadata.d.ts +25 -0
- package/dist/src/general/metadata.js +25 -0
- package/dist/src/server/components/helper_script.d.ts +19 -0
- package/dist/src/server/components/helper_script.js +19 -0
- package/dist/src/server/components/link.d.ts +20 -0
- package/dist/src/server/components/link.js +20 -0
- package/dist/src/server/components/server_provider.d.ts +29 -0
- package/dist/src/server/components/server_provider.js +29 -0
- package/dist/src/server/functions/locale_static_params.d.ts +12 -0
- package/dist/src/server/functions/locale_static_params.js +12 -0
- package/dist/src/server/functions/server.d.ts +41 -0
- package/dist/src/server/functions/server.js +41 -0
- package/dist/src/server/functions/use_functions.d.ts +22 -0
- package/dist/src/server/functions/use_functions.js +22 -0
- package/dist/src/theme_switcher/components/theme_switcher.d.ts +10 -0
- package/dist/src/theme_switcher/components/theme_switcher.js +10 -0
- package/dist/src/types/types.d.ts +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,22 +18,72 @@ and Cloudflare environment.
|
|
|
18
18
|
npm install cloudflare-next-intl
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Setup
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
This package resolves your routing config through the `@intl-config` module
|
|
24
|
+
alias, so setup has two required steps — both must be done for the package
|
|
25
|
+
to work.
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
### 1. Create your config file
|
|
26
28
|
|
|
27
29
|
```typescript
|
|
30
|
+
// src/i18n/intl_config.ts
|
|
28
31
|
import { setIntlConfig } from "cloudflare-next-intl/setIntlConfig";
|
|
29
32
|
|
|
30
33
|
export default setIntlConfig({
|
|
31
34
|
locales: ["en", "de"],
|
|
32
35
|
defaultLocale: "en",
|
|
33
|
-
// ... other
|
|
36
|
+
// ... other RoutingConfig fields (localePrefix, localeCookie, localeDetection)
|
|
34
37
|
});
|
|
35
38
|
```
|
|
36
39
|
|
|
40
|
+
### 2. Point `@intl-config` at it in `next.config`
|
|
41
|
+
|
|
42
|
+
Required for both webpack and Turbopack — omitting either breaks the build
|
|
43
|
+
mode that uses it. Path is relative to `next.config`.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// next.config.ts
|
|
47
|
+
import type { NextConfig } from "next";
|
|
48
|
+
import path from "path";
|
|
49
|
+
|
|
50
|
+
const nextConfig: NextConfig = {
|
|
51
|
+
turbopack: {
|
|
52
|
+
resolveAlias: {
|
|
53
|
+
"@intl-config": "./src/i18n/intl_config.ts",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
webpack(config) {
|
|
57
|
+
config.resolve.alias = {
|
|
58
|
+
...config.resolve.alias,
|
|
59
|
+
"@intl-config": path.resolve(__dirname, "src/i18n/intl_config"),
|
|
60
|
+
};
|
|
61
|
+
return config;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default nextConfig;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If this alias is missing, `cloudflare-next-intl/middleware` throws
|
|
69
|
+
`Please set config file and set path to it in next.config as in the example`
|
|
70
|
+
at startup.
|
|
71
|
+
|
|
72
|
+
### 3. Wire up the middleware
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// src/middleware.ts
|
|
76
|
+
import intlMiddleware from "cloudflare-next-intl/middleware";
|
|
77
|
+
|
|
78
|
+
export const middleware = intlMiddleware;
|
|
79
|
+
|
|
80
|
+
export const config = {
|
|
81
|
+
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
37
87
|
### Server Components
|
|
38
88
|
|
|
39
89
|
```tsx
|
|
@@ -61,6 +111,81 @@ export function Navigation() {
|
|
|
61
111
|
}
|
|
62
112
|
```
|
|
63
113
|
|
|
114
|
+
### Locale-aware links (non-locale-switching)
|
|
115
|
+
|
|
116
|
+
Use `Link` (server-safe, from `./Link`) for normal navigation that should
|
|
117
|
+
stay on the current locale — it prepends the locale segment for you:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import Link from "cloudflare-next-intl/Link";
|
|
121
|
+
|
|
122
|
+
<Link href="/about">About</Link> // -> "/about" or "/de/about"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`LocaleLink` (client-only) is for explicitly switching locale, e.g. a
|
|
126
|
+
language switcher — see the Client Components example above.
|
|
127
|
+
|
|
128
|
+
### Reading the current locale
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// Server Components
|
|
132
|
+
import { getLocale } from "cloudflare-next-intl/server";
|
|
133
|
+
const locale = await getLocale();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
// Client Components ("use client")
|
|
138
|
+
import { useLocale } from "cloudflare-next-intl/use";
|
|
139
|
+
const locale = useLocale();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`useTranslations`/`useLocale` from `cloudflare-next-intl/use` also work
|
|
143
|
+
inside Server Components without `await` (backed by React's `use()`), as
|
|
144
|
+
long as they're rendered under `IntlProvider`.
|
|
145
|
+
|
|
146
|
+
### Root layout wiring
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { IntlProvider, IntlHelperScript, getLocaleStaticParams } from "cloudflare-next-intl/server";
|
|
150
|
+
|
|
151
|
+
export const generateStaticParams = getLocaleStaticParams;
|
|
152
|
+
|
|
153
|
+
export default async function RootLayout({ children, params }) {
|
|
154
|
+
const { locale } = await params;
|
|
155
|
+
return (
|
|
156
|
+
<html lang={locale}>
|
|
157
|
+
<head>
|
|
158
|
+
<IntlHelperScript />
|
|
159
|
+
</head>
|
|
160
|
+
<body>
|
|
161
|
+
<IntlProvider language={locale}>{children}</IntlProvider>
|
|
162
|
+
</body>
|
|
163
|
+
</html>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### SEO metadata (hreflang/canonical)
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { alternatesLinks } from "cloudflare-next-intl/metadata";
|
|
172
|
+
|
|
173
|
+
export async function generateMetadata({ params }) {
|
|
174
|
+
const { locale } = await params;
|
|
175
|
+
return {
|
|
176
|
+
alternates: alternatesLinks({ url: "https://example.com", locale, linkPart: "/about" }),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Theme switcher
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
import ThemeSwitcher from "cloudflare-next-intl/ThemeSwitcher";
|
|
185
|
+
|
|
186
|
+
<ThemeSwitcher lightLabelText="Light" darkLabelText="Dark" />
|
|
187
|
+
```
|
|
188
|
+
|
|
64
189
|
## License
|
|
65
190
|
|
|
66
191
|
MIT
|
|
@@ -4,5 +4,27 @@ type NextLinkProps = Omit<ComponentProps<'a'>, keyof LinkProps> & Omit<LinkProps
|
|
|
4
4
|
export type LocaleLinkProps = NextLinkProps & {
|
|
5
5
|
locale: string;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Client-only link component for linking to a SPECIFIC locale — e.g. a
|
|
9
|
+
* language switcher. Import from `cloudflare-next-intl/LocaleLink`.
|
|
10
|
+
*
|
|
11
|
+
* For normal in-app navigation that should stay on the current locale, use
|
|
12
|
+
* the server-side `Link` (`cloudflare-next-intl/Link`) instead — it infers
|
|
13
|
+
* the locale automatically and doesn't require `"use client"`.
|
|
14
|
+
*
|
|
15
|
+
* Renders inside a `Suspense` boundary; falls back to a disabled `<a>`
|
|
16
|
+
* (`pointer-events-none`) while resolving.
|
|
17
|
+
*
|
|
18
|
+
* @param locale Required. The locale to link to (e.g. `"de"`), prepended to
|
|
19
|
+
* `href` regardless of the current locale.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* "use client";
|
|
24
|
+
* import LocaleLink from "cloudflare-next-intl/LocaleLink";
|
|
25
|
+
*
|
|
26
|
+
* <LocaleLink href="/about" locale="de">Über uns</LocaleLink> // -> "/de/about"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
7
29
|
declare const LocaleLink: import("react").ForwardRefExoticComponent<Omit<LocaleLinkProps, "ref"> & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
8
30
|
export default LocaleLink;
|
|
@@ -4,5 +4,27 @@ import LocaleLinkClient from './locale_link_client';
|
|
|
4
4
|
function LocaleLinkComponent(params, ref) {
|
|
5
5
|
return _jsx(Suspense, { fallback: _jsx("a", { ...params, ref: ref, className: params.className + ' pointer-events-none' }), children: _jsx(LocaleLinkClient, { ref: ref, ...params }) });
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Client-only link component for linking to a SPECIFIC locale — e.g. a
|
|
9
|
+
* language switcher. Import from `cloudflare-next-intl/LocaleLink`.
|
|
10
|
+
*
|
|
11
|
+
* For normal in-app navigation that should stay on the current locale, use
|
|
12
|
+
* the server-side `Link` (`cloudflare-next-intl/Link`) instead — it infers
|
|
13
|
+
* the locale automatically and doesn't require `"use client"`.
|
|
14
|
+
*
|
|
15
|
+
* Renders inside a `Suspense` boundary; falls back to a disabled `<a>`
|
|
16
|
+
* (`pointer-events-none`) while resolving.
|
|
17
|
+
*
|
|
18
|
+
* @param locale Required. The locale to link to (e.g. `"de"`), prepended to
|
|
19
|
+
* `href` regardless of the current locale.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* "use client";
|
|
24
|
+
* import LocaleLink from "cloudflare-next-intl/LocaleLink";
|
|
25
|
+
*
|
|
26
|
+
* <LocaleLink href="/about" locale="de">Über uns</LocaleLink> // -> "/de/about"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
7
29
|
const LocaleLink = forwardRef(LocaleLinkComponent);
|
|
8
30
|
export default LocaleLink;
|
|
@@ -1 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-only: reads a `document.cookie` value by name. Pairs with
|
|
3
|
+
* {@link setCookie} for your OWN client-side cookies — this package's
|
|
4
|
+
* locale/theme cookies are managed internally, you don't need this for those.
|
|
5
|
+
*
|
|
6
|
+
* @param name Cookie name to look up.
|
|
7
|
+
* @returns The decoded cookie value, or `null` if not found (or on error,
|
|
8
|
+
* logged instead of thrown).
|
|
9
|
+
*/
|
|
1
10
|
export default function getCookie(name: string): string | null;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* Client-only: reads a `document.cookie` value by name. Pairs with
|
|
4
|
+
* {@link setCookie} for your OWN client-side cookies — this package's
|
|
5
|
+
* locale/theme cookies are managed internally, you don't need this for those.
|
|
6
|
+
*
|
|
7
|
+
* @param name Cookie name to look up.
|
|
8
|
+
* @returns The decoded cookie value, or `null` if not found (or on error,
|
|
9
|
+
* logged instead of thrown).
|
|
10
|
+
*/
|
|
2
11
|
export default function getCookie(name) {
|
|
3
12
|
try {
|
|
4
13
|
const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-only: sets a `document.cookie` value directly. Not used by this
|
|
3
|
+
* package's own locale handling (that goes through `intlMiddleware` server-side)
|
|
4
|
+
* — this is a small utility for your OWN client-side cookies (e.g. a
|
|
5
|
+
* "dismissed banner" flag).
|
|
6
|
+
*
|
|
7
|
+
* @param name Cookie name.
|
|
8
|
+
* @param value Cookie value; stringified via template literal (no encoding
|
|
9
|
+
* applied — avoid values containing `;`).
|
|
10
|
+
* @param maxAge Seconds until expiry. Defaults to 1 year.
|
|
11
|
+
*
|
|
12
|
+
* Always `path=/; SameSite=Lax`. Swallows errors (e.g. in restrictive
|
|
13
|
+
* environments) and logs them instead of throwing.
|
|
14
|
+
*/
|
|
1
15
|
export default function setCookie({ name, value, maxAge }: {
|
|
2
16
|
name: string;
|
|
3
17
|
value: unknown;
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* Client-only: sets a `document.cookie` value directly. Not used by this
|
|
4
|
+
* package's own locale handling (that goes through `intlMiddleware` server-side)
|
|
5
|
+
* — this is a small utility for your OWN client-side cookies (e.g. a
|
|
6
|
+
* "dismissed banner" flag).
|
|
7
|
+
*
|
|
8
|
+
* @param name Cookie name.
|
|
9
|
+
* @param value Cookie value; stringified via template literal (no encoding
|
|
10
|
+
* applied — avoid values containing `;`).
|
|
11
|
+
* @param maxAge Seconds until expiry. Defaults to 1 year.
|
|
12
|
+
*
|
|
13
|
+
* Always `path=/; SameSite=Lax`. Swallows errors (e.g. in restrictive
|
|
14
|
+
* environments) and logs them instead of throwing.
|
|
15
|
+
*/
|
|
2
16
|
export default function setCookie({ name, value, maxAge }) {
|
|
3
17
|
try {
|
|
4
18
|
const cookieString = `${name}=${value}; path=/; max-age=${maxAge ?? 31536000}; SameSite=Lax;`;
|
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
import type { TranslatorReturnType } from "../../types/types";
|
|
2
|
+
/**
|
|
3
|
+
* Client Component `useLocale` — reached via the default condition of the
|
|
4
|
+
* `cloudflare-next-intl/use` subpath (Server Components get the
|
|
5
|
+
* `use_functions.ts` variant automatically instead; always import from
|
|
6
|
+
* `"cloudflare-next-intl/use"`, never this file directly).
|
|
7
|
+
*
|
|
8
|
+
* Reads the locale from React context set up by `IntlProvider`.
|
|
9
|
+
*
|
|
10
|
+
* @returns The current locale (e.g. `"en"`).
|
|
11
|
+
* @throws If rendered outside `IntlProvider`.
|
|
12
|
+
*/
|
|
2
13
|
export declare function useLocale(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Client Component `useTranslations` — see {@link useLocale} for the
|
|
16
|
+
* subpath-resolution note.
|
|
17
|
+
*
|
|
18
|
+
* @param namespace Dot-separated key prefix into your messages file.
|
|
19
|
+
* @returns A `(key: string) => string` translation function, memoized on
|
|
20
|
+
* `[language, messages, namespace]`.
|
|
21
|
+
* @throws If rendered outside `IntlProvider`.
|
|
22
|
+
*/
|
|
3
23
|
export declare function useTranslations(namespace: string): TranslatorReturnType;
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
import { useContext, useMemo } from "react";
|
|
3
3
|
import { LocaleContext } from "../components/client_provider";
|
|
4
4
|
import { getTranslationsImpl } from "../../general/general_functions";
|
|
5
|
+
/**
|
|
6
|
+
* Client Component `useLocale` — reached via the default condition of the
|
|
7
|
+
* `cloudflare-next-intl/use` subpath (Server Components get the
|
|
8
|
+
* `use_functions.ts` variant automatically instead; always import from
|
|
9
|
+
* `"cloudflare-next-intl/use"`, never this file directly).
|
|
10
|
+
*
|
|
11
|
+
* Reads the locale from React context set up by `IntlProvider`.
|
|
12
|
+
*
|
|
13
|
+
* @returns The current locale (e.g. `"en"`).
|
|
14
|
+
* @throws If rendered outside `IntlProvider`.
|
|
15
|
+
*/
|
|
5
16
|
export function useLocale() {
|
|
6
17
|
const context = useContext(LocaleContext);
|
|
7
18
|
if (context === undefined) {
|
|
@@ -9,6 +20,15 @@ export function useLocale() {
|
|
|
9
20
|
}
|
|
10
21
|
return context.language;
|
|
11
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Client Component `useTranslations` — see {@link useLocale} for the
|
|
25
|
+
* subpath-resolution note.
|
|
26
|
+
*
|
|
27
|
+
* @param namespace Dot-separated key prefix into your messages file.
|
|
28
|
+
* @returns A `(key: string) => string` translation function, memoized on
|
|
29
|
+
* `[language, messages, namespace]`.
|
|
30
|
+
* @throws If rendered outside `IntlProvider`.
|
|
31
|
+
*/
|
|
12
32
|
export function useTranslations(namespace) {
|
|
13
33
|
const context = useContext(LocaleContext);
|
|
14
34
|
if (context === undefined) {
|
|
@@ -1 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client hook: like `next/navigation`'s `usePathname`, but with the locale
|
|
3
|
+
* segment stripped — so `/de/about` returns `/about`, matching the
|
|
4
|
+
* locale-agnostic paths used elsewhere in this package (e.g. `Link` href).
|
|
5
|
+
* Must be used inside `IntlProvider`/`LocaleContext` (via {@link useLocale}).
|
|
6
|
+
*
|
|
7
|
+
* @returns The current pathname without its locale prefix (e.g. `/about`, or
|
|
8
|
+
* `/` for the root).
|
|
9
|
+
*/
|
|
1
10
|
export default function usePathname(): string;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { usePathname as nextUsePathname } from "next/navigation";
|
|
3
3
|
import { useLocale } from "./client_hooks";
|
|
4
|
+
/**
|
|
5
|
+
* Client hook: like `next/navigation`'s `usePathname`, but with the locale
|
|
6
|
+
* segment stripped — so `/de/about` returns `/about`, matching the
|
|
7
|
+
* locale-agnostic paths used elsewhere in this package (e.g. `Link` href).
|
|
8
|
+
* Must be used inside `IntlProvider`/`LocaleContext` (via {@link useLocale}).
|
|
9
|
+
*
|
|
10
|
+
* @returns The current pathname without its locale prefix (e.g. `/about`, or
|
|
11
|
+
* `/` for the root).
|
|
12
|
+
*/
|
|
4
13
|
export default function usePathname() {
|
|
5
14
|
const pathname = nextUsePathname();
|
|
6
15
|
const locale = useLocale();
|
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
import type { LocalePrefixMode, Locales, RoutingConfig } from '../types/types';
|
|
2
|
+
/**
|
|
3
|
+
* Defines and type-checks your app's i18n routing config.
|
|
4
|
+
*
|
|
5
|
+
* Identity function at runtime — it exists purely so TypeScript infers
|
|
6
|
+
* `AppLocales`/`AppLocalePrefixMode` from the literal config object you pass
|
|
7
|
+
* in, giving you autocomplete/type errors on `locale` params elsewhere.
|
|
8
|
+
*
|
|
9
|
+
* Export the result from the file referenced by `@intl-config` (see your
|
|
10
|
+
* `next.config`), e.g.:
|
|
11
|
+
* ```ts
|
|
12
|
+
* export default setIntlConfig({
|
|
13
|
+
* locales: ["en", "fr"] as const,
|
|
14
|
+
* defaultLocale: "en",
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
2
18
|
export declare function setIntlConfig<const AppLocales extends Locales, const AppLocalePrefixMode extends LocalePrefixMode = 'as-needed'>(config: RoutingConfig<AppLocales, AppLocalePrefixMode>): RoutingConfig<AppLocales, AppLocalePrefixMode>;
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines and type-checks your app's i18n routing config.
|
|
3
|
+
*
|
|
4
|
+
* Identity function at runtime — it exists purely so TypeScript infers
|
|
5
|
+
* `AppLocales`/`AppLocalePrefixMode` from the literal config object you pass
|
|
6
|
+
* in, giving you autocomplete/type errors on `locale` params elsewhere.
|
|
7
|
+
*
|
|
8
|
+
* Export the result from the file referenced by `@intl-config` (see your
|
|
9
|
+
* `next.config`), e.g.:
|
|
10
|
+
* ```ts
|
|
11
|
+
* export default setIntlConfig({
|
|
12
|
+
* locales: ["en", "fr"] as const,
|
|
13
|
+
* defaultLocale: "en",
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
1
17
|
export function setIntlConfig(config) {
|
|
2
18
|
return config;
|
|
3
19
|
}
|
|
@@ -2,6 +2,19 @@ import type { NextRequest } from 'next/server';
|
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
3
|
import type { MiddlewareCustomHandler } from '../types/types';
|
|
4
4
|
export declare const localesSet: Set<string>;
|
|
5
|
+
/**
|
|
6
|
+
* This middleware function runs for every incoming request. Handles locale
|
|
7
|
+
* detection/routing, then optionally defers to your own custom logic.
|
|
8
|
+
*
|
|
9
|
+
* @param request The incoming request (pass through from your `middleware.ts`).
|
|
10
|
+
* @param options.middlewareHandler Your own logic (auth, feature flags, etc.),
|
|
11
|
+
* run alongside locale routing — see {@link MiddlewareCustomHandler} for the
|
|
12
|
+
* full contract (when it runs, what `targetUrl` means, what to return).
|
|
13
|
+
* @param options.runHandlerOnRedirect By default, `middlewareHandler` only
|
|
14
|
+
* runs when the library is NOT performing a locale redirect (i.e. on
|
|
15
|
+
* rewrite or `next()`). Set to `true` to also run it on redirects.
|
|
16
|
+
* Defaults to `false`.
|
|
17
|
+
*/
|
|
5
18
|
export default function intlMiddleware(request: NextRequest, options?: {
|
|
6
19
|
middlewareHandler?: MiddlewareCustomHandler;
|
|
7
20
|
runHandlerOnRedirect?: boolean;
|
|
@@ -19,7 +19,19 @@ async function getIsBotValue(userAgent) {
|
|
|
19
19
|
}
|
|
20
20
|
const getIsBotValueCache = cache(getIsBotValue);
|
|
21
21
|
export const localesSet = new Set(config.locales);
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* This middleware function runs for every incoming request. Handles locale
|
|
24
|
+
* detection/routing, then optionally defers to your own custom logic.
|
|
25
|
+
*
|
|
26
|
+
* @param request The incoming request (pass through from your `middleware.ts`).
|
|
27
|
+
* @param options.middlewareHandler Your own logic (auth, feature flags, etc.),
|
|
28
|
+
* run alongside locale routing — see {@link MiddlewareCustomHandler} for the
|
|
29
|
+
* full contract (when it runs, what `targetUrl` means, what to return).
|
|
30
|
+
* @param options.runHandlerOnRedirect By default, `middlewareHandler` only
|
|
31
|
+
* runs when the library is NOT performing a locale redirect (i.e. on
|
|
32
|
+
* rewrite or `next()`). Set to `true` to also run it on redirects.
|
|
33
|
+
* Defaults to `false`.
|
|
34
|
+
*/
|
|
23
35
|
export default async function intlMiddleware(request, options) {
|
|
24
36
|
try {
|
|
25
37
|
let initialChosenLocale;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// NOTE: currently disabled — this file exports nothing at runtime, even
|
|
3
|
+
// though "./getLayoutStates" is listed in package.json's exports map.
|
|
4
|
+
// Do not rely on `cloudflare-next-intl/getLayoutStates` until this is
|
|
5
|
+
// re-enabled; use `getLocale()` + read the theme cookie manually instead.
|
|
2
6
|
// "use server";
|
|
3
7
|
// import { cookies } from "next/headers";
|
|
4
8
|
// import { localeCookieName, isDarkCookieKey } from "../config/cookie_key";
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the `alternates` field for Next's `generateMetadata` — a canonical
|
|
3
|
+
* URL plus per-locale `hreflang` links, exported memoized as `alternatesLinks`
|
|
4
|
+
* from `cloudflare-next-intl/metadata`.
|
|
5
|
+
*
|
|
6
|
+
* @param url Absolute base URL of your site (no locale, no path),
|
|
7
|
+
* e.g. `"https://example.com"`.
|
|
8
|
+
* @param locale The current page's locale — used to decide the
|
|
9
|
+
* `canonical` URL (only set for `defaultLocale` unless you pass one).
|
|
10
|
+
* @param linkPart The path segment after the locale, e.g. `"/about"`.
|
|
11
|
+
* Pass `"/"` or omit for the root page.
|
|
12
|
+
* @param canonical Optional override for the canonical URL.
|
|
13
|
+
* @returns `{ canonical, languages }` ready to spread into `Metadata.alternates`,
|
|
14
|
+
* or `undefined` if building the links threw (logged, not re-thrown).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* export async function generateMetadata({ params }) {
|
|
19
|
+
* const { locale } = await params;
|
|
20
|
+
* return {
|
|
21
|
+
* alternates: alternatesLinks({ url: "https://example.com", locale, linkPart: "/about" }),
|
|
22
|
+
* };
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
1
26
|
export declare function iAlternatesLinks({ locale, url, canonical, linkPart }: {
|
|
2
27
|
url: string;
|
|
3
28
|
locale: string;
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { cache } from "react";
|
|
2
2
|
import config from "../config/intl_config";
|
|
3
|
+
/**
|
|
4
|
+
* Builds the `alternates` field for Next's `generateMetadata` — a canonical
|
|
5
|
+
* URL plus per-locale `hreflang` links, exported memoized as `alternatesLinks`
|
|
6
|
+
* from `cloudflare-next-intl/metadata`.
|
|
7
|
+
*
|
|
8
|
+
* @param url Absolute base URL of your site (no locale, no path),
|
|
9
|
+
* e.g. `"https://example.com"`.
|
|
10
|
+
* @param locale The current page's locale — used to decide the
|
|
11
|
+
* `canonical` URL (only set for `defaultLocale` unless you pass one).
|
|
12
|
+
* @param linkPart The path segment after the locale, e.g. `"/about"`.
|
|
13
|
+
* Pass `"/"` or omit for the root page.
|
|
14
|
+
* @param canonical Optional override for the canonical URL.
|
|
15
|
+
* @returns `{ canonical, languages }` ready to spread into `Metadata.alternates`,
|
|
16
|
+
* or `undefined` if building the links threw (logged, not re-thrown).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* export async function generateMetadata({ params }) {
|
|
21
|
+
* const { locale } = await params;
|
|
22
|
+
* return {
|
|
23
|
+
* alternates: alternatesLinks({ url: "https://example.com", locale, linkPart: "/about" }),
|
|
24
|
+
* };
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
3
28
|
export function iAlternatesLinks({ locale, url, canonical, linkPart }) {
|
|
4
29
|
try {
|
|
5
30
|
const linkPartValue = linkPart == '/' ? undefined : linkPart;
|
|
@@ -1 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server component exported as `IntlHelperScript` from
|
|
3
|
+
* `cloudflare-next-intl/IntlHelperScript`. Renders inline bootstrap
|
|
4
|
+
* `<script>` tags that run before hydration to avoid FOUC/flicker:
|
|
5
|
+
* - syncs dark-mode class from the theme cookie (or `prefers-color-scheme`)
|
|
6
|
+
* - redirects to the locale-prefixed URL if the locale cookie disagrees
|
|
7
|
+
* with the current path (covers client-side navigation edge cases)
|
|
8
|
+
* - (prod only) checks `BUILD_ID` and force-reloads on stale deploys
|
|
9
|
+
*
|
|
10
|
+
* Place it once in your root layout's `<head>`, alongside `IntlProvider`.
|
|
11
|
+
* No props.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <head>
|
|
16
|
+
* <IntlHelperScript />
|
|
17
|
+
* </head>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
1
20
|
export default function HelperScript(): Component | null;
|
|
@@ -4,6 +4,25 @@ import config from "../../config/intl_config";
|
|
|
4
4
|
import ClientHelperScript from "../../client/components/client_helper_script";
|
|
5
5
|
const isDev = process.env.NODE_ENV === 'development';
|
|
6
6
|
const secureCookieAttribute = isDev ? '+ " Secure;"' : '';
|
|
7
|
+
/**
|
|
8
|
+
* Server component exported as `IntlHelperScript` from
|
|
9
|
+
* `cloudflare-next-intl/IntlHelperScript`. Renders inline bootstrap
|
|
10
|
+
* `<script>` tags that run before hydration to avoid FOUC/flicker:
|
|
11
|
+
* - syncs dark-mode class from the theme cookie (or `prefers-color-scheme`)
|
|
12
|
+
* - redirects to the locale-prefixed URL if the locale cookie disagrees
|
|
13
|
+
* with the current path (covers client-side navigation edge cases)
|
|
14
|
+
* - (prod only) checks `BUILD_ID` and force-reloads on stale deploys
|
|
15
|
+
*
|
|
16
|
+
* Place it once in your root layout's `<head>`, alongside `IntlProvider`.
|
|
17
|
+
* No props.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <head>
|
|
22
|
+
* <IntlHelperScript />
|
|
23
|
+
* </head>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
7
26
|
export default function HelperScript() {
|
|
8
27
|
return _jsxs(_Fragment, { children: [!isDev &&
|
|
9
28
|
_jsx("script", { id: "build-id-script", children: `(async function() {
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { type LinkProps } from 'next/link';
|
|
2
2
|
import { type ComponentProps } from 'react';
|
|
3
3
|
type NextLinkProps = Omit<ComponentProps<'a'>, keyof LinkProps> & Omit<LinkProps, 'locale'>;
|
|
4
|
+
/**
|
|
5
|
+
* Server-safe, locale-aware drop-in replacement for `next/link`. Import
|
|
6
|
+
* from `cloudflare-next-intl/Link` (a separate subpath from the client-side
|
|
7
|
+
* `LocaleLink`).
|
|
8
|
+
*
|
|
9
|
+
* Prepends the current locale segment to `href` automatically when the
|
|
10
|
+
* current locale isn't the `defaultLocale` — you never build the
|
|
11
|
+
* `/en/about`-style path yourself. To link to a SPECIFIC locale (a language
|
|
12
|
+
* switcher) use `LocaleLink` instead, which takes an explicit `locale` prop.
|
|
13
|
+
*
|
|
14
|
+
* All other `next/link` props (`prefetch`, `replace`, `scroll`, etc.) and
|
|
15
|
+
* standard `<a>` props are passed straight through.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import Link from "cloudflare-next-intl/Link";
|
|
20
|
+
*
|
|
21
|
+
* <Link href="/about">About</Link> // -> "/about" or "/de/about"
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
4
24
|
declare const Link: import("react").ForwardRefExoticComponent<Omit<NextLinkProps, "ref"> & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
5
25
|
export default Link;
|
|
@@ -22,5 +22,25 @@ function CustomLinkFunction({ href, prefetch, ...rest }, ref) {
|
|
|
22
22
|
}
|
|
23
23
|
return _jsx(LinkComponent, { ref: ref, href: pathnames, prefetch: prefetch, ...rest });
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Server-safe, locale-aware drop-in replacement for `next/link`. Import
|
|
27
|
+
* from `cloudflare-next-intl/Link` (a separate subpath from the client-side
|
|
28
|
+
* `LocaleLink`).
|
|
29
|
+
*
|
|
30
|
+
* Prepends the current locale segment to `href` automatically when the
|
|
31
|
+
* current locale isn't the `defaultLocale` — you never build the
|
|
32
|
+
* `/en/about`-style path yourself. To link to a SPECIFIC locale (a language
|
|
33
|
+
* switcher) use `LocaleLink` instead, which takes an explicit `locale` prop.
|
|
34
|
+
*
|
|
35
|
+
* All other `next/link` props (`prefetch`, `replace`, `scroll`, etc.) and
|
|
36
|
+
* standard `<a>` props are passed straight through.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import Link from "cloudflare-next-intl/Link";
|
|
41
|
+
*
|
|
42
|
+
* <Link href="/about">About</Link> // -> "/about" or "/de/about"
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
25
45
|
const Link = forwardRef(CustomLinkFunction);
|
|
26
46
|
export default Link;
|
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
import type { TranslationObject } from "../../types/types";
|
|
2
|
+
/**
|
|
3
|
+
* Server component that provides locale/messages context to the rest of the
|
|
4
|
+
* tree. Exported publicly as `IntlProvider` from `cloudflare-next-intl/serverProvider`.
|
|
5
|
+
*
|
|
6
|
+
* Wrap this around your app once, near the root layout, below `[locale]`.
|
|
7
|
+
* It seeds the server-side locale/message caches (for `getLocale`/`getTranslations`)
|
|
8
|
+
* and also passes them to the client `LocaleContext` (for `useLocale`/`useTranslations`
|
|
9
|
+
* in client components).
|
|
10
|
+
*
|
|
11
|
+
* @param language The current route's locale (typically the `[locale]` route
|
|
12
|
+
* param). Must be one of your configured `locales` — calls `notFound()`
|
|
13
|
+
* otherwise.
|
|
14
|
+
* @param messages Optional pre-loaded messages for `language`. If omitted,
|
|
15
|
+
* they're loaded via `getMessage(language)`.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* export default async function RootLayout({ children, params }) {
|
|
20
|
+
* const { locale } = await params;
|
|
21
|
+
* return (
|
|
22
|
+
* <html lang={locale}>
|
|
23
|
+
* <body>
|
|
24
|
+
* <IntlProvider language={locale}>{children}</IntlProvider>
|
|
25
|
+
* </body>
|
|
26
|
+
* </html>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
2
31
|
export default function LocationzationProvider({ language, messages, children }: {
|
|
3
32
|
language: string;
|
|
4
33
|
messages?: TranslationObject;
|
|
@@ -4,6 +4,35 @@ import { getMessage } from "../functions/server";
|
|
|
4
4
|
import dynamic from "next/dynamic";
|
|
5
5
|
import { localesSet } from "../../config/middleware";
|
|
6
6
|
const LocationzationClientProvider = dynamic(() => import("../../client/components/client_provider"));
|
|
7
|
+
/**
|
|
8
|
+
* Server component that provides locale/messages context to the rest of the
|
|
9
|
+
* tree. Exported publicly as `IntlProvider` from `cloudflare-next-intl/serverProvider`.
|
|
10
|
+
*
|
|
11
|
+
* Wrap this around your app once, near the root layout, below `[locale]`.
|
|
12
|
+
* It seeds the server-side locale/message caches (for `getLocale`/`getTranslations`)
|
|
13
|
+
* and also passes them to the client `LocaleContext` (for `useLocale`/`useTranslations`
|
|
14
|
+
* in client components).
|
|
15
|
+
*
|
|
16
|
+
* @param language The current route's locale (typically the `[locale]` route
|
|
17
|
+
* param). Must be one of your configured `locales` — calls `notFound()`
|
|
18
|
+
* otherwise.
|
|
19
|
+
* @param messages Optional pre-loaded messages for `language`. If omitted,
|
|
20
|
+
* they're loaded via `getMessage(language)`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* export default async function RootLayout({ children, params }) {
|
|
25
|
+
* const { locale } = await params;
|
|
26
|
+
* return (
|
|
27
|
+
* <html lang={locale}>
|
|
28
|
+
* <body>
|
|
29
|
+
* <IntlProvider language={locale}>{children}</IntlProvider>
|
|
30
|
+
* </body>
|
|
31
|
+
* </html>
|
|
32
|
+
* );
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
7
36
|
export default async function LocationzationProvider({ language, messages, children }) {
|
|
8
37
|
if (!localesSet.has(language)) {
|
|
9
38
|
const { notFound } = await import("next/navigation");
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates the `[locale]` route params for every configured locale — pass
|
|
3
|
+
* directly as your `[locale]/layout.tsx`'s `generateStaticParams` so Next
|
|
4
|
+
* pre-renders/statically-generates a route for each locale.
|
|
5
|
+
*
|
|
6
|
+
* @returns One `{ locale }` object per entry in your `setIntlConfig({ locales })`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* export const generateStaticParams = getLocaleStaticParams;
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
1
13
|
export declare function getLocaleStaticParams(): {
|
|
2
14
|
locale: string;
|
|
3
15
|
}[];
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import config from "../../config/intl_config";
|
|
2
|
+
/**
|
|
3
|
+
* Generates the `[locale]` route params for every configured locale — pass
|
|
4
|
+
* directly as your `[locale]/layout.tsx`'s `generateStaticParams` so Next
|
|
5
|
+
* pre-renders/statically-generates a route for each locale.
|
|
6
|
+
*
|
|
7
|
+
* @returns One `{ locale }` object per entry in your `setIntlConfig({ locales })`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* export const generateStaticParams = getLocaleStaticParams;
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
2
14
|
export function getLocaleStaticParams() {
|
|
3
15
|
return config.locales.map((locale) => ({ locale }));
|
|
4
16
|
}
|
|
@@ -6,6 +6,14 @@ import type { TranslationObject, TranslatorReturnType } from "../../types/types"
|
|
|
6
6
|
* @returns A promise that resolves to the TranslationObject for the given locale.
|
|
7
7
|
*/
|
|
8
8
|
declare function iGetMessage(locale: string): Promise<TranslationObject>;
|
|
9
|
+
/**
|
|
10
|
+
* Server-only: loads (and caches) the translation messages for a locale.
|
|
11
|
+
* Use {@link getTranslations} instead unless you need the raw message object.
|
|
12
|
+
*
|
|
13
|
+
* @param locale The locale to load messages for (e.g. `"en"`).
|
|
14
|
+
* @returns The `TranslationObject` for that locale.
|
|
15
|
+
* @throws via `notFound()` if `locale` isn't in your configured locales.
|
|
16
|
+
*/
|
|
9
17
|
export declare const getMessage: typeof iGetMessage;
|
|
10
18
|
/**
|
|
11
19
|
* Retrieves a translation function for a specific namespace and locale.
|
|
@@ -15,6 +23,25 @@ export declare const getMessage: typeof iGetMessage;
|
|
|
15
23
|
* @returns A promise that resolves to a function, which takes a key and returns the translated string.
|
|
16
24
|
*/
|
|
17
25
|
declare function iGetTranslations(namespace: string, locale?: string): Promise<TranslatorReturnType>;
|
|
26
|
+
/**
|
|
27
|
+
* Server Component only: gets a translation function for a namespace.
|
|
28
|
+
*
|
|
29
|
+
* @param namespace Dot-separated key prefix into your messages file
|
|
30
|
+
* (e.g. `"HomePage"`, `"Common.buttons"`).
|
|
31
|
+
* @param locale Optional. Defaults to {@link getLocale}'s result — pass
|
|
32
|
+
* this explicitly only if you already resolved the locale (e.g. from route
|
|
33
|
+
* params) to avoid an extra lookup.
|
|
34
|
+
* @returns A function `(key: string) => string` that looks up `key` inside
|
|
35
|
+
* `namespace`.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* export default async function Page() {
|
|
40
|
+
* const t = await getTranslations("HomePage");
|
|
41
|
+
* return <h1>{t("title")}</h1>;
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
18
45
|
export declare const getTranslations: typeof iGetTranslations;
|
|
19
46
|
/**
|
|
20
47
|
* Determines the current locale. It first checks for an explicitly set locale,
|
|
@@ -22,5 +49,19 @@ export declare const getTranslations: typeof iGetTranslations;
|
|
|
22
49
|
* @returns A promise that resolves to the determined Language.
|
|
23
50
|
*/
|
|
24
51
|
declare function iGetLocale(): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Server Component only: resolves the current request's locale.
|
|
54
|
+
*
|
|
55
|
+
* Order of resolution: an explicitly-set locale (e.g. via `IntlProvider`)
|
|
56
|
+
* takes priority, then falls back to the `NEXT_LOCALE`-style cookie set by
|
|
57
|
+
* `intlMiddleware`, then to `defaultLocale` from your `setIntlConfig` config.
|
|
58
|
+
*
|
|
59
|
+
* @returns The resolved locale string (e.g. `"en"`).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* const locale = await getLocale();
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
25
66
|
export declare const getLocale: typeof iGetLocale;
|
|
26
67
|
export {};
|
|
@@ -33,6 +33,14 @@ async function iGetMessage(locale) {
|
|
|
33
33
|
return getMessageCache(locale); // Assert non-null because it's guaranteed to be in the map
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Server-only: loads (and caches) the translation messages for a locale.
|
|
38
|
+
* Use {@link getTranslations} instead unless you need the raw message object.
|
|
39
|
+
*
|
|
40
|
+
* @param locale The locale to load messages for (e.g. `"en"`).
|
|
41
|
+
* @returns The `TranslationObject` for that locale.
|
|
42
|
+
* @throws via `notFound()` if `locale` isn't in your configured locales.
|
|
43
|
+
*/
|
|
36
44
|
export const getMessage = cache(iGetMessage);
|
|
37
45
|
/**
|
|
38
46
|
* Retrieves a translation function for a specific namespace and locale.
|
|
@@ -53,6 +61,25 @@ async function iGetTranslations(namespace, locale) {
|
|
|
53
61
|
const serverMessages = await iGetMessage(effectiveLocale);
|
|
54
62
|
return getTranslationsImpl(effectiveLocale, serverMessages, namespace, cacheKey);
|
|
55
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Server Component only: gets a translation function for a namespace.
|
|
66
|
+
*
|
|
67
|
+
* @param namespace Dot-separated key prefix into your messages file
|
|
68
|
+
* (e.g. `"HomePage"`, `"Common.buttons"`).
|
|
69
|
+
* @param locale Optional. Defaults to {@link getLocale}'s result — pass
|
|
70
|
+
* this explicitly only if you already resolved the locale (e.g. from route
|
|
71
|
+
* params) to avoid an extra lookup.
|
|
72
|
+
* @returns A function `(key: string) => string` that looks up `key` inside
|
|
73
|
+
* `namespace`.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* export default async function Page() {
|
|
78
|
+
* const t = await getTranslations("HomePage");
|
|
79
|
+
* return <h1>{t("title")}</h1>;
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
56
83
|
export const getTranslations = cache(iGetTranslations);
|
|
57
84
|
/**
|
|
58
85
|
* Determines the current locale. It first checks for an explicitly set locale,
|
|
@@ -83,4 +110,18 @@ async function iGetLocale() {
|
|
|
83
110
|
return config.defaultLocale;
|
|
84
111
|
}
|
|
85
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Server Component only: resolves the current request's locale.
|
|
115
|
+
*
|
|
116
|
+
* Order of resolution: an explicitly-set locale (e.g. via `IntlProvider`)
|
|
117
|
+
* takes priority, then falls back to the `NEXT_LOCALE`-style cookie set by
|
|
118
|
+
* `intlMiddleware`, then to `defaultLocale` from your `setIntlConfig` config.
|
|
119
|
+
*
|
|
120
|
+
* @returns The resolved locale string (e.g. `"en"`).
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const locale = await getLocale();
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
86
127
|
export const getLocale = cache(iGetLocale);
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import type { TranslatorReturnType } from "../../types/types";
|
|
2
|
+
/**
|
|
3
|
+
* React Server Component `useLocale`, reached via the `cloudflare-next-intl/use`
|
|
4
|
+
* subpath's `react-server` condition (resolved automatically — you always
|
|
5
|
+
* just `import { useLocale } from "cloudflare-next-intl/use"`; the matching
|
|
6
|
+
* client-hook version from `client_hooks.ts` is used automatically in client
|
|
7
|
+
* components instead).
|
|
8
|
+
*
|
|
9
|
+
* Uses React's `use()` on the locale promise resolved by `getLocale()`/
|
|
10
|
+
* `IntlProvider` — must be called within a component tree wrapped in
|
|
11
|
+
* `IntlProvider`.
|
|
12
|
+
*
|
|
13
|
+
* @returns The current locale (e.g. `"en"`).
|
|
14
|
+
* @throws If called without an `IntlProvider` above it in the tree.
|
|
15
|
+
*/
|
|
2
16
|
export declare function useLocaleImpl(): string;
|
|
3
17
|
export declare const useLocale: typeof useLocaleImpl;
|
|
18
|
+
/**
|
|
19
|
+
* React Server Component `useTranslations` — see {@link useLocaleImpl} for
|
|
20
|
+
* the `react-server`/client resolution note.
|
|
21
|
+
*
|
|
22
|
+
* @param namespace Dot-separated key prefix into your messages file.
|
|
23
|
+
* @returns A `(key: string) => string` translation function.
|
|
24
|
+
* @throws If called without an `IntlProvider` above it in the tree.
|
|
25
|
+
*/
|
|
4
26
|
declare function useTranslationsImpl(namespace: string): TranslatorReturnType;
|
|
5
27
|
export declare const useTranslations: typeof useTranslationsImpl;
|
|
6
28
|
export {};
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { getTranslationsImpl } from "../../general/general_functions";
|
|
2
2
|
import { getLocale, getMessage } from "./server";
|
|
3
3
|
import { cache, use } from "react";
|
|
4
|
+
/**
|
|
5
|
+
* React Server Component `useLocale`, reached via the `cloudflare-next-intl/use`
|
|
6
|
+
* subpath's `react-server` condition (resolved automatically — you always
|
|
7
|
+
* just `import { useLocale } from "cloudflare-next-intl/use"`; the matching
|
|
8
|
+
* client-hook version from `client_hooks.ts` is used automatically in client
|
|
9
|
+
* components instead).
|
|
10
|
+
*
|
|
11
|
+
* Uses React's `use()` on the locale promise resolved by `getLocale()`/
|
|
12
|
+
* `IntlProvider` — must be called within a component tree wrapped in
|
|
13
|
+
* `IntlProvider`.
|
|
14
|
+
*
|
|
15
|
+
* @returns The current locale (e.g. `"en"`).
|
|
16
|
+
* @throws If called without an `IntlProvider` above it in the tree.
|
|
17
|
+
*/
|
|
4
18
|
export function useLocaleImpl() {
|
|
5
19
|
const language = use(getLocale());
|
|
6
20
|
if (language === undefined) {
|
|
@@ -9,6 +23,14 @@ export function useLocaleImpl() {
|
|
|
9
23
|
return language;
|
|
10
24
|
}
|
|
11
25
|
export const useLocale = cache(useLocaleImpl);
|
|
26
|
+
/**
|
|
27
|
+
* React Server Component `useTranslations` — see {@link useLocaleImpl} for
|
|
28
|
+
* the `react-server`/client resolution note.
|
|
29
|
+
*
|
|
30
|
+
* @param namespace Dot-separated key prefix into your messages file.
|
|
31
|
+
* @returns A `(key: string) => string` translation function.
|
|
32
|
+
* @throws If called without an `IntlProvider` above it in the tree.
|
|
33
|
+
*/
|
|
12
34
|
function useTranslationsImpl(namespace) {
|
|
13
35
|
const language = use(getLocale());
|
|
14
36
|
const messages = use(getMessage(language));
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Light/dark theme toggle button, exported as `ThemeSwitcher` from
|
|
3
|
+
* `cloudflare-next-intl/ThemeSwitcher`. Persists the choice via the
|
|
4
|
+
* theme cookie this package's `IntlHelperScript` reads on load (so the
|
|
5
|
+
* correct theme applies before hydration, no flash).
|
|
6
|
+
*
|
|
7
|
+
* @param lightLabelText Accessible label shown/used when in light mode.
|
|
8
|
+
* @param darkLabelText Accessible label shown/used when in dark mode.
|
|
9
|
+
* @param className Optional class applied to the underlying button.
|
|
10
|
+
*/
|
|
1
11
|
export default function ThemeSwticher(params: {
|
|
2
12
|
className?: string;
|
|
3
13
|
lightLabelText: string;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Moon, Sun } from "./icons";
|
|
3
3
|
import ThemeSwticherButton from "./theme_switcher_button";
|
|
4
|
+
/**
|
|
5
|
+
* Light/dark theme toggle button, exported as `ThemeSwitcher` from
|
|
6
|
+
* `cloudflare-next-intl/ThemeSwitcher`. Persists the choice via the
|
|
7
|
+
* theme cookie this package's `IntlHelperScript` reads on load (so the
|
|
8
|
+
* correct theme applies before hydration, no flash).
|
|
9
|
+
*
|
|
10
|
+
* @param lightLabelText Accessible label shown/used when in light mode.
|
|
11
|
+
* @param darkLabelText Accessible label shown/used when in dark mode.
|
|
12
|
+
* @param className Optional class applied to the underlying button.
|
|
13
|
+
*/
|
|
4
14
|
export default function ThemeSwticher(params) {
|
|
5
15
|
return _jsxs(ThemeSwticherButton, { ...params, children: [_jsx(Sun, { className: "transition-transform duration-500 ease-in-out" +
|
|
6
16
|
" rotate-0 scale-100 opacity-100 cursor-pointer" + // Default (light mode) state
|
|
@@ -1,9 +1,64 @@
|
|
|
1
1
|
import type { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import type { Languages } from 'next/dist/lib/metadata/types/alternative-urls-types';
|
|
3
3
|
import type { Videos } from 'next/dist/lib/metadata/types/metadata-types';
|
|
4
|
+
/**
|
|
5
|
+
* Custom middleware hook, run by `intlMiddleware` for your own logic
|
|
6
|
+
* (e.g. auth, feature flags, A/B tests) — on top of the library's own
|
|
7
|
+
* locale routing (locale-prefix rewrite/redirect).
|
|
8
|
+
*
|
|
9
|
+
* Called AFTER the library has resolved the locale for this request, but
|
|
10
|
+
* BEFORE it builds its own `NextResponse`:
|
|
11
|
+
* - When `targetUrl` is `undefined`: the request already had a valid
|
|
12
|
+
* locale prefix (e.g. `/en/about`) — the library would otherwise call
|
|
13
|
+
* `NextResponse.next()`.
|
|
14
|
+
* - When `targetUrl` is set: the library resolved a locale-prefixed URL
|
|
15
|
+
* the request should be routed to (e.g. `/` -> `/en/`). By default the
|
|
16
|
+
* library still performs this rewrite/redirect itself — `targetUrl` is
|
|
17
|
+
* informational, so you can react to it (e.g. log it, add a header),
|
|
18
|
+
* NOT something you are required to apply yourself.
|
|
19
|
+
* - If `initialChosenLocale === defaultLocale`, the library rewrites to
|
|
20
|
+
* `targetUrl` (URL bar unchanged).
|
|
21
|
+
* - Otherwise, the library redirects to `targetUrl` (only when
|
|
22
|
+
* `runHandlerOnRedirect: true` is also passed — by default this
|
|
23
|
+
* handler does NOT run on redirects).
|
|
24
|
+
*
|
|
25
|
+
* @param request The incoming request.
|
|
26
|
+
* @param locale The resolved locale for this request (e.g. `"en"`).
|
|
27
|
+
* @param targetUrl The locale-prefixed URL the library will rewrite/redirect
|
|
28
|
+
* to, or `undefined` when no rewrite/redirect is needed.
|
|
29
|
+
* @returns - A `NextResponse` to fully REPLACE the library's default
|
|
30
|
+
* response (e.g. `NextResponse.redirect(...)` to send an
|
|
31
|
+
* unauthenticated user to `/login` instead).
|
|
32
|
+
* - `null` to keep the library's default response
|
|
33
|
+
* (rewrite/redirect/`next()`) as-is — this is the common case.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* middlewareHandler: (request, locale, targetUrl) => {
|
|
38
|
+
* const session = request.cookies.get("session")?.value;
|
|
39
|
+
* if (!session) {
|
|
40
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
41
|
+
* }
|
|
42
|
+
* return null; // keep default locale routing
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
4
46
|
export type MiddlewareCustomHandler = (request: NextRequest, locale: string, targetUrl: URL | undefined) => NextResponse<unknown> | null | Promise<NextResponse<unknown> | null>;
|
|
47
|
+
/** Your app's list of supported locale codes, e.g. `["en", "de"] as const`. */
|
|
5
48
|
export type Locales = readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* NOTE: currently unused by `intlMiddleware`'s actual routing logic (it
|
|
51
|
+
* always rewrites for `defaultLocale` and redirects otherwise) — reserved
|
|
52
|
+
* for future use. Setting `localePrefix` on {@link RoutingConfig} has no
|
|
53
|
+
* runtime effect yet.
|
|
54
|
+
*/
|
|
6
55
|
export type LocalePrefixMode = 'always' | 'as-needed' | 'never';
|
|
56
|
+
/**
|
|
57
|
+
* The config object you build with `setIntlConfig` and export from the file
|
|
58
|
+
* referenced by the `@intl-config` alias in `next.config` (see the package
|
|
59
|
+
* README's Setup section). Consumed internally by `intlMiddleware`,
|
|
60
|
+
* `getLocale`, `getTranslations`, and friends.
|
|
61
|
+
*/
|
|
7
62
|
export interface RoutingConfig<AppLocales extends Locales, AppLocalePrefixMode extends LocalePrefixMode> {
|
|
8
63
|
/**
|
|
9
64
|
* All available locales.
|