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 +13 -0
- package/dist/index.cjs +22 -4
- package/dist/index.d.cts +42 -9
- package/dist/index.d.ts +42 -9
- package/dist/index.js +22 -5
- package/package.json +3 -2
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/
|
|
343
|
+
// src/message/tokenize/utils/extract-attributes.ts
|
|
344
344
|
var ATTR_REGEX = /\s+([a-zA-Z_][a-zA-Z0-9_]*)="([^"]*)"/g;
|
|
345
|
-
var
|
|
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 =
|
|
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/
|
|
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
|
-
/**
|
|
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
|
|
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,
|
|
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
|
-
*
|
|
462
|
-
*
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
|
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,
|
|
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
|
-
*
|
|
462
|
-
*
|
|
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
|
-
|
|
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/
|
|
341
|
+
// src/message/tokenize/utils/extract-attributes.ts
|
|
342
342
|
var ATTR_REGEX = /\s+([a-zA-Z_][a-zA-Z0-9_]*)="([^"]*)"/g;
|
|
343
|
-
var
|
|
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 =
|
|
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/
|
|
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
|
-
|
|
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.
|
|
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"
|