cloudflare-next-intl 0.9.11 → 0.9.13
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 +6 -5
- package/dist/src/config/cookie_key.d.ts +2 -0
- package/dist/src/config/cookie_key.js +2 -0
- package/dist/src/config/middleware.js +37 -9
- package/dist/src/cookie_consent/client/cookie_consent_provider.d.ts +1 -1
- package/dist/src/cookie_consent/client/cookie_consent_provider.js +17 -4
- package/dist/src/server/components/server_provider.js +1 -4
- package/dist/src/server/components/server_provider_static.js +1 -4
- package/dist/src/server/functions/geo.js +67 -0
- package/dist/src/types/types.d.ts +8 -0
- package/dist/src/vite/auto_dynamic_pages_plugin.d.ts +8 -0
- package/dist/src/vite/auto_dynamic_pages_plugin.js +38 -0
- package/dist/src/vite/index.d.ts +1 -0
- package/dist/src/vite/index.js +1 -0
- package/dist/src/vite/plugin.d.ts +2 -0
- package/dist/src/vite/plugin.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -256,11 +256,12 @@ export default defineConfig({
|
|
|
256
256
|
```
|
|
257
257
|
|
|
258
258
|
##### What `cloudflareNextIntl()` Does
|
|
259
|
-
1. **
|
|
260
|
-
2. **
|
|
261
|
-
3. **
|
|
262
|
-
4. **
|
|
263
|
-
5. **
|
|
259
|
+
1. **Auto Dynamic Pages for SSG (`autoDynamicPages`)**: Automatically scans your Next.js/Vinext App Router pages during Vite configuration (`configResolved`) and inserts `export const dynamic = "force-static"` for all static pages that do not access dynamic APIs. This ensures Vinext builds all public marketing and static pages into SSG HTML automatically without extra build scripts or manually writing `export const dynamic = "force-static"`.
|
|
260
|
+
2. **Build-Time & Dev Image Optimizer (`imageOptimizer`)**: Automatically scans your image directories (`public/images`, `public/icons`), downscales oversized assets, produces sibling formats (`webp` by default; also supports `avif`, `png`, `jpeg`, `gif`, `tiff`, `heif`, `jp2`, `jxl`), generates 8px `.blur.webp` thumbnails with Next.js-matching SVG Gaussian blur placeholders, and provides transparent `<Image placeholder="blur" />` shimming via virtual modules. When more than one format is generated for an image, the shim renders a `<picture>` with one `<source>` per format — ordered exactly as configured — so the browser picks the best format it supports, with the original untouched file as an `onError` fallback if a generated asset fails to load. When the same image is used at different widths across the codebase, each size gets its own generated variant, and each `<Image>` usage automatically resolves to the closest matching size.
|
|
261
|
+
3. **Locale File Bundling & Resolution (`localeFiles`)**: Resolves `@locale-file/*` to your `./messages` directory and transforms dynamic imports into `import.meta.glob('/messages/*.json', { eager: true })` for lightning-fast locale loading on Cloudflare Workers.
|
|
262
|
+
4. **User-Agent Stub (`userAgentStub`)**: Prevents Next.js `user-agent` from importing `node:fs` during workerd runtime execution (which otherwise causes runtime 404 / 500 crashes in Workers proxy/middleware).
|
|
263
|
+
5. **Cloudflare Workers Client Stub (`cfWorkersClientStub`)**: Stubs `cloudflare:workers` in client builds so shared modules can be referenced without client bundling errors.
|
|
264
|
+
6. **Build ID Asset Emission (`buildIdAsset`)**: Emits `BUILD_ID` static asset in the client build directory from `process.env.__VINEXT_SHARED_BUILD_ID` or `process.env.__VINEXT_BUILD_ID`.
|
|
264
265
|
|
|
265
266
|
##### Plugin Options
|
|
266
267
|
All features are enabled by default, and can be individually configured or toggled off:
|
|
@@ -3,3 +3,5 @@ export declare const isBotCookieKey = "__is_bot_key__";
|
|
|
3
3
|
export declare const isDarkCookieKey = "__is_dark_key__";
|
|
4
4
|
export declare const cookieConsentCookieKey = "__cookie_consent_key__";
|
|
5
5
|
export declare const privacyPolicyDateCookieKey = "__privacy_policy_date_key__";
|
|
6
|
+
export declare const countryCookieKey = "__cf_country__";
|
|
7
|
+
export declare const timezoneCookieKey = "__cf_timezone__";
|
|
@@ -3,3 +3,5 @@ export const isBotCookieKey = '__is_bot_key__';
|
|
|
3
3
|
export const isDarkCookieKey = '__is_dark_key__';
|
|
4
4
|
export const cookieConsentCookieKey = '__cookie_consent_key__';
|
|
5
5
|
export const privacyPolicyDateCookieKey = '__privacy_policy_date_key__';
|
|
6
|
+
export const countryCookieKey = '__cf_country__';
|
|
7
|
+
export const timezoneCookieKey = '__cf_timezone__';
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server.js';
|
|
2
2
|
import { languageDetecotr } from '../server/functions/get_user_locale.js';
|
|
3
3
|
import config from './intl_config.js';
|
|
4
|
-
import { isBotCookieKey, localeCookieName } from './cookie_key.js';
|
|
4
|
+
import { countryCookieKey, isBotCookieKey, localeCookieName, timezoneCookieKey } from './cookie_key.js';
|
|
5
5
|
import { cache } from 'react';
|
|
6
6
|
import reportError from '../error_handling/report_error.js';
|
|
7
|
+
import { defaultCountryHeaderNames, defaultTimezoneHeaderNames } from '../server/functions/geo.js';
|
|
7
8
|
const sameSite = false;
|
|
8
9
|
const defaultCookieOption = {
|
|
9
10
|
path: '/',
|
|
@@ -24,6 +25,14 @@ async function getIsBotValue(userAgent) {
|
|
|
24
25
|
const getIsBotValueCache = cache(getIsBotValue);
|
|
25
26
|
export const localesSet = new Set(config.locales);
|
|
26
27
|
let updateSessionModule;
|
|
28
|
+
function getFirstHeaderValue(headers, names) {
|
|
29
|
+
for (const name of names) {
|
|
30
|
+
const value = headers.get(name);
|
|
31
|
+
if (value)
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
27
36
|
export default async function intlMiddleware(request, options) {
|
|
28
37
|
try {
|
|
29
38
|
let initialChosenLocale;
|
|
@@ -59,14 +68,19 @@ export default async function intlMiddleware(request, options) {
|
|
|
59
68
|
pathWithoutLocale = pathname;
|
|
60
69
|
}
|
|
61
70
|
const effectiveLocaleForRequest = urlLocale ?? initialChosenLocale;
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
const cf = request.cf;
|
|
72
|
+
const countryHeaderNames = config.cookieConsent?.countryHeaderNames
|
|
73
|
+
?? config.generate?.countryHeaderNames
|
|
74
|
+
?? defaultCountryHeaderNames;
|
|
75
|
+
const timezoneHeaderNames = config.generate?.timezoneHeaderNames
|
|
76
|
+
?? defaultTimezoneHeaderNames;
|
|
77
|
+
const countryCookieName = config.cookieConsent?.countryCookieName
|
|
78
|
+
?? config.generate?.countryCookieName
|
|
79
|
+
?? countryCookieKey;
|
|
80
|
+
const timezoneCookieName = config.generate?.timezoneCookieName
|
|
81
|
+
?? timezoneCookieKey;
|
|
82
|
+
const country = cf?.country || getFirstHeaderValue(request.headers, countryHeaderNames);
|
|
83
|
+
const timezone = cf?.timezone || getFirstHeaderValue(request.headers, timezoneHeaderNames);
|
|
70
84
|
const requestHeaders = new Headers(request.headers);
|
|
71
85
|
requestHeaders.set('x-pathname', pathWithoutLocale);
|
|
72
86
|
requestHeaders.set('x-search', search);
|
|
@@ -123,9 +137,23 @@ export default async function intlMiddleware(request, options) {
|
|
|
123
137
|
response.headers.set('x-search', search);
|
|
124
138
|
if (country) {
|
|
125
139
|
response.headers.set('x-cf-country', country);
|
|
140
|
+
response.cookies.set(countryCookieName, country, {
|
|
141
|
+
path: '/',
|
|
142
|
+
maxAge: 86400,
|
|
143
|
+
httpOnly: false,
|
|
144
|
+
secure: process.env.NODE_ENV === 'production',
|
|
145
|
+
sameSite: 'lax',
|
|
146
|
+
});
|
|
126
147
|
}
|
|
127
148
|
if (timezone) {
|
|
128
149
|
response.headers.set('x-cf-timezone', timezone);
|
|
150
|
+
response.cookies.set(timezoneCookieName, timezone, {
|
|
151
|
+
path: '/',
|
|
152
|
+
maxAge: 86400,
|
|
153
|
+
httpOnly: false,
|
|
154
|
+
secure: process.env.NODE_ENV === 'production',
|
|
155
|
+
sameSite: 'lax',
|
|
156
|
+
});
|
|
129
157
|
}
|
|
130
158
|
if (!isRedirect && config.firebaseAuth && config.firebaseAuth.middlewareEnabled !== false) {
|
|
131
159
|
if (!updateSessionModule) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CookieConsentContextType } from '../types.js';
|
|
2
2
|
export declare const CookieConsentContext: import("react").Context<CookieConsentContextType | null>;
|
|
3
|
-
export default function CookieConsentProvider({ requiresConsent, children }: {
|
|
3
|
+
export default function CookieConsentProvider({ requiresConsent: requiresConsentProp, children }: {
|
|
4
4
|
requiresConsent?: boolean;
|
|
5
5
|
children: React.ReactNode;
|
|
6
6
|
}): React.ReactElement;
|
|
@@ -6,7 +6,8 @@ import config from '../../config/intl_config.js';
|
|
|
6
6
|
import requireCookieConsentConfig from '../require_config.js';
|
|
7
7
|
import getCookie from '../../client/functions/get_cookie.js';
|
|
8
8
|
import setCookie from '../../client/functions/set_cookie.js';
|
|
9
|
-
import { cookieConsentCookieKey, privacyPolicyDateCookieKey } from '../../config/cookie_key.js';
|
|
9
|
+
import { cookieConsentCookieKey, countryCookieKey, privacyPolicyDateCookieKey } from '../../config/cookie_key.js';
|
|
10
|
+
import { defaultGdprCountries } from '../gdpr_countries.js';
|
|
10
11
|
export const CookieConsentContext = createContext(null);
|
|
11
12
|
function parseConsent(raw) {
|
|
12
13
|
if (raw === 'true')
|
|
@@ -15,8 +16,9 @@ function parseConsent(raw) {
|
|
|
15
16
|
return false;
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const defaultGdprCountriesSet = new Set(defaultGdprCountries);
|
|
20
|
+
export default function CookieConsentProvider({ requiresConsent: requiresConsentProp = true, children }) {
|
|
21
|
+
const { consentCookieName, dateCookieName, maxAge, policyDate, privacyPolicyPath, showPrivacyPolicy, gdprCountries } = useMemo(() => {
|
|
20
22
|
const cc = requireCookieConsentConfig(config.cookieConsent);
|
|
21
23
|
return {
|
|
22
24
|
consentCookieName: cc.consentCookieName ?? cookieConsentCookieKey,
|
|
@@ -25,17 +27,28 @@ export default function CookieConsentProvider({ requiresConsent = true, children
|
|
|
25
27
|
policyDate: cc.privacyPolicyDate ? new Date(cc.privacyPolicyDate) : null,
|
|
26
28
|
privacyPolicyPath: cc.privacyPolicyPath ?? '/privacy-policy',
|
|
27
29
|
showPrivacyPolicy: cc.showPrivacyPolicy ?? true,
|
|
30
|
+
gdprCountries: cc.gdprCountries,
|
|
28
31
|
};
|
|
29
32
|
}, []);
|
|
30
33
|
const [consent, setConsentState] = useState(null);
|
|
31
34
|
const [privacyPolicyUpdated, setPrivacyPolicyUpdated] = useState(false);
|
|
32
35
|
const [isMounted, setIsMounted] = useState(false);
|
|
36
|
+
const [requiresConsent, setRequiresConsent] = useState(requiresConsentProp);
|
|
33
37
|
const pathname = usePathname();
|
|
34
38
|
useEffect(() => {
|
|
35
39
|
const rawConsent = getCookie(consentCookieName);
|
|
36
40
|
const storedConsent = parseConsent(rawConsent);
|
|
37
41
|
const isFirstVisit = rawConsent === null;
|
|
38
42
|
setConsentState(storedConsent);
|
|
43
|
+
if (requiresConsentProp) {
|
|
44
|
+
const countryCookie = getCookie(countryCookieKey);
|
|
45
|
+
if (countryCookie) {
|
|
46
|
+
const gdprSet = gdprCountries
|
|
47
|
+
? new Set(gdprCountries)
|
|
48
|
+
: defaultGdprCountriesSet;
|
|
49
|
+
setRequiresConsent(gdprSet.has(countryCookie));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
39
52
|
setIsMounted(true);
|
|
40
53
|
if (isFirstVisit || !policyDate)
|
|
41
54
|
return;
|
|
@@ -46,7 +59,7 @@ export default function CookieConsentProvider({ requiresConsent = true, children
|
|
|
46
59
|
}
|
|
47
60
|
const storedDate = new Date(storedDateRaw);
|
|
48
61
|
setPrivacyPolicyUpdated(!Number.isNaN(storedDate.getTime()) && storedDate < policyDate);
|
|
49
|
-
}, [consentCookieName, dateCookieName, maxAge, policyDate]);
|
|
62
|
+
}, [consentCookieName, dateCookieName, maxAge, policyDate, requiresConsentProp, gdprCountries]);
|
|
50
63
|
const setConsent = useCallback((value) => {
|
|
51
64
|
if (value === null) {
|
|
52
65
|
setCookie({ name: consentCookieName, value: 'null', maxAge });
|
|
@@ -4,7 +4,6 @@ import { getMessage } from "../functions/server.js";
|
|
|
4
4
|
import dynamic from "next/dynamic.js";
|
|
5
5
|
import { localesSet } from "../../config/middleware.js";
|
|
6
6
|
import config from "../../config/intl_config.js";
|
|
7
|
-
import resolveRequiresConsent from "../../cookie_consent/gdpr_countries.js";
|
|
8
7
|
import installConsoleErrorOverride from "../../error_handling/install_console_error_override.js";
|
|
9
8
|
import reportError from "../../error_handling/report_error.js";
|
|
10
9
|
const LocationzationClientProvider = dynamic(() => import("../../client/components/client_provider.js"));
|
|
@@ -43,9 +42,7 @@ export default async function LocationzationProvider({ language, messages, stati
|
|
|
43
42
|
let requiresConsent = true;
|
|
44
43
|
if (config.cookieConsent) {
|
|
45
44
|
const isDevEnvironment = process.env.NODE_ENV === 'development';
|
|
46
|
-
requiresConsent = !isDevEnvironment
|
|
47
|
-
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling, config.cookieConsent.countryHeaderNames, config.generate)
|
|
48
|
-
: false;
|
|
45
|
+
requiresConsent = !isDevEnvironment;
|
|
49
46
|
const analyticsAllowedInEnv = config.cookieConsent.enableAnalyticsInDevMode === true || !isDevEnvironment;
|
|
50
47
|
if (config.cookieConsent.autoWireAnalytics !== false && analyticsAllowedInEnv) {
|
|
51
48
|
if (config.cookieConsent.getAnalytics) {
|
|
@@ -4,7 +4,6 @@ import { getMessage } from "../functions/server.js";
|
|
|
4
4
|
import dynamic from "next/dynamic.js";
|
|
5
5
|
import { localesSet } from "../../config/middleware.js";
|
|
6
6
|
import config from "../../config/intl_config.js";
|
|
7
|
-
import resolveRequiresConsent from "../../cookie_consent/gdpr_countries.js";
|
|
8
7
|
import installConsoleErrorOverride from "../../error_handling/install_console_error_override.js";
|
|
9
8
|
import reportError from "../../error_handling/report_error.js";
|
|
10
9
|
const LocationzationClientProvider = dynamic(() => import("../../client/components/client_provider_static.js"));
|
|
@@ -32,9 +31,7 @@ export default async function LocationzationProvider({ language, messages, child
|
|
|
32
31
|
let requiresConsent = true;
|
|
33
32
|
if (config.cookieConsent) {
|
|
34
33
|
const isDevEnvironment = process.env.NODE_ENV === 'development';
|
|
35
|
-
requiresConsent = !isDevEnvironment
|
|
36
|
-
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling, config.cookieConsent.countryHeaderNames, config.generate)
|
|
37
|
-
: false;
|
|
34
|
+
requiresConsent = !isDevEnvironment;
|
|
38
35
|
const analyticsAllowedInEnv = config.cookieConsent.enableAnalyticsInDevMode === true || !isDevEnvironment;
|
|
39
36
|
if (config.cookieConsent.autoWireAnalytics !== false && analyticsAllowedInEnv) {
|
|
40
37
|
if (config.cookieConsent.getAnalytics) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { countryCookieKey, timezoneCookieKey } from '../../config/cookie_key.js';
|
|
1
2
|
export const defaultCountryHeaderNames = ['x-cf-country', 'cf-ipcountry'];
|
|
2
3
|
export const defaultTimezoneHeaderNames = ['x-cf-timezone', 'cf-timezone'];
|
|
3
4
|
function extractHeader(h, name) {
|
|
@@ -26,6 +27,28 @@ function extractFromHeaderNames(h, headerNames) {
|
|
|
26
27
|
}
|
|
27
28
|
return undefined;
|
|
28
29
|
}
|
|
30
|
+
function extractCookieHeader(h, name) {
|
|
31
|
+
const cookieHeader = extractHeader(h, 'cookie');
|
|
32
|
+
if (!cookieHeader)
|
|
33
|
+
return undefined;
|
|
34
|
+
const parts = cookieHeader.split(';');
|
|
35
|
+
for (const part of parts) {
|
|
36
|
+
const index = part.indexOf('=');
|
|
37
|
+
if (index === -1)
|
|
38
|
+
continue;
|
|
39
|
+
const key = part.slice(0, index).trim();
|
|
40
|
+
if (key !== name)
|
|
41
|
+
continue;
|
|
42
|
+
const value = part.slice(index + 1).trim();
|
|
43
|
+
return value ? decodeURIComponent(value) : undefined;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function extractCookie(cookieStore, name) {
|
|
48
|
+
const cookie = cookieStore?.get?.(name);
|
|
49
|
+
const value = typeof cookie === 'string' ? cookie : cookie?.value;
|
|
50
|
+
return value || undefined;
|
|
51
|
+
}
|
|
29
52
|
export async function getCountry(input, generate, headerNames) {
|
|
30
53
|
const gen = generate ?? await configuredGenerate();
|
|
31
54
|
const names = headerNames
|
|
@@ -36,11 +59,21 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
36
59
|
const country = extractFromHeaderNames(input.headers, names);
|
|
37
60
|
if (country)
|
|
38
61
|
return country;
|
|
62
|
+
const cookieCountry = extractCookieHeader(input.headers, countryCookieKey);
|
|
63
|
+
if (cookieCountry)
|
|
64
|
+
return cookieCountry;
|
|
39
65
|
}
|
|
40
66
|
else if (typeof input.get === 'function') {
|
|
41
67
|
const country = extractFromHeaderNames(input, names);
|
|
42
68
|
if (country)
|
|
43
69
|
return country;
|
|
70
|
+
const cookieCountry = extractCookieHeader(input, countryCookieKey);
|
|
71
|
+
if (cookieCountry)
|
|
72
|
+
return cookieCountry;
|
|
73
|
+
}
|
|
74
|
+
const cookieCountry = extractCookie(input.cookies, countryCookieKey);
|
|
75
|
+
if (cookieCountry) {
|
|
76
|
+
return cookieCountry;
|
|
44
77
|
}
|
|
45
78
|
const cf = input.cf;
|
|
46
79
|
if (cf?.country && typeof cf.country === 'string' && cf.country.length > 0) {
|
|
@@ -53,6 +86,18 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
53
86
|
const country = extractFromHeaderNames(h, names);
|
|
54
87
|
if (country)
|
|
55
88
|
return country;
|
|
89
|
+
const cookieCountry = extractCookieHeader(h, countryCookieKey);
|
|
90
|
+
if (cookieCountry)
|
|
91
|
+
return cookieCountry;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const { cookies } = await import('next/headers.js');
|
|
97
|
+
const c = await cookies();
|
|
98
|
+
const country = extractCookie(c, countryCookieKey);
|
|
99
|
+
if (country)
|
|
100
|
+
return country;
|
|
56
101
|
}
|
|
57
102
|
catch {
|
|
58
103
|
}
|
|
@@ -89,11 +134,21 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
89
134
|
const tz = extractFromHeaderNames(input.headers, names);
|
|
90
135
|
if (tz)
|
|
91
136
|
return tz;
|
|
137
|
+
const cookieTimezone = extractCookieHeader(input.headers, timezoneCookieKey);
|
|
138
|
+
if (cookieTimezone)
|
|
139
|
+
return cookieTimezone;
|
|
92
140
|
}
|
|
93
141
|
else if (typeof input.get === 'function') {
|
|
94
142
|
const tz = extractFromHeaderNames(input, names);
|
|
95
143
|
if (tz)
|
|
96
144
|
return tz;
|
|
145
|
+
const cookieTimezone = extractCookieHeader(input, timezoneCookieKey);
|
|
146
|
+
if (cookieTimezone)
|
|
147
|
+
return cookieTimezone;
|
|
148
|
+
}
|
|
149
|
+
const cookieTimezone = extractCookie(input.cookies, timezoneCookieKey);
|
|
150
|
+
if (cookieTimezone) {
|
|
151
|
+
return cookieTimezone;
|
|
97
152
|
}
|
|
98
153
|
const cf = input.cf;
|
|
99
154
|
if (cf?.timezone && typeof cf.timezone === 'string' && cf.timezone.length > 0) {
|
|
@@ -106,6 +161,18 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
106
161
|
const tz = extractFromHeaderNames(h, names);
|
|
107
162
|
if (tz)
|
|
108
163
|
return tz;
|
|
164
|
+
const cookieTimezone = extractCookieHeader(h, timezoneCookieKey);
|
|
165
|
+
if (cookieTimezone)
|
|
166
|
+
return cookieTimezone;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const { cookies } = await import('next/headers.js');
|
|
172
|
+
const c = await cookies();
|
|
173
|
+
const tz = extractCookie(c, timezoneCookieKey);
|
|
174
|
+
if (tz)
|
|
175
|
+
return tz;
|
|
109
176
|
}
|
|
110
177
|
catch {
|
|
111
178
|
}
|
|
@@ -29,10 +29,17 @@ export interface GenerateRoutingConfig {
|
|
|
29
29
|
} | undefined);
|
|
30
30
|
getCloudflareContext?: CookieConsentGetCloudflareContext;
|
|
31
31
|
countryHeaderNames?: readonly string[];
|
|
32
|
+
countryCookieName?: string;
|
|
32
33
|
timezoneHeaderNames?: readonly string[];
|
|
34
|
+
timezoneCookieName?: string;
|
|
33
35
|
}
|
|
34
36
|
export type RequestOrHeaders = Request | Headers | {
|
|
35
37
|
headers?: Headers | Record<string, string | null | undefined>;
|
|
38
|
+
cookies?: {
|
|
39
|
+
get?: (name: string) => {
|
|
40
|
+
value?: string;
|
|
41
|
+
} | string | undefined;
|
|
42
|
+
};
|
|
36
43
|
cf?: {
|
|
37
44
|
country?: string;
|
|
38
45
|
timezone?: string;
|
|
@@ -75,6 +82,7 @@ export interface CookieConsentRoutingConfig {
|
|
|
75
82
|
autoAnalyticsEvents?: AutoAnalyticsEventsConfig;
|
|
76
83
|
getCountryCode?: () => string | undefined | Promise<string | undefined>;
|
|
77
84
|
countryHeaderNames?: readonly string[];
|
|
85
|
+
countryCookieName?: string;
|
|
78
86
|
gdprCountries?: readonly string[];
|
|
79
87
|
enableAnalyticsInDevMode?: boolean;
|
|
80
88
|
autoWireDialogs?: boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { type DynamicPagesCheckMode } from "../dynamic_pages_check/index.js";
|
|
3
|
+
export interface AutoDynamicPagesPluginOptions {
|
|
4
|
+
appDir?: string;
|
|
5
|
+
mode?: DynamicPagesCheckMode;
|
|
6
|
+
target?: 'next' | 'vinext';
|
|
7
|
+
}
|
|
8
|
+
export declare function autoDynamicPagesPlugin(options?: AutoDynamicPagesPluginOptions): Plugin;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { checkDynamicPages } from "../dynamic_pages_check/index.js";
|
|
4
|
+
export function autoDynamicPagesPlugin(options = {}) {
|
|
5
|
+
let ran = false;
|
|
6
|
+
return {
|
|
7
|
+
name: "cloudflare-next-intl-auto-dynamic-pages",
|
|
8
|
+
enforce: "pre",
|
|
9
|
+
async configResolved(config) {
|
|
10
|
+
if (ran)
|
|
11
|
+
return;
|
|
12
|
+
ran = true;
|
|
13
|
+
const root = config.root || process.cwd();
|
|
14
|
+
let appDir = options.appDir;
|
|
15
|
+
if (!appDir) {
|
|
16
|
+
if (existsSync(resolve(root, "src/app"))) {
|
|
17
|
+
appDir = resolve(root, "src/app");
|
|
18
|
+
}
|
|
19
|
+
else if (existsSync(resolve(root, "app"))) {
|
|
20
|
+
appDir = resolve(root, "app");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (!appDir || !existsSync(appDir)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
await checkDynamicPages({
|
|
28
|
+
appDir,
|
|
29
|
+
mode: options.mode ?? "fix",
|
|
30
|
+
target: options.target ?? "vinext",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.warn("[cloudflare-next-intl] autoDynamicPages check error:", err);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
package/dist/src/vite/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { autoDynamicPagesPlugin, type AutoDynamicPagesPluginOptions } from "./auto_dynamic_pages_plugin.js";
|
|
1
2
|
export { buildIdAsset } from "./build_id_asset.js";
|
|
2
3
|
export { userAgentStubPlugin, USER_AGENT_STUB_ID, USER_AGENT_STUB_CODE } from "./user_agent_stub.js";
|
|
3
4
|
export { cfWorkersClientStubPlugin, CF_WORKERS_CLIENT_STUB_ID, CF_WORKERS_CLIENT_STUB_CODE } from "./cf_workers_client_stub.js";
|
package/dist/src/vite/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { autoDynamicPagesPlugin } from "./auto_dynamic_pages_plugin.js";
|
|
1
2
|
export { buildIdAsset } from "./build_id_asset.js";
|
|
2
3
|
export { userAgentStubPlugin, USER_AGENT_STUB_ID, USER_AGENT_STUB_CODE } from "./user_agent_stub.js";
|
|
3
4
|
export { cfWorkersClientStubPlugin, CF_WORKERS_CLIENT_STUB_ID, CF_WORKERS_CLIENT_STUB_CODE } from "./cf_workers_client_stub.js";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import { type LocaleFilePluginOptions } from "./locale_file_plugin.js";
|
|
3
3
|
import { type ImageOptimizerPluginOptions } from "../image_optimizer/index.js";
|
|
4
|
+
import { type AutoDynamicPagesPluginOptions } from "./auto_dynamic_pages_plugin.js";
|
|
4
5
|
export interface CloudflareNextIntlOptions extends LocaleFilePluginOptions {
|
|
6
|
+
autoDynamicPages?: boolean | AutoDynamicPagesPluginOptions;
|
|
5
7
|
buildIdAsset?: boolean | string;
|
|
6
8
|
localeFiles?: boolean;
|
|
7
9
|
userAgentStub?: boolean;
|
package/dist/src/vite/plugin.js
CHANGED
|
@@ -3,8 +3,14 @@ import { userAgentStubPlugin } from "./user_agent_stub.js";
|
|
|
3
3
|
import { cfWorkersClientStubPlugin } from "./cf_workers_client_stub.js";
|
|
4
4
|
import { localeFilePlugin } from "./locale_file_plugin.js";
|
|
5
5
|
import { imageOptimizerPlugin } from "../image_optimizer/index.js";
|
|
6
|
+
import { autoDynamicPagesPlugin } from "./auto_dynamic_pages_plugin.js";
|
|
6
7
|
export function cloudflareNextIntl(options = {}) {
|
|
7
8
|
const plugins = [];
|
|
9
|
+
if (options.autoDynamicPages !== false) {
|
|
10
|
+
plugins.push(autoDynamicPagesPlugin(typeof options.autoDynamicPages === "object"
|
|
11
|
+
? options.autoDynamicPages
|
|
12
|
+
: undefined));
|
|
13
|
+
}
|
|
8
14
|
if (options.imageOptimizer !== false) {
|
|
9
15
|
plugins.push(imageOptimizerPlugin(typeof options.imageOptimizer === "object"
|
|
10
16
|
? options.imageOptimizer
|