intor-translator 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,6 +64,8 @@ translator.t("hello"); // -> Hello World
64
64
  translator.t("greeting", { name: "John doe" }); // -> Hello, John doe!
65
65
  ```
66
66
 
67
+ ---
68
+
67
69
  ## Handlers & Hooks
68
70
 
69
71
  Intor Translator is powered by **a flexible pipeline** that lets you control how translations behave and how they are rendered.
@@ -94,5 +96,16 @@ Hooks run through the pipeline and can intercept any stage, use them to:
94
96
 
95
97
  ---
96
98
 
99
+ # Rich Message Processing
100
+
101
+ This module provides a semantic message processing flow for **_translated rich-formatted strings_**.
102
+
103
+ - Tokenize → AST → renderer-driven output
104
+ - Environment-agnostic by design
105
+
106
+ Read the documentation: [Message Processing ↗](https://github.com/yiming-liao/intor-translator/tree/main/src/message)
107
+
108
+ ---
109
+
97
110
  **_For more advanced usage, see the full examples._**
98
111
  [View examples ↗](https://github.com/yiming-liao/intor-translator/tree/main/examples)
package/dist/index.cjs CHANGED
@@ -340,9 +340,9 @@ var ScopeTranslator = class extends CoreTranslator {
340
340
  }
341
341
  };
342
342
 
343
- // src/message/tokenize/parse-attributes.ts
343
+ // src/message/tokenize/utils/extract-attributes.ts
344
344
  var ATTR_REGEX = /\s+([a-zA-Z_][a-zA-Z0-9_]*)="([^"]*)"/g;
345
- var parseAttributes = (input) => {
345
+ var extractAttributes = (input) => {
346
346
  const attributes = {};
347
347
  let match;
348
348
  let consumed = "";
@@ -379,7 +379,7 @@ var tokenize = (message) => {
379
379
  const openMatch = message.slice(pos).match(OPEN_TAG_REGEX);
380
380
  if (openMatch) {
381
381
  const [, name, rawAttributes] = openMatch;
382
- const attributes = parseAttributes(rawAttributes);
382
+ const attributes = extractAttributes(rawAttributes);
383
383
  if (attributes) {
384
384
  flushText();
385
385
  tokens.push({
@@ -411,7 +411,7 @@ var tokenize = (message) => {
411
411
  return tokens;
412
412
  };
413
413
 
414
- // src/message/build-ast/build-ast.ts
414
+ // src/message/ast/build-ast.ts
415
415
  function buildAST(tokens) {
416
416
  const root = [];
417
417
  const stack = [];
@@ -466,5 +466,23 @@ function parseRichMessage(message) {
466
466
  return buildAST(tokens);
467
467
  }
468
468
 
469
+ // src/message/render/render.ts
470
+ function render(nodes, renderer) {
471
+ return nodes.map((node) => {
472
+ if (node.type === "text") {
473
+ return renderer.text(node.value);
474
+ }
475
+ const children = render(node.children, renderer);
476
+ return renderer.tag(node.name, node.attributes, children);
477
+ });
478
+ }
479
+
480
+ // src/message/render-rich-message.ts
481
+ function renderRichMessage(message, renderer) {
482
+ const nodes = parseRichMessage(message);
483
+ return render(nodes, renderer);
484
+ }
485
+
469
486
  exports.Translator = ScopeTranslator;
470
487
  exports.parseRichMessage = parseRichMessage;
488
+ exports.renderRichMessage = renderRichMessage;
package/dist/index.d.cts CHANGED
@@ -430,7 +430,7 @@ declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown, L ex
430
430
  scoped<PK extends LocalizedNodeKeys<M, L> | undefined = undefined>(preKey?: PK): PK extends string ? ScopeTranslatorMethods<M, L, ScopedLeafKeys<M, PK, L>> : ScopeTranslatorMethods<M, L>;
431
431
  }
432
432
 
433
- /** Parsed tag attributes map. */
433
+ /** Semantic tag attributes map. */
434
434
  type Attributes = Record<string, string>;
435
435
 
436
436
  /** Semantic node produced by the AST builder. */
@@ -451,16 +451,49 @@ interface TagNode {
451
451
  /**
452
452
  * Parse a rich-formatted message string into a semantic AST.
453
453
  *
454
- * This is the high-level entry point for processing translated messages
455
- * that contain semantic tags (e.g. <b>, <a>, <i>).
454
+ * This function is a high-level entry point for processing translated
455
+ * messages that contain semantic tags (e.g. <b>, <a>, <i>).
456
456
  *
457
- * Internally, this function:
458
- * - Tokenizes the input string into semantic tokens
459
- * - Builds a nested AST from the token stream
457
+ * Internally, it performs the following steps:
460
458
  *
461
- * Consumers should treat the returned AST as a semantic structure
462
- * suitable for rendering or further processing.
459
+ * - message (string)
460
+ * - tokenize
461
+ * - build AST
462
+ *
463
+ * The returned AST represents the semantic structure of the message
464
+ * and is intended to be consumed by renderers or further processing stages.
463
465
  */
464
466
  declare function parseRichMessage(message: string): ASTNode[];
465
467
 
466
- export { type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MissingHandler, type NestedMessage, type NodeKeys, type Replacement, type ScopedLeafKeys, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage };
468
+ /**
469
+ * Renderer interface for semantic message ASTs.
470
+ *
471
+ * A renderer defines how semantic nodes are transformed into a concrete output
472
+ * representation (e.g. string, DOM nodes, React elements).
473
+ *
474
+ * This interface is stateless by design.
475
+ * All rendering behavior is expressed through implementation.
476
+ */
477
+ interface Renderer<Output> {
478
+ /** Render a plain text node. */
479
+ text(value: string): Output;
480
+ /** Render a semantic tag node with attributes and rendered children. */
481
+ tag(name: string, attributes: Attributes, children: Output[]): Output;
482
+ }
483
+
484
+ /**
485
+ * Render a rich-formatted message into a concrete output using a renderer.
486
+ *
487
+ * This function orchestrates the full rich message pipeline:
488
+ *
489
+ * - message (string) ⬇
490
+ * - tokenize
491
+ * - build AST
492
+ * - render via provided renderer
493
+ *
494
+ * All rendering behavior is defined by the given renderer, making this
495
+ * function environment-agnostic (string, DOM, React, etc.).
496
+ */
497
+ declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
498
+
499
+ export { type ASTNode, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MissingHandler, type NestedMessage, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage, renderRichMessage };
package/dist/index.d.ts CHANGED
@@ -430,7 +430,7 @@ declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown, L ex
430
430
  scoped<PK extends LocalizedNodeKeys<M, L> | undefined = undefined>(preKey?: PK): PK extends string ? ScopeTranslatorMethods<M, L, ScopedLeafKeys<M, PK, L>> : ScopeTranslatorMethods<M, L>;
431
431
  }
432
432
 
433
- /** Parsed tag attributes map. */
433
+ /** Semantic tag attributes map. */
434
434
  type Attributes = Record<string, string>;
435
435
 
436
436
  /** Semantic node produced by the AST builder. */
@@ -451,16 +451,49 @@ interface TagNode {
451
451
  /**
452
452
  * Parse a rich-formatted message string into a semantic AST.
453
453
  *
454
- * This is the high-level entry point for processing translated messages
455
- * that contain semantic tags (e.g. <b>, <a>, <i>).
454
+ * This function is a high-level entry point for processing translated
455
+ * messages that contain semantic tags (e.g. <b>, <a>, <i>).
456
456
  *
457
- * Internally, this function:
458
- * - Tokenizes the input string into semantic tokens
459
- * - Builds a nested AST from the token stream
457
+ * Internally, it performs the following steps:
460
458
  *
461
- * Consumers should treat the returned AST as a semantic structure
462
- * suitable for rendering or further processing.
459
+ * - message (string)
460
+ * - tokenize
461
+ * - build AST
462
+ *
463
+ * The returned AST represents the semantic structure of the message
464
+ * and is intended to be consumed by renderers or further processing stages.
463
465
  */
464
466
  declare function parseRichMessage(message: string): ASTNode[];
465
467
 
466
- export { type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MissingHandler, type NestedMessage, type NodeKeys, type Replacement, type ScopedLeafKeys, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage };
468
+ /**
469
+ * Renderer interface for semantic message ASTs.
470
+ *
471
+ * A renderer defines how semantic nodes are transformed into a concrete output
472
+ * representation (e.g. string, DOM nodes, React elements).
473
+ *
474
+ * This interface is stateless by design.
475
+ * All rendering behavior is expressed through implementation.
476
+ */
477
+ interface Renderer<Output> {
478
+ /** Render a plain text node. */
479
+ text(value: string): Output;
480
+ /** Render a semantic tag node with attributes and rendered children. */
481
+ tag(name: string, attributes: Attributes, children: Output[]): Output;
482
+ }
483
+
484
+ /**
485
+ * Render a rich-formatted message into a concrete output using a renderer.
486
+ *
487
+ * This function orchestrates the full rich message pipeline:
488
+ *
489
+ * - message (string) ⬇
490
+ * - tokenize
491
+ * - build AST
492
+ * - render via provided renderer
493
+ *
494
+ * All rendering behavior is defined by the given renderer, making this
495
+ * function environment-agnostic (string, DOM, React, etc.).
496
+ */
497
+ declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
498
+
499
+ export { type ASTNode, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MissingHandler, type NestedMessage, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage, renderRichMessage };
package/dist/index.js CHANGED
@@ -338,9 +338,9 @@ var ScopeTranslator = class extends CoreTranslator {
338
338
  }
339
339
  };
340
340
 
341
- // src/message/tokenize/parse-attributes.ts
341
+ // src/message/tokenize/utils/extract-attributes.ts
342
342
  var ATTR_REGEX = /\s+([a-zA-Z_][a-zA-Z0-9_]*)="([^"]*)"/g;
343
- var parseAttributes = (input) => {
343
+ var extractAttributes = (input) => {
344
344
  const attributes = {};
345
345
  let match;
346
346
  let consumed = "";
@@ -377,7 +377,7 @@ var tokenize = (message) => {
377
377
  const openMatch = message.slice(pos).match(OPEN_TAG_REGEX);
378
378
  if (openMatch) {
379
379
  const [, name, rawAttributes] = openMatch;
380
- const attributes = parseAttributes(rawAttributes);
380
+ const attributes = extractAttributes(rawAttributes);
381
381
  if (attributes) {
382
382
  flushText();
383
383
  tokens.push({
@@ -409,7 +409,7 @@ var tokenize = (message) => {
409
409
  return tokens;
410
410
  };
411
411
 
412
- // src/message/build-ast/build-ast.ts
412
+ // src/message/ast/build-ast.ts
413
413
  function buildAST(tokens) {
414
414
  const root = [];
415
415
  const stack = [];
@@ -464,4 +464,21 @@ function parseRichMessage(message) {
464
464
  return buildAST(tokens);
465
465
  }
466
466
 
467
- export { ScopeTranslator as Translator, parseRichMessage };
467
+ // src/message/render/render.ts
468
+ function render(nodes, renderer) {
469
+ return nodes.map((node) => {
470
+ if (node.type === "text") {
471
+ return renderer.text(node.value);
472
+ }
473
+ const children = render(node.children, renderer);
474
+ return renderer.tag(node.name, node.attributes, children);
475
+ });
476
+ }
477
+
478
+ // src/message/render-rich-message.ts
479
+ function renderRichMessage(message, renderer) {
480
+ const nodes = parseRichMessage(message);
481
+ return render(nodes, renderer);
482
+ }
483
+
484
+ export { ScopeTranslator as Translator, parseRichMessage, renderRichMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor-translator",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "🤖 A modern, type-safe i18n engine.",
5
5
  "author": {
6
6
  "name": "Yiming Liao",
@@ -57,7 +57,8 @@
57
57
  "lint": "eslint",
58
58
  "lint:debug": "eslint --debug",
59
59
  "knip": "knip --config .config/knip.config.ts",
60
- "examples:html": "vite --config examples/html/vite.config.ts"
60
+ "examples:html": "vite --config examples/html/basic/vite.config.ts",
61
+ "examples:html:rich": "vite --config examples/html/rich/vite.config.ts"
61
62
  },
62
63
  "dependencies": {
63
64
  "rura": "1.0.7"