intor 1.0.39 → 2.0.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.
@@ -2,9 +2,11 @@
2
2
 
3
3
  var React7 = require('react');
4
4
  var logry = require('logry');
5
+ var Keyv = require('keyv');
5
6
  var intorTranslator = require('intor-translator');
6
7
  var NextLink = require('next/link');
7
8
  var navigation = require('next/navigation');
9
+ var formatUrl = require('next/dist/shared/lib/router/utils/format-url');
8
10
 
9
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
12
 
@@ -27,33 +29,26 @@ function _interopNamespace(e) {
27
29
  }
28
30
 
29
31
  var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
32
+ var Keyv__default = /*#__PURE__*/_interopDefault(Keyv);
30
33
  var NextLink__default = /*#__PURE__*/_interopDefault(NextLink);
31
34
 
32
- // src/adapters/next-client/contexts/intor-config/intor-config-context.ts
33
- var IntorConfigContext = React7__namespace.createContext(void 0);
34
- var IntorConfigProvider = ({
35
+ // src/adapters/next/contexts/intor-provider/intor-provider.tsx
36
+ var ConfigContext = React7__namespace.createContext(void 0);
37
+ function ConfigProvider({
35
38
  value: { config, pathname },
36
39
  children
37
- }) => {
38
- const value = React7__namespace.useMemo(
39
- () => ({
40
- config,
41
- pathname
42
- }),
43
- [config, pathname]
44
- );
45
- return /* @__PURE__ */ React7__namespace.createElement(IntorConfigContext.Provider, { value }, children);
46
- };
47
- var useIntorConfig = () => {
48
- const context = React7__namespace.useContext(IntorConfigContext);
49
- if (!context) {
50
- throw new Error("useIntorConfig must be used within IntorConfigProvider");
51
- }
40
+ }) {
41
+ const value = React7__namespace.useMemo(() => ({ config, pathname }), [config, pathname]);
42
+ return /* @__PURE__ */ React7__namespace.createElement(ConfigContext.Provider, { value }, children);
43
+ }
44
+ function useConfig() {
45
+ const context = React7__namespace.useContext(ConfigContext);
46
+ if (!context) throw new Error("useConfig must be used within ConfigProvider");
52
47
  return context;
53
- };
54
- var IntorLocaleContext = React7__namespace.createContext(void 0);
48
+ }
49
+ var LocaleContext = React7__namespace.createContext(void 0);
55
50
 
56
- // src/adapters/next-client/utils/build-cookie-string.ts
51
+ // src/adapters/next/shared/utils/build-cookie-string.ts
57
52
  var buildCookieString = (cookie, locale) => {
58
53
  const parts = [];
59
54
  parts.push(`${cookie.name}=${encodeURIComponent(locale)}`);
@@ -77,22 +72,18 @@ var buildCookieString = (cookie, locale) => {
77
72
  return parts.join("; ");
78
73
  };
79
74
 
80
- // src/adapters/next-client/utils/set-locale-cookie-client.ts
81
- var setLocaleCookieClient = ({
75
+ // src/adapters/next/shared/utils/set-locale-cookie-browser.ts
76
+ var setLocaleCookieBrowser = ({
82
77
  cookie,
83
78
  locale
84
79
  }) => {
85
- if (typeof window === "undefined") {
86
- return;
87
- }
88
- if (cookie.disabled || !cookie.autoSetCookie) {
89
- return;
90
- }
80
+ if (typeof window === "undefined") return;
81
+ if (cookie.disabled || !cookie.autoSetCookie) return;
91
82
  const cookieString = buildCookieString(cookie, locale);
92
83
  document.cookie = cookieString;
93
84
  };
94
85
 
95
- // src/adapters/next-client/contexts/intor-locale/utils/change-locale.ts
86
+ // src/adapters/next/contexts/locale/utils/change-locale.ts
96
87
  var changeLocale = ({
97
88
  currentLocale,
98
89
  newLocale,
@@ -101,32 +92,153 @@ var changeLocale = ({
101
92
  setLocale,
102
93
  refetchMessages
103
94
  }) => {
104
- if (typeof document === "undefined") {
105
- return;
106
- }
95
+ if (typeof document === "undefined") return;
107
96
  const loaderType = loaderOptions?.type;
108
- if (newLocale === currentLocale) {
109
- return;
110
- }
97
+ if (newLocale === currentLocale) return;
111
98
  if (loaderType === "import") {
112
99
  console.warn(
113
100
  `[Intor] You are using dynamic import to switch languages. Please make sure to use the wrapped <Link> component to trigger a page reload, ensuring that the translation data is dynamically updated.`
114
101
  );
115
102
  }
116
103
  setLocale(newLocale);
117
- setLocaleCookieClient({ cookie, locale: newLocale });
104
+ setLocaleCookieBrowser({ cookie, locale: newLocale });
118
105
  document.documentElement.lang = newLocale;
119
106
  if (loaderType === "api" && refetchMessages) {
120
107
  void refetchMessages(newLocale);
121
108
  }
122
109
  };
123
- var IntorMessagesContext = React7__namespace.createContext(void 0);
110
+ var MessagesContext = React7__namespace.createContext(void 0);
111
+
112
+ // src/modules/config/constants/cache.constants.ts
113
+ var DEFAULT_CACHE_OPTIONS = {
114
+ enabled: process.env.NODE_ENV === "production",
115
+ ttl: 60 * 60 * 1e3
116
+ // 1 hour
117
+ };
118
+
119
+ // src/shared/logger/global-logger-pool.ts
120
+ function getGlobalLoggerPool() {
121
+ if (!globalThis.__INTOR_LOGGER_POOL__) {
122
+ globalThis.__INTOR_LOGGER_POOL__ = /* @__PURE__ */ new Map();
123
+ }
124
+ return globalThis.__INTOR_LOGGER_POOL__;
125
+ }
126
+
127
+ // src/shared/logger/get-logger.ts
128
+ var DEFAULT_FORMATTER_CONFIG = {
129
+ node: { meta: { compact: true }, lineBreaksAfter: 1 }
130
+ };
131
+ function getLogger({
132
+ id,
133
+ formatterConfig = DEFAULT_FORMATTER_CONFIG,
134
+ ...options
135
+ }) {
136
+ const pool = getGlobalLoggerPool();
137
+ let logger = pool.get(id);
138
+ if (!logger) {
139
+ logger = logry.logry({ id, formatterConfig, ...options });
140
+ pool.set(id, logger);
141
+ if (pool.size > 1e3) {
142
+ const keys = Array.from(pool.keys());
143
+ for (const key of keys.slice(0, 200)) pool.delete(key);
144
+ }
145
+ }
146
+ return logger;
147
+ }
148
+ function getGlobalMessagesPool() {
149
+ if (!globalThis.__INTOR_MESSAGES_POOL__) {
150
+ globalThis.__INTOR_MESSAGES_POOL__ = new Keyv__default.default();
151
+ }
152
+ return globalThis.__INTOR_MESSAGES_POOL__;
153
+ }
154
+
155
+ // src/shared/utils/merge-messages.ts
156
+ var mergeMessages = (staticMessages = {}, loadedMessages = {}) => {
157
+ const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
158
+ for (const locale in loadedMessages) {
159
+ const loaded = loadedMessages[locale];
160
+ if (!result[locale]) {
161
+ result[locale] = loaded;
162
+ continue;
163
+ }
164
+ result[locale] = {
165
+ ...result[locale],
166
+ ...loaded
167
+ };
168
+ }
169
+ return result;
170
+ };
171
+
172
+ // src/shared/utils/normalize-cache-key.ts
173
+ var CACHE_KEY_DELIMITER = "|";
174
+ var sanitize = (k) => k.replaceAll(/[\u200B-\u200D\uFEFF]/g, "").replaceAll(/[\r\n]/g, "").trim();
175
+ var normalizeCacheKey = (key, delimiter = CACHE_KEY_DELIMITER) => {
176
+ if (!key) return null;
177
+ if (Array.isArray(key)) {
178
+ if (key.length === 0) return null;
179
+ const normalized = key.map((k) => {
180
+ if (k === null) return "__null";
181
+ if (k === void 0) return "__undefined";
182
+ if (typeof k === "boolean") return k ? "__true" : "__false";
183
+ return sanitize(String(k));
184
+ });
185
+ return normalized.join(delimiter);
186
+ }
187
+ if (typeof key === "boolean") return key ? "__true" : "__false";
188
+ return String(key);
189
+ };
190
+
191
+ // src/shared/constants/prefix-placeholder.ts
192
+ var PREFIX_PLACEHOLDER = "{locale}";
193
+
194
+ // src/shared/utils/resolve-namespaces.ts
195
+ var resolveNamespaces = ({
196
+ config,
197
+ pathname
198
+ }) => {
199
+ const { loader } = config;
200
+ const {
201
+ routeNamespaces = {},
202
+ namespaces: fallbackNamespaces
203
+ } = loader;
204
+ const { unprefixedPathname } = extractPathname({ config, pathname });
205
+ const standardizedPathname = standardizePathname({
206
+ config,
207
+ pathname: unprefixedPathname
208
+ });
209
+ const placeholderRemovedPathname = standardizedPathname.replace(
210
+ `/${PREFIX_PLACEHOLDER}`,
211
+ ""
212
+ );
213
+ const defaultNamespaces = routeNamespaces.default ?? [];
214
+ const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
215
+ if (exactMatchNamespaces) {
216
+ return [...defaultNamespaces, ...exactMatchNamespaces];
217
+ }
218
+ let bestMatch = "";
219
+ let bestNamespaces;
220
+ const prefixPatterns = Object.keys(routeNamespaces).filter(
221
+ (pattern) => pattern.endsWith("/*")
222
+ );
223
+ for (const pattern of prefixPatterns) {
224
+ const basePath = pattern.replace(/\/\*$/, "");
225
+ if (standardizedPathname.startsWith(basePath)) {
226
+ if (basePath.length > bestMatch.length) {
227
+ bestMatch = basePath;
228
+ bestNamespaces = routeNamespaces[pattern];
229
+ }
230
+ }
231
+ }
232
+ const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
233
+ if (matchedNamespaces.length > 0) {
234
+ return [...defaultNamespaces, ...matchedNamespaces];
235
+ } else {
236
+ return [...defaultNamespaces];
237
+ }
238
+ };
124
239
 
125
240
  // src/shared/utils/pathname/normalize-pathname.ts
126
241
  var normalizePathname = (rawPathname, options = {}) => {
127
- if (typeof rawPathname !== "string") {
128
- throw new TypeError("Expected rawPathname to be a string");
129
- }
130
242
  const length = rawPathname.length;
131
243
  let start = 0;
132
244
  let end = length - 1;
@@ -156,300 +268,245 @@ var normalizePathname = (rawPathname, options = {}) => {
156
268
  return result || "/";
157
269
  };
158
270
 
159
- // src/modules/intor-messages-loader/fetch-api-messages/build-search-params.ts
160
- var buildSearchParams = (params) => {
161
- const searchParams = new URLSearchParams();
162
- const appendParam = (key, value) => {
163
- if (value === void 0 || value === null) {
164
- return;
271
+ // src/shared/utils/pathname/extract-pathname.ts
272
+ var extractPathname = ({
273
+ config,
274
+ pathname: rawPathname
275
+ }) => {
276
+ const { routing, defaultLocale } = config;
277
+ const { basePath, prefix } = routing;
278
+ const normalizedPathname = normalizePathname(rawPathname);
279
+ let prefixedPathname = normalizedPathname;
280
+ if (basePath && normalizedPathname.startsWith(basePath + "/")) {
281
+ prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
282
+ } else if (basePath && normalizedPathname === basePath) {
283
+ prefixedPathname = "/";
284
+ }
285
+ const pathParts = prefixedPathname.split("/").filter(Boolean);
286
+ const maybeLocale = pathParts[0] || "";
287
+ const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
288
+ let unprefixedPathname = prefixedPathname;
289
+ if (prefix === "all") {
290
+ if (isLocalePrefixed) {
291
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
165
292
  }
166
- if (Array.isArray(value) && value.length > 0) {
167
- value.forEach((v) => v && searchParams.append(key, v));
168
- } else {
169
- searchParams.append(key, value);
293
+ } else if (prefix === "except-default") {
294
+ if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
295
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
170
296
  }
297
+ }
298
+ return {
299
+ basePath,
300
+ prefixedPathname,
301
+ unprefixedPathname,
302
+ maybeLocale,
303
+ isLocalePrefixed: Boolean(isLocalePrefixed)
171
304
  };
172
- Object.entries(params).forEach(([key, value]) => {
173
- appendParam(key, value);
174
- });
175
- return searchParams;
176
305
  };
177
- var fetcher = async ({
306
+
307
+ // src/shared/utils/pathname/standardize-pathname.ts
308
+ var standardizePathname = ({
309
+ config,
310
+ pathname
311
+ }) => {
312
+ const { routing } = config;
313
+ const { basePath } = routing;
314
+ const parts = [
315
+ normalizePathname(basePath),
316
+ PREFIX_PLACEHOLDER,
317
+ normalizePathname(pathname)
318
+ ];
319
+ const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
320
+ return normalizePathname(standardizedPathname);
321
+ };
322
+
323
+ // src/modules/messages/load-api-messages/fetch-messages.ts
324
+ var fetchMessages = async ({
178
325
  apiUrl,
326
+ apiHeaders,
179
327
  locale,
180
328
  searchParams,
181
- loggerId
329
+ logger: loggerOptions = { id: "default" }
182
330
  }) => {
183
- const logger = logry.logry({ id: loggerId, scope: "fetcher" });
331
+ const baseLogger = getLogger({ ...loggerOptions });
332
+ const logger = baseLogger.child({ scope: "fetch-messages" });
184
333
  try {
185
334
  const params = new URLSearchParams(searchParams);
186
335
  params.append("locale", locale);
187
336
  const url = `${apiUrl}?${params.toString()}`;
337
+ const headers = {
338
+ "Content-Type": "application/json",
339
+ ...apiHeaders
340
+ };
188
341
  const response = await fetch(url, {
189
342
  method: "GET",
190
- headers: { "Content-Type": "application/json" },
343
+ headers,
191
344
  cache: "no-store"
192
345
  });
193
346
  if (!response.ok) {
194
- throw new Error(
195
- `Fetch failed for locale "${locale}" at URL: ${url} - ${response.status} ${response.statusText}`
196
- );
347
+ throw new Error(`Fetch failed: ${locale} (${response.status})`);
197
348
  }
198
349
  const data = await response.json();
199
350
  if (data == null || typeof data === "object" && Object.keys(data).length === 0) {
200
- throw new Error(
201
- `Missing or invalid messages for locale "${locale}" at URL: ${url}`
202
- );
351
+ throw new Error(`Invalid messages: ${locale}`);
203
352
  }
204
353
  return data;
205
- } catch {
354
+ } catch (error) {
206
355
  logger.warn(`Failed to fetch messages for locale "${locale}".`, {
207
356
  locale,
208
357
  apiUrl,
209
- searchParams: decodeURIComponent(searchParams.toString())
358
+ searchParams: decodeURIComponent(searchParams.toString()),
359
+ error
210
360
  });
211
- return void 0;
361
+ return;
212
362
  }
213
363
  };
214
364
 
215
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-fallback-messages.ts
216
- var fetchFallbackMessages = async (apiUrl, searchParams, fallbackLocales, loggerId) => {
365
+ // src/modules/messages/load-api-messages/fetch-fallback-messages.ts
366
+ var fetchFallbackMessages = async ({
367
+ apiUrl,
368
+ apiHeaders,
369
+ searchParams,
370
+ fallbackLocales,
371
+ logger
372
+ }) => {
217
373
  for (const fallbackLocale of fallbackLocales) {
218
- const result = await fetcher({
374
+ const result = await fetchMessages({
219
375
  apiUrl,
220
376
  searchParams,
221
377
  locale: fallbackLocale,
222
- loggerId
378
+ apiHeaders,
379
+ logger
223
380
  });
224
381
  if (result) {
225
382
  return { locale: fallbackLocale, messages: result };
226
383
  }
227
384
  }
228
- return void 0;
385
+ return;
229
386
  };
230
387
 
231
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-api-messages.ts
232
- var fetchApiMessages = async ({
388
+ // src/modules/messages/load-api-messages/utils/build-search-params.ts
389
+ var buildSearchParams = (params) => {
390
+ const searchParams = new URLSearchParams();
391
+ const appendParam = (key, value) => {
392
+ if (value === void 0 || value === null) return;
393
+ if (Array.isArray(value) && value.length === 0) return;
394
+ if (Array.isArray(value)) {
395
+ value.forEach((v) => v && searchParams.append(key, v));
396
+ } else {
397
+ searchParams.append(key, value);
398
+ }
399
+ };
400
+ Object.entries(params).forEach(([key, value]) => {
401
+ appendParam(key, value);
402
+ });
403
+ return searchParams;
404
+ };
405
+
406
+ // src/modules/messages/load-api-messages/load-api-messages.ts
407
+ var loadApiMessages = async ({
233
408
  apiUrl,
409
+ apiHeaders,
234
410
  basePath,
235
411
  locale,
236
412
  fallbackLocales = [],
237
413
  namespaces = [],
238
- loggerId
414
+ cache = DEFAULT_CACHE_OPTIONS,
415
+ logger: loggerOptions = { id: "default" }
239
416
  }) => {
240
- const logger = logry.logry({ id: loggerId, scope: "fetchApiMessages" });
417
+ const baseLogger = getLogger({ ...loggerOptions });
418
+ const logger = baseLogger.child({ scope: "load-api-messages" });
241
419
  if (!apiUrl) {
242
- logger.warn("No apiUrl provided for fetchApiMessages. Skipping fetch.");
243
- return void 0;
420
+ logger.warn("No apiUrl provided. Skipping fetch.");
421
+ return;
244
422
  }
245
- const searchParams = buildSearchParams({
423
+ const pool = getGlobalMessagesPool();
424
+ const key = normalizeCacheKey([
425
+ loggerOptions.id,
246
426
  basePath,
247
- loggerId,
248
- namespaces
249
- });
250
- const messages = await fetcher({
427
+ locale,
428
+ [...fallbackLocales ?? []].sort().join(","),
429
+ [...namespaces ?? []].sort().join(",")
430
+ ]);
431
+ if (cache.enabled && key) {
432
+ const cached = await pool.get(key);
433
+ if (cached) {
434
+ logger.debug("Messages cache hit.", { key });
435
+ return cached;
436
+ }
437
+ }
438
+ const searchParams = buildSearchParams({ basePath, namespaces });
439
+ const messages = await fetchMessages({
251
440
  apiUrl,
441
+ apiHeaders,
252
442
  searchParams,
253
443
  locale,
254
- loggerId
444
+ logger: loggerOptions
255
445
  });
256
446
  if (messages) {
447
+ if (cache.enabled && key) {
448
+ await pool.set(key, messages, cache.ttl);
449
+ }
257
450
  return messages;
258
451
  }
259
- const fallbackResult = await fetchFallbackMessages(
452
+ const fallbackResult = await fetchFallbackMessages({
260
453
  apiUrl,
454
+ apiHeaders,
261
455
  searchParams,
262
456
  fallbackLocales,
263
- loggerId
264
- );
457
+ logger: loggerOptions
458
+ });
265
459
  if (fallbackResult) {
266
460
  logger.info("Fallback locale succeeded.", {
267
461
  usedLocale: fallbackResult.locale,
268
462
  apiUrl,
269
463
  searchParams: decodeURIComponent(searchParams.toString())
270
464
  });
465
+ if (cache.enabled && key) {
466
+ await pool.set(key, fallbackResult.messages, cache.ttl);
467
+ }
271
468
  return fallbackResult.messages;
272
469
  }
273
470
  logger.warn("Failed to fetch messages for all locales.", {
274
471
  locale,
275
472
  fallbackLocales
276
473
  });
277
- return void 0;
278
- };
279
-
280
- // src/shared/utils/pathname/extract-pathname.ts
281
- var extractPathname = ({
282
- config,
283
- pathname: rawPathname
284
- }) => {
285
- const { routing, defaultLocale } = config;
286
- const { basePath, prefix } = routing;
287
- const normalizedPathname = normalizePathname(rawPathname);
288
- let prefixedPathname = normalizedPathname;
289
- if (basePath && normalizedPathname.startsWith(basePath + "/")) {
290
- prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
291
- } else if (basePath && normalizedPathname === basePath) {
292
- prefixedPathname = "/";
293
- }
294
- const pathParts = prefixedPathname.split("/").filter(Boolean);
295
- const maybeLocale = pathParts[0] || "";
296
- const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
297
- let unprefixedPathname = prefixedPathname;
298
- if (prefix === "all") {
299
- if (isLocalePrefixed) {
300
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
301
- }
302
- } else if (prefix === "except-default") {
303
- if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
304
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
305
- }
306
- }
307
- return {
308
- basePath,
309
- prefixedPathname,
310
- unprefixedPathname,
311
- maybeLocale,
312
- isLocalePrefixed: Boolean(isLocalePrefixed)
313
- };
314
- };
315
-
316
- // src/shared/utils/pathname/standardize-pathname.ts
317
- var standardizePathname = ({
318
- config,
319
- pathname
320
- }) => {
321
- const { routing, prefixPlaceHolder } = config;
322
- const { basePath } = routing;
323
- const parts = [
324
- normalizePathname(basePath),
325
- normalizePathname(prefixPlaceHolder),
326
- normalizePathname(pathname)
327
- ];
328
- const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
329
- return normalizePathname(standardizedPathname);
330
- };
331
-
332
- // src/shared/utils/resolve-namespaces.ts
333
- var resolveNamespaces = ({
334
- config,
335
- pathname
336
- }) => {
337
- const { loaderOptions, prefixPlaceHolder } = config;
338
- const {
339
- routeNamespaces = {},
340
- namespaces: fallbackNamespaces
341
- } = loaderOptions;
342
- const { unprefixedPathname } = extractPathname({ config, pathname });
343
- const standardizedPathname = standardizePathname({
344
- config,
345
- pathname: unprefixedPathname
346
- });
347
- const placeholderRemovedPathname = standardizedPathname.replace(
348
- `/${prefixPlaceHolder}`,
349
- ""
350
- );
351
- const defaultNamespaces = routeNamespaces.default ?? [];
352
- const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
353
- if (exactMatchNamespaces) {
354
- return [...defaultNamespaces, ...exactMatchNamespaces];
355
- }
356
- let bestMatch = "";
357
- let bestNamespaces;
358
- const prefixPatterns = Object.keys(routeNamespaces).filter(
359
- (pattern) => pattern.endsWith("/*")
360
- );
361
- for (const pattern of prefixPatterns) {
362
- const basePath = pattern.replace(/\/\*$/, "");
363
- if (standardizedPathname.startsWith(basePath)) {
364
- if (basePath.length > bestMatch.length) {
365
- bestMatch = basePath;
366
- bestNamespaces = routeNamespaces[pattern];
367
- }
368
- }
369
- }
370
- const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
371
- if (matchedNamespaces.length > 0) {
372
- return [...defaultNamespaces, ...matchedNamespaces];
373
- } else {
374
- return [...defaultNamespaces];
375
- }
474
+ return;
376
475
  };
377
476
 
378
- // src/adapters/next-client/hooks/api/use-fetch-messages.ts
379
- var useFetchMessages = ({
380
- onError
381
- }) => {
382
- const fetcher2 = async (params) => {
383
- try {
384
- const data = await fetchApiMessages(params);
385
- return data;
386
- } catch (error) {
387
- onError?.(error, params.apiUrl);
388
- return null;
389
- }
390
- };
391
- return { fetcher: fetcher2 };
392
- };
393
-
394
- // src/shared/utils/merge-static-and-dynamic-messages.ts
395
- var mergeStaticAndDynamicMessages = (staticMessages = {}, dynamicMessages = {}) => {
396
- const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
397
- for (const locale in dynamicMessages) {
398
- const dynamic = dynamicMessages[locale];
399
- if (!result[locale]) {
400
- result[locale] = dynamic;
401
- continue;
402
- }
403
- result[locale] = {
404
- ...result[locale],
405
- ...dynamic
406
- };
407
- }
408
- return result;
409
- };
410
-
411
- // src/adapters/next-client/hooks/api/use-refetch-messages.ts
477
+ // src/adapters/next/contexts/messages/utils/use-refetch-messages.ts
412
478
  var useRefetchMessages = ({
413
479
  config,
414
480
  pathname,
415
481
  setLoadedMessages,
416
- setIsLoadingMessages,
417
- onError
418
- // Error handler
482
+ setIsLoadingMessages
419
483
  }) => {
420
484
  const { messages: staticMessages } = config;
421
485
  const namespaces = React7__namespace.useMemo(() => {
422
- if (!config.loaderOptions) {
423
- return [];
424
- }
486
+ if (!config.loader) return [];
425
487
  return resolveNamespaces({ config, pathname });
426
488
  }, [config, pathname]);
427
- const { fetcher: fetcher2 } = useFetchMessages({ onError });
428
489
  const refetchMessages = React7__namespace.useCallback(
429
490
  async (newLocale) => {
430
- if (config.loaderOptions?.type === "api") {
491
+ if (config.loader?.type === "api") {
431
492
  setIsLoadingMessages(true);
432
- const dynamicMessages = await fetcher2({
433
- ...config.loaderOptions,
493
+ const loadedMessages = await loadApiMessages({
494
+ ...config.loader,
434
495
  locale: newLocale,
435
496
  fallbackLocales: config.fallbackLocales[newLocale] || [],
436
497
  namespaces,
437
- loggerId: config.id
498
+ logger: { id: config.id }
438
499
  });
439
- const messages = mergeStaticAndDynamicMessages(
440
- staticMessages,
441
- dynamicMessages
442
- );
500
+ const messages = mergeMessages(staticMessages, loadedMessages);
443
501
  setLoadedMessages(messages);
444
502
  setIsLoadingMessages(false);
445
503
  }
446
504
  },
447
505
  [
448
- config.loaderOptions,
506
+ config.loader,
449
507
  config.fallbackLocales,
450
508
  config.id,
451
509
  setIsLoadingMessages,
452
- fetcher2,
453
510
  namespaces,
454
511
  staticMessages,
455
512
  setLoadedMessages
@@ -458,12 +515,12 @@ var useRefetchMessages = ({
458
515
  return { refetchMessages };
459
516
  };
460
517
 
461
- // src/adapters/next-client/contexts/intor-messages/intor-messages-provider.tsx
462
- var IntorMessagesProvider = ({
518
+ // src/adapters/next/contexts/messages/provider.tsx
519
+ function MessagesProvider({
463
520
  value: { messages },
464
521
  children
465
- }) => {
466
- const { config, pathname } = useIntorConfig();
522
+ }) {
523
+ const { config, pathname } = useConfig();
467
524
  const [loadedMessages, setLoadedMessages] = React7__namespace.useState(null);
468
525
  const [isLoadingMessages, setIsLoadingMessages] = React7__namespace.useState(false);
469
526
  const { refetchMessages } = useRefetchMessages({
@@ -482,22 +539,19 @@ var IntorMessagesProvider = ({
482
539
  }),
483
540
  [loadedMessages, messages, isLoadingMessages, refetchMessages]
484
541
  );
485
- return /* @__PURE__ */ React7__namespace.createElement(IntorMessagesContext.Provider, { value }, children);
486
- };
487
- var useIntorMessages = () => {
488
- const context = React7__namespace.useContext(IntorMessagesContext);
489
- if (!context) {
490
- throw new Error(
491
- "useIntorMessages must be used within a IntorMessagesProvider"
492
- );
493
- }
542
+ return /* @__PURE__ */ React7__namespace.createElement(MessagesContext.Provider, { value }, children);
543
+ }
544
+ function useMessages() {
545
+ const context = React7__namespace.useContext(MessagesContext);
546
+ if (!context)
547
+ throw new Error("useMessages must be used within a MessagesProvider");
494
548
  return context;
495
- };
549
+ }
496
550
  var useInitLazyLoad = ({
497
551
  loaderOptions,
498
552
  currentLocale
499
553
  }) => {
500
- const { refetchMessages } = useIntorMessages();
554
+ const { refetchMessages } = useMessages();
501
555
  const lazyLoad = !!loaderOptions?.lazyLoad;
502
556
  const isFirstLoadedRef = React7__namespace.useRef(false);
503
557
  React7__namespace.useEffect(() => {
@@ -512,34 +566,26 @@ var useInitLocaleCookie = ({
512
566
  locale
513
567
  }) => {
514
568
  React7__namespace.useEffect(() => {
515
- if (typeof document === "undefined") {
516
- return;
517
- }
569
+ if (typeof document === "undefined") return;
518
570
  const { cookie, routing } = config;
519
571
  const { firstVisit } = routing;
520
572
  const cookies = document.cookie.split(";").map((c) => c.trim());
521
573
  const isCookieExists = cookies.some((c) => c.startsWith(`${cookie.name}=`));
522
- if (isCookieExists) {
523
- return;
524
- }
525
- if (!firstVisit.redirect) {
526
- return;
527
- }
528
- if (cookie.disabled || !cookie.autoSetCookie) {
529
- return;
530
- }
531
- setLocaleCookieClient({ cookie, locale });
574
+ if (isCookieExists) return;
575
+ if (!firstVisit.redirect) return;
576
+ if (cookie.disabled || !cookie.autoSetCookie) return;
577
+ setLocaleCookieBrowser({ cookie, locale });
532
578
  }, []);
533
579
  };
534
580
 
535
- // src/adapters/next-client/contexts/intor-locale/intor-locale-provider.tsx
536
- var IntorLocaleProvider = ({
581
+ // src/adapters/next/contexts/locale/provider.tsx
582
+ function LocaleProvider({
537
583
  value: { initialLocale },
538
584
  children
539
- }) => {
540
- const { config } = useIntorConfig();
541
- const { refetchMessages } = useIntorMessages();
542
- const { loaderOptions, cookie } = config;
585
+ }) {
586
+ const { config } = useConfig();
587
+ const { refetchMessages } = useMessages();
588
+ const { loader: loaderOptions, cookie } = config;
543
589
  const [currentLocale, setCurrentLocale] = React7__namespace.useState(initialLocale);
544
590
  useInitLazyLoad({ loaderOptions, currentLocale });
545
591
  useInitLocaleCookie({ config, locale: initialLocale });
@@ -563,23 +609,33 @@ var IntorLocaleProvider = ({
563
609
  }),
564
610
  [currentLocale, setLocale]
565
611
  );
566
- return /* @__PURE__ */ React7__namespace.createElement(IntorLocaleContext.Provider, { value }, children);
567
- };
568
- var useIntorLocale = () => {
569
- const context = React7__namespace.useContext(IntorLocaleContext);
570
- if (!context) {
571
- throw new Error("useIntorLocale must be used within a IntorLocaleProvider");
572
- }
612
+ return /* @__PURE__ */ React7__namespace.createElement(LocaleContext.Provider, { value }, children);
613
+ }
614
+ function useLocale() {
615
+ const context = React7__namespace.useContext(LocaleContext);
616
+ if (!context)
617
+ throw new Error("useLocale must be used within a LocaleProvider");
573
618
  return context;
574
- };
575
- var IntorTranslatorContext = React7__namespace.createContext(void 0);
619
+ }
620
+ var TranslatorContext = React7__namespace.createContext(void 0);
576
621
  var TranslateHandlersContext = React7__namespace.createContext(void 0);
577
- var useTranslateHandlers = () => {
622
+ var TranslateHandlersProvider = ({
623
+ children,
624
+ handlers
625
+ }) => {
626
+ const value = handlers;
627
+ return /* @__PURE__ */ React7__namespace.createElement(TranslateHandlersContext.Provider, { value }, children);
628
+ };
629
+ function useTranslateHandlers() {
578
630
  const context = React7__namespace.useContext(TranslateHandlersContext);
631
+ if (!context)
632
+ throw new Error(
633
+ "useTranslateHandlers must be used within a TranslateHandlersProvider"
634
+ );
579
635
  return context;
580
- };
636
+ }
581
637
  var useInitLoadingState = (config) => {
582
- const lazyLoad = !!config.loaderOptions?.lazyLoad;
638
+ const lazyLoad = !!config.loader?.lazyLoad;
583
639
  const [isCsr, setIsCsr] = React7__namespace.useState(false);
584
640
  React7__namespace.useEffect(() => {
585
641
  setIsCsr(true);
@@ -588,14 +644,12 @@ var useInitLoadingState = (config) => {
588
644
  return isBeforeCSRLoading;
589
645
  };
590
646
 
591
- // src/adapters/next-client/contexts/intor-translator/intor-translator-provider.tsx
647
+ // src/adapters/next/contexts/translator/provider.tsx
592
648
  var EMPTY_OBJECT = Object.freeze({});
593
- var IntorTranslatorProvider = ({
594
- children
595
- }) => {
596
- const { config } = useIntorConfig();
597
- const { messages, isLoading } = useIntorMessages();
598
- const { locale } = useIntorLocale();
649
+ function TranslatorProvider({ children }) {
650
+ const { config } = useConfig();
651
+ const { messages, isLoading } = useMessages();
652
+ const { locale } = useLocale();
599
653
  const translatorHandlers = useTranslateHandlers();
600
654
  const { fallbackLocales, translator: translatorOptions } = config;
601
655
  const isBeforeCSRLoading = useInitLoadingState(config);
@@ -620,79 +674,69 @@ var IntorTranslatorProvider = ({
620
674
  translatorOptions?.loadingMessage,
621
675
  translatorOptions?.placeholder
622
676
  ]);
623
- return /* @__PURE__ */ React7__namespace.createElement(IntorTranslatorContext.Provider, { value }, children);
624
- };
625
- function useIntorTranslator() {
626
- const context = React7__namespace.useContext(IntorTranslatorContext);
627
- if (!context) {
677
+ return /* @__PURE__ */ React7__namespace.createElement(TranslatorContext.Provider, { value }, children);
678
+ }
679
+ function useTranslator() {
680
+ const context = React7__namespace.useContext(TranslatorContext);
681
+ if (!context)
628
682
  throw new Error(
629
683
  "useIntorTranslator must be used within IntorTranslatorProvider"
630
684
  );
631
- }
632
685
  return context;
633
686
  }
634
687
 
635
- // src/adapters/next-client/hooks/use-intor/use-intor.ts
636
- function useIntorWithPreKey(preKey) {
637
- const { translator } = useIntorTranslator();
638
- const { setLocale } = useIntorLocale();
639
- const scoped = translator.scoped(
640
- preKey
641
- );
642
- return {
643
- messages: translator.messages,
644
- locale: translator.locale,
645
- isLoading: translator.isLoading,
646
- setLocale,
647
- hasKey: scoped.hasKey,
648
- t: scoped.t
649
- };
650
- }
651
- function useIntorWithoutPreKey() {
652
- const { translator } = useIntorTranslator();
653
- const { setLocale } = useIntorLocale();
654
- const scoped = translator.scoped();
655
- return {
688
+ // src/adapters/next/contexts/intor-provider/intor-provider.tsx
689
+ var IntorProvider = ({
690
+ value: { config, pathname, initialLocale, messages },
691
+ children
692
+ }) => {
693
+ return /* @__PURE__ */ React7__namespace.createElement(ConfigProvider, { value: { config, pathname } }, /* @__PURE__ */ React7__namespace.createElement(MessagesProvider, { value: { messages } }, /* @__PURE__ */ React7__namespace.createElement(LocaleProvider, { value: { initialLocale } }, /* @__PURE__ */ React7__namespace.createElement(TranslatorProvider, null, children))));
694
+ };
695
+
696
+ // src/adapters/next/hooks/use-intor/use-intor.ts
697
+ function useIntor(preKey) {
698
+ const { translator } = useTranslator();
699
+ const { setLocale } = useLocale();
700
+ const sharedMethod = {
656
701
  messages: translator.messages,
657
702
  locale: translator.locale,
658
703
  isLoading: translator.isLoading,
659
- setLocale,
660
- hasKey: scoped.hasKey,
661
- t: scoped.t
704
+ setLocale
662
705
  };
663
- }
664
- function useIntor(preKey) {
665
706
  if (preKey) {
666
- return useIntorWithPreKey(preKey);
707
+ const { hasKey, t } = translator.scoped(preKey);
708
+ return { ...sharedMethod, hasKey, t };
709
+ } else {
710
+ const { hasKey, t } = translator;
711
+ return { ...sharedMethod, hasKey, t };
667
712
  }
668
- return useIntorWithoutPreKey();
669
713
  }
670
714
 
671
- // src/adapters/next-client/utils/locale-prefix-pathname.ts
715
+ // src/adapters/next/shared/utils/locale-prefix-pathname.ts
672
716
  var localePrefixPathname = ({
673
717
  config,
674
718
  pathname: standardizedPathname,
675
719
  locale
676
720
  }) => {
677
- const { routing, prefixPlaceHolder } = config;
721
+ const { routing } = config;
678
722
  const { prefix } = routing;
679
723
  if (prefix !== "none" && !locale) {
680
724
  throw new Error('No locale when using prefix "all", "except-default"');
681
725
  }
682
726
  if (prefix === "all") {
683
- return standardizedPathname.replace(prefixPlaceHolder, locale);
727
+ return standardizedPathname.replace(PREFIX_PLACEHOLDER, locale);
684
728
  }
685
729
  if (prefix === "except-default") {
686
730
  if (locale === config.defaultLocale) {
687
- return standardizedPathname.replace(`/${prefixPlaceHolder}`, "");
731
+ return standardizedPathname.replace(`/${PREFIX_PLACEHOLDER}`, "");
688
732
  } else {
689
- return standardizedPathname.replace(prefixPlaceHolder, locale);
733
+ return standardizedPathname.replace(PREFIX_PLACEHOLDER, locale);
690
734
  }
691
735
  }
692
- return standardizedPathname.replace(`/${prefixPlaceHolder}`, "");
736
+ return standardizedPathname.replace(`/${PREFIX_PLACEHOLDER}`, "");
693
737
  };
694
738
 
695
- // src/adapters/next-client/utils/localize-pathname.ts
739
+ // src/adapters/next/shared/utils/localize-pathname.ts
696
740
  var localizePathname = ({
697
741
  config,
698
742
  pathname: rawPathname,
@@ -718,13 +762,13 @@ var localizePathname = ({
718
762
  };
719
763
  };
720
764
 
721
- // src/adapters/next-client/utils/should-use-full-reload.ts
722
- var shouldUseFullReload = (loaderOptions) => {
765
+ // src/adapters/next/tools/utils/should-full-reload.ts
766
+ var shouldFullReload = (loaderOptions) => {
723
767
  return loaderOptions?.type === "import" || loaderOptions?.type === "api" && loaderOptions.fullReload === true;
724
768
  };
725
769
  var usePathname = () => {
726
- const { config } = useIntorConfig();
727
- const { locale } = useIntorLocale();
770
+ const { config } = useConfig();
771
+ const { locale } = useLocale();
728
772
  const rawPathname = navigation.usePathname();
729
773
  const { localePrefixedPathname } = localizePathname({
730
774
  config,
@@ -733,8 +777,6 @@ var usePathname = () => {
733
777
  });
734
778
  return localePrefixedPathname;
735
779
  };
736
-
737
- // src/adapters/next-client/tools/Link.tsx
738
780
  var Link = ({
739
781
  href,
740
782
  locale,
@@ -742,31 +784,32 @@ var Link = ({
742
784
  onClick,
743
785
  ...props
744
786
  }) => {
745
- const { config } = useIntorConfig();
746
- const { locale: currentLocale, setLocale } = useIntorLocale();
787
+ const { config } = useConfig();
788
+ const { locale: currentLocale, setLocale } = useLocale();
747
789
  const targetLocale = locale || currentLocale;
748
790
  const pathname = usePathname();
791
+ const formattedUrl = href ? typeof href === "string" ? href : formatUrl.formatUrl(href) : void 0;
749
792
  const { localePrefixedPathname } = localizePathname({
750
793
  config,
751
- pathname: href ?? pathname,
794
+ pathname: formattedUrl ?? pathname,
752
795
  locale: targetLocale
753
796
  });
754
- href = localePrefixedPathname;
797
+ const resolvedHref = localePrefixedPathname;
755
798
  const handleClick = (e) => {
756
799
  onClick?.(e);
757
- if (shouldUseFullReload(config.loaderOptions)) {
758
- setLocaleCookieClient({ cookie: config.cookie, locale: targetLocale });
759
- window.location.href = href;
800
+ if (shouldFullReload(config.loader)) {
801
+ setLocaleCookieBrowser({ cookie: config.cookie, locale: targetLocale });
802
+ window.location.href = resolvedHref;
760
803
  return;
761
804
  } else {
762
805
  setLocale(targetLocale);
763
806
  }
764
807
  };
765
- return /* @__PURE__ */ React7__namespace.createElement(NextLink__default.default, { href, onClick: handleClick, ...props }, children);
808
+ return /* @__PURE__ */ React7__namespace.createElement(NextLink__default.default, { href: resolvedHref, onClick: handleClick, ...props }, children);
766
809
  };
767
810
  var useRouter = () => {
768
- const { config } = useIntorConfig();
769
- const { locale: currentLocale, setLocale } = useIntorLocale();
811
+ const { config } = useConfig();
812
+ const { locale: currentLocale, setLocale } = useLocale();
770
813
  const { push, replace, ...rest } = navigation.useRouter();
771
814
  const pushWithLocale = (href, options) => {
772
815
  const targetLocale = options?.locale || currentLocale;
@@ -778,7 +821,7 @@ var useRouter = () => {
778
821
  });
779
822
  href = localePrefixedPathname;
780
823
  }
781
- if (shouldUseFullReload(config.loaderOptions)) {
824
+ if (shouldFullReload(config.loader)) {
782
825
  window.location.href = href;
783
826
  return;
784
827
  } else {
@@ -796,7 +839,7 @@ var useRouter = () => {
796
839
  });
797
840
  href = localePrefixedPathname;
798
841
  }
799
- if (shouldUseFullReload(config.loaderOptions)) {
842
+ if (shouldFullReload(config.loader)) {
800
843
  window.location.href = href;
801
844
  return;
802
845
  } else {
@@ -811,16 +854,13 @@ var useRouter = () => {
811
854
  };
812
855
  };
813
856
 
814
- exports.IntorConfigProvider = IntorConfigProvider;
815
- exports.IntorLocaleProvider = IntorLocaleProvider;
816
- exports.IntorMessagesProvider = IntorMessagesProvider;
817
- exports.IntorTranslatorProvider = IntorTranslatorProvider;
857
+ // src/adapters/next/shared/constants/pathname-header-name.ts
858
+ var PATHNAME_HEADER_NAME = "x-intor-pathname";
859
+
860
+ exports.IntorProvider = IntorProvider;
818
861
  exports.Link = Link;
819
- exports.TranslateHandlersContext = TranslateHandlersContext;
862
+ exports.PATHNAME_HEADER_NAME = PATHNAME_HEADER_NAME;
863
+ exports.TranslateHandlersProvider = TranslateHandlersProvider;
820
864
  exports.useIntor = useIntor;
821
- exports.useIntorConfig = useIntorConfig;
822
- exports.useIntorLocale = useIntorLocale;
823
- exports.useIntorMessages = useIntorMessages;
824
- exports.useIntorTranslator = useIntorTranslator;
825
865
  exports.usePathname = usePathname;
826
866
  exports.useRouter = useRouter;