intor 2.4.7 → 2.4.9

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.
Files changed (29) hide show
  1. package/README.md +3 -8
  2. package/dist/core/export/server/index.js +2 -3
  3. package/dist/core/src/server/helpers/get-translator.js +3 -2
  4. package/dist/core/src/server/translator/init-translator.js +6 -3
  5. package/dist/express/src/adapters/express/get-translator.js +5 -4
  6. package/dist/express/src/server/helpers/get-translator.js +3 -2
  7. package/dist/express/src/server/translator/init-translator.js +6 -3
  8. package/dist/fastify/src/adapters/fastify/get-translator.js +5 -4
  9. package/dist/fastify/src/server/helpers/get-translator.js +3 -2
  10. package/dist/fastify/src/server/translator/init-translator.js +6 -3
  11. package/dist/next/src/adapters/next/create-intor-handler.js +37 -35
  12. package/dist/next/src/adapters/next/server/get-translator.js +5 -4
  13. package/dist/next/src/server/helpers/get-translator.js +3 -2
  14. package/dist/next/src/server/translator/init-translator.js +6 -3
  15. package/dist/types/export/server/index.d.ts +1 -1
  16. package/dist/types/src/adapters/next/create-intor-handler.d.ts +2 -1
  17. package/dist/types/src/client/react/helpers/use-intor.d.ts +1 -2
  18. package/dist/types/src/client/react/provider/intor-provider.d.ts +1 -2
  19. package/dist/types/src/client/react/provider/types.d.ts +10 -11
  20. package/dist/types/src/client/react/provider/use-intor-context.d.ts +1 -2
  21. package/dist/types/src/core/index.d.ts +1 -1
  22. package/dist/types/src/core/types/generated.d.ts +35 -31
  23. package/dist/types/src/core/types/index.d.ts +1 -1
  24. package/dist/types/src/server/helpers/get-translator.d.ts +2 -0
  25. package/dist/types/src/server/index.d.ts +2 -1
  26. package/dist/types/src/server/translator/index.d.ts +1 -0
  27. package/dist/types/src/server/translator/init-translator.d.ts +2 -0
  28. package/dist/types/src/server/translator/types.d.ts +9 -0
  29. package/package.json +1 -1
package/README.md CHANGED
@@ -21,11 +21,6 @@ The i18n library for modern JavaScript
21
21
  </div>
22
22
 
23
23
  > [!NOTE]
24
- > Intor began as an internal i18n tool.
25
- >
26
- > After multiple private iterations, it evolved into a minimal,
27
- > framework-agnostic translation system.
28
- >
29
- > **v3 marks its first intentional public release.**
30
- >
31
- > _Currently available as v2.x. v3 is in active development._
24
+ > Intor is evolving toward long-term stability.
25
+ > **v3 will be the first fully stable release.**
26
+ > _Current: v2.x · v3 in development._
@@ -1,10 +1,9 @@
1
1
  export { intor } from '../../src/server/intor/intor.js';
2
- export { loadMessages } from '../../src/server/messages/load-messages.js';
3
- import 'node:path';
4
- import 'p-limit';
5
2
  import '../../src/core/error/intor-error.js';
6
3
  import 'logry';
4
+ import 'p-limit';
7
5
  import 'intor-translator';
6
+ import 'node:path';
8
7
  export { clearMessagesPool } from '../../src/server/messages/load-local-messages/cache/messages-pool.js';
9
8
  import 'node:fs/promises';
10
9
  export { getTranslator } from '../../src/server/helpers/get-translator.js';
@@ -9,14 +9,15 @@ import { initTranslator } from '../translator/init-translator.js';
9
9
  * Get a server-side translator for the current execution context.
10
10
  */
11
11
  async function getTranslator(config, params) {
12
- const { locale, readers, allowCacheWrite, fetch, preKey, handlers, plugins } = params;
12
+ const { locale, loader, readers, allowCacheWrite = false, fetch, handlers, plugins, preKey, } = params;
13
13
  // Initialize a locale-bound translator snapshot with messages loaded
14
14
  const translator = await initTranslator(config, locale, {
15
+ loader,
15
16
  readers,
16
17
  allowCacheWrite,
17
18
  fetch: fetch || globalThis.fetch,
18
- plugins,
19
19
  handlers,
20
+ plugins,
20
21
  });
21
22
  const scoped = translator.scoped(preKey);
22
23
  return {
@@ -15,11 +15,11 @@ import 'node:fs/promises';
15
15
  * - Creates an immutable Translator instance for server usage
16
16
  */
17
17
  async function initTranslator(config, locale, options) {
18
- const { readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
- const loader = resolveLoaderOptions(config, "server");
18
+ const { loader, readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
+ const loaderOptions = resolveLoaderOptions(config, "server");
20
20
  // Load messages
21
21
  let messages = {};
22
- if (loader) {
22
+ if (loaderOptions && !loader) {
23
23
  const loaded = await loadMessages({
24
24
  config,
25
25
  locale,
@@ -29,6 +29,9 @@ async function initTranslator(config, locale, options) {
29
29
  });
30
30
  messages = loaded || {};
31
31
  }
32
+ if (loader) {
33
+ messages = await loader(config, locale);
34
+ }
32
35
  // Create immutable translator snapshot
33
36
  return createTranslator({ config, locale, messages, handlers, plugins });
34
37
  }
@@ -14,14 +14,15 @@ import { getTranslator as getTranslator$1 } from '../../server/helpers/get-trans
14
14
  * @platform Express
15
15
  */
16
16
  async function getTranslator(config, req, params) {
17
- const { preKey, handlers, plugins, readers, allowCacheWrite } = params || {};
17
+ const { loader, readers, allowCacheWrite, handlers, plugins, preKey } = params || {};
18
18
  return getTranslator$1(config, {
19
19
  locale: req.intor?.locale || config.defaultLocale,
20
- preKey,
21
- handlers,
22
- plugins,
20
+ loader,
23
21
  readers,
24
22
  allowCacheWrite,
23
+ handlers,
24
+ plugins,
25
+ preKey,
25
26
  });
26
27
  }
27
28
 
@@ -9,14 +9,15 @@ import { initTranslator } from '../translator/init-translator.js';
9
9
  * Get a server-side translator for the current execution context.
10
10
  */
11
11
  async function getTranslator(config, params) {
12
- const { locale, readers, allowCacheWrite, fetch, preKey, handlers, plugins } = params;
12
+ const { locale, loader, readers, allowCacheWrite = false, fetch, handlers, plugins, preKey, } = params;
13
13
  // Initialize a locale-bound translator snapshot with messages loaded
14
14
  const translator = await initTranslator(config, locale, {
15
+ loader,
15
16
  readers,
16
17
  allowCacheWrite,
17
18
  fetch: fetch || globalThis.fetch,
18
- plugins,
19
19
  handlers,
20
+ plugins,
20
21
  });
21
22
  const scoped = translator.scoped(preKey);
22
23
  return {
@@ -15,11 +15,11 @@ import 'node:fs/promises';
15
15
  * - Creates an immutable Translator instance for server usage
16
16
  */
17
17
  async function initTranslator(config, locale, options) {
18
- const { readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
- const loader = resolveLoaderOptions(config);
18
+ const { loader, readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
+ const loaderOptions = resolveLoaderOptions(config);
20
20
  // Load messages
21
21
  let messages = {};
22
- if (loader) {
22
+ if (loaderOptions && !loader) {
23
23
  const loaded = await loadMessages({
24
24
  config,
25
25
  locale,
@@ -29,6 +29,9 @@ async function initTranslator(config, locale, options) {
29
29
  });
30
30
  messages = loaded || {};
31
31
  }
32
+ if (loader) {
33
+ messages = await loader(config, locale);
34
+ }
32
35
  // Create immutable translator snapshot
33
36
  return createTranslator({ config, locale, messages, handlers, plugins });
34
37
  }
@@ -14,14 +14,15 @@ import { getTranslator as getTranslator$1 } from '../../server/helpers/get-trans
14
14
  * @platform Fastify
15
15
  */
16
16
  async function getTranslator(config, request, params) {
17
- const { preKey, handlers, plugins, readers, allowCacheWrite } = params || {};
17
+ const { loader, readers, allowCacheWrite, handlers, plugins, preKey } = params || {};
18
18
  return getTranslator$1(config, {
19
19
  locale: request.intor?.locale || config.defaultLocale,
20
- preKey,
21
- handlers,
22
- plugins,
20
+ loader,
23
21
  readers,
24
22
  allowCacheWrite,
23
+ handlers,
24
+ plugins,
25
+ preKey,
25
26
  });
26
27
  }
27
28
 
@@ -9,14 +9,15 @@ import { initTranslator } from '../translator/init-translator.js';
9
9
  * Get a server-side translator for the current execution context.
10
10
  */
11
11
  async function getTranslator(config, params) {
12
- const { locale, readers, allowCacheWrite, fetch, preKey, handlers, plugins } = params;
12
+ const { locale, loader, readers, allowCacheWrite = false, fetch, handlers, plugins, preKey, } = params;
13
13
  // Initialize a locale-bound translator snapshot with messages loaded
14
14
  const translator = await initTranslator(config, locale, {
15
+ loader,
15
16
  readers,
16
17
  allowCacheWrite,
17
18
  fetch: fetch || globalThis.fetch,
18
- plugins,
19
19
  handlers,
20
+ plugins,
20
21
  });
21
22
  const scoped = translator.scoped(preKey);
22
23
  return {
@@ -15,11 +15,11 @@ import 'node:fs/promises';
15
15
  * - Creates an immutable Translator instance for server usage
16
16
  */
17
17
  async function initTranslator(config, locale, options) {
18
- const { readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
- const loader = resolveLoaderOptions(config);
18
+ const { loader, readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
+ const loaderOptions = resolveLoaderOptions(config);
20
20
  // Load messages
21
21
  let messages = {};
22
- if (loader) {
22
+ if (loaderOptions && !loader) {
23
23
  const loaded = await loadMessages({
24
24
  config,
25
25
  locale,
@@ -29,6 +29,9 @@ async function initTranslator(config, locale, options) {
29
29
  });
30
30
  messages = loaded || {};
31
31
  }
32
+ if (loader) {
33
+ messages = await loader(config, locale);
34
+ }
32
35
  // Create immutable translator snapshot
33
36
  return createTranslator({ config, locale, messages, handlers, plugins });
34
37
  }
@@ -17,40 +17,42 @@ import { getLocaleFromAcceptLanguage } from '../../routing/locale/get-locale-fro
17
17
  *
18
18
  * @platform Next.js
19
19
  */
20
- const createIntorHandler = async (config, request) => {
21
- const { host, searchParams, pathname: rawPathname } = request.nextUrl;
22
- // Locale from Accept-Language header
23
- const acceptLanguageHeader = request.headers.get("accept-language");
24
- const localeFromAcceptLanguage = getLocaleFromAcceptLanguage(acceptLanguageHeader, config.supportedLocales);
25
- // Check whether this navigation flow has already redirected
26
- const hasRedirected = request.headers.get(INTOR_HEADERS.REDIRECTED) === "1";
27
- // ----------------------------------------------------------
28
- // Resolve inbound routing decision (pure computation)
29
- // ----------------------------------------------------------
30
- const { locale, localeSource, pathname, shouldRedirect } = await resolveInbound(config, rawPathname, {
31
- host,
32
- query: normalizeQuery(Object.fromEntries(searchParams.entries())),
33
- cookie: request.cookies.get(config.cookie.name)?.value,
34
- detected: localeFromAcceptLanguage || config.defaultLocale,
35
- }, { hasRedirected });
36
- // ----------------------------------------------------------
37
- // Prepare Next.js response (redirect or pass-through)
38
- // ----------------------------------------------------------
39
- const url = request.nextUrl.clone();
40
- url.pathname = pathname;
41
- const response = shouldRedirect
42
- ? NextResponse.redirect(url)
43
- : NextResponse.next();
44
- // ----------------------------------------------------------
45
- // Attach routing metadata to response headers
46
- // ----------------------------------------------------------
47
- response.headers.set(INTOR_HEADERS.LOCALE, locale);
48
- response.headers.set(INTOR_HEADERS.LOCALE_SOURCE, localeSource);
49
- response.headers.set(INTOR_HEADERS.PATHNAME, pathname);
50
- // Mark redirect to prevent infinite loops in this flow
51
- if (shouldRedirect)
52
- response.headers.set(INTOR_HEADERS.REDIRECTED, "1");
53
- return response;
54
- };
20
+ function createIntorHandler(config) {
21
+ return async function intorHandler(request) {
22
+ const { host, searchParams, pathname: rawPathname } = request.nextUrl;
23
+ // Locale from Accept-Language header
24
+ const acceptLanguageHeader = request.headers.get("accept-language");
25
+ const localeFromAcceptLanguage = getLocaleFromAcceptLanguage(acceptLanguageHeader, config.supportedLocales);
26
+ // Check whether this navigation flow has already redirected
27
+ const hasRedirected = request.headers.get(INTOR_HEADERS.REDIRECTED) === "1";
28
+ // ----------------------------------------------------------
29
+ // Resolve inbound routing decision (pure computation)
30
+ // ----------------------------------------------------------
31
+ const { locale, localeSource, pathname, shouldRedirect } = await resolveInbound(config, rawPathname, {
32
+ host,
33
+ query: normalizeQuery(Object.fromEntries(searchParams.entries())),
34
+ cookie: request.cookies.get(config.cookie.name)?.value,
35
+ detected: localeFromAcceptLanguage || config.defaultLocale,
36
+ }, { hasRedirected });
37
+ // ----------------------------------------------------------
38
+ // Prepare Next.js response (redirect or pass-through)
39
+ // ----------------------------------------------------------
40
+ const url = request.nextUrl.clone();
41
+ url.pathname = pathname;
42
+ const response = shouldRedirect
43
+ ? NextResponse.redirect(url)
44
+ : NextResponse.next();
45
+ // ----------------------------------------------------------
46
+ // Attach routing metadata to response headers
47
+ // ----------------------------------------------------------
48
+ response.headers.set(INTOR_HEADERS.LOCALE, locale);
49
+ response.headers.set(INTOR_HEADERS.LOCALE_SOURCE, localeSource);
50
+ response.headers.set(INTOR_HEADERS.PATHNAME, pathname);
51
+ // Mark redirect to prevent infinite loops in this flow
52
+ if (shouldRedirect)
53
+ response.headers.set(INTOR_HEADERS.REDIRECTED, "1");
54
+ return response;
55
+ };
56
+ }
55
57
 
56
58
  export { createIntorHandler };
@@ -15,14 +15,15 @@ import { getLocale } from './get-locale.js';
15
15
  * @platform Next.js
16
16
  */
17
17
  async function getTranslator(config, params) {
18
- const { preKey, handlers, plugins, readers, allowCacheWrite } = params || {};
18
+ const { loader, readers, allowCacheWrite, handlers, plugins, preKey } = params || {};
19
19
  return getTranslator$1(config, {
20
20
  locale: await getLocale(config),
21
- preKey,
22
- handlers,
23
- plugins,
21
+ loader,
24
22
  readers,
25
23
  allowCacheWrite,
24
+ handlers,
25
+ plugins,
26
+ preKey,
26
27
  });
27
28
  }
28
29
 
@@ -9,14 +9,15 @@ import { initTranslator } from '../translator/init-translator.js';
9
9
  * Get a server-side translator for the current execution context.
10
10
  */
11
11
  async function getTranslator(config, params) {
12
- const { locale, readers, allowCacheWrite, fetch, preKey, handlers, plugins } = params;
12
+ const { locale, loader, readers, allowCacheWrite = false, fetch, handlers, plugins, preKey, } = params;
13
13
  // Initialize a locale-bound translator snapshot with messages loaded
14
14
  const translator = await initTranslator(config, locale, {
15
+ loader,
15
16
  readers,
16
17
  allowCacheWrite,
17
18
  fetch: fetch || globalThis.fetch,
18
- plugins,
19
19
  handlers,
20
+ plugins,
20
21
  });
21
22
  const scoped = translator.scoped(preKey);
22
23
  return {
@@ -15,11 +15,11 @@ import 'node:fs/promises';
15
15
  * - Creates an immutable Translator instance for server usage
16
16
  */
17
17
  async function initTranslator(config, locale, options) {
18
- const { readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
- const loader = resolveLoaderOptions(config, "server");
18
+ const { loader, readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
19
+ const loaderOptions = resolveLoaderOptions(config, "server");
20
20
  // Load messages
21
21
  let messages = {};
22
- if (loader) {
22
+ if (loaderOptions && !loader) {
23
23
  const loaded = await loadMessages({
24
24
  config,
25
25
  locale,
@@ -29,6 +29,9 @@ async function initTranslator(config, locale, options) {
29
29
  });
30
30
  messages = loaded || {};
31
31
  }
32
+ if (loader) {
33
+ messages = await loader(config, locale);
34
+ }
32
35
  // Create immutable translator snapshot
33
36
  return createTranslator({ config, locale, messages, handlers, plugins });
34
37
  }
@@ -1 +1 @@
1
- export { intor, type IntorValue, loadMessages, clearMessagesPool, getTranslator, } from "../../src/server";
1
+ export { intor, type IntorValue, clearMessagesPool, getTranslator, type MessagesLoader, } from "../../src/server";
@@ -1,5 +1,6 @@
1
1
  import type { IntorResolvedConfig } from "../../config";
2
2
  import type { NextRequest } from "next/server";
3
+ import { NextResponse } from "next/server";
3
4
  /**
4
5
  * Resolves locale-aware routing for the current execution context.
5
6
  *
@@ -9,4 +10,4 @@ import type { NextRequest } from "next/server";
9
10
  *
10
11
  * @platform Next.js
11
12
  */
12
- export declare const createIntorHandler: (config: IntorResolvedConfig, request: NextRequest) => Promise<Response>;
13
+ export declare function createIntorHandler(config: IntorResolvedConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
@@ -1,5 +1,4 @@
1
1
  import type { IntorValue } from "../provider";
2
2
  import type { IntorResolvedConfig } from "../../../config";
3
- import type { GenConfigKeys } from "../../../core";
4
3
  import type { Locale, LocaleMessages } from "intor-translator";
5
- export declare function useIntor<CK extends GenConfigKeys = "__default__">(config: IntorResolvedConfig, loader: (config: IntorResolvedConfig, locale: Locale) => Promise<LocaleMessages>): Omit<IntorValue<CK>, "handlers" | "plugins">;
4
+ export declare function useIntor(config: IntorResolvedConfig, loader: (config: IntorResolvedConfig, locale: Locale) => Promise<LocaleMessages>): Omit<IntorValue, "handlers" | "plugins">;
@@ -1,5 +1,4 @@
1
1
  import type { IntorContextValue, IntorProviderProps } from "./types";
2
- import type { GenConfigKeys } from "../../../core";
3
2
  import * as React from "react";
4
3
  export declare const IntorContext: React.Context<IntorContextValue | undefined>;
5
- export declare function IntorProvider<CK extends GenConfigKeys = "__default__">({ value: { config, locale: initialLocale, messages, handlers, plugins, onLocaleChange, isLoading: externalIsLoading, }, children, }: IntorProviderProps<CK>): import("react/jsx-runtime").JSX.Element;
4
+ export declare function IntorProvider({ value: { config, locale: initialLocale, messages, handlers, plugins, onLocaleChange, isLoading: externalIsLoading, }, children, }: IntorProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -1,24 +1,23 @@
1
1
  import type { IntorResolvedConfig } from "../../../config";
2
- import type { GenConfigKeys, GenLocale, GenMessages } from "../../../core";
3
- import type { TranslateHandlers, TranslateHook, TranslatorPlugin } from "intor-translator";
2
+ import type { Locale, LocaleMessages, TranslateHandlers, TranslateHook, TranslatorPlugin } from "intor-translator";
4
3
  import type { Translator } from "intor-translator";
5
4
  import type * as React from "react";
6
- export interface IntorValue<CK extends GenConfigKeys = "__default__"> {
5
+ export interface IntorValue {
7
6
  config: IntorResolvedConfig;
8
- locale: GenLocale<CK>;
9
- messages?: Readonly<GenMessages<CK>>;
7
+ locale: Locale;
8
+ messages?: Readonly<LocaleMessages>;
10
9
  isLoading?: boolean;
11
- onLocaleChange?: (newLocale: GenLocale<CK>) => Promise<void> | void;
10
+ onLocaleChange?: (newLocale: Locale) => Promise<void> | void;
12
11
  handlers?: TranslateHandlers;
13
12
  plugins?: (TranslatorPlugin | TranslateHook)[];
14
13
  }
15
- export interface IntorProviderProps<CK extends GenConfigKeys = "__default__"> {
16
- value: IntorValue<CK>;
14
+ export interface IntorProviderProps {
15
+ value: IntorValue;
17
16
  children: React.ReactNode;
18
17
  }
19
- export type IntorContextValue<CK extends GenConfigKeys = "__default__"> = {
18
+ export type IntorContextValue = {
20
19
  config: IntorResolvedConfig;
21
- locale: GenLocale<CK>;
22
- setLocale: (locale: GenLocale<CK>) => void;
20
+ locale: Locale;
21
+ setLocale: (locale: Locale) => void;
23
22
  translator: Translator<unknown>;
24
23
  };
@@ -1,3 +1,2 @@
1
1
  import type { IntorContextValue } from "./types";
2
- import type { GenConfigKeys } from "../../../core";
3
- export declare function useIntorContext<CK extends GenConfigKeys = "__default__">(): IntorContextValue<CK>;
2
+ export declare function useIntorContext(): IntorContextValue;
@@ -5,4 +5,4 @@ export { getLogger, clearLoggerPool } from "./logger";
5
5
  export { loadRemoteMessages, mergeMessages, isValidMessages, nestObjectFromPath, type MessagesReader, type MessagesReaders, INTOR_PREFIX, INTOR_MESSAGES_KIND_KEY, INTOR_MESSAGES_KIND, getMessagesKind, type IntorMessagesKind, } from "./messages";
6
6
  export { createHtmlRenderer, type TagRenderers, type HtmlTagRenderers, } from "./render";
7
7
  export { createTranslator, type CreateTranslatorParams, createTRich, } from "./translator";
8
- export type { INTOR_GENERATED_KEY, IfGen, GenConfigKeys, GenConfig, GenMessages, GenLocale, GenReplacements, GenRich, TranslatorInstance, RoutingLocaleSource, RoutingLocaleCarrier, LocalePathPrefix, RuntimeFetch, } from "./types";
8
+ export type { INTOR_GENERATED_KEY, GenConfigKeys, GenConfig, GenMessages, GenLocale, GenReplacements, GenRich, TranslatorInstance, RoutingLocaleSource, RoutingLocaleCarrier, LocalePathPrefix, RuntimeFetch, } from "./types";
@@ -1,41 +1,44 @@
1
1
  import type { PREFIX_PLACEHOLDER } from "../constants";
2
2
  import type { Locale, LocaleMessages, Replacement, Rich } from "intor-translator";
3
3
  /**
4
- * ================================================
5
- * Generated-aware type system for Intor.
6
- *
7
- * This module defines conditional and fallback types that adapt
8
- * based on whether generated types are present.
9
- * ================================================
4
+ * =================================================
5
+ * Generated-aware type system for Intor
6
+ * =================================================
10
7
  */
11
8
  /**
12
- * Internal sentinel key indicating that Intor generated types are present.
13
- * - Used by conditional types to switch between fallback and generated modes.
14
- * - Type-level only. Not for runtime or user-facing usage.
9
+ * Sentinel key injected by CLI when generated types exist.
10
+ * Used purely for type-level generation detection.
15
11
  */
16
12
  export type INTOR_GENERATED_KEY = "__intor_generated__";
17
13
  /**
18
- * Conditional type for generated types.
19
- * - Uses key presence on `IntorGeneratedTypes` to detect generation.
14
+ * Detect whether generated types are present.
20
15
  */
21
- export type IfGen<Then, Else = never> = IntorGeneratedTypes extends {
16
+ type HasGenerated = IntorGeneratedTypes extends {
22
17
  [K in INTOR_GENERATED_KEY]: true;
23
- } ? Then : Else;
18
+ } ? true : false;
24
19
  /**
25
- * Config keys provided by generated types.
26
- * - Excludes internal sentinel
20
+ * Extract valid configuration keys from generated types.
21
+ * (Excludes sentinel key.)
27
22
  */
28
23
  type GeneratedConfigKeys = Exclude<keyof IntorGeneratedTypes, INTOR_GENERATED_KEY>;
29
24
  /**
30
- * Union of all configuration keys.
31
- * - Defaults to `string` if `IntorGeneratedTypes` does not exist.
25
+ * Public configuration key union.
26
+ * Falls back to `string` in non-generated mode.
27
+ */
28
+ export type GenConfigKeys = HasGenerated extends true ? GeneratedConfigKeys : string;
29
+ /**
30
+ * Fallback configuration shape (non-generated mode).
32
31
  */
33
- export type GenConfigKeys = IfGen<GeneratedConfigKeys, string>;
32
+ type FallbackConfig = {
33
+ Locales: Locale;
34
+ Messages: LocaleMessages;
35
+ Replacements: Replacement;
36
+ Rich: Rich;
37
+ };
34
38
  /**
35
- * Configuration shape for a given config key.
36
- * - If `IntorGeneratedTypes` is not defined, falls back to default shape.
39
+ * Extract generated configuration shape safely.
37
40
  */
38
- export type GenConfig<CK extends GenConfigKeys> = IfGen<CK extends keyof IntorGeneratedTypes ? IntorGeneratedTypes[CK] extends {
41
+ type ExtractGeneratedConfig<T> = T extends {
39
42
  Locales: infer L extends string;
40
43
  Messages: Record<typeof PREFIX_PLACEHOLDER, infer M>;
41
44
  Replacements: infer RE;
@@ -45,18 +48,19 @@ export type GenConfig<CK extends GenConfigKeys> = IfGen<CK extends keyof IntorGe
45
48
  Messages: Record<L, M>;
46
49
  Replacements: RE;
47
50
  Rich: RI;
48
- } : never : never, {
49
- Locales: Locale;
50
- Messages: LocaleMessages;
51
- Replacements: Replacement;
52
- Rich: Rich;
53
- }>;
54
- /** Resolves message schema for a given config key */
51
+ } : never;
52
+ /**
53
+ * Configuration shape resolver.
54
+ *
55
+ * - Uses generated types when available.
56
+ * - Falls back to default shape otherwise.
57
+ */
58
+ export type GenConfig<CK extends GenConfigKeys> = HasGenerated extends true ? CK extends GeneratedConfigKeys ? ExtractGeneratedConfig<IntorGeneratedTypes[CK]> : never : FallbackConfig;
59
+ /**
60
+ * Derived helpers
61
+ */
55
62
  export type GenMessages<CK extends GenConfigKeys> = GenConfig<CK>["Messages"];
56
- /** Resolves locale union for a given config key */
57
63
  export type GenLocale<CK extends GenConfigKeys> = GenConfig<CK>["Locales"];
58
- /** Resolves replacement schema for a given config key */
59
64
  export type GenReplacements<CK extends GenConfigKeys> = GenConfig<CK>["Replacements"];
60
- /** Resolves rich tag schema for a given config key */
61
65
  export type GenRich<CK extends GenConfigKeys> = GenConfig<CK>["Rich"];
62
66
  export {};
@@ -1,4 +1,4 @@
1
- export type { INTOR_GENERATED_KEY, IfGen, GenConfigKeys, GenConfig, GenMessages, GenLocale, GenReplacements, GenRich, } from "./generated";
1
+ export type { INTOR_GENERATED_KEY, GenConfigKeys, GenConfig, GenMessages, GenLocale, GenReplacements, GenRich, } from "./generated";
2
2
  export type { TranslatorInstance } from "./translator-instance";
3
3
  export type { RoutingLocaleSource, RoutingLocaleCarrier, LocalePathPrefix, } from "./routing";
4
4
  export type { RuntimeFetch } from "./runtime-fetch";
@@ -1,8 +1,10 @@
1
1
  import type { IntorResolvedConfig } from "../../config";
2
2
  import type { LocalizedPreKey, TranslateHandlers, TranslateHook, TranslatorPlugin } from "intor-translator";
3
3
  import { type GenConfigKeys, type GenLocale, type GenMessages, type GenReplacements, type GenRich, type MessagesReaders, type RuntimeFetch, type TranslatorInstance } from "../../core";
4
+ import { type MessagesLoader } from "../translator";
4
5
  export interface GetTranslatorParams<CK extends GenConfigKeys = "__default__"> {
5
6
  locale: GenLocale<CK> | (string & {});
7
+ loader?: MessagesLoader;
6
8
  readers?: MessagesReaders;
7
9
  allowCacheWrite?: boolean;
8
10
  fetch?: RuntimeFetch;
@@ -1,3 +1,4 @@
1
1
  export { intor, type IntorValue } from "./intor";
2
- export { loadMessages, clearMessagesPool } from "./messages";
2
+ export { clearMessagesPool } from "./messages";
3
3
  export { getTranslator, type GetTranslatorParams } from "./helpers";
4
+ export type { MessagesLoader } from "./translator";
@@ -1 +1,2 @@
1
1
  export { initTranslator } from "../translator/init-translator";
2
+ export type { MessagesLoader } from "./types";
@@ -1,8 +1,10 @@
1
+ import type { MessagesLoader } from "./types";
1
2
  import type { IntorResolvedConfig } from "../../config";
2
3
  import type { Locale, Translator } from "intor-translator";
3
4
  import { type CreateTranslatorParams } from "../../core";
4
5
  import { type LoadMessagesParams } from "../messages";
5
6
  interface InitTranslatorOptions extends Pick<LoadMessagesParams, "readers" | "allowCacheWrite" | "fetch">, Pick<CreateTranslatorParams, "handlers" | "plugins"> {
7
+ loader?: MessagesLoader;
6
8
  }
7
9
  /**
8
10
  * Initialize a locale-bound Translator snapshot.
@@ -0,0 +1,9 @@
1
+ import type { IntorResolvedConfig } from "../../config";
2
+ import type { LocaleMessages } from "intor-translator";
3
+ /**
4
+ * Runtime message loader override.
5
+ *
6
+ * Loads locale messages imperatively at runtime, bypassing
7
+ * message loading defined in the Intor config.
8
+ */
9
+ export type MessagesLoader = (config: IntorResolvedConfig, locale: string) => Promise<LocaleMessages>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor",
3
- "version": "2.4.7",
3
+ "version": "2.4.9",
4
4
  "description": "The i18n library for modern JavaScript",
5
5
  "author": "Yiming Liao",
6
6
  "homepage": "https://github.com/yiming-liao/intor#readme",