@better-i18n/use-intl 0.7.0 → 0.8.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +20 -9
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +46 -39
- package/dist/provider.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export type { LanguageSwitcherProps } from "./components.js";
|
|
|
9
9
|
export { LocaleDropdown } from "./components/locale-dropdown.js";
|
|
10
10
|
export type { LocaleDropdownProps, LocaleDropdownRenderContext, } from "./components/locale-dropdown.js";
|
|
11
11
|
export type { Messages, BetterI18nProviderConfig, BetterI18nContextValue, } from "./types.js";
|
|
12
|
-
export { extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, type LocaleConfig, } from "@better-i18n/core";
|
|
12
|
+
export { getLocaleCookie, extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, type LocaleConfig, } from "@better-i18n/core";
|
|
13
13
|
export { IntlProvider } from "use-intl";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,SAAS,EAET,eAAe,EACf,YAAY,EACZ,WAAW,EACX,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,YAAY,EACV,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,iCAAiC,CAAC;AAGzC,YAAY,EACV,QAAQ,EACR,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,SAAS,EAET,eAAe,EACf,YAAY,EACZ,WAAW,EACX,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,YAAY,EACV,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,iCAAiC,CAAC;AAGzC,YAAY,EACV,QAAQ,EACR,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,8 @@ export { useLocalePath } from "./hooks/useLocalePath.js";
|
|
|
10
10
|
// Components
|
|
11
11
|
export { LanguageSwitcher } from "./components.js";
|
|
12
12
|
export { LocaleDropdown } from "./components/locale-dropdown.js";
|
|
13
|
-
// Re-export locale utilities from core (convenience)
|
|
14
|
-
export { extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, } from "@better-i18n/core";
|
|
13
|
+
// Re-export locale + cookie utilities from core (convenience)
|
|
14
|
+
export { getLocaleCookie, extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, } from "@better-i18n/core";
|
|
15
15
|
// Re-export commonly used use-intl components
|
|
16
16
|
export { IntlProvider } from "use-intl";
|
|
17
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,kBAAkB;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,SAAS;AACT,4BAA4B;AAC5B,eAAe,EACf,YAAY,EACZ,WAAW,EACX,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,gCAAgC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAajE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,kBAAkB;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,SAAS;AACT,4BAA4B;AAC5B,eAAe,EACf,YAAY,EACZ,WAAW,EACX,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,gCAAgC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAajE,8DAA8D;AAC9D,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GAEjB,MAAM,mBAAmB,CAAC;AAE3B,8CAA8C;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -50,25 +50,36 @@ export interface BetterI18nProviderProps extends Omit<BetterI18nProviderConfig,
|
|
|
50
50
|
* Persist the active locale to a cookie so returning visitors
|
|
51
51
|
* get their previously chosen language — even without geo-IP detection.
|
|
52
52
|
*
|
|
53
|
-
* - `true` — uses the default cookie name `"
|
|
54
|
-
* - `string` — custom cookie name (e.g., `"
|
|
55
|
-
* - `false` / `undefined` — no persistence (default
|
|
53
|
+
* - `true` — uses the default cookie name `"locale"`
|
|
54
|
+
* - `string` — custom cookie name (e.g., `"preferred-locale"`)
|
|
55
|
+
* - `false` / `undefined` — no persistence (default)
|
|
56
56
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
57
|
+
* **Read + write:** On mount, reads the cookie as a fallback when no SSR
|
|
58
|
+
* data is available (SPA/static builds). On every locale change, writes
|
|
59
|
+
* the cookie so the server can read it on the next visit.
|
|
59
60
|
*
|
|
60
|
-
*
|
|
61
|
+
* **Same name everywhere:** Use the same cookie name on the server
|
|
62
|
+
* (`localeCookie` on `createBetterAuthProvider` or Vite plugin) and
|
|
63
|
+
* in non-React code (`getLocaleCookie()` from `@better-i18n/core`).
|
|
61
64
|
*
|
|
62
65
|
* @example
|
|
63
66
|
* ```tsx
|
|
64
|
-
* <BetterI18nProvider project="acme/web"
|
|
67
|
+
* <BetterI18nProvider project="acme/web" localeCookie>
|
|
68
|
+
* <App />
|
|
69
|
+
* </BetterI18nProvider>
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* // Custom cookie name — must match server-side localeCookie option
|
|
75
|
+
* <BetterI18nProvider project="acme/web" localeCookie="preferred-locale">
|
|
65
76
|
* <App />
|
|
66
77
|
* </BetterI18nProvider>
|
|
67
78
|
* ```
|
|
68
79
|
*
|
|
69
80
|
* @default false
|
|
70
81
|
*/
|
|
71
|
-
|
|
82
|
+
localeCookie?: boolean | string;
|
|
72
83
|
}
|
|
73
84
|
/**
|
|
74
85
|
* Provider component that combines Better i18n CDN with use-intl
|
|
@@ -103,5 +114,5 @@ export interface BetterI18nProviderProps extends Omit<BetterI18nProviderConfig,
|
|
|
103
114
|
* }
|
|
104
115
|
* ```
|
|
105
116
|
*/
|
|
106
|
-
export declare function BetterI18nProvider({ children, project: propProject, locale: propLocale, messages: propMessages, timeZone, now, onError, cdnBaseUrl, debug, logLevel, fetch: customFetch, storage, staticData, fetchTimeout, retryCount, initialLanguages: propInitialLanguages, localePrefix, getMessageFallback: customGetMessageFallback, onLocaleChange,
|
|
117
|
+
export declare function BetterI18nProvider({ children, project: propProject, locale: propLocale, messages: propMessages, timeZone, now, onError, cdnBaseUrl, debug, logLevel, fetch: customFetch, storage, staticData, fetchTimeout, retryCount, initialLanguages: propInitialLanguages, localePrefix, getMessageFallback: customGetMessageFallback, onLocaleChange, localeCookie: localeCookieProp, }: BetterI18nProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
107
118
|
//# sourceMappingURL=provider.d.ts.map
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlF,OAAO,KAAK,EAAE,wBAAwB,EAAY,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlF,OAAO,KAAK,EAAE,wBAAwB,EAAY,MAAM,YAAY,CAAC;AAqCrE,MAAM,WAAW,uBACf,SAAQ,IAAI,CAAC,wBAAwB,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5D,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;IACpC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;IAChD,oDAAoD;IACpD,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC1B,KAAK,EAAE,KAAK,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,KAAK,MAAM,CAAC;IACb;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EACR,GAAG,EACH,OAAO,EACP,UAAU,EACV,KAAK,EACL,QAAQ,EACR,KAAK,EAAE,WAAW,EAClB,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,gBAAgB,EAAE,oBAAoB,EACtC,YAA0B,EAC1B,kBAAkB,EAAE,wBAAwB,EAC5C,cAAc,EACd,YAAY,EAAE,gBAAwB,GACvC,EAAE,uBAAuB,2CA+PzB"}
|
package/dist/provider.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { createI18nCore } from "@better-i18n/core";
|
|
3
|
+
import { createI18nCore, getLocaleCookie } from "@better-i18n/core";
|
|
4
4
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
5
5
|
import { IntlProvider } from "use-intl";
|
|
6
6
|
import { BetterI18nContext } from "./context.js";
|
|
@@ -22,16 +22,8 @@ function readSSRData() {
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
* Used as fallback when SSR data is not available (static/SPA builds).
|
|
28
|
-
*/
|
|
29
|
-
function readCookieLocale(cookieName) {
|
|
30
|
-
if (typeof document === "undefined")
|
|
31
|
-
return null;
|
|
32
|
-
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${cookieName}=([^;]*)`));
|
|
33
|
-
return match?.[1] ?? null;
|
|
34
|
-
}
|
|
25
|
+
/** BCP 47 locale tag for URL segment detection. */
|
|
26
|
+
const LOCALE_RE = /^[a-zA-Z]{2,8}(?:-[a-zA-Z0-9]{1,8})*$/;
|
|
35
27
|
/**
|
|
36
28
|
* Provider component that combines Better i18n CDN with use-intl
|
|
37
29
|
*
|
|
@@ -65,7 +57,7 @@ function readCookieLocale(cookieName) {
|
|
|
65
57
|
* }
|
|
66
58
|
* ```
|
|
67
59
|
*/
|
|
68
|
-
export function BetterI18nProvider({ children, project: propProject, locale: propLocale, messages: propMessages, timeZone, now, onError, cdnBaseUrl, debug, logLevel, fetch: customFetch, storage, staticData, fetchTimeout, retryCount, initialLanguages: propInitialLanguages, localePrefix = "as-needed", getMessageFallback: customGetMessageFallback, onLocaleChange,
|
|
60
|
+
export function BetterI18nProvider({ children, project: propProject, locale: propLocale, messages: propMessages, timeZone, now, onError, cdnBaseUrl, debug, logLevel, fetch: customFetch, storage, staticData, fetchTimeout, retryCount, initialLanguages: propInitialLanguages, localePrefix = "as-needed", getMessageFallback: customGetMessageFallback, onLocaleChange, localeCookie: localeCookieProp = false, }) {
|
|
69
61
|
// ─── SSR Data (from @better-i18n/vite plugin) ─────────────────────
|
|
70
62
|
// Read plugin-injected translations synchronously from DOM.
|
|
71
63
|
// Runs once as a lazy initializer — before first paint, zero FOUC.
|
|
@@ -78,19 +70,18 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
78
70
|
}
|
|
79
71
|
const initialMessages = propMessages || ssrData?.messages;
|
|
80
72
|
const initialLanguages = propInitialLanguages || ssrData?.languages;
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
const
|
|
84
|
-
? "
|
|
85
|
-
:
|
|
86
|
-
// Locale resolution chain: prop → SSR → cookie (persist or plugin) → "en"
|
|
87
|
-
const initialLocale = propLocale
|
|
88
|
-
|| ssrData?.locale
|
|
89
|
-
|| (persistCookieName && readCookieLocale(persistCookieName))
|
|
90
|
-
|| (localeCookie && readCookieLocale(localeCookie))
|
|
91
|
-
|| "en";
|
|
73
|
+
// Resolve cookie name: prop > Vite plugin SSR data > none
|
|
74
|
+
// Same name is used for both reading (init) and writing (on locale change).
|
|
75
|
+
const cookieName = localeCookieProp === true
|
|
76
|
+
? "locale"
|
|
77
|
+
: localeCookieProp || ssrData?.localeCookie || undefined;
|
|
92
78
|
// ─── Locale State ─────────────────────────────────────────────────
|
|
93
|
-
|
|
79
|
+
// Use a lazy initializer so cookie reads run exactly once (not on every render).
|
|
80
|
+
// Locale resolution chain: prop → SSR → cookie → "en"
|
|
81
|
+
const [managedLocale, setManagedLocale] = useState(() => propLocale
|
|
82
|
+
|| ssrData?.locale
|
|
83
|
+
|| (cookieName ? getLocaleCookie(cookieName) : null)
|
|
84
|
+
|| "en");
|
|
94
85
|
// Sync when external prop changes (e.g., router navigation updates propLocale)
|
|
95
86
|
useEffect(() => {
|
|
96
87
|
if (propLocale)
|
|
@@ -98,20 +89,20 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
98
89
|
}, [propLocale]);
|
|
99
90
|
const locale = managedLocale;
|
|
100
91
|
// ─── Locale Persistence ──────────────────────────────────────────
|
|
101
|
-
//
|
|
92
|
+
// Write locale cookie on every change (including initial mount).
|
|
102
93
|
// This ensures returning visitors get their last-used language even
|
|
103
94
|
// without geo-IP detection (not everyone uses Cloudflare).
|
|
104
95
|
useEffect(() => {
|
|
105
|
-
if (!
|
|
96
|
+
if (!cookieName || typeof document === "undefined")
|
|
106
97
|
return;
|
|
107
|
-
document.cookie = `${
|
|
108
|
-
}, [locale,
|
|
98
|
+
document.cookie = `${cookieName}=${locale}; path=/; max-age=31536000; SameSite=Lax`;
|
|
99
|
+
}, [locale, cookieName]);
|
|
109
100
|
// setLocale: updates internal state, persists cookie, updates URL, notifies parent
|
|
110
101
|
const setLocale = useCallback((newLocale) => {
|
|
111
102
|
setManagedLocale(newLocale);
|
|
112
|
-
//
|
|
113
|
-
if (
|
|
114
|
-
document.cookie = `${
|
|
103
|
+
// Write cookie immediately (before onLocaleChange navigation).
|
|
104
|
+
if (cookieName && typeof document !== "undefined") {
|
|
105
|
+
document.cookie = `${cookieName}=${newLocale};path=/;max-age=${60 * 60 * 24 * 365};SameSite=Lax`;
|
|
115
106
|
}
|
|
116
107
|
// Notify consumer (e.g., router navigation)
|
|
117
108
|
if (onLocaleChange) {
|
|
@@ -128,7 +119,9 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
128
119
|
const segments = path.split("/").filter(Boolean);
|
|
129
120
|
const firstSegment = segments[0];
|
|
130
121
|
const supportedLocales = ssrData?.supportedLocales;
|
|
131
|
-
|
|
122
|
+
// Match BCP 47 tags: "en", "pt-BR", "zh-Hans" (2-8 alpha + optional subtags)
|
|
123
|
+
const isLocaleSegment = firstSegment !== undefined &&
|
|
124
|
+
LOCALE_RE.test(firstSegment) &&
|
|
132
125
|
(!supportedLocales || supportedLocales.includes(firstSegment));
|
|
133
126
|
if (isLocaleSegment) {
|
|
134
127
|
segments[0] = newLocale;
|
|
@@ -136,16 +129,19 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
136
129
|
else {
|
|
137
130
|
segments.unshift(newLocale);
|
|
138
131
|
}
|
|
139
|
-
window.history.replaceState(null, "",
|
|
132
|
+
window.history.replaceState(null, "", `/${segments.join("/")}${window.location.search}`);
|
|
140
133
|
}
|
|
141
|
-
}, [onLocaleChange,
|
|
134
|
+
}, [onLocaleChange, cookieName, localePrefix, ssrData]);
|
|
142
135
|
// ─── Messages State ───────────────────────────────────────────────
|
|
143
136
|
// Track the locale that initial messages were **actually built for**.
|
|
144
137
|
// When messages come from SSR (vite plugin), their locale is ssrData.locale.
|
|
145
|
-
// When messages come from props, their locale matches
|
|
138
|
+
// When messages come from props, their locale matches managedLocale at mount time.
|
|
146
139
|
// This distinction prevents a critical bug: propLocale="tr" + ssrData.messages="en"
|
|
147
140
|
// would incorrectly mark English messages as fresh for Turkish, skipping CDN fetch.
|
|
148
|
-
|
|
141
|
+
//
|
|
142
|
+
// Stored in state (not derived on each render) so it stays anchored to mount-time
|
|
143
|
+
// values even after locale switches cause re-renders.
|
|
144
|
+
const [initialMessagesLocale] = useState(() => propMessages ? managedLocale : ssrData?.locale);
|
|
149
145
|
const [clientMessages, setClientMessages] = useState();
|
|
150
146
|
// Use initial messages only when they match the current locale.
|
|
151
147
|
// After locale switch, fall through to clientMessages (CDN-fetched).
|
|
@@ -154,10 +150,16 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
154
150
|
const [languages, setLanguages] = useState(initialLanguages ?? []);
|
|
155
151
|
const [isLoadingMessages, setIsLoadingMessages] = useState(initialMessages === undefined);
|
|
156
152
|
const [isLoadingLanguages, setIsLoadingLanguages] = useState(!initialLanguages);
|
|
157
|
-
//
|
|
153
|
+
// Capture the locale that was active at mount — used as `defaultLocale` for
|
|
154
|
+
// the core instance. This must NOT change on locale switches: the core's
|
|
155
|
+
// `defaultLocale` is a startup hint for the CDN client, not the live locale.
|
|
156
|
+
// Putting `locale` in the deps would recreate the core (and its TtlCache) on
|
|
157
|
+
// every language switch, defeating the in-memory cache entirely.
|
|
158
|
+
const [mountLocale] = useState(locale);
|
|
159
|
+
// Create i18n core instance — stable for the lifetime of the provider.
|
|
158
160
|
const i18nCore = useMemo(() => createI18nCore({
|
|
159
161
|
project,
|
|
160
|
-
defaultLocale:
|
|
162
|
+
defaultLocale: mountLocale,
|
|
161
163
|
cdnBaseUrl,
|
|
162
164
|
debug,
|
|
163
165
|
logLevel,
|
|
@@ -166,7 +168,12 @@ export function BetterI18nProvider({ children, project: propProject, locale: pro
|
|
|
166
168
|
staticData,
|
|
167
169
|
fetchTimeout,
|
|
168
170
|
retryCount,
|
|
169
|
-
}),
|
|
171
|
+
}),
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
[project, cdnBaseUrl, debug, logLevel, customFetch, storage, staticData, fetchTimeout, retryCount]
|
|
174
|
+
// `mountLocale` intentionally excluded — it never changes after mount.
|
|
175
|
+
// `locale` intentionally excluded — see comment above.
|
|
176
|
+
);
|
|
170
177
|
// Load languages on mount — skip if SSR already provided them
|
|
171
178
|
useEffect(() => {
|
|
172
179
|
if (initialLanguages)
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-i18n/use-intl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Better i18n integration for use-intl (React, TanStack Start)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"prepublishOnly": "bun run build"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@better-i18n/core": "^0.
|
|
61
|
+
"@better-i18n/core": "^0.7.0",
|
|
62
62
|
"@floating-ui/react": "^0.27.19"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|