@better-i18n/next 0.5.2 → 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/dist/client.d.ts +99 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +230 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +78 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +177 -0
- package/dist/middleware.js.map +1 -0
- package/dist/proxy.d.ts +2 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +2 -0
- package/dist/proxy.js.map +1 -0
- package/dist/server.d.ts +71 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +128 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +23 -15
- package/src/client.tsx +0 -324
- package/src/config.ts +0 -40
- package/src/index.ts +0 -116
- package/src/middleware.ts +0 -243
- package/src/proxy.ts +0 -1
- package/src/server.ts +0 -164
- package/src/types.ts +0 -66
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { LanguageOption, Messages } from "@better-i18n/core";
|
|
3
|
+
import type { I18nConfig } from "./types.js";
|
|
4
|
+
export interface BetterI18nProviderProps {
|
|
5
|
+
/** Initial locale from server (getLocale()) */
|
|
6
|
+
locale: string;
|
|
7
|
+
/** Initial messages from server (getMessages()) */
|
|
8
|
+
messages: Messages;
|
|
9
|
+
/** i18n config — only project and defaultLocale are required */
|
|
10
|
+
config: I18nConfig;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Provider that wraps `NextIntlClientProvider` and enables instant locale
|
|
15
|
+
* switching without a server round-trip.
|
|
16
|
+
*
|
|
17
|
+
* When `useSetLocale()` is called inside this provider, it:
|
|
18
|
+
* 1. Sets a cookie (for server-side persistence on next navigation)
|
|
19
|
+
* 2. Fetches new messages from CDN on the client
|
|
20
|
+
* 3. Re-renders the tree with new locale + messages instantly
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* // app/layout.tsx
|
|
25
|
+
* import { BetterI18nProvider } from '@better-i18n/next/client'
|
|
26
|
+
*
|
|
27
|
+
* export default async function RootLayout({ children }) {
|
|
28
|
+
* const locale = await getLocale()
|
|
29
|
+
* const messages = await getMessages()
|
|
30
|
+
*
|
|
31
|
+
* return (
|
|
32
|
+
* <BetterI18nProvider
|
|
33
|
+
* locale={locale}
|
|
34
|
+
* messages={messages}
|
|
35
|
+
* config={{ project: 'acme/dashboard', defaultLocale: 'en' }}
|
|
36
|
+
* >
|
|
37
|
+
* {children}
|
|
38
|
+
* </BetterI18nProvider>
|
|
39
|
+
* )
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function BetterI18nProvider({ locale: initialLocale, messages: initialMessages, config, children, }: BetterI18nProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export type UseManifestLanguagesResult = {
|
|
45
|
+
languages: LanguageOption[];
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
error: Error | null;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* React hook to fetch manifest languages on the client
|
|
51
|
+
*
|
|
52
|
+
* Uses `createI18nCore` from `@better-i18n/core` internally with
|
|
53
|
+
* request deduplication to prevent duplicate fetches.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const { languages, isLoading, error } = useManifestLanguages({
|
|
58
|
+
* project: 'acme/dashboard',
|
|
59
|
+
* defaultLocale: 'en',
|
|
60
|
+
* })
|
|
61
|
+
*
|
|
62
|
+
* if (isLoading) return <Spinner />
|
|
63
|
+
* if (error) return <Error message={error.message} />
|
|
64
|
+
*
|
|
65
|
+
* return (
|
|
66
|
+
* <select>
|
|
67
|
+
* {languages.map(lang => (
|
|
68
|
+
* <option key={lang.code} value={lang.code}>
|
|
69
|
+
* {lang.nativeName || lang.name || lang.code}
|
|
70
|
+
* </option>
|
|
71
|
+
* ))}
|
|
72
|
+
* </select>
|
|
73
|
+
* )
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare const useManifestLanguages: (config: I18nConfig) => UseManifestLanguagesResult;
|
|
77
|
+
/**
|
|
78
|
+
* React hook that returns a function to switch the active locale.
|
|
79
|
+
*
|
|
80
|
+
* - **With `BetterI18nProvider`**: Fetches new messages client-side from CDN
|
|
81
|
+
* and updates the UI instantly — no page refresh needed.
|
|
82
|
+
* - **Without provider (standalone)**: Pass a config object. Sets a cookie and
|
|
83
|
+
* calls `router.refresh()` for a soft server re-render.
|
|
84
|
+
*
|
|
85
|
+
* @example With provider (recommended — instant switching)
|
|
86
|
+
* ```tsx
|
|
87
|
+
* // Wrap your layout with BetterI18nProvider, then:
|
|
88
|
+
* const setLocale = useSetLocale()
|
|
89
|
+
* <button onClick={() => setLocale('tr')}>Türkçe</button>
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @example Standalone (soft refresh)
|
|
93
|
+
* ```tsx
|
|
94
|
+
* const setLocale = useSetLocale({ project: 'acme/dashboard', defaultLocale: 'en' })
|
|
95
|
+
* <button onClick={() => setLocale('tr')}>Türkçe</button>
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function useSetLocale(config?: I18nConfig): (locale: string) => void;
|
|
99
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAU7C,MAAM,WAAW,uBAAuB;IACtC,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,QAAQ,EAAE,QAAQ,CAAC;IACnB,gEAAgE;IAChE,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,eAAe,EACzB,MAAM,EACN,QAAQ,GACT,EAAE,uBAAuB,2CAqDzB;AAID,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB,CAAC;AAcF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,UAAU,KAAG,0BAuFzD,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAkB1E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import { NextIntlClientProvider } from "next-intl";
|
|
6
|
+
import { createI18nCore, parseProject } from "@better-i18n/core";
|
|
7
|
+
import { normalizeConfig } from "./config.js";
|
|
8
|
+
const BetterI18nContext = createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* Provider that wraps `NextIntlClientProvider` and enables instant locale
|
|
11
|
+
* switching without a server round-trip.
|
|
12
|
+
*
|
|
13
|
+
* When `useSetLocale()` is called inside this provider, it:
|
|
14
|
+
* 1. Sets a cookie (for server-side persistence on next navigation)
|
|
15
|
+
* 2. Fetches new messages from CDN on the client
|
|
16
|
+
* 3. Re-renders the tree with new locale + messages instantly
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // app/layout.tsx
|
|
21
|
+
* import { BetterI18nProvider } from '@better-i18n/next/client'
|
|
22
|
+
*
|
|
23
|
+
* export default async function RootLayout({ children }) {
|
|
24
|
+
* const locale = await getLocale()
|
|
25
|
+
* const messages = await getMessages()
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <BetterI18nProvider
|
|
29
|
+
* locale={locale}
|
|
30
|
+
* messages={messages}
|
|
31
|
+
* config={{ project: 'acme/dashboard', defaultLocale: 'en' }}
|
|
32
|
+
* >
|
|
33
|
+
* {children}
|
|
34
|
+
* </BetterI18nProvider>
|
|
35
|
+
* )
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function BetterI18nProvider({ locale: initialLocale, messages: initialMessages, config, children, }) {
|
|
40
|
+
const normalized = useMemo(() => normalizeConfig(config), [
|
|
41
|
+
config.project,
|
|
42
|
+
config.defaultLocale,
|
|
43
|
+
config.cookieName,
|
|
44
|
+
config.cdnBaseUrl,
|
|
45
|
+
]);
|
|
46
|
+
const [locale, setLocaleState] = useState(initialLocale);
|
|
47
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
48
|
+
// Sync with server-provided values when they change (e.g. navigation to a new page)
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
setLocaleState(initialLocale);
|
|
51
|
+
setMessages(initialMessages);
|
|
52
|
+
}, [initialLocale, initialMessages]);
|
|
53
|
+
const setLocale = useCallback(async (newLocale) => {
|
|
54
|
+
if (newLocale === locale)
|
|
55
|
+
return;
|
|
56
|
+
// 1. Set cookie for server-side persistence
|
|
57
|
+
document.cookie = `${normalized.cookieName}=${newLocale}; path=/; max-age=31536000; samesite=lax`;
|
|
58
|
+
// 2. Fetch new messages from CDN
|
|
59
|
+
const { workspaceId, projectSlug } = parseProject(normalized.project);
|
|
60
|
+
const cdnBase = normalized.cdnBaseUrl || "https://cdn.better-i18n.com";
|
|
61
|
+
const url = `${cdnBase}/${workspaceId}/${projectSlug}/${newLocale}/translations.json`;
|
|
62
|
+
try {
|
|
63
|
+
const res = await fetch(url);
|
|
64
|
+
if (!res.ok)
|
|
65
|
+
throw new Error(`HTTP ${res.status}`);
|
|
66
|
+
const newMessages = await res.json();
|
|
67
|
+
// 3. Instant client-side update — no server round-trip
|
|
68
|
+
setLocaleState(newLocale);
|
|
69
|
+
setMessages(newMessages);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
console.error("[better-i18n] Client-side locale switch failed, falling back to refresh:", err);
|
|
73
|
+
// Fallback: let the server handle it
|
|
74
|
+
window.location.reload();
|
|
75
|
+
}
|
|
76
|
+
}, [locale, normalized]);
|
|
77
|
+
return (_jsx(BetterI18nContext.Provider, { value: { setLocale }, children: _jsx(NextIntlClientProvider, { locale: locale, messages: messages, children: children }) }));
|
|
78
|
+
}
|
|
79
|
+
// Client-side request deduplication cache
|
|
80
|
+
const clientCache = new Map();
|
|
81
|
+
const getCacheKey = (project, cdnBaseUrl) => `${cdnBaseUrl || "https://cdn.better-i18n.com"}|${project}`;
|
|
82
|
+
/**
|
|
83
|
+
* React hook to fetch manifest languages on the client
|
|
84
|
+
*
|
|
85
|
+
* Uses `createI18nCore` from `@better-i18n/core` internally with
|
|
86
|
+
* request deduplication to prevent duplicate fetches.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* const { languages, isLoading, error } = useManifestLanguages({
|
|
91
|
+
* project: 'acme/dashboard',
|
|
92
|
+
* defaultLocale: 'en',
|
|
93
|
+
* })
|
|
94
|
+
*
|
|
95
|
+
* if (isLoading) return <Spinner />
|
|
96
|
+
* if (error) return <Error message={error.message} />
|
|
97
|
+
*
|
|
98
|
+
* return (
|
|
99
|
+
* <select>
|
|
100
|
+
* {languages.map(lang => (
|
|
101
|
+
* <option key={lang.code} value={lang.code}>
|
|
102
|
+
* {lang.nativeName || lang.name || lang.code}
|
|
103
|
+
* </option>
|
|
104
|
+
* ))}
|
|
105
|
+
* </select>
|
|
106
|
+
* )
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export const useManifestLanguages = (config) => {
|
|
110
|
+
const normalized = useMemo(() => normalizeConfig(config), [
|
|
111
|
+
config.project,
|
|
112
|
+
config.defaultLocale,
|
|
113
|
+
config.cdnBaseUrl,
|
|
114
|
+
config.debug,
|
|
115
|
+
config.logLevel,
|
|
116
|
+
]);
|
|
117
|
+
const i18nCore = useMemo(() => createI18nCore({
|
|
118
|
+
project: normalized.project,
|
|
119
|
+
defaultLocale: normalized.defaultLocale,
|
|
120
|
+
cdnBaseUrl: normalized.cdnBaseUrl,
|
|
121
|
+
debug: normalized.debug,
|
|
122
|
+
logLevel: normalized.logLevel,
|
|
123
|
+
}), [normalized]);
|
|
124
|
+
const cacheKey = getCacheKey(normalized.project, normalized.cdnBaseUrl);
|
|
125
|
+
const cached = clientCache.get(cacheKey);
|
|
126
|
+
const [languages, setLanguages] = useState(cached?.data ?? []);
|
|
127
|
+
const [isLoading, setIsLoading] = useState(!cached?.data);
|
|
128
|
+
const [error, setError] = useState(cached?.error ?? null);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
let isMounted = true;
|
|
131
|
+
const run = async () => {
|
|
132
|
+
const entry = clientCache.get(cacheKey) ?? {};
|
|
133
|
+
// Return cached data if available
|
|
134
|
+
if (entry.data) {
|
|
135
|
+
if (isMounted) {
|
|
136
|
+
setLanguages(entry.data);
|
|
137
|
+
setIsLoading(false);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Deduplicate in-flight requests
|
|
142
|
+
if (!entry.promise) {
|
|
143
|
+
entry.promise = i18nCore
|
|
144
|
+
.getLanguages()
|
|
145
|
+
.then((langs) => {
|
|
146
|
+
clientCache.set(cacheKey, { data: langs });
|
|
147
|
+
return langs;
|
|
148
|
+
})
|
|
149
|
+
.catch((err) => {
|
|
150
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
151
|
+
clientCache.set(cacheKey, { error });
|
|
152
|
+
throw error;
|
|
153
|
+
});
|
|
154
|
+
clientCache.set(cacheKey, entry);
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const langs = await entry.promise;
|
|
158
|
+
if (isMounted) {
|
|
159
|
+
setLanguages(langs);
|
|
160
|
+
setError(null);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (isMounted) {
|
|
165
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
if (isMounted) {
|
|
170
|
+
setIsLoading(false);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
run();
|
|
175
|
+
return () => {
|
|
176
|
+
isMounted = false;
|
|
177
|
+
};
|
|
178
|
+
}, [cacheKey, i18nCore]);
|
|
179
|
+
return { languages, isLoading, error };
|
|
180
|
+
};
|
|
181
|
+
// ─── useSetLocale ────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* React hook that returns a function to switch the active locale.
|
|
184
|
+
*
|
|
185
|
+
* - **With `BetterI18nProvider`**: Fetches new messages client-side from CDN
|
|
186
|
+
* and updates the UI instantly — no page refresh needed.
|
|
187
|
+
* - **Without provider (standalone)**: Pass a config object. Sets a cookie and
|
|
188
|
+
* calls `router.refresh()` for a soft server re-render.
|
|
189
|
+
*
|
|
190
|
+
* @example With provider (recommended — instant switching)
|
|
191
|
+
* ```tsx
|
|
192
|
+
* // Wrap your layout with BetterI18nProvider, then:
|
|
193
|
+
* const setLocale = useSetLocale()
|
|
194
|
+
* <button onClick={() => setLocale('tr')}>Türkçe</button>
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @example Standalone (soft refresh)
|
|
198
|
+
* ```tsx
|
|
199
|
+
* const setLocale = useSetLocale({ project: 'acme/dashboard', defaultLocale: 'en' })
|
|
200
|
+
* <button onClick={() => setLocale('tr')}>Türkçe</button>
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export function useSetLocale(config) {
|
|
204
|
+
const ctx = useContext(BetterI18nContext);
|
|
205
|
+
// If BetterI18nProvider is in the tree, use instant client-side switching
|
|
206
|
+
if (ctx) {
|
|
207
|
+
return ctx.setLocale;
|
|
208
|
+
}
|
|
209
|
+
// Standalone fallback: cookie + router.refresh()
|
|
210
|
+
if (!config) {
|
|
211
|
+
throw new Error("[better-i18n] useSetLocale() requires either a <BetterI18nProvider> ancestor " +
|
|
212
|
+
"or a config argument. Use useSetLocale({ project, defaultLocale }) for standalone mode.");
|
|
213
|
+
}
|
|
214
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
215
|
+
return useStandaloneSetLocale(config);
|
|
216
|
+
}
|
|
217
|
+
/** Internal standalone hook — cookie + router.refresh() */
|
|
218
|
+
function useStandaloneSetLocale(config) {
|
|
219
|
+
const normalized = useMemo(() => normalizeConfig(config), [
|
|
220
|
+
config.project,
|
|
221
|
+
config.defaultLocale,
|
|
222
|
+
config.cookieName,
|
|
223
|
+
]);
|
|
224
|
+
const router = useRouter();
|
|
225
|
+
return useCallback((locale) => {
|
|
226
|
+
document.cookie = `${normalized.cookieName}=${locale}; path=/; max-age=31536000; samesite=lax`;
|
|
227
|
+
router.refresh();
|
|
228
|
+
}, [normalized.cookieName, router]);
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { parseProject } from "@better-i18n/core";
|
|
2
|
+
import type { I18nConfig, NormalizedConfig } from "./types.js";
|
|
3
|
+
export { parseProject };
|
|
4
|
+
/**
|
|
5
|
+
* Normalize Next.js i18n config with defaults
|
|
6
|
+
*/
|
|
7
|
+
export declare const normalizeConfig: (config: I18nConfig) => NormalizedConfig;
|
|
8
|
+
/**
|
|
9
|
+
* Get the project base URL on CDN
|
|
10
|
+
*/
|
|
11
|
+
export declare const getProjectBaseUrl: (config: NormalizedConfig) => string;
|
|
12
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG/D,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,KAAG,gBAoBpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,gBAAgB,KAAG,MAC9B,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseProject, getProjectBaseUrl as coreGetProjectBaseUrl, normalizeConfig as coreNormalizeConfig, } from "@better-i18n/core";
|
|
2
|
+
// Re-export parseProject from core
|
|
3
|
+
export { parseProject };
|
|
4
|
+
/**
|
|
5
|
+
* Normalize Next.js i18n config with defaults
|
|
6
|
+
*/
|
|
7
|
+
export const normalizeConfig = (config) => {
|
|
8
|
+
// Use core normalization for base config
|
|
9
|
+
const coreConfig = coreNormalizeConfig({
|
|
10
|
+
project: config.project,
|
|
11
|
+
defaultLocale: config.defaultLocale,
|
|
12
|
+
cdnBaseUrl: config.cdnBaseUrl,
|
|
13
|
+
manifestCacheTtlMs: config.manifestCacheTtlMs,
|
|
14
|
+
debug: config.debug,
|
|
15
|
+
logLevel: config.logLevel,
|
|
16
|
+
fetch: config.fetch,
|
|
17
|
+
});
|
|
18
|
+
// Add Next.js-specific defaults
|
|
19
|
+
return {
|
|
20
|
+
...coreConfig,
|
|
21
|
+
localePrefix: config.localePrefix ?? "as-needed",
|
|
22
|
+
cookieName: config.cookieName ?? "locale",
|
|
23
|
+
manifestRevalidateSeconds: config.manifestRevalidateSeconds ?? 3600,
|
|
24
|
+
messagesRevalidateSeconds: config.messagesRevalidateSeconds ?? 30,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Get the project base URL on CDN
|
|
29
|
+
*/
|
|
30
|
+
export const getProjectBaseUrl = (config) => coreGetProjectBaseUrl(config);
|
|
31
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,iBAAiB,IAAI,qBAAqB,EAC1C,eAAe,IAAI,mBAAmB,GACvC,MAAM,mBAAmB,CAAC;AAG3B,mCAAmC;AACnC,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAkB,EAAoB,EAAE;IACtE,yCAAyC;IACzC,MAAM,UAAU,GAAG,mBAAmB,CAAC;QACrC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;IAEH,gCAAgC;IAChC,OAAO;QACL,GAAG,UAAU;QACb,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,WAAW;QAChD,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,QAAQ;QACzC,yBAAyB,EAAE,MAAM,CAAC,yBAAyB,IAAI,IAAI;QACnE,yBAAyB,EAAE,MAAM,CAAC,yBAAyB,IAAI,EAAE;KAClE,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAwB,EAAU,EAAE,CACpE,qBAAqB,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { I18nConfig } from "./types.js";
|
|
2
|
+
import { createBetterI18nMiddleware, composeMiddleware, type MiddlewareCallback } from "./middleware.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a complete i18n setup for Next.js
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // i18n/config.ts
|
|
9
|
+
* import { createI18n } from '@better-i18n/next'
|
|
10
|
+
*
|
|
11
|
+
* export const i18n = createI18n({
|
|
12
|
+
* project: 'acme/dashboard',
|
|
13
|
+
* defaultLocale: 'en',
|
|
14
|
+
* localePrefix: 'always',
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* // i18n/request.ts
|
|
18
|
+
* export default i18n.requestConfig
|
|
19
|
+
*
|
|
20
|
+
* // middleware.ts (simple)
|
|
21
|
+
* export default i18n.middleware
|
|
22
|
+
*
|
|
23
|
+
* // middleware.ts (with auth - Clerk-style)
|
|
24
|
+
* export default i18n.betterMiddleware(async (request, { locale }) => {
|
|
25
|
+
* if (needsLogin) {
|
|
26
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
27
|
+
* }
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare const createI18n: (config: I18nConfig) => {
|
|
32
|
+
config: import("./types.js").NormalizedConfig;
|
|
33
|
+
requestConfig: (params: import("next-intl/server").GetRequestConfigParams) => import("next-intl/server").RequestConfig | Promise<import("next-intl/server").RequestConfig>;
|
|
34
|
+
/** @deprecated Use betterMiddleware() for Clerk-style callback support */
|
|
35
|
+
middleware: (request: import("next/server.js").NextRequest) => Promise<import("next/server.js").NextResponse<unknown>>;
|
|
36
|
+
proxy: (request: import("next/server.js").NextRequest) => Promise<import("next/server.js").NextResponse<unknown>>;
|
|
37
|
+
getManifest: (options?: {
|
|
38
|
+
forceRefresh?: boolean;
|
|
39
|
+
}) => Promise<import("@better-i18n/core").ManifestResponse>;
|
|
40
|
+
getLocales: () => Promise<string[]>;
|
|
41
|
+
getMessages: (locale: string) => Promise<import("@better-i18n/core").Messages>;
|
|
42
|
+
/**
|
|
43
|
+
* Create middleware with optional Clerk-style callback for auth integration
|
|
44
|
+
*
|
|
45
|
+
* @example Simple usage
|
|
46
|
+
* ```ts
|
|
47
|
+
* export default i18n.betterMiddleware();
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example With auth callback
|
|
51
|
+
* ```ts
|
|
52
|
+
* export default i18n.betterMiddleware(async (request, { locale, response }) => {
|
|
53
|
+
* if (needsLogin) {
|
|
54
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
55
|
+
* }
|
|
56
|
+
* // Return nothing = i18n response is used (headers preserved!)
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
betterMiddleware: (callback?: MiddlewareCallback) => (request: import("next/server.js").NextRequest) => Promise<import("next/server.js").NextResponse>;
|
|
61
|
+
};
|
|
62
|
+
export { createBetterI18nMiddleware, composeMiddleware };
|
|
63
|
+
export type { MiddlewareContext, MiddlewareCallback } from "./middleware.js";
|
|
64
|
+
export { createNextI18nCore } from "./server.js";
|
|
65
|
+
export { BetterI18nProvider, useManifestLanguages, useSetLocale } from "./client.js";
|
|
66
|
+
export type { BetterI18nProviderProps } from "./client.js";
|
|
67
|
+
export type { I18nConfig, LanguageOption, Locale, LocalePrefix, LogLevel, ManifestLanguage, ManifestResponse, Messages, } from "./types.js";
|
|
68
|
+
export type { I18nMiddlewareConfig } from "@better-i18n/core";
|
|
69
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,OAAO,EAGL,0BAA0B,EAC1B,iBAAiB,EACjB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU;;;IAOzC,0EAA0E;;;;oBA0D1E,CAAC;;;;IAnDD;;;;;;;;;;;;;;;;;OAiBG;kCAC2B,kBAAkB;CAgBnD,CAAC;AAGF,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACrF,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAG3D,YAAY,EACV,UAAU,EACV,cAAc,EACd,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { normalizeConfig } from "./config.js";
|
|
2
|
+
import { createNextI18nCore, createNextIntlRequestConfig, } from "./server.js";
|
|
3
|
+
import { createI18nMiddleware, createI18nProxy, createBetterI18nMiddleware, composeMiddleware, } from "./middleware.js";
|
|
4
|
+
/**
|
|
5
|
+
* Create a complete i18n setup for Next.js
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // i18n/config.ts
|
|
10
|
+
* import { createI18n } from '@better-i18n/next'
|
|
11
|
+
*
|
|
12
|
+
* export const i18n = createI18n({
|
|
13
|
+
* project: 'acme/dashboard',
|
|
14
|
+
* defaultLocale: 'en',
|
|
15
|
+
* localePrefix: 'always',
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // i18n/request.ts
|
|
19
|
+
* export default i18n.requestConfig
|
|
20
|
+
*
|
|
21
|
+
* // middleware.ts (simple)
|
|
22
|
+
* export default i18n.middleware
|
|
23
|
+
*
|
|
24
|
+
* // middleware.ts (with auth - Clerk-style)
|
|
25
|
+
* export default i18n.betterMiddleware(async (request, { locale }) => {
|
|
26
|
+
* if (needsLogin) {
|
|
27
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
28
|
+
* }
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const createI18n = (config) => {
|
|
33
|
+
const normalized = normalizeConfig(config);
|
|
34
|
+
const i18n = createNextI18nCore(normalized);
|
|
35
|
+
return {
|
|
36
|
+
config: normalized,
|
|
37
|
+
requestConfig: createNextIntlRequestConfig(normalized),
|
|
38
|
+
/** @deprecated Use betterMiddleware() for Clerk-style callback support */
|
|
39
|
+
middleware: createI18nMiddleware(normalized),
|
|
40
|
+
proxy: createI18nProxy(normalized),
|
|
41
|
+
getManifest: i18n.getManifest,
|
|
42
|
+
getLocales: i18n.getLocales,
|
|
43
|
+
getMessages: i18n.getMessages,
|
|
44
|
+
/**
|
|
45
|
+
* Create middleware with optional Clerk-style callback for auth integration
|
|
46
|
+
*
|
|
47
|
+
* @example Simple usage
|
|
48
|
+
* ```ts
|
|
49
|
+
* export default i18n.betterMiddleware();
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example With auth callback
|
|
53
|
+
* ```ts
|
|
54
|
+
* export default i18n.betterMiddleware(async (request, { locale, response }) => {
|
|
55
|
+
* if (needsLogin) {
|
|
56
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
57
|
+
* }
|
|
58
|
+
* // Return nothing = i18n response is used (headers preserved!)
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
betterMiddleware: (callback) => {
|
|
63
|
+
return createBetterI18nMiddleware({
|
|
64
|
+
project: normalized.project,
|
|
65
|
+
defaultLocale: normalized.defaultLocale,
|
|
66
|
+
localePrefix: normalized.localePrefix,
|
|
67
|
+
detection: {
|
|
68
|
+
cookie: true,
|
|
69
|
+
browserLanguage: true,
|
|
70
|
+
cookieName: normalized.cookieName,
|
|
71
|
+
},
|
|
72
|
+
}, callback);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
// Modern standalone middleware exports
|
|
77
|
+
export { createBetterI18nMiddleware, composeMiddleware };
|
|
78
|
+
// Core instance factory
|
|
79
|
+
export { createNextI18nCore } from "./server.js";
|
|
80
|
+
// Client hooks & provider
|
|
81
|
+
export { BetterI18nProvider, useManifestLanguages, useSetLocale } from "./client.js";
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,iBAAiB,GAElB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAkB,EAAE,EAAE;IAC/C,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE5C,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,aAAa,EAAE,2BAA2B,CAAC,UAAU,CAAC;QACtD,0EAA0E;QAC1E,UAAU,EAAE,oBAAoB,CAAC,UAAU,CAAC;QAC5C,KAAK,EAAE,eAAe,CAAC,UAAU,CAAC;QAClC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;QAE7B;;;;;;;;;;;;;;;;;WAiBG;QACH,gBAAgB,EAAE,CAAC,QAA6B,EAAE,EAAE;YAClD,OAAO,0BAA0B,CAC/B;gBACE,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,aAAa,EAAE,UAAU,CAAC,aAAa;gBACvC,YAAY,EAAE,UAAU,CAAC,YAAY;gBACrC,SAAS,EAAE;oBACT,MAAM,EAAE,IAAI;oBACZ,eAAe,EAAE,IAAI;oBACrB,UAAU,EAAE,UAAU,CAAC,UAAU;iBAClC;aACF,EACD,QAAQ,CACT,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,uCAAuC;AACvC,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,CAAC;AAGzD,wBAAwB;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import type { I18nMiddlewareConfig } from "@better-i18n/core";
|
|
3
|
+
import type { I18nConfig } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Context passed to the middleware callback (Clerk-style pattern)
|
|
6
|
+
*/
|
|
7
|
+
export interface MiddlewareContext {
|
|
8
|
+
/** Detected locale from the request */
|
|
9
|
+
locale: string;
|
|
10
|
+
/** The i18n response with headers already set - can be modified */
|
|
11
|
+
response: NextResponse;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Callback function for Clerk-style middleware composition
|
|
15
|
+
*
|
|
16
|
+
* @param request - The incoming Next.js request
|
|
17
|
+
* @param context - Contains locale and response from i18n middleware
|
|
18
|
+
* @returns NextResponse to short-circuit (e.g., redirect), or void to continue with i18n response
|
|
19
|
+
*/
|
|
20
|
+
export type MiddlewareCallback = (request: NextRequest, context: MiddlewareContext) => Promise<NextResponse | void> | NextResponse | void;
|
|
21
|
+
/**
|
|
22
|
+
* Legacy Next-intl based middleware
|
|
23
|
+
*/
|
|
24
|
+
export declare const createI18nMiddleware: (config: I18nConfig) => (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
25
|
+
export declare const createI18nProxy: (config: I18nConfig) => (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
26
|
+
/**
|
|
27
|
+
* Modern composable middleware for Better i18n (Clerk-style pattern)
|
|
28
|
+
*
|
|
29
|
+
* Delegates to next-intl's middleware internally to ensure full compatibility
|
|
30
|
+
* with `getRequestConfig({ requestLocale })` while keeping our compose-friendly
|
|
31
|
+
* API and custom locale detection options.
|
|
32
|
+
*
|
|
33
|
+
* @example Simple usage (no callback)
|
|
34
|
+
* ```ts
|
|
35
|
+
* export default createBetterI18nMiddleware({
|
|
36
|
+
* project: "acme/dashboard",
|
|
37
|
+
* defaultLocale: "en",
|
|
38
|
+
* localePrefix: "always",
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example With callback (Clerk-style - recommended for auth)
|
|
43
|
+
* ```ts
|
|
44
|
+
* export default createBetterI18nMiddleware({
|
|
45
|
+
* project: "acme/dashboard",
|
|
46
|
+
* defaultLocale: "en",
|
|
47
|
+
* localePrefix: "always",
|
|
48
|
+
* }, async (request, { locale, response }) => {
|
|
49
|
+
* // Auth logic here - locale and response are available
|
|
50
|
+
* if (needsLogin) {
|
|
51
|
+
* return NextResponse.redirect(new URL(`/${locale}/login`, request.url));
|
|
52
|
+
* }
|
|
53
|
+
* // Return nothing = i18n response is used (headers preserved!)
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function createBetterI18nMiddleware(config: I18nMiddlewareConfig, callback?: MiddlewareCallback): (request: NextRequest) => Promise<NextResponse>;
|
|
58
|
+
/**
|
|
59
|
+
* Helper to compose multiple Next.js middleware
|
|
60
|
+
*
|
|
61
|
+
* @deprecated Use `createBetterI18nMiddleware` with a callback instead (Clerk-style pattern).
|
|
62
|
+
* The callback approach is more reliable and gives you access to the detected locale.
|
|
63
|
+
*
|
|
64
|
+
* @example Migration
|
|
65
|
+
* ```ts
|
|
66
|
+
* // Before (deprecated):
|
|
67
|
+
* export default composeMiddleware(i18nMiddleware, authMiddleware);
|
|
68
|
+
*
|
|
69
|
+
* // After (recommended):
|
|
70
|
+
* export default createBetterI18nMiddleware(config, async (req, { locale, response }) => {
|
|
71
|
+
* // Auth logic here
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @see https://github.com/better-i18n/better-i18n#middleware-composition
|
|
76
|
+
*/
|
|
77
|
+
export declare function composeMiddleware(...middlewares: Array<(req: NextRequest) => Promise<NextResponse>>): (request: NextRequest) => Promise<NextResponse>;
|
|
78
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAI9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,YAAY,GAAG,IAAI,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,UAAU,MAIpB,SAAS,WAAW,mCAYtD,CAAC;AAEF,eAAO,MAAM,eAAe,WAlBiB,UAAU,MAIpB,SAAS,WAAW,mCAcJ,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,CAAC,EAAE,kBAAkB,IAkBf,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,CA+E3D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,WAAW,EAAE,KAAK,CAAC,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,IAUpD,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,CA0B3D"}
|