intor 2.3.30 → 2.3.32

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 (148) hide show
  1. package/dist/core/export/index.js +1 -1
  2. package/dist/core/export/server/index.js +1 -1
  3. package/dist/core/src/config/resolvers/resolve-fallback-locales.js +1 -0
  4. package/dist/core/src/config/resolvers/resolve-routing-options.js +1 -0
  5. package/dist/core/src/config/validators/validate-default-locale.js +1 -0
  6. package/dist/core/src/config/validators/validate-id.js +1 -0
  7. package/dist/core/src/config/validators/validate-supported-locales.js +1 -0
  8. package/dist/{svelte/src/client/svelte/render/create-svelte-renderer.js → core/src/core/render/create-html-renderer.js} +6 -7
  9. package/dist/{svelte/src/client/svelte → core/src/core}/render/utils/render-attributes.js +7 -5
  10. package/dist/core/src/core/translator/create-t-rich.js +22 -0
  11. package/dist/core/src/routing/pathname/canonicalize-pathname.js +1 -0
  12. package/dist/core/src/routing/pathname/materialize-pathname.js +1 -0
  13. package/dist/core/src/routing/pathname/standardize-pathname.js +1 -0
  14. package/dist/core/src/server/helpers/get-translator.js +12 -3
  15. package/dist/core/src/server/intor/intor.js +1 -0
  16. package/dist/core/src/server/messages/load-local-messages/load-local-messages.js +1 -0
  17. package/dist/core/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +1 -0
  18. package/dist/core/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +1 -0
  19. package/dist/core/src/server/messages/load-messages.js +1 -0
  20. package/dist/core/src/server/translator/create-translator.js +5 -15
  21. package/dist/core/src/server/translator/init-translator.js +6 -12
  22. package/dist/express/src/adapters/express/helpers/get-translator.js +1 -1
  23. package/dist/express/src/adapters/express/middleware/create-intor-middleware.js +3 -10
  24. package/dist/express/src/core/render/create-html-renderer.js +44 -0
  25. package/dist/express/src/core/render/utils/escape-html.js +10 -0
  26. package/dist/express/src/core/render/utils/render-attributes.js +17 -0
  27. package/dist/express/src/core/translator/create-t-rich.js +22 -0
  28. package/dist/express/src/routing/inbound/resolve-locale/resolve-locale.js +1 -0
  29. package/dist/express/src/routing/locale/get-locale-from-pathname.js +1 -0
  30. package/dist/express/src/routing/pathname/canonicalize-pathname.js +1 -0
  31. package/dist/express/src/routing/pathname/materialize-pathname.js +1 -0
  32. package/dist/express/src/routing/pathname/standardize-pathname.js +1 -0
  33. package/dist/express/src/server/helpers/get-translator.js +12 -3
  34. package/dist/express/src/server/messages/load-local-messages/load-local-messages.js +1 -0
  35. package/dist/express/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +1 -0
  36. package/dist/express/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +1 -0
  37. package/dist/express/src/server/messages/load-messages.js +1 -0
  38. package/dist/express/src/server/translator/create-translator.js +5 -15
  39. package/dist/express/src/server/translator/init-translator.js +6 -12
  40. package/dist/next/src/adapters/next/navigation/link.js +1 -0
  41. package/dist/next/src/adapters/next/navigation/redirect.js +1 -0
  42. package/dist/next/src/adapters/next/navigation/use-router.js +1 -0
  43. package/dist/next/src/adapters/next/proxy/intor-proxy.js +2 -1
  44. package/dist/next/src/adapters/next/server/get-locale.js +1 -0
  45. package/dist/next/src/adapters/next/server/get-translator.js +1 -1
  46. package/dist/next/src/adapters/next/server/intor.js +1 -1
  47. package/dist/next/src/client/shared/navigation/execute-navigation.js +1 -0
  48. package/dist/next/src/core/render/create-html-renderer.js +44 -0
  49. package/dist/next/src/core/render/utils/escape-html.js +10 -0
  50. package/dist/next/src/core/render/utils/render-attributes.js +17 -0
  51. package/dist/next/src/core/translator/create-t-rich.js +22 -0
  52. package/dist/next/src/policies/shoud-full-reload.js +1 -0
  53. package/dist/next/src/routing/inbound/resolve-locale/resolve-locale.js +1 -0
  54. package/dist/next/src/routing/locale/get-locale-from-pathname.js +1 -0
  55. package/dist/next/src/routing/pathname/canonicalize-pathname.js +1 -0
  56. package/dist/next/src/routing/pathname/materialize-pathname.js +1 -0
  57. package/dist/next/src/routing/pathname/standardize-pathname.js +1 -0
  58. package/dist/next/src/server/helpers/get-translator.js +12 -3
  59. package/dist/next/src/server/intor/intor.js +1 -0
  60. package/dist/next/src/server/messages/load-local-messages/load-local-messages.js +1 -0
  61. package/dist/next/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +1 -0
  62. package/dist/next/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +1 -0
  63. package/dist/next/src/server/messages/load-messages.js +1 -0
  64. package/dist/next/src/server/translator/create-translator.js +5 -15
  65. package/dist/next/src/server/translator/init-translator.js +6 -12
  66. package/dist/react/src/client/react/helpers/use-intor.js +1 -0
  67. package/dist/react/src/client/react/provider/effects/use-locale-effects.js +1 -0
  68. package/dist/react/src/client/react/render/create-react-renderer.js +0 -1
  69. package/dist/react/src/client/react/translator/create-t-rich.js +7 -4
  70. package/dist/react/src/client/react/translator/use-translator.js +3 -3
  71. package/dist/react/src/client/shared/helpers/get-client-locale.js +1 -0
  72. package/dist/react/src/client/shared/messages/create-refetch-messages.js +1 -0
  73. package/dist/svelte/src/client/shared/helpers/get-client-locale.js +1 -0
  74. package/dist/svelte/src/client/shared/messages/create-refetch-messages.js +1 -0
  75. package/dist/svelte/src/client/svelte/provider/effects/locale-effects.js +1 -0
  76. package/dist/svelte/src/client/svelte/provider/intor-provider.svelte +7 -2
  77. package/dist/svelte/src/client/svelte/translator/use-translator.js +5 -7
  78. package/dist/svelte/src/core/render/create-html-renderer.js +44 -0
  79. package/dist/svelte/src/core/render/utils/escape-html.js +10 -0
  80. package/dist/svelte/src/core/render/utils/render-attributes.js +17 -0
  81. package/dist/svelte/src/core/translator/create-t-rich.js +22 -0
  82. package/dist/svelte-kit/src/adapters/svelte-kit/navigation/use-navigation.js +1 -0
  83. package/dist/svelte-kit/src/adapters/svelte-kit/server/create-intor-handle.js +26 -17
  84. package/dist/svelte-kit/src/adapters/svelte-kit/server/intor.js +1 -1
  85. package/dist/svelte-kit/src/adapters/svelte-kit/server/utils/is-svelte-kit-ssg.js +15 -0
  86. package/dist/svelte-kit/src/client/shared/navigation/execute-navigation.js +1 -0
  87. package/dist/svelte-kit/src/policies/shoud-full-reload.js +1 -0
  88. package/dist/svelte-kit/src/routing/inbound/resolve-locale/resolve-locale.js +1 -0
  89. package/dist/svelte-kit/src/routing/locale/get-locale-from-pathname.js +1 -0
  90. package/dist/svelte-kit/src/routing/pathname/canonicalize-pathname.js +1 -0
  91. package/dist/svelte-kit/src/routing/pathname/materialize-pathname.js +1 -0
  92. package/dist/svelte-kit/src/routing/pathname/standardize-pathname.js +1 -0
  93. package/dist/svelte-kit/src/server/intor/intor.js +1 -0
  94. package/dist/svelte-kit/src/server/messages/load-local-messages/load-local-messages.js +1 -0
  95. package/dist/svelte-kit/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +1 -0
  96. package/dist/svelte-kit/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +1 -0
  97. package/dist/svelte-kit/src/server/messages/load-messages.js +1 -0
  98. package/dist/svelte-kit/src/server/translator/create-translator.js +5 -15
  99. package/dist/svelte-kit/src/server/translator/init-translator.js +6 -12
  100. package/dist/types/export/internal/index.d.ts +1 -1
  101. package/dist/types/export/svelte/index.d.ts +1 -1
  102. package/dist/types/src/adapters/svelte-kit/server/utils/is-svelte-kit-ssg.d.ts +8 -0
  103. package/dist/types/src/client/react/render/index.d.ts +1 -1
  104. package/dist/types/src/client/react/render/types.d.ts +2 -6
  105. package/dist/types/src/client/react/translator/create-t-rich.d.ts +2 -2
  106. package/dist/types/src/client/react/translator/translator-instance.d.ts +1 -1
  107. package/dist/types/src/client/svelte/index.d.ts +1 -1
  108. package/dist/types/src/client/svelte/provider/index.d.ts +1 -0
  109. package/dist/types/src/client/svelte/provider/types.d.ts +4 -0
  110. package/dist/types/src/client/svelte/translator/translator-instance.d.ts +3 -4
  111. package/dist/types/src/client/vue/render/index.d.ts +1 -1
  112. package/dist/types/src/client/vue/render/types.d.ts +2 -6
  113. package/dist/types/src/client/vue/translator/create-t-rich.d.ts +2 -3
  114. package/dist/types/src/client/vue/translator/translator-instance.d.ts +1 -1
  115. package/dist/types/src/core/index.d.ts +2 -0
  116. package/dist/types/src/core/render/create-html-renderer.d.ts +11 -0
  117. package/dist/types/src/core/render/index.d.ts +2 -0
  118. package/dist/types/src/core/render/types.d.ts +10 -0
  119. package/dist/types/src/core/translator/create-t-rich.d.ts +12 -0
  120. package/dist/types/src/core/translator/index.d.ts +1 -0
  121. package/dist/types/src/server/helpers/get-translator.d.ts +4 -4
  122. package/dist/types/src/server/translator/create-translator.d.ts +5 -13
  123. package/dist/types/src/server/translator/init-translator.d.ts +6 -7
  124. package/dist/types/src/server/translator/translator-instance.d.ts +5 -3
  125. package/dist/vue/src/client/shared/helpers/get-client-locale.js +1 -0
  126. package/dist/vue/src/client/shared/messages/create-refetch-messages.js +1 -0
  127. package/dist/vue/src/client/vue/helpers/use-intor.js +1 -0
  128. package/dist/vue/src/client/vue/provider/effects/use-locale-effects.js +1 -0
  129. package/dist/vue/src/client/vue/render/create-vue-renderer.js +0 -1
  130. package/dist/vue/src/client/vue/translator/create-t-rich.js +6 -8
  131. package/dist/vue/src/client/vue/translator/use-translator.js +4 -6
  132. package/package.json +17 -17
  133. package/dist/express/src/core/constants/headers.js +0 -6
  134. package/dist/react/src/client/react/render/render-rich-message-react.js +0 -22
  135. package/dist/svelte/src/client/svelte/render/render-rich-message-svelte.js +0 -20
  136. package/dist/svelte/src/client/svelte/translator/create-t-rich.js +0 -23
  137. package/dist/svelte-kit/src/core/constants/headers.js +0 -6
  138. package/dist/types/src/client/react/render/render-rich-message-react.d.ts +0 -14
  139. package/dist/types/src/client/svelte/render/create-svelte-renderer.d.ts +0 -14
  140. package/dist/types/src/client/svelte/render/index.d.ts +0 -2
  141. package/dist/types/src/client/svelte/render/render-rich-message-svelte.d.ts +0 -12
  142. package/dist/types/src/client/svelte/render/types.d.ts +0 -8
  143. package/dist/types/src/client/svelte/translator/create-t-rich.d.ts +0 -15
  144. package/dist/types/src/client/vue/render/render-rich-message-vue.d.ts +0 -14
  145. package/dist/vue/src/client/vue/render/render-rich-message-vue.js +0 -19
  146. /package/dist/{svelte/src/client/svelte → core/src/core}/render/utils/escape-html.js +0 -0
  147. /package/dist/types/src/{client/svelte → core}/render/utils/escape-html.d.ts +0 -0
  148. /package/dist/types/src/{client/svelte → core}/render/utils/render-attributes.d.ts +0 -0
@@ -8,7 +8,7 @@ import 'p-limit';
8
8
  export { isValidMessages } from '../src/core/messages/utils/is-valid-messages.js';
9
9
  export { mergeMessages } from '../src/core/messages/merge-messages.js';
10
10
  export { INTOR_MESSAGES_KIND, INTOR_MESSAGES_KIND_KEY, INTOR_PREFIX, getMessagesKind } from '../src/core/messages/internal-metadata.js';
11
+ export { Translator, tokenize } from 'intor-translator';
11
12
  export { defineIntorConfig } from '../src/config/define-intor-config.js';
12
13
  import '../src/config/constants/cookie.js';
13
14
  export { localizePathname } from '../src/routing/pathname/localize-pathname.js';
14
- export { Translator, tokenize } from 'intor-translator';
@@ -4,7 +4,7 @@ import 'node:path';
4
4
  import 'p-limit';
5
5
  import '../../src/core/error/intor-error.js';
6
6
  import 'logry';
7
+ import 'intor-translator';
7
8
  export { clearMessagesPool } from '../../src/server/messages/load-local-messages/cache/messages-pool.js';
8
9
  import 'node:fs/promises';
9
- import 'intor-translator';
10
10
  export { getTranslator } from '../../src/server/helpers/get-translator.js';
@@ -1,6 +1,7 @@
1
1
  import '../../core/error/intor-error.js';
2
2
  import { getLogger } from '../../core/logger/get-logger.js';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
 
5
6
  /**
6
7
  * Resolves fallbackLocales into a runtime-safe mapping.
@@ -2,6 +2,7 @@ import '../../core/error/intor-error.js';
2
2
  import { deepMerge } from '../../core/utils/deep-merge.js';
3
3
  import 'logry';
4
4
  import 'p-limit';
5
+ import 'intor-translator';
5
6
  import { DEFAULT_ROUTING_OPTIONS } from '../constants/routing.js';
6
7
  import '../constants/cookie.js';
7
8
 
@@ -1,6 +1,7 @@
1
1
  import { IntorError, IntorErrorCode } from '../../core/error/intor-error.js';
2
2
  import 'logry';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
 
5
6
  /**
6
7
  * Validates that the configured defaultLocale is supported.
@@ -1,6 +1,7 @@
1
1
  import { IntorError, IntorErrorCode } from '../../core/error/intor-error.js';
2
2
  import 'logry';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
 
5
6
  /**
6
7
  * Validates that the given id is a non-empty string.
@@ -1,6 +1,7 @@
1
1
  import { IntorError, IntorErrorCode } from '../../core/error/intor-error.js';
2
2
  import 'logry';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
 
5
6
  /**
6
7
  * Validates that supportedLocales is provided and non-empty.
@@ -2,15 +2,14 @@ import { escapeHtml } from './utils/escape-html.js';
2
2
  import { renderAttributes } from './utils/render-attributes.js';
3
3
 
4
4
  /**
5
- * Create a Svelte renderer for semantic rich messages.
5
+ * Create an HTML string renderer for semantic rich messages.
6
6
  *
7
- * - Transforms semantic AST nodes into HTML strings.
8
- * - Intended to be used with {@html ...} in Svelte templates.
7
+ * - Transforms semantic rich AST nodes into escaped HTML strings.
8
+ * - Can be used in any HTML-based environment.
9
9
  *
10
10
  * This renderer is intentionally minimal and stateless.
11
11
  */
12
- const createSvelteRenderer = (options) => {
13
- const { tagRenderers } = options ?? {};
12
+ const createHtmlRenderer = (tagRenderers) => {
14
13
  return {
15
14
  /** Render plain text nodes */
16
15
  text(value) {
@@ -37,9 +36,9 @@ const createSvelteRenderer = (options) => {
37
36
  if (Array.isArray(value)) {
38
37
  return value.map((v) => escapeHtml(String(v))).join("");
39
38
  }
40
- throw new Error("[intor] Svelte renderer cannot render raw non-string values. ");
39
+ throw new Error("[intor] HTML renderer cannot render raw non-primitive values.");
41
40
  },
42
41
  };
43
42
  };
44
43
 
45
- export { createSvelteRenderer };
44
+ export { createHtmlRenderer };
@@ -4,11 +4,13 @@ function renderAttributes(attributes) {
4
4
  if (!attributes)
5
5
  return "";
6
6
  return Object.entries(attributes)
7
- .map(([key, value]) => value === true
8
- ? ` ${key}`
9
- : value != null
10
- ? ` ${key}="${escapeHtml(String(value))}"`
11
- : "")
7
+ .map(([key, value]) => {
8
+ if (value === true)
9
+ return ` ${key}`;
10
+ if (value == null)
11
+ return "";
12
+ return ` ${key}="${escapeHtml(String(value))}"`;
13
+ })
12
14
  .join("");
13
15
  }
14
16
 
@@ -0,0 +1,22 @@
1
+ import { renderRichMessage } from 'intor-translator';
2
+ import { createHtmlRenderer } from '../render/create-html-renderer.js';
3
+
4
+ /**
5
+ * Create an HTML-string rich translation function.
6
+ *
7
+ * - Resolves translated messages via `translator.t`
8
+ * - Renders semantic rich tags into escaped HTML strings
9
+ * - Supports optional scoped keys via `preKey`
10
+ *
11
+ * Can be used in any HTML-based environment (Astro, Svelte, SSR, etc.).
12
+ */
13
+ const createTRich = (t) => {
14
+ return (key, tagRenderers, replacements) => {
15
+ const message = t(key, replacements);
16
+ const renderer = createHtmlRenderer(tagRenderers);
17
+ const nodes = renderRichMessage(message, renderer);
18
+ return nodes.join("");
19
+ };
20
+ };
21
+
22
+ export { createTRich };
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Returns a canonical, locale-agnostic pathname.
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Materializes a standardized pathname by applying
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Standardizes a canonical pathname into an internal routing template
@@ -1,3 +1,7 @@
1
+ import '../../core/error/intor-error.js';
2
+ import 'logry';
3
+ import 'p-limit';
4
+ import { createTRich } from '../../core/translator/create-t-rich.js';
1
5
  import { initTranslator } from '../translator/init-translator.js';
2
6
 
3
7
  // Implementation
@@ -8,15 +12,20 @@ async function getTranslator(config, params) {
8
12
  readers,
9
13
  allowCacheWrite,
10
14
  fetch: fetch || globalThis.fetch,
11
- preKey,
12
15
  plugins,
13
16
  handlers,
14
17
  });
18
+ const scoped = translator.scoped(preKey);
15
19
  return {
16
20
  messages: translator.messages,
17
21
  locale: translator.locale,
18
- hasKey: translator.hasKey,
19
- t: translator.t,
22
+ hasKey: scoped.hasKey,
23
+ t: scoped.t,
24
+ tRich: createTRich(scoped.t),
25
+ // NOTE:
26
+ // The runtime implementation is intentionally erased.
27
+ // Type safety is guaranteed by public type contracts.
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
29
  };
21
30
  }
22
31
 
@@ -1,6 +1,7 @@
1
1
  import '../../core/error/intor-error.js';
2
2
  import { getLogger } from '../../core/logger/get-logger.js';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
  import { initTranslator } from '../translator/init-translator.js';
5
6
 
6
7
  /**
@@ -3,6 +3,7 @@ import pLimit from 'p-limit';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import { normalizeCacheKey } from '../../../core/utils/normalizers/normalize-cache-key.js';
5
5
  import { getLogger } from '../../../core/logger/get-logger.js';
6
+ import 'intor-translator';
6
7
  import { getMessagesPool } from './cache/messages-pool.js';
7
8
  import { readLocaleMessages } from './read-locale-messages/read-locale-messages.js';
8
9
 
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import '../../../../../core/error/intor-error.js';
4
4
  import { getLogger } from '../../../../../core/logger/get-logger.js';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Recursively collects message file metadata under a given locale root.
@@ -5,6 +5,7 @@ import { getLogger } from '../../../../../core/logger/get-logger.js';
5
5
  import 'p-limit';
6
6
  import { isValidMessages } from '../../../../../core/messages/utils/is-valid-messages.js';
7
7
  import { nestObjectFromPath } from '../../../../../core/messages/utils/nest-object-from-path.js';
8
+ import 'intor-translator';
8
9
  import { jsonReader } from './utils/json-reader.js';
9
10
 
10
11
  /**
@@ -2,6 +2,7 @@ import '../../core/error/intor-error.js';
2
2
  import { resolveLoaderOptions } from '../../core/utils/resolve-loader-options.js';
3
3
  import { getLogger } from '../../core/logger/get-logger.js';
4
4
  import { loadRemoteMessages } from '../../core/messages/load-remote-messages/load-remote-messages.js';
5
+ import 'intor-translator';
5
6
  import { loadLocalMessages } from './load-local-messages/load-local-messages.js';
6
7
 
7
8
  /**
@@ -2,17 +2,14 @@ import { Translator } from 'intor-translator';
2
2
  import { mergeMessages } from '../../core/messages/merge-messages.js';
3
3
 
4
4
  /**
5
- * Create a server-side translator snapshot.
5
+ * Create a server-side Translator instance for a fixed locale.
6
6
  *
7
7
  * - Merges static config messages with runtime-loaded messages
8
- * - Creates a Translator instance for a fixed locale
9
- * - Optionally scopes the translator with a preKey
10
- *
11
- * The returned object is a read-only translation view
12
- * and does not expose the underlying Translator instance.
8
+ * - Initializes a Translator bound to a specific locale
9
+ * - Injects fallback rules, handlers, and plugins from config
13
10
  */
14
11
  function createTranslator(params) {
15
- const { config, locale, messages, preKey, handlers, plugins } = params;
12
+ const { config, locale, messages, handlers, plugins } = params;
16
13
  // Merge static config messages with runtime-loaded messages
17
14
  const finalMessages = mergeMessages(config.messages, messages, {
18
15
  config,
@@ -27,14 +24,7 @@ function createTranslator(params) {
27
24
  handlers,
28
25
  plugins,
29
26
  });
30
- // Apply scoped view when preKey is provided
31
- const scoped = preKey ? translator.scoped(preKey) : null;
32
- return {
33
- messages: finalMessages,
34
- locale,
35
- hasKey: scoped ? scoped.hasKey : translator.hasKey,
36
- t: scoped ? scoped.t : translator.t,
37
- };
27
+ return translator;
38
28
  }
39
29
 
40
30
  export { createTranslator };
@@ -2,19 +2,20 @@ import '../../core/error/intor-error.js';
2
2
  import { resolveLoaderOptions } from '../../core/utils/resolve-loader-options.js';
3
3
  import 'logry';
4
4
  import 'p-limit';
5
+ import 'intor-translator';
5
6
  import { loadMessages } from '../messages/load-messages.js';
6
7
  import 'node:path';
7
8
  import 'node:fs/promises';
8
9
  import { createTranslator } from './create-translator.js';
9
10
 
10
11
  /**
11
- * Initializes a server-side translator for a specific locale.
12
+ * Initialize a locale-bound Translator snapshot.
12
13
  *
13
- * - Performs message loading during initialization.
14
- * - Returns an immutable translator snapshot.
14
+ * - Resolves loader options and loads messages if configured
15
+ * - Creates an immutable Translator instance for server usage
15
16
  */
16
17
  async function initTranslator(config, locale, options) {
17
- const { readers, allowCacheWrite = false, fetch, preKey, handlers, plugins, } = options;
18
+ const { readers, allowCacheWrite = false, fetch, handlers, plugins, } = options;
18
19
  const loader = resolveLoaderOptions(config, "server");
19
20
  // Load messages
20
21
  let messages = {};
@@ -29,14 +30,7 @@ async function initTranslator(config, locale, options) {
29
30
  messages = loaded || {};
30
31
  }
31
32
  // Create immutable translator snapshot
32
- return createTranslator({
33
- config,
34
- locale,
35
- messages,
36
- preKey,
37
- handlers,
38
- plugins,
39
- });
33
+ return createTranslator({ config, locale, messages, handlers, plugins });
40
34
  }
41
35
 
42
36
  export { initTranslator };
@@ -1,9 +1,9 @@
1
1
  import '../../../core/error/intor-error.js';
2
2
  import 'logry';
3
3
  import 'p-limit';
4
+ import 'intor-translator';
4
5
  import 'node:path';
5
6
  import 'node:fs/promises';
6
- import 'intor-translator';
7
7
  import { getTranslator as getTranslator$1 } from '../../../server/helpers/get-translator.js';
8
8
 
9
9
  // Implementation
@@ -1,13 +1,12 @@
1
- import { INTOR_HEADERS } from '../../../core/constants/headers.js';
2
1
  import '../../../core/error/intor-error.js';
3
2
  import { normalizeQuery } from '../../../core/utils/normalizers/normalize-query.js';
4
3
  import 'logry';
5
4
  import 'p-limit';
5
+ import 'intor-translator';
6
6
  import { resolveInbound } from '../../../routing/inbound/resolve-inbound.js';
7
7
  import { getLocaleFromAcceptLanguage } from '../../../routing/locale/get-locale-from-accept-language.js';
8
8
  import 'node:path';
9
9
  import 'node:fs/promises';
10
- import 'intor-translator';
11
10
  import { getTranslator } from '../../../server/helpers/get-translator.js';
12
11
  import { parseCookieHeader } from '../../../server/shared/utils/parse-cookie-header.js';
13
12
 
@@ -23,7 +22,7 @@ import { parseCookieHeader } from '../../../server/shared/utils/parse-cookie-hea
23
22
  */
24
23
  function createIntorMiddleware(config, options) {
25
24
  return async function intorMiddleware(req, _res, next) {
26
- // locale from accept-language header
25
+ // Locale from Accept-Language header
27
26
  const acceptLanguage = req.headers["accept-language"];
28
27
  const localeFromAcceptLanguage = getLocaleFromAcceptLanguage(acceptLanguage, config.supportedLocales);
29
28
  // ----------------------------------------------------------
@@ -36,14 +35,9 @@ function createIntorMiddleware(config, options) {
36
35
  detected: localeFromAcceptLanguage || config.defaultLocale,
37
36
  });
38
37
  // --------------------------------------------------
39
- // Attach routing metadata to response headers
40
- // --------------------------------------------------
41
- req.headers[INTOR_HEADERS.LOCALE] = locale;
42
- req.headers[INTOR_HEADERS.LOCALE_SOURCE] = localeSource;
43
- req.headers[INTOR_HEADERS.PATHNAME] = pathname;
44
- // --------------------------------------------------
45
38
  // Bind inbound routing context
46
39
  // --------------------------------------------------
40
+ req.intor = { locale, localeSource, pathname };
47
41
  const { hasKey, t } = (await getTranslator(config, {
48
42
  locale,
49
43
  handlers: options?.handlers,
@@ -51,7 +45,6 @@ function createIntorMiddleware(config, options) {
51
45
  readers: options?.readers,
52
46
  allowCacheWrite: true,
53
47
  }));
54
- req.intor = { locale, localeSource, pathname };
55
48
  // DX shortcuts (optional)
56
49
  req.locale = locale;
57
50
  req.hasKey = hasKey;
@@ -0,0 +1,44 @@
1
+ import { escapeHtml } from './utils/escape-html.js';
2
+ import { renderAttributes } from './utils/render-attributes.js';
3
+
4
+ /**
5
+ * Create an HTML string renderer for semantic rich messages.
6
+ *
7
+ * - Transforms semantic rich AST nodes into escaped HTML strings.
8
+ * - Can be used in any HTML-based environment.
9
+ *
10
+ * This renderer is intentionally minimal and stateless.
11
+ */
12
+ const createHtmlRenderer = (tagRenderers) => {
13
+ return {
14
+ /** Render plain text nodes */
15
+ text(value) {
16
+ return escapeHtml(value);
17
+ },
18
+ /** Render semantic tag nodes */
19
+ tag(name, attributes, children) {
20
+ const tagRenderer = tagRenderers?.[name];
21
+ if (tagRenderer) {
22
+ return typeof tagRenderer === "function"
23
+ ? tagRenderer(children)
24
+ : tagRenderer;
25
+ }
26
+ // Default behavior: render as native HTML tag
27
+ return `<${name}${renderAttributes(attributes)}>${children.join("")}</${name}>`;
28
+ },
29
+ /** Render raw (non-tokenized) message values as escaped HTML strings */
30
+ raw(value) {
31
+ if (value == null)
32
+ return "";
33
+ if (typeof value === "string" || typeof value === "number") {
34
+ return escapeHtml(String(value));
35
+ }
36
+ if (Array.isArray(value)) {
37
+ return value.map((v) => escapeHtml(String(v))).join("");
38
+ }
39
+ throw new Error("[intor] HTML renderer cannot render raw non-primitive values.");
40
+ },
41
+ };
42
+ };
43
+
44
+ export { createHtmlRenderer };
@@ -0,0 +1,10 @@
1
+ function escapeHtml(value) {
2
+ return value
3
+ .replaceAll("&", "&amp;")
4
+ .replaceAll("<", "&lt;")
5
+ .replaceAll(">", "&gt;")
6
+ .replaceAll('"', "&quot;")
7
+ .replaceAll("'", "&#39;");
8
+ }
9
+
10
+ export { escapeHtml };
@@ -0,0 +1,17 @@
1
+ import { escapeHtml } from './escape-html.js';
2
+
3
+ function renderAttributes(attributes) {
4
+ if (!attributes)
5
+ return "";
6
+ return Object.entries(attributes)
7
+ .map(([key, value]) => {
8
+ if (value === true)
9
+ return ` ${key}`;
10
+ if (value == null)
11
+ return "";
12
+ return ` ${key}="${escapeHtml(String(value))}"`;
13
+ })
14
+ .join("");
15
+ }
16
+
17
+ export { renderAttributes };
@@ -0,0 +1,22 @@
1
+ import { renderRichMessage } from 'intor-translator';
2
+ import { createHtmlRenderer } from '../render/create-html-renderer.js';
3
+
4
+ /**
5
+ * Create an HTML-string rich translation function.
6
+ *
7
+ * - Resolves translated messages via `translator.t`
8
+ * - Renders semantic rich tags into escaped HTML strings
9
+ * - Supports optional scoped keys via `preKey`
10
+ *
11
+ * Can be used in any HTML-based environment (Astro, Svelte, SSR, etc.).
12
+ */
13
+ const createTRich = (t) => {
14
+ return (key, tagRenderers, replacements) => {
15
+ const message = t(key, replacements);
16
+ const renderer = createHtmlRenderer(tagRenderers);
17
+ const nodes = renderRichMessage(message, renderer);
18
+ return nodes.join("");
19
+ };
20
+ };
21
+
22
+ export { createTRich };
@@ -2,6 +2,7 @@ import '../../../core/error/intor-error.js';
2
2
  import { normalizeLocale } from '../../../core/utils/normalizers/normalize-locale.js';
3
3
  import 'logry';
4
4
  import 'p-limit';
5
+ import 'intor-translator';
5
6
 
6
7
  /**
7
8
  * Resolve the active locale from inbound routing configuration.
@@ -2,6 +2,7 @@ import '../../core/error/intor-error.js';
2
2
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
3
3
  import 'logry';
4
4
  import 'p-limit';
5
+ import 'intor-translator';
5
6
 
6
7
  /**
7
8
  * Get locale from pathname.
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Returns a canonical, locale-agnostic pathname.
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Materializes a standardized pathname by applying
@@ -3,6 +3,7 @@ import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Standardizes a canonical pathname into an internal routing template
@@ -1,3 +1,7 @@
1
+ import '../../core/error/intor-error.js';
2
+ import 'logry';
3
+ import 'p-limit';
4
+ import { createTRich } from '../../core/translator/create-t-rich.js';
1
5
  import { initTranslator } from '../translator/init-translator.js';
2
6
 
3
7
  // Implementation
@@ -8,15 +12,20 @@ async function getTranslator(config, params) {
8
12
  readers,
9
13
  allowCacheWrite,
10
14
  fetch: fetch || globalThis.fetch,
11
- preKey,
12
15
  plugins,
13
16
  handlers,
14
17
  });
18
+ const scoped = translator.scoped(preKey);
15
19
  return {
16
20
  messages: translator.messages,
17
21
  locale: translator.locale,
18
- hasKey: translator.hasKey,
19
- t: translator.t,
22
+ hasKey: scoped.hasKey,
23
+ t: scoped.t,
24
+ tRich: createTRich(scoped.t),
25
+ // NOTE:
26
+ // The runtime implementation is intentionally erased.
27
+ // Type safety is guaranteed by public type contracts.
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
29
  };
21
30
  }
22
31
 
@@ -3,6 +3,7 @@ import pLimit from 'p-limit';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import { normalizeCacheKey } from '../../../core/utils/normalizers/normalize-cache-key.js';
5
5
  import { getLogger } from '../../../core/logger/get-logger.js';
6
+ import 'intor-translator';
6
7
  import { getMessagesPool } from './cache/messages-pool.js';
7
8
  import { readLocaleMessages } from './read-locale-messages/read-locale-messages.js';
8
9
 
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import '../../../../../core/error/intor-error.js';
4
4
  import { getLogger } from '../../../../../core/logger/get-logger.js';
5
5
  import 'p-limit';
6
+ import 'intor-translator';
6
7
 
7
8
  /**
8
9
  * Recursively collects message file metadata under a given locale root.
@@ -5,6 +5,7 @@ import { getLogger } from '../../../../../core/logger/get-logger.js';
5
5
  import 'p-limit';
6
6
  import { isValidMessages } from '../../../../../core/messages/utils/is-valid-messages.js';
7
7
  import { nestObjectFromPath } from '../../../../../core/messages/utils/nest-object-from-path.js';
8
+ import 'intor-translator';
8
9
  import { jsonReader } from './utils/json-reader.js';
9
10
 
10
11
  /**
@@ -2,6 +2,7 @@ import '../../core/error/intor-error.js';
2
2
  import { resolveLoaderOptions } from '../../core/utils/resolve-loader-options.js';
3
3
  import { getLogger } from '../../core/logger/get-logger.js';
4
4
  import { loadRemoteMessages } from '../../core/messages/load-remote-messages/load-remote-messages.js';
5
+ import 'intor-translator';
5
6
  import { loadLocalMessages } from './load-local-messages/load-local-messages.js';
6
7
 
7
8
  /**
@@ -2,17 +2,14 @@ import { Translator } from 'intor-translator';
2
2
  import { mergeMessages } from '../../core/messages/merge-messages.js';
3
3
 
4
4
  /**
5
- * Create a server-side translator snapshot.
5
+ * Create a server-side Translator instance for a fixed locale.
6
6
  *
7
7
  * - Merges static config messages with runtime-loaded messages
8
- * - Creates a Translator instance for a fixed locale
9
- * - Optionally scopes the translator with a preKey
10
- *
11
- * The returned object is a read-only translation view
12
- * and does not expose the underlying Translator instance.
8
+ * - Initializes a Translator bound to a specific locale
9
+ * - Injects fallback rules, handlers, and plugins from config
13
10
  */
14
11
  function createTranslator(params) {
15
- const { config, locale, messages, preKey, handlers, plugins } = params;
12
+ const { config, locale, messages, handlers, plugins } = params;
16
13
  // Merge static config messages with runtime-loaded messages
17
14
  const finalMessages = mergeMessages(config.messages, messages, {
18
15
  config,
@@ -27,14 +24,7 @@ function createTranslator(params) {
27
24
  handlers,
28
25
  plugins,
29
26
  });
30
- // Apply scoped view when preKey is provided
31
- const scoped = preKey ? translator.scoped(preKey) : null;
32
- return {
33
- messages: finalMessages,
34
- locale,
35
- hasKey: scoped ? scoped.hasKey : translator.hasKey,
36
- t: scoped ? scoped.t : translator.t,
37
- };
27
+ return translator;
38
28
  }
39
29
 
40
30
  export { createTranslator };