cloudflare-next-intl 0.5.1 → 0.5.3
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 +11 -2
- package/dist/src/client/components/client_provider.d.ts +9 -1
- package/dist/src/client/components/client_provider.js +4 -2
- package/dist/src/cookie_consent/client/components/cookie_consent_dialog.js +2 -2
- package/dist/src/cookie_consent/client/cookie_consent_provider.js +7 -7
- package/dist/src/cookie_consent/index.d.ts +2 -0
- package/dist/src/cookie_consent/types.d.ts +8 -0
- package/dist/src/server/components/server_provider.js +1 -1
- package/dist/src/types/types.d.ts +22 -0
- package/package.json +1 -1
- package/dist/src/general/get_layout_states.d.ts +0 -0
- package/dist/src/general/get_layout_states.js +0 -39
package/README.md
CHANGED
|
@@ -188,8 +188,10 @@ import ThemeSwitcher from "cloudflare-next-intl/ThemeSwitcher";
|
|
|
188
188
|
### Cookie consent
|
|
189
189
|
|
|
190
190
|
Set `cookieConsent` on your `RoutingConfig` to enable — `IntlProvider` then
|
|
191
|
-
auto-wires `CookieConsentProvider
|
|
192
|
-
`cookieConsent.secrets`/`getSecrets` is set)
|
|
191
|
+
auto-wires `CookieConsentProvider`, `CookieConsentAnalytics` (if
|
|
192
|
+
`cookieConsent.secrets`/`getSecrets` is set), and both `CookieConsentDialog`/
|
|
193
|
+
`PrivacyPolicyUpdateDialog` (with their built-in default styling and
|
|
194
|
+
English/Ukrainian copy) with no manual nesting needed.
|
|
193
195
|
|
|
194
196
|
```typescript
|
|
195
197
|
// intl-config.ts
|
|
@@ -210,10 +212,17 @@ export default setIntlConfig({
|
|
|
210
212
|
getCloudflareContext,
|
|
211
213
|
// gdprCountries: [...], // defaults to EU/EEA + UK + Switzerland
|
|
212
214
|
// enableAnalyticsInDevMode: true, // analytics stay off in dev otherwise
|
|
215
|
+
// autoWireDialogs: false, // opt out and render the dialogs yourself
|
|
216
|
+
// dialogProps: { acceptText: "Accept" }, // forwarded to CookieConsentDialog
|
|
217
|
+
// updateDialogProps: { closeText: "Got it" }, // forwarded to PrivacyPolicyUpdateDialog
|
|
213
218
|
},
|
|
214
219
|
});
|
|
215
220
|
```
|
|
216
221
|
|
|
222
|
+
`CookieConsentDialog`/`PrivacyPolicyUpdateDialog` render automatically — no
|
|
223
|
+
JSX needed in your layout. Set `autoWireDialogs: false` to render them
|
|
224
|
+
yourself instead (e.g. for full control over placement):
|
|
225
|
+
|
|
217
226
|
```tsx
|
|
218
227
|
import { CookieConsentDialog, PrivacyPolicyUpdateDialog, useCookieConsent } from "cloudflare-next-intl/cookieConsent";
|
|
219
228
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { TranslationObject } from "../../types/types";
|
|
2
2
|
import type { SerializedAuthUser } from "../../firebase_auth/types";
|
|
3
3
|
import type { CookieConsentAnalyticsSecrets } from "../../types/types";
|
|
4
|
+
import type { CookieConsentDialogProps } from "../../cookie_consent/client/components/cookie_consent_dialog";
|
|
5
|
+
import type { PrivacyPolicyUpdateDialogProps } from "../../cookie_consent/client/components/privacy_policy_update_dialog";
|
|
4
6
|
interface LocaleContextType {
|
|
5
7
|
language: string;
|
|
6
8
|
messages: TranslationObject;
|
|
7
9
|
}
|
|
8
10
|
export declare const LocaleContext: import("react").Context<LocaleContextType | undefined>;
|
|
9
|
-
export default function LocationzationClientProvider({ language, messages, initialAuthUser, skipAuthProvider, analyticsSecrets, requiresConsent, children }: {
|
|
11
|
+
export default function LocationzationClientProvider({ language, messages, initialAuthUser, skipAuthProvider, analyticsSecrets, requiresConsent, autoWireDialogs, dialogProps, updateDialogProps, children }: {
|
|
10
12
|
language: string;
|
|
11
13
|
messages: TranslationObject;
|
|
12
14
|
initialAuthUser?: SerializedAuthUser | null;
|
|
@@ -21,6 +23,12 @@ export default function LocationzationClientProvider({ language, messages, initi
|
|
|
21
23
|
* for a first-time visitor instead of `null`.
|
|
22
24
|
*/
|
|
23
25
|
requiresConsent?: boolean;
|
|
26
|
+
/** From `cookieConsent.autoWireDialogs` — renders `CookieConsentDialog`/`PrivacyPolicyUpdateDialog` automatically when `true` (default). */
|
|
27
|
+
autoWireDialogs?: boolean;
|
|
28
|
+
/** From `cookieConsent.dialogProps` — forwarded as-is to the auto-wired `CookieConsentDialog`. */
|
|
29
|
+
dialogProps?: CookieConsentDialogProps;
|
|
30
|
+
/** From `cookieConsent.updateDialogProps` — forwarded as-is to the auto-wired `PrivacyPolicyUpdateDialog`. */
|
|
31
|
+
updateDialogProps?: PrivacyPolicyUpdateDialogProps;
|
|
24
32
|
children: React.ReactNode;
|
|
25
33
|
}): Component;
|
|
26
34
|
export {};
|
|
@@ -15,7 +15,9 @@ export const LocaleContext = createContext(undefined);
|
|
|
15
15
|
const AuthUserProvider = dynamic(() => import("../../firebase_auth/client/auth_user_provider"));
|
|
16
16
|
const CookieConsentProvider = dynamic(() => import("../../cookie_consent/client/cookie_consent_provider"));
|
|
17
17
|
const CookieConsentAnalytics = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_analytics"));
|
|
18
|
-
|
|
18
|
+
const CookieConsentDialog = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_dialog"));
|
|
19
|
+
const PrivacyPolicyUpdateDialog = dynamic(() => import("../../cookie_consent/client/components/privacy_policy_update_dialog"));
|
|
20
|
+
export default function LocationzationClientProvider({ language, messages, initialAuthUser = null, skipAuthProvider = false, analyticsSecrets, requiresConsent = true, autoWireDialogs = true, dialogProps, updateDialogProps, children }) {
|
|
19
21
|
setLocaleCache(language);
|
|
20
22
|
setMessageForLocaleCache(language, messages);
|
|
21
23
|
// `LocaleContext.Provider` stays the outermost element here — the
|
|
@@ -28,7 +30,7 @@ export default function LocationzationClientProvider({ language, messages, initi
|
|
|
28
30
|
providedChildren = _jsx(AuthUserProvider, { initialUser: initialAuthUser, children: children });
|
|
29
31
|
}
|
|
30
32
|
if (config.cookieConsent) {
|
|
31
|
-
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsSecrets && _jsx(CookieConsentAnalytics, { secrets: analyticsSecrets })] });
|
|
33
|
+
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsSecrets && _jsx(CookieConsentAnalytics, { secrets: analyticsSecrets }), autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
|
|
32
34
|
}
|
|
33
35
|
const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
|
|
34
36
|
return _jsx(LocaleContext.Provider, { value: contextValue, children: providedChildren });
|
|
@@ -12,8 +12,8 @@ import { defaultCookieDialogClassNames } from './default_dialog_styles';
|
|
|
12
12
|
* particular design system.
|
|
13
13
|
*/
|
|
14
14
|
export default function CookieConsentDialog({ message, link, privacyPolicyLinkText, acceptText, declineText, hideDecline = false, id = 'cookie-consent-dialog', classNames, styles, render, }) {
|
|
15
|
-
const { consent, setConsent, privacyPolicyPath } = useCookieConsent();
|
|
16
|
-
if (consent !== null)
|
|
15
|
+
const { consent, isMounted, setConsent, privacyPolicyPath } = useCookieConsent();
|
|
16
|
+
if (!isMounted || consent !== null)
|
|
17
17
|
return null;
|
|
18
18
|
if (render)
|
|
19
19
|
return _jsx(_Fragment, { children: render({ setConsent }) });
|
|
@@ -58,14 +58,14 @@ export default function CookieConsentProvider({ requiresConsent = true, children
|
|
|
58
58
|
}, []);
|
|
59
59
|
const [consent, setConsentState] = useState(null);
|
|
60
60
|
const [privacyPolicyUpdated, setPrivacyPolicyUpdated] = useState(false);
|
|
61
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
61
62
|
useEffect(() => {
|
|
62
63
|
const storedConsent = parseConsent(getCookie(consentCookieName));
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (storedConsent === null || !policyDate)
|
|
64
|
+
const autoAccepted = storedConsent === null && !requiresConsent;
|
|
65
|
+
setConsentState(autoAccepted ? true : storedConsent);
|
|
66
|
+
setIsMounted(true);
|
|
67
|
+
const isFirstVisit = storedConsent === null && !autoAccepted;
|
|
68
|
+
if (isFirstVisit || !policyDate)
|
|
69
69
|
return;
|
|
70
70
|
const storedDateRaw = getCookie(dateCookieName);
|
|
71
71
|
if (!storedDateRaw) {
|
|
@@ -90,6 +90,6 @@ export default function CookieConsentProvider({ requiresConsent = true, children
|
|
|
90
90
|
setPrivacyPolicyUpdated(false);
|
|
91
91
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
92
92
|
}, []);
|
|
93
|
-
const contextValue = useMemo(() => ({ consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath }), [consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath]);
|
|
93
|
+
const contextValue = useMemo(() => ({ consent, privacyPolicyUpdated, isMounted, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath }), [consent, privacyPolicyUpdated, isMounted, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath]);
|
|
94
94
|
return (_jsx(CookieConsentContext.Provider, { value: contextValue, children: children }));
|
|
95
95
|
}
|
|
@@ -5,4 +5,6 @@ export { default as PrivacyPolicyUpdateDialog } from './client/components/privac
|
|
|
5
5
|
export { default as CookieConsentAnalytics } from './client/components/cookie_consent_analytics';
|
|
6
6
|
export { defaultGdprCountries } from './gdpr_countries';
|
|
7
7
|
export type { CookieConsentContextType, ConsentValue, CookieDialogClassNames, CookieDialogStyles } from './types';
|
|
8
|
+
export type { CookieConsentDialogProps } from './client/components/cookie_consent_dialog';
|
|
9
|
+
export type { PrivacyPolicyUpdateDialogProps } from './client/components/privacy_policy_update_dialog';
|
|
8
10
|
export type { CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from '../types/types';
|
|
@@ -4,6 +4,14 @@ export type ConsentValue = boolean | null;
|
|
|
4
4
|
export interface CookieConsentContextType {
|
|
5
5
|
/** Current consent value; `null` until the visitor decides. */
|
|
6
6
|
consent: ConsentValue;
|
|
7
|
+
/**
|
|
8
|
+
* `false` until the client has read the stored consent/date cookies once
|
|
9
|
+
* (always `false` during SSR and the first client render, to avoid a
|
|
10
|
+
* hydration mismatch). The default dialog components render nothing
|
|
11
|
+
* until this is `true`, so a returning visitor's decided consent never
|
|
12
|
+
* flashes the banner before disappearing.
|
|
13
|
+
*/
|
|
14
|
+
isMounted: boolean;
|
|
7
15
|
/**
|
|
8
16
|
* `true` once a privacy-policy update has been detected (stored consent
|
|
9
17
|
* predates `cookieConsent.privacyPolicyDate`) and hasn't been
|
|
@@ -77,5 +77,5 @@ export default async function LocationzationProvider({ language, messages, child
|
|
|
77
77
|
: config.cookieConsent.secrets;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
return _jsx(LocationzationClientProvider, { language: language, messages: messagesValue, initialAuthUser: initialAuthUser, skipAuthProvider: !autoWireClientProvider, analyticsSecrets: analyticsSecrets, requiresConsent: requiresConsent, children: children });
|
|
80
|
+
return _jsx(LocationzationClientProvider, { language: language, messages: messagesValue, initialAuthUser: initialAuthUser, skipAuthProvider: !autoWireClientProvider, analyticsSecrets: analyticsSecrets, requiresConsent: requiresConsent, autoWireDialogs: config.cookieConsent?.autoWireDialogs !== false, dialogProps: config.cookieConsent?.dialogProps, updateDialogProps: config.cookieConsent?.updateDialogProps, children: children });
|
|
81
81
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { 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
|
+
import type { CookieConsentDialogProps } from '../cookie_consent/client/components/cookie_consent_dialog';
|
|
5
|
+
import type { PrivacyPolicyUpdateDialogProps } from '../cookie_consent/client/components/privacy_policy_update_dialog';
|
|
4
6
|
/**
|
|
5
7
|
* Custom middleware hook, run by `intlMiddleware` for your own logic
|
|
6
8
|
* (e.g. auth, feature flags, A/B tests) — on top of the library's own
|
|
@@ -179,6 +181,26 @@ export interface CookieConsentRoutingConfig {
|
|
|
179
181
|
* scripts locally.
|
|
180
182
|
*/
|
|
181
183
|
enableAnalyticsInDevMode?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Whether `IntlProvider` should automatically render
|
|
186
|
+
* `CookieConsentDialog` and `PrivacyPolicyUpdateDialog` (with their
|
|
187
|
+
* built-in default styling/EN+UK copy) at the end of your app tree.
|
|
188
|
+
* Defaults to `true` whenever `cookieConsent` is set. Set `false` to
|
|
189
|
+
* keep `cookieConsent` configured for `useCookieConsent()`/analytics
|
|
190
|
+
* only and render your own dialogs (or the exported components)
|
|
191
|
+
* yourself, wherever you like in the tree.
|
|
192
|
+
*/
|
|
193
|
+
autoWireDialogs?: boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Props forwarded as-is to the auto-wired `CookieConsentDialog`.
|
|
196
|
+
* Ignored when `autoWireDialogs` is `false`.
|
|
197
|
+
*/
|
|
198
|
+
dialogProps?: CookieConsentDialogProps;
|
|
199
|
+
/**
|
|
200
|
+
* Props forwarded as-is to the auto-wired `PrivacyPolicyUpdateDialog`.
|
|
201
|
+
* Ignored when `autoWireDialogs` is `false`.
|
|
202
|
+
*/
|
|
203
|
+
updateDialogProps?: PrivacyPolicyUpdateDialogProps;
|
|
182
204
|
}
|
|
183
205
|
/**
|
|
184
206
|
* Minimal shape read from your `getCloudflareContext()` return value — only
|
package/package.json
CHANGED
|
File without changes
|
|
@@ -1,39 +0,0 @@
|
|
|
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.
|
|
6
|
-
// "use server";
|
|
7
|
-
// import { cookies } from "next/headers";
|
|
8
|
-
// import { localeCookieName, isDarkCookieKey } from "../config/cookie_key";
|
|
9
|
-
// import config from "../config/intl_config";
|
|
10
|
-
// interface HtmlParamProps {
|
|
11
|
-
// className?: string;
|
|
12
|
-
// suppressHydrationWarning?: boolean;
|
|
13
|
-
// lang: string;
|
|
14
|
-
// }
|
|
15
|
-
// export default async function getLayoutStates(): Promise<{
|
|
16
|
-
// isDark: boolean | null;
|
|
17
|
-
// locale: string;
|
|
18
|
-
// htmlParam?: HtmlParamProps;
|
|
19
|
-
// }> {
|
|
20
|
-
// const cookie = await cookies();
|
|
21
|
-
// const isDarkMode = cookie.get(isDarkCookieKey)?.value;
|
|
22
|
-
// const isDark = getCookieBooleanValue(isDarkMode);
|
|
23
|
-
// const cookieLocale = (cookie.get(localeCookieName)?.value as string) ?? config.defaultLocale;
|
|
24
|
-
// const htmlParam: HtmlParamProps = { suppressHydrationWarning: !isDarkMode, lang: cookieLocale };
|
|
25
|
-
// if (isDark === true) {
|
|
26
|
-
// htmlParam.className = 'dark';
|
|
27
|
-
// }
|
|
28
|
-
// return { isDark, locale: cookieLocale, htmlParam };
|
|
29
|
-
// }
|
|
30
|
-
// function getCookieBooleanValue(cookieValue: string | undefined): boolean | null {
|
|
31
|
-
// switch (cookieValue) {
|
|
32
|
-
// case "true":
|
|
33
|
-
// return true;
|
|
34
|
-
// case "false":
|
|
35
|
-
// return false;
|
|
36
|
-
// default:
|
|
37
|
-
// return null;
|
|
38
|
-
// }
|
|
39
|
-
// }
|