intor 2.1.0 → 2.2.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.
@@ -4,8 +4,8 @@ var React7 = require('react');
4
4
  var logry = require('logry');
5
5
  var Keyv = require('keyv');
6
6
  var intorTranslator = require('intor-translator');
7
- var NextLink = require('next/link');
8
7
  var formatUrl = require('next/dist/shared/lib/router/utils/format-url');
8
+ var NextLink = require('next/link');
9
9
  var navigation = require('next/navigation');
10
10
  var headers = require('next/headers');
11
11
 
@@ -48,66 +48,6 @@ function useConfig() {
48
48
  return context;
49
49
  }
50
50
  var LocaleContext = React7__namespace.createContext(void 0);
51
-
52
- // src/adapters/next/shared/utils/build-cookie-string.ts
53
- var buildCookieString = (cookie, locale) => {
54
- const parts = [];
55
- parts.push(`${cookie.name}=${encodeURIComponent(locale)}`);
56
- if (cookie.maxAge) {
57
- const expires = new Date(Date.now() + cookie.maxAge * 1e3).toUTCString();
58
- parts.push(`expires=${expires}`);
59
- parts.push(`max-age=${cookie.maxAge}`);
60
- }
61
- parts.push(`path=${cookie.path ?? "/"}`);
62
- if (cookie.domain) {
63
- parts.push(`domain=${cookie.domain}`);
64
- }
65
- if (cookie.sameSite) {
66
- parts.push(
67
- `SameSite=${cookie.sameSite[0].toUpperCase()}${cookie.sameSite.slice(1).toLowerCase()}`
68
- );
69
- }
70
- if (cookie.secure !== false) {
71
- parts.push(`Secure`);
72
- }
73
- return parts.join("; ");
74
- };
75
-
76
- // src/adapters/next/shared/utils/set-locale-cookie-browser.ts
77
- var setLocaleCookieBrowser = ({
78
- cookie,
79
- locale
80
- }) => {
81
- if (typeof window === "undefined") return;
82
- if (cookie.disabled || !cookie.autoSetCookie) return;
83
- const cookieString = buildCookieString(cookie, locale);
84
- document.cookie = cookieString;
85
- };
86
-
87
- // src/adapters/next/contexts/locale/utils/change-locale.ts
88
- var changeLocale = ({
89
- currentLocale,
90
- newLocale,
91
- loaderOptions,
92
- cookie,
93
- setLocale,
94
- refetchMessages
95
- }) => {
96
- if (typeof document === "undefined") return;
97
- const loaderType = loaderOptions?.type;
98
- if (newLocale === currentLocale) return;
99
- if (loaderType === "import") {
100
- console.warn(
101
- `[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.`
102
- );
103
- }
104
- setLocale(newLocale);
105
- setLocaleCookieBrowser({ cookie, locale: newLocale });
106
- document.documentElement.lang = newLocale;
107
- if (loaderType === "api" && refetchMessages) {
108
- void refetchMessages(newLocale);
109
- }
110
- };
111
51
  var MessagesContext = React7__namespace.createContext(void 0);
112
52
 
113
53
  // src/modules/config/constants/cache.constants.ts
@@ -146,7 +86,7 @@ function getLogger({
146
86
  });
147
87
  pool.set(id, logger);
148
88
  if (pool.size > 1e3) {
149
- const keys = Array.from(pool.keys());
89
+ const keys = [...pool.keys()];
150
90
  for (const key of keys.slice(0, 200)) pool.delete(key);
151
91
  }
152
92
  }
@@ -161,7 +101,7 @@ function getGlobalMessagesPool() {
161
101
 
162
102
  // src/shared/utils/merge-messages.ts
163
103
  var mergeMessages = (staticMessages = {}, loadedMessages = {}) => {
164
- const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
104
+ const result = Object.keys(staticMessages).length > 0 ? { ...staticMessages } : {};
165
105
  for (const locale in loadedMessages) {
166
106
  const loaded = loadedMessages[locale];
167
107
  if (!result[locale]) {
@@ -180,7 +120,7 @@ var mergeMessages = (staticMessages = {}, loadedMessages = {}) => {
180
120
  var CACHE_KEY_DELIMITER = "|";
181
121
  var sanitize = (k) => k.replaceAll(/[\u200B-\u200D\uFEFF]/g, "").replaceAll(/[\r\n]/g, "").trim();
182
122
  var normalizeCacheKey = (key, delimiter = CACHE_KEY_DELIMITER) => {
183
- if (!key) return null;
123
+ if (key === null || key === void 0) return null;
184
124
  if (Array.isArray(key)) {
185
125
  if (key.length === 0) return null;
186
126
  const normalized = key.map((k) => {
@@ -204,56 +144,44 @@ var resolveNamespaces = ({
204
144
  pathname
205
145
  }) => {
206
146
  const { loader } = config;
207
- const {
208
- routeNamespaces = {},
209
- namespaces: fallbackNamespaces
210
- } = loader;
211
- const { unprefixedPathname } = extractPathname({ config, pathname });
212
- const standardizedPathname = standardizePathname({
213
- config,
214
- pathname: unprefixedPathname
215
- });
147
+ const { routeNamespaces = {}, namespaces } = loader || {};
148
+ const standardizedPathname = standardizePathname({ config, pathname });
216
149
  const placeholderRemovedPathname = standardizedPathname.replace(
217
150
  `/${PREFIX_PLACEHOLDER}`,
218
151
  ""
219
152
  );
220
- const defaultNamespaces = routeNamespaces.default ?? [];
221
- const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
222
- if (exactMatchNamespaces) {
223
- return [...defaultNamespaces, ...exactMatchNamespaces];
224
- }
225
- let bestMatch = "";
226
- let bestNamespaces;
153
+ const collected = [
154
+ ...routeNamespaces.default || [],
155
+ // default
156
+ ...namespaces || [],
157
+ // default
158
+ ...routeNamespaces[standardizedPathname] || [],
159
+ // exact match
160
+ ...routeNamespaces[placeholderRemovedPathname] || []
161
+ // exact match
162
+ ];
227
163
  const prefixPatterns = Object.keys(routeNamespaces).filter(
228
164
  (pattern) => pattern.endsWith("/*")
229
165
  );
230
166
  for (const pattern of prefixPatterns) {
231
167
  const basePath = pattern.replace(/\/\*$/, "");
232
- if (standardizedPathname.startsWith(basePath)) {
233
- if (basePath.length > bestMatch.length) {
234
- bestMatch = basePath;
235
- bestNamespaces = routeNamespaces[pattern];
236
- }
168
+ if (standardizedPathname.startsWith(basePath) || placeholderRemovedPathname.startsWith(basePath)) {
169
+ collected.push(...routeNamespaces[pattern] || []);
237
170
  }
238
171
  }
239
- const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
240
- if (matchedNamespaces.length > 0) {
241
- return [...defaultNamespaces, ...matchedNamespaces];
242
- } else {
243
- return [...defaultNamespaces];
244
- }
172
+ return [...new Set(collected)];
245
173
  };
246
174
 
247
175
  // src/shared/utils/locale/normalize-locale.ts
176
+ var toCanonical = (input) => {
177
+ try {
178
+ return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
179
+ } catch {
180
+ return;
181
+ }
182
+ };
248
183
  var normalizeLocale = (locale = "", supportedLocales = []) => {
249
184
  if (!locale || supportedLocales.length === 0) return;
250
- const toCanonical = (input) => {
251
- try {
252
- return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
253
- } catch {
254
- return;
255
- }
256
- };
257
185
  const canonicalLocale = toCanonical(locale);
258
186
  if (!canonicalLocale) return;
259
187
  const supportedCanonicalMap = /* @__PURE__ */ new Map();
@@ -284,12 +212,12 @@ var resolvePreferredLocale = (acceptLanguageHeader, supportedLocales) => {
284
212
  const supportedLocalesSet = new Set(supportedLocales);
285
213
  const preferred = acceptLanguageHeader.split(",").map((part) => {
286
214
  const [lang, qValue] = part.split(";");
287
- const q = qValue ? parseFloat(qValue.split("=")[1]) : 1;
288
- if (isNaN(q)) {
215
+ const q = qValue ? Number.parseFloat(qValue.split("=")[1]) : 1;
216
+ if (Number.isNaN(q)) {
289
217
  return { lang: lang.trim(), q: 0 };
290
218
  }
291
219
  return { lang: lang.trim(), q };
292
- }).sort((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
220
+ }).toSorted((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
293
221
  return preferred;
294
222
  };
295
223
 
@@ -298,8 +226,8 @@ var normalizePathname = (rawPathname, options = {}) => {
298
226
  const length = rawPathname.length;
299
227
  let start = 0;
300
228
  let end = length - 1;
301
- while (start <= end && rawPathname.charCodeAt(start) <= 32) start++;
302
- while (end >= start && rawPathname.charCodeAt(end) <= 32) end--;
229
+ while (start <= end && (rawPathname.codePointAt(start) ?? 0) <= 32) start++;
230
+ while (end >= start && (rawPathname.codePointAt(end) ?? 0) <= 32) end--;
303
231
  if (start > end) return "/";
304
232
  let result = "";
305
233
  let hasSlash = false;
@@ -310,11 +238,7 @@ var normalizePathname = (rawPathname, options = {}) => {
310
238
  hasSlash = true;
311
239
  }
312
240
  } else {
313
- if (hasSlash || result === "") {
314
- result += "/" + char;
315
- } else {
316
- result += char;
317
- }
241
+ result += hasSlash || result === "" ? "/" + char : char;
318
242
  hasSlash = false;
319
243
  }
320
244
  }
@@ -338,8 +262,8 @@ var extractPathname = ({
338
262
  } else if (basePath && normalizedPathname === basePath) {
339
263
  prefixedPathname = "/";
340
264
  }
341
- const pathParts = prefixedPathname.split("/").filter(Boolean);
342
- const maybeLocale = pathParts[0] || "";
265
+ const pathPart = prefixedPathname.split("/").find(Boolean);
266
+ const maybeLocale = pathPart || "";
343
267
  const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
344
268
  let unprefixedPathname = prefixedPathname;
345
269
  if (prefix === "all") {
@@ -372,7 +296,7 @@ var standardizePathname = ({
372
296
  PREFIX_PLACEHOLDER,
373
297
  normalizePathname(pathname)
374
298
  ];
375
- const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
299
+ const standardizedPathname = parts.join("/").replaceAll(/\/{2,}/g, "/");
376
300
  return normalizePathname(standardizedPathname);
377
301
  };
378
302
 
@@ -484,8 +408,8 @@ var loadApiMessages = async ({
484
408
  loggerOptions.id,
485
409
  basePath,
486
410
  locale,
487
- [...fallbackLocales ?? []].sort().join(","),
488
- [...namespaces ?? []].sort().join(",")
411
+ (fallbackLocales ?? []).toSorted().join(","),
412
+ (namespaces ?? []).toSorted().join(",")
489
413
  ]);
490
414
  if (cache.enabled && key) {
491
415
  const cached = await pool?.get(key);
@@ -606,6 +530,8 @@ function useMessages() {
606
530
  throw new Error("useMessages must be used within a MessagesProvider");
607
531
  return context;
608
532
  }
533
+
534
+ // src/adapters/next/contexts/locale/utils/use-init-lazy-load.ts
609
535
  var useInitLazyLoad = ({
610
536
  loaderOptions,
611
537
  currentLocale
@@ -620,6 +546,41 @@ var useInitLazyLoad = ({
620
546
  }
621
547
  }, [lazyLoad, currentLocale, refetchMessages, isFirstLoadedRef]);
622
548
  };
549
+
550
+ // src/adapters/next/shared/utils/build-cookie-string.ts
551
+ var buildCookieString = (cookie, locale) => {
552
+ const parts = [`${cookie.name}=${encodeURIComponent(locale)}`];
553
+ if (cookie.maxAge) {
554
+ const expires = new Date(Date.now() + cookie.maxAge * 1e3).toUTCString();
555
+ parts.push(`expires=${expires}`, `max-age=${cookie.maxAge}`);
556
+ }
557
+ parts.push(`path=${cookie.path ?? "/"}`);
558
+ if (cookie.domain) {
559
+ parts.push(`domain=${cookie.domain}`);
560
+ }
561
+ if (cookie.sameSite) {
562
+ parts.push(
563
+ `SameSite=${cookie.sameSite[0].toUpperCase()}${cookie.sameSite.slice(1).toLowerCase()}`
564
+ );
565
+ }
566
+ if (cookie.secure !== false) {
567
+ parts.push(`Secure`);
568
+ }
569
+ return parts.join("; ");
570
+ };
571
+
572
+ // src/adapters/next/shared/utils/set-locale-cookie-browser.ts
573
+ var setLocaleCookieBrowser = ({
574
+ cookie,
575
+ locale
576
+ }) => {
577
+ if (globalThis.window === void 0) return;
578
+ if (cookie.disabled || !cookie.autoSetCookie) return;
579
+ const cookieString = buildCookieString(cookie, locale);
580
+ document.cookie = cookieString;
581
+ };
582
+
583
+ // src/adapters/next/contexts/locale/utils/use-init-locale-cookie.ts
623
584
  var useInitLocaleCookie = ({
624
585
  config,
625
586
  locale
@@ -637,6 +598,31 @@ var useInitLocaleCookie = ({
637
598
  }, []);
638
599
  };
639
600
 
601
+ // src/adapters/next/contexts/locale/utils/change-locale.ts
602
+ var changeLocale = ({
603
+ currentLocale,
604
+ newLocale,
605
+ loaderOptions,
606
+ cookie,
607
+ setLocale,
608
+ refetchMessages
609
+ }) => {
610
+ if (typeof document === "undefined") return;
611
+ const loaderType = loaderOptions?.type;
612
+ if (newLocale === currentLocale) return;
613
+ if (loaderType === "import") {
614
+ console.warn(
615
+ `[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.`
616
+ );
617
+ }
618
+ setLocale(newLocale);
619
+ setLocaleCookieBrowser({ cookie, locale: newLocale });
620
+ document.documentElement.lang = newLocale;
621
+ if (loaderType === "api" && refetchMessages) {
622
+ void refetchMessages(newLocale);
623
+ }
624
+ };
625
+
640
626
  // src/adapters/next/contexts/locale/provider.tsx
641
627
  function LocaleProvider({
642
628
  value: { initialLocale },
@@ -735,7 +721,7 @@ function useTranslator() {
735
721
  const context = React7__namespace.useContext(TranslatorContext);
736
722
  if (!context)
737
723
  throw new Error(
738
- "useIntorTranslator must be used within IntorTranslatorProvider"
724
+ "useTranslator must be used within IntorTranslatorProvider"
739
725
  );
740
726
  return context;
741
727
  }
@@ -758,13 +744,12 @@ function useTranslator2(preKey) {
758
744
  isLoading: translator.isLoading,
759
745
  setLocale
760
746
  };
761
- if (preKey) {
762
- const { hasKey, t } = translator.scoped(preKey);
763
- return { ...props, hasKey, t };
764
- } else {
765
- const { hasKey, t } = translator;
766
- return { ...props, hasKey, t };
767
- }
747
+ const scoped = translator.scoped(preKey);
748
+ return {
749
+ ...props,
750
+ hasKey: preKey ? scoped.hasKey : translator.hasKey,
751
+ t: preKey ? scoped.t : translator.t
752
+ };
768
753
  }
769
754
 
770
755
  // src/adapters/next/shared/utils/locale-prefix-pathname.ts
@@ -784,15 +769,11 @@ var localePrefixPathname = ({
784
769
  );
785
770
  }
786
771
  if (prefix === "except-default") {
787
- if (locale === config.defaultLocale) {
788
- return normalizePathname(
789
- standardizedPathname.replaceAll(`/${PREFIX_PLACEHOLDER}`, "")
790
- );
791
- } else {
792
- return normalizePathname(
793
- standardizedPathname.replaceAll(PREFIX_PLACEHOLDER, locale)
794
- );
795
- }
772
+ return locale === config.defaultLocale ? normalizePathname(
773
+ standardizedPathname.replaceAll(`/${PREFIX_PLACEHOLDER}`, "")
774
+ ) : normalizePathname(
775
+ standardizedPathname.replaceAll(PREFIX_PLACEHOLDER, locale)
776
+ );
796
777
  }
797
778
  return normalizePathname(
798
779
  standardizedPathname.replaceAll(`/${PREFIX_PLACEHOLDER}`, "")
@@ -884,7 +865,7 @@ var useLocaleSwitch = () => {
884
865
  if (isExternal) return;
885
866
  if (shouldFullReload({ config, targetPathname, locale, currentLocale })) {
886
867
  setLocaleCookieBrowser({ cookie: config.cookie, locale: targetLocale });
887
- window.location.href = resolvedHref;
868
+ globalThis.location.href = resolvedHref;
888
869
  return;
889
870
  } else {
890
871
  setLocale(targetLocale);
@@ -1,8 +1,8 @@
1
- import * as React from 'react';
2
1
  import { Level, NormalizerConfig, FormatterConfig, LoggerPreset } from 'logry/edge';
3
- import { Locale, LocaleNamespaceMessages, FallbackLocalesMap, TranslateHandlers, InferTranslatorKey, LocaleKey, Replacement, RichReplacement, NodeKeys, UnionLocaleMessages, ScopedLeafKeys } from 'intor-translator';
4
- import { LinkProps as LinkProps$1 } from 'next/link';
2
+ import { Locale, LocaleMessages, FallbackLocalesMap, TranslateHandlers, ScopedLeafKeys, LocalizedLeafKeys, Replacement, LocalizedNodeKeys } from 'intor-translator';
3
+ import * as React from 'react';
5
4
  import { Url } from 'next/dist/shared/lib/router/router';
5
+ import { LinkProps as LinkProps$1 } from 'next/link';
6
6
  import * as next_dist_shared_lib_app_router_context_shared_runtime from 'next/dist/shared/lib/app-router-context.shared-runtime';
7
7
  import { NavigateOptions } from 'next/dist/shared/lib/app-router-context.shared-runtime';
8
8
  import { RedirectType } from 'next/navigation';
@@ -115,7 +115,7 @@ type WithLoader = {
115
115
  };
116
116
  type IntorResolvedConfig = (WithLoader | WithoutLoader) & {
117
117
  readonly id: string;
118
- readonly messages?: LocaleNamespaceMessages;
118
+ readonly messages?: LocaleMessages;
119
119
  readonly defaultLocale: Locale;
120
120
  readonly fallbackLocales: FallbackLocalesMap;
121
121
  readonly translator?: TranslatorOptions;
@@ -130,7 +130,7 @@ interface IntorProviderProps {
130
130
  config: IntorResolvedConfig;
131
131
  initialLocale: Locale;
132
132
  pathname: string;
133
- messages: Readonly<LocaleNamespaceMessages>;
133
+ messages: Readonly<LocaleMessages>;
134
134
  };
135
135
  children: React.ReactNode;
136
136
  }
@@ -146,37 +146,64 @@ declare const TranslateHandlersProvider: ({ children, handlers, }: TranslateHand
146
146
 
147
147
  declare const PREFIX_PLACEHOLDER = "{locale}";
148
148
 
149
+ /**
150
+ * Conditional type for generated types.
151
+ * - Returns `Then` if `IntorGeneratedTypes` exists, otherwise `Else`.
152
+ */
149
153
  type IfGen<Then, Else = never> = IntorGeneratedTypes extends void ? Else : Then;
154
+ /**
155
+ * Union of all configuration keys.
156
+ * - Defaults to `string` if `IntorGeneratedTypes` does not exist.
157
+ */
150
158
  type GenConfigKeys = IfGen<keyof IntorGeneratedTypes, string>;
151
- type GenConfig<C extends GenConfigKeys = "__default__"> = IntorGeneratedTypes extends void ? {
159
+ /**
160
+ * Configuration shape for a given config key.
161
+ * - If `IntorGeneratedTypes` is not defined, falls back to default shape.
162
+ * Otherwise, picks `Locales` and `Messages` according to the key.
163
+ */
164
+ type GenConfig<CK extends GenConfigKeys = "__default__"> = IntorGeneratedTypes extends void ? {
152
165
  Locales: string;
153
- Messages: LocaleNamespaceMessages;
154
- } : C extends keyof IntorGeneratedTypes ? {
155
- Locales: IntorGeneratedTypes[C]["Locales"];
166
+ Messages: LocaleMessages;
167
+ } : CK extends keyof IntorGeneratedTypes ? {
168
+ Locales: IntorGeneratedTypes[CK]["Locales"];
156
169
  Messages: {
157
- [K in IntorGeneratedTypes[C]["Locales"]]: IntorGeneratedTypes[C]["Messages"][typeof PREFIX_PLACEHOLDER];
170
+ [K in IntorGeneratedTypes[CK]["Locales"]]: IntorGeneratedTypes[CK]["Messages"][typeof PREFIX_PLACEHOLDER];
158
171
  };
159
172
  } : never;
160
- type GenMessages<C extends GenConfigKeys = "__default__"> = GenConfig<C>["Messages"];
161
- type GenLocaleFallback = Locale;
162
- type GenLocale<Config extends string = "__default__"> = Config extends keyof IntorGeneratedTypes ? IntorGeneratedTypes[Config]["Locales"] : GenLocaleFallback;
173
+ /** Extracts messages for a given config key */
174
+ type GenMessages<CK extends GenConfigKeys = "__default__"> = GenConfig<CK>["Messages"];
175
+ /** Extracts locales for a given config key */
176
+ type GenLocale<CK extends GenConfigKeys = "__default__"> = GenConfig<CK>["Locales"];
163
177
 
164
- type PreKey<C extends GenConfigKeys = "__default__"> = NodeKeys<UnionLocaleMessages<GenMessages<C>>>;
165
- interface TranslatorBaseProps<M> {
178
+ /** Base properties shared by all translator instances. */
179
+ interface TranslatorBaseProps<M = unknown> {
180
+ /** `messages`: The message object containing all translations. */
166
181
  messages: M;
167
- locale: LocaleKey<M>;
182
+ /** Current locale in use. */
183
+ locale: Locale<M>;
168
184
  }
169
- interface TranslatorClientProps<M> {
185
+ /** Properties specific to client-side translator behavior. */
186
+ interface TranslatorClientProps<M = unknown> {
187
+ /** `isLoading`: Indicates whether translations are currently loading. */
170
188
  isLoading: boolean;
171
- setLocale: (locale: LocaleKey<M>) => void;
189
+ /** `setLocale`: Function to update the current locale. */
190
+ setLocale: (locale: Locale<M>) => void;
172
191
  }
173
- type TranslatorInstance<M> = {
174
- hasKey: (key?: IfGen<InferTranslatorKey<M>, string>, targetLocale?: LocaleKey<M> | undefined) => boolean;
175
- t: <Result = string>(key?: IfGen<InferTranslatorKey<M>, string>, replacements?: Replacement | RichReplacement) => Result;
176
- } & TranslatorBaseProps<M> & TranslatorClientProps<M>;
177
- type ScopedTranslatorInstance<M, K extends string> = {
178
- hasKey: (key?: IfGen<ScopedLeafKeys<M, K> & string, string>, targetLocale?: LocaleKey<M>) => boolean;
179
- t: (key?: IfGen<ScopedLeafKeys<M, K> & string, string>, replacements?: Replacement | RichReplacement) => string;
192
+ /**
193
+ * Conditional key type for TranslatorInstance.
194
+ * - Resolves to `ScopedLeafKeys` if a pre-key `PK` is provided,
195
+ * otherwise resolves to `LocalizedLeafKeys`.
196
+ */
197
+ type Key<M, PK> = IfGen<PK extends string ? ScopedLeafKeys<M, PK> : LocalizedLeafKeys<M>, string>;
198
+ /**
199
+ * Translator instance type.
200
+ * Combines base props, client props, and core translation methods.
201
+ */
202
+ type TranslatorInstance<M, PK extends string | undefined = undefined> = {
203
+ /** Check if a given key exists in the messages. */
204
+ hasKey: (key?: Key<M, PK>, targetLocale?: Locale<M>) => boolean;
205
+ /** Translate a given key into its string representation. */
206
+ t: <Result = string>(key?: Key<M, PK>, replacements?: Replacement) => Result;
180
207
  } & TranslatorBaseProps<M> & TranslatorClientProps<M>;
181
208
 
182
209
  /**
@@ -186,8 +213,8 @@ type ScopedTranslatorInstance<M, K extends string> = {
186
213
  * - Supports optional `preKey` to create a scoped translator for nested keys.
187
214
  * - Can accept a generic type parameter `M` to strongly type your messages.
188
215
  */
189
- declare function useTranslator<C extends GenConfigKeys = "__default__">(): TranslatorInstance<GenMessages<C>>;
190
- declare function useTranslator<C extends GenConfigKeys = "__default__", K extends PreKey<C> = PreKey<C>>(preKey: IfGen<K, string>): ScopedTranslatorInstance<GenMessages<C>, K>;
216
+ declare function useTranslator<CK extends GenConfigKeys = "__default__">(): TranslatorInstance<GenMessages<CK>>;
217
+ declare function useTranslator<CK extends GenConfigKeys = "__default__", PK extends string = LocalizedNodeKeys<GenMessages<CK>>>(preKey: IfGen<PK, string>): TranslatorInstance<GenMessages<CK>, PK>;
191
218
 
192
219
  interface LinkProps extends Omit<LinkProps$1, "href">, Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
193
220
  href?: Url;
@@ -1,8 +1,8 @@
1
- import * as React from 'react';
2
1
  import { Level, NormalizerConfig, FormatterConfig, LoggerPreset } from 'logry/edge';
3
- import { Locale, LocaleNamespaceMessages, FallbackLocalesMap, TranslateHandlers, InferTranslatorKey, LocaleKey, Replacement, RichReplacement, NodeKeys, UnionLocaleMessages, ScopedLeafKeys } from 'intor-translator';
4
- import { LinkProps as LinkProps$1 } from 'next/link';
2
+ import { Locale, LocaleMessages, FallbackLocalesMap, TranslateHandlers, ScopedLeafKeys, LocalizedLeafKeys, Replacement, LocalizedNodeKeys } from 'intor-translator';
3
+ import * as React from 'react';
5
4
  import { Url } from 'next/dist/shared/lib/router/router';
5
+ import { LinkProps as LinkProps$1 } from 'next/link';
6
6
  import * as next_dist_shared_lib_app_router_context_shared_runtime from 'next/dist/shared/lib/app-router-context.shared-runtime';
7
7
  import { NavigateOptions } from 'next/dist/shared/lib/app-router-context.shared-runtime';
8
8
  import { RedirectType } from 'next/navigation';
@@ -115,7 +115,7 @@ type WithLoader = {
115
115
  };
116
116
  type IntorResolvedConfig = (WithLoader | WithoutLoader) & {
117
117
  readonly id: string;
118
- readonly messages?: LocaleNamespaceMessages;
118
+ readonly messages?: LocaleMessages;
119
119
  readonly defaultLocale: Locale;
120
120
  readonly fallbackLocales: FallbackLocalesMap;
121
121
  readonly translator?: TranslatorOptions;
@@ -130,7 +130,7 @@ interface IntorProviderProps {
130
130
  config: IntorResolvedConfig;
131
131
  initialLocale: Locale;
132
132
  pathname: string;
133
- messages: Readonly<LocaleNamespaceMessages>;
133
+ messages: Readonly<LocaleMessages>;
134
134
  };
135
135
  children: React.ReactNode;
136
136
  }
@@ -146,37 +146,64 @@ declare const TranslateHandlersProvider: ({ children, handlers, }: TranslateHand
146
146
 
147
147
  declare const PREFIX_PLACEHOLDER = "{locale}";
148
148
 
149
+ /**
150
+ * Conditional type for generated types.
151
+ * - Returns `Then` if `IntorGeneratedTypes` exists, otherwise `Else`.
152
+ */
149
153
  type IfGen<Then, Else = never> = IntorGeneratedTypes extends void ? Else : Then;
154
+ /**
155
+ * Union of all configuration keys.
156
+ * - Defaults to `string` if `IntorGeneratedTypes` does not exist.
157
+ */
150
158
  type GenConfigKeys = IfGen<keyof IntorGeneratedTypes, string>;
151
- type GenConfig<C extends GenConfigKeys = "__default__"> = IntorGeneratedTypes extends void ? {
159
+ /**
160
+ * Configuration shape for a given config key.
161
+ * - If `IntorGeneratedTypes` is not defined, falls back to default shape.
162
+ * Otherwise, picks `Locales` and `Messages` according to the key.
163
+ */
164
+ type GenConfig<CK extends GenConfigKeys = "__default__"> = IntorGeneratedTypes extends void ? {
152
165
  Locales: string;
153
- Messages: LocaleNamespaceMessages;
154
- } : C extends keyof IntorGeneratedTypes ? {
155
- Locales: IntorGeneratedTypes[C]["Locales"];
166
+ Messages: LocaleMessages;
167
+ } : CK extends keyof IntorGeneratedTypes ? {
168
+ Locales: IntorGeneratedTypes[CK]["Locales"];
156
169
  Messages: {
157
- [K in IntorGeneratedTypes[C]["Locales"]]: IntorGeneratedTypes[C]["Messages"][typeof PREFIX_PLACEHOLDER];
170
+ [K in IntorGeneratedTypes[CK]["Locales"]]: IntorGeneratedTypes[CK]["Messages"][typeof PREFIX_PLACEHOLDER];
158
171
  };
159
172
  } : never;
160
- type GenMessages<C extends GenConfigKeys = "__default__"> = GenConfig<C>["Messages"];
161
- type GenLocaleFallback = Locale;
162
- type GenLocale<Config extends string = "__default__"> = Config extends keyof IntorGeneratedTypes ? IntorGeneratedTypes[Config]["Locales"] : GenLocaleFallback;
173
+ /** Extracts messages for a given config key */
174
+ type GenMessages<CK extends GenConfigKeys = "__default__"> = GenConfig<CK>["Messages"];
175
+ /** Extracts locales for a given config key */
176
+ type GenLocale<CK extends GenConfigKeys = "__default__"> = GenConfig<CK>["Locales"];
163
177
 
164
- type PreKey<C extends GenConfigKeys = "__default__"> = NodeKeys<UnionLocaleMessages<GenMessages<C>>>;
165
- interface TranslatorBaseProps<M> {
178
+ /** Base properties shared by all translator instances. */
179
+ interface TranslatorBaseProps<M = unknown> {
180
+ /** `messages`: The message object containing all translations. */
166
181
  messages: M;
167
- locale: LocaleKey<M>;
182
+ /** Current locale in use. */
183
+ locale: Locale<M>;
168
184
  }
169
- interface TranslatorClientProps<M> {
185
+ /** Properties specific to client-side translator behavior. */
186
+ interface TranslatorClientProps<M = unknown> {
187
+ /** `isLoading`: Indicates whether translations are currently loading. */
170
188
  isLoading: boolean;
171
- setLocale: (locale: LocaleKey<M>) => void;
189
+ /** `setLocale`: Function to update the current locale. */
190
+ setLocale: (locale: Locale<M>) => void;
172
191
  }
173
- type TranslatorInstance<M> = {
174
- hasKey: (key?: IfGen<InferTranslatorKey<M>, string>, targetLocale?: LocaleKey<M> | undefined) => boolean;
175
- t: <Result = string>(key?: IfGen<InferTranslatorKey<M>, string>, replacements?: Replacement | RichReplacement) => Result;
176
- } & TranslatorBaseProps<M> & TranslatorClientProps<M>;
177
- type ScopedTranslatorInstance<M, K extends string> = {
178
- hasKey: (key?: IfGen<ScopedLeafKeys<M, K> & string, string>, targetLocale?: LocaleKey<M>) => boolean;
179
- t: (key?: IfGen<ScopedLeafKeys<M, K> & string, string>, replacements?: Replacement | RichReplacement) => string;
192
+ /**
193
+ * Conditional key type for TranslatorInstance.
194
+ * - Resolves to `ScopedLeafKeys` if a pre-key `PK` is provided,
195
+ * otherwise resolves to `LocalizedLeafKeys`.
196
+ */
197
+ type Key<M, PK> = IfGen<PK extends string ? ScopedLeafKeys<M, PK> : LocalizedLeafKeys<M>, string>;
198
+ /**
199
+ * Translator instance type.
200
+ * Combines base props, client props, and core translation methods.
201
+ */
202
+ type TranslatorInstance<M, PK extends string | undefined = undefined> = {
203
+ /** Check if a given key exists in the messages. */
204
+ hasKey: (key?: Key<M, PK>, targetLocale?: Locale<M>) => boolean;
205
+ /** Translate a given key into its string representation. */
206
+ t: <Result = string>(key?: Key<M, PK>, replacements?: Replacement) => Result;
180
207
  } & TranslatorBaseProps<M> & TranslatorClientProps<M>;
181
208
 
182
209
  /**
@@ -186,8 +213,8 @@ type ScopedTranslatorInstance<M, K extends string> = {
186
213
  * - Supports optional `preKey` to create a scoped translator for nested keys.
187
214
  * - Can accept a generic type parameter `M` to strongly type your messages.
188
215
  */
189
- declare function useTranslator<C extends GenConfigKeys = "__default__">(): TranslatorInstance<GenMessages<C>>;
190
- declare function useTranslator<C extends GenConfigKeys = "__default__", K extends PreKey<C> = PreKey<C>>(preKey: IfGen<K, string>): ScopedTranslatorInstance<GenMessages<C>, K>;
216
+ declare function useTranslator<CK extends GenConfigKeys = "__default__">(): TranslatorInstance<GenMessages<CK>>;
217
+ declare function useTranslator<CK extends GenConfigKeys = "__default__", PK extends string = LocalizedNodeKeys<GenMessages<CK>>>(preKey: IfGen<PK, string>): TranslatorInstance<GenMessages<CK>, PK>;
191
218
 
192
219
  interface LinkProps extends Omit<LinkProps$1, "href">, Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
193
220
  href?: Url;