intor-translator 1.2.0 → 1.2.2

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
@@ -3,7 +3,7 @@
3
3
  <div align="center">
4
4
 
5
5
  A modern **i18n engine** powered by a customizable, type-safe translation pipeline.
6
- Easy to adopt, modular at its core, and fully extensible.
6
+ Easy to use, modular at its core, and fully extensible.
7
7
 
8
8
  </div>
9
9
 
@@ -12,8 +12,8 @@ Easy to adopt, modular at its core, and fully extensible.
12
12
  [![NPM version](https://img.shields.io/npm/v/intor-translator?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/intor-translator)
13
13
  [![Bundle size](https://img.shields.io/bundlephobia/minzip/intor-translator?style=flat&colorA=000000&colorB=000000)](https://bundlephobia.com/package/intor-translator)
14
14
  [![Coverage Status](https://img.shields.io/coveralls/github/yiming-liao/intor-translator.svg?branch=main&style=flat&colorA=000000&colorB=000000)](https://coveralls.io/github/yiming-liao/intor-translator?branch=main)
15
- [![License](https://img.shields.io/npm/l/intor-translator?style=flat&colorA=000000&colorB=000000)](LICENSE)
16
15
  [![TypeScript](https://img.shields.io/badge/TypeScript-%E2%9C%94-blue?style=flat&colorA=000000&colorB=000000)](https://www.typescriptlang.org/)
16
+ [![License](https://img.shields.io/npm/l/intor-translator?style=flat&colorA=000000&colorB=000000)](LICENSE)
17
17
 
18
18
  </div>
19
19
 
@@ -30,12 +30,20 @@ Easy to adopt, modular at its core, and fully extensible.
30
30
  ```bash
31
31
  # npm
32
32
  npm install intor-translator
33
+
33
34
  # yarn
34
35
  yarn add intor-translator
36
+
35
37
  # pnpm
36
38
  pnpm add intor-translator
37
39
  ```
38
40
 
41
+ Or load it directly from a CDN:
42
+
43
+ ```js
44
+ import { Translator } from "https://cdn.jsdelivr.net/npm/intor-translator/+esm";
45
+ ```
46
+
39
47
  ## Quick Start
40
48
 
41
49
  ```typescript
package/dist/index.cjs CHANGED
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var rura = require('rura');
4
+
5
+ // src/translators/core-translator/core-translator.ts
6
+
3
7
  // src/translators/shared/utils/find-message-in-locales.ts
4
8
  var findMessageInLocales = ({
5
9
  messages,
@@ -23,18 +27,18 @@ var findMessageInLocales = ({
23
27
  }
24
28
  };
25
29
 
26
- // src/pipeline/hooks/find-message.hook.ts
27
- var findMessageHook = {
28
- name: "findMessage",
29
- order: 200,
30
- run(ctx) {
30
+ // src/pipeline/hooks/find-message.ts
31
+ var findMessage = rura.rura.createHook(
32
+ "findMessage",
33
+ (ctx) => {
31
34
  ctx.rawMessage = findMessageInLocales({
32
35
  messages: ctx.messages,
33
36
  candidateLocales: ctx.candidateLocales,
34
37
  key: ctx.key
35
38
  });
36
- }
37
- };
39
+ },
40
+ 200
41
+ );
38
42
 
39
43
  // src/pipeline/utils/make-handler-context.ts
40
44
  function makeHandlerContext(ctx) {
@@ -52,19 +56,19 @@ function makeHandlerContext(ctx) {
52
56
  });
53
57
  }
54
58
 
55
- // src/pipeline/hooks/format.hook.ts
56
- var formatHook = {
57
- name: "format",
58
- order: 500,
59
- run(ctx) {
59
+ // src/pipeline/hooks/format.ts
60
+ var format = rura.rura.createHook(
61
+ "format",
62
+ (ctx) => {
60
63
  const { config, rawMessage } = ctx;
61
64
  const { formatHandler } = config.handlers || {};
62
65
  if (!formatHandler || rawMessage === void 0) return;
63
66
  ctx.formattedMessage = formatHandler(
64
67
  makeHandlerContext(ctx)
65
68
  );
66
- }
67
- };
69
+ },
70
+ 500
71
+ );
68
72
 
69
73
  // src/translators/shared/utils/replace-values.ts
70
74
  var replaceValues = (message, params) => {
@@ -85,11 +89,10 @@ var replaceValues = (message, params) => {
85
89
  return replaced;
86
90
  };
87
91
 
88
- // src/pipeline/hooks/interpolate.hook.ts
89
- var interpolateHook = {
90
- name: "interpolate",
91
- order: 600,
92
- run(ctx) {
92
+ // src/pipeline/hooks/interpolate.ts
93
+ var interpolate = rura.rura.createHook(
94
+ "interpolate",
95
+ (ctx) => {
93
96
  const { rawMessage, formattedMessage, replacements } = ctx;
94
97
  const message = formattedMessage ?? rawMessage;
95
98
  if (typeof message !== "string" || !replacements) {
@@ -97,51 +100,48 @@ var interpolateHook = {
97
100
  return;
98
101
  }
99
102
  ctx.finalMessage = replaceValues(message, replacements);
100
- }
101
- };
102
-
103
- // src/pipeline/hooks/loading.hook.ts
104
- var loadingHook = {
105
- name: "loading",
106
- order: 300,
107
- run(ctx) {
103
+ },
104
+ 600
105
+ );
106
+ var loading = rura.rura.createHook(
107
+ "loading",
108
+ (ctx) => {
108
109
  const { config, isLoading } = ctx;
109
110
  if (!isLoading) return;
110
111
  const { loadingHandler } = config.handlers || {};
111
112
  if (loadingHandler) {
112
113
  return {
113
- done: true,
114
- value: loadingHandler(makeHandlerContext(ctx))
114
+ early: true,
115
+ output: loadingHandler(makeHandlerContext(ctx))
115
116
  };
116
117
  }
117
118
  const { loadingMessage } = config;
118
119
  if (loadingMessage) {
119
- return { done: true, value: loadingMessage };
120
+ return { early: true, output: loadingMessage };
120
121
  }
121
- }
122
- };
123
-
124
- // src/pipeline/hooks/missing.hook.ts
125
- var missingHook = {
126
- name: "missing",
127
- order: 400,
128
- run(ctx) {
122
+ },
123
+ 300
124
+ );
125
+ var missing = rura.rura.createHook(
126
+ "missing",
127
+ (ctx) => {
129
128
  const { config, key, rawMessage } = ctx;
130
129
  if (rawMessage !== void 0) return;
131
130
  const { missingHandler } = config.handlers || {};
132
131
  if (missingHandler) {
133
132
  return {
134
- done: true,
135
- value: missingHandler(makeHandlerContext(ctx))
133
+ early: true,
134
+ output: missingHandler(makeHandlerContext(ctx))
136
135
  };
137
136
  }
138
137
  const { placeholder } = config;
139
138
  if (placeholder) {
140
- return { done: true, value: placeholder };
139
+ return { early: true, output: placeholder };
141
140
  }
142
- return { done: true, value: key };
143
- }
144
- };
141
+ return { early: true, output: key };
142
+ },
143
+ 400
144
+ );
145
145
 
146
146
  // src/translators/shared/utils/resolve-candidate-locales.ts
147
147
  var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
@@ -150,26 +150,26 @@ var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
150
150
  return [locale, ...filteredFallbacks];
151
151
  };
152
152
 
153
- // src/pipeline/hooks/resolve-locales.hook.ts
154
- var resolveLocalesHook = {
155
- name: "resolveLocales",
156
- order: 100,
157
- run(ctx) {
153
+ // src/pipeline/hooks/resolve-locales.ts
154
+ var resolveLocales = rura.rura.createHook(
155
+ "resolveLocales",
156
+ (ctx) => {
158
157
  ctx.candidateLocales = resolveCandidateLocales(
159
158
  ctx.locale,
160
159
  ctx.config.fallbackLocales
161
160
  );
162
- }
163
- };
161
+ },
162
+ 100
163
+ );
164
164
 
165
- // src/pipeline/hooks/index.ts
165
+ // src/pipeline/index.ts
166
166
  var DEFAULT_HOOKS = [
167
- resolveLocalesHook,
168
- findMessageHook,
169
- loadingHook,
170
- missingHook,
171
- formatHook,
172
- interpolateHook
167
+ resolveLocales,
168
+ findMessage,
169
+ loading,
170
+ missing,
171
+ format,
172
+ interpolate
173
173
  ];
174
174
 
175
175
  // src/translators/base-translator/base-translator.ts
@@ -235,27 +235,16 @@ var hasKey = ({
235
235
  });
236
236
  return !!message;
237
237
  };
238
-
239
- // src/pipeline/run-pipeline.ts
240
- function runPipeline(ctx, hooks) {
241
- for (const hook of hooks) {
242
- const result = hook.run(ctx);
243
- if (result?.done) {
244
- return result.value;
245
- }
246
- }
247
- return ctx.finalMessage ?? ctx.rawMessage;
248
- }
249
-
250
- // src/translators/shared/translate.ts
251
238
  function translate(options) {
252
- const ctx = {
239
+ const context = {
253
240
  ...options,
254
241
  config: options.translateConfig,
255
242
  candidateLocales: [],
256
243
  meta: {}
257
244
  };
258
- return runPipeline(ctx, options.hooks);
245
+ const { early, ctx, output } = rura.rura.run(context, options.hooks);
246
+ if (early === true) return output;
247
+ return ctx.finalMessage;
259
248
  }
260
249
 
261
250
  // src/translators/core-translator/core-translator.ts
@@ -286,6 +275,12 @@ var CoreTranslator = class extends BaseTranslator {
286
275
  }
287
276
  this.sortHooks();
288
277
  }
278
+ /** Outputs a debug overview of the active pipeline. */
279
+ debugHooks() {
280
+ return rura.rura.createPipeline(this.hooks).debugHooks(
281
+ (hooks) => `\u{1F916} Intor Translator pipeline (${hooks.length} hooks)`
282
+ );
283
+ }
289
284
  /** Check if a key exists in the specified locale or current locale. */
290
285
  hasKey = (key, targetLocale) => {
291
286
  return hasKey({
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { RuraHook } from 'rura';
2
+
1
3
  /**
2
4
  * A nested message structure or a simple string message.
3
5
  *
@@ -319,28 +321,8 @@ interface TranslateContext<Result = unknown> {
319
321
  }
320
322
  /**
321
323
  * A single step in the translate pipeline.
322
- *
323
- * @template Result - Final translated value type.
324
324
  */
325
- interface TranslateHook<Result = unknown> {
326
- /** Unique name for this hook, used for debugging and introspection. */
327
- name: string;
328
- /**
329
- * Optional execution order.
330
- * - Lower values run earlier; hooks without order run last-in registration order.
331
- */
332
- order?: number;
333
- /**
334
- * Run the hook with the current context.
335
- * - Return `{ done: true, value }` to short-circuit the pipeline.
336
- */
337
- run(ctx: TranslateContext<Result>): void | {
338
- /** Indicates the pipeline should stop after this hook. */
339
- done: true;
340
- /** Final value to return from the translate call. */
341
- value: Result;
342
- };
343
- }
325
+ type TranslateHook = RuraHook<TranslateContext>;
344
326
 
345
327
  /**
346
328
  * Options for initializing a translator
@@ -428,6 +410,8 @@ declare class CoreTranslator<M extends LocaleMessages, L extends keyof M | "unio
428
410
  private sortHooks;
429
411
  /** Register a plugin or a raw pipeline hook. */
430
412
  use(plugin: TranslatorPlugin | TranslateHook): void;
413
+ /** Outputs a debug overview of the active pipeline. */
414
+ debugHooks(): void;
431
415
  /** Check if a key exists in the specified locale or current locale. */
432
416
  hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
433
417
  /** Get the translated message for a key, with optional replacements. */
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { RuraHook } from 'rura';
2
+
1
3
  /**
2
4
  * A nested message structure or a simple string message.
3
5
  *
@@ -319,28 +321,8 @@ interface TranslateContext<Result = unknown> {
319
321
  }
320
322
  /**
321
323
  * A single step in the translate pipeline.
322
- *
323
- * @template Result - Final translated value type.
324
324
  */
325
- interface TranslateHook<Result = unknown> {
326
- /** Unique name for this hook, used for debugging and introspection. */
327
- name: string;
328
- /**
329
- * Optional execution order.
330
- * - Lower values run earlier; hooks without order run last-in registration order.
331
- */
332
- order?: number;
333
- /**
334
- * Run the hook with the current context.
335
- * - Return `{ done: true, value }` to short-circuit the pipeline.
336
- */
337
- run(ctx: TranslateContext<Result>): void | {
338
- /** Indicates the pipeline should stop after this hook. */
339
- done: true;
340
- /** Final value to return from the translate call. */
341
- value: Result;
342
- };
343
- }
325
+ type TranslateHook = RuraHook<TranslateContext>;
344
326
 
345
327
  /**
346
328
  * Options for initializing a translator
@@ -428,6 +410,8 @@ declare class CoreTranslator<M extends LocaleMessages, L extends keyof M | "unio
428
410
  private sortHooks;
429
411
  /** Register a plugin or a raw pipeline hook. */
430
412
  use(plugin: TranslatorPlugin | TranslateHook): void;
413
+ /** Outputs a debug overview of the active pipeline. */
414
+ debugHooks(): void;
431
415
  /** Check if a key exists in the specified locale or current locale. */
432
416
  hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
433
417
  /** Get the translated message for a key, with optional replacements. */
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ import { rura } from 'rura';
2
+
3
+ // src/translators/core-translator/core-translator.ts
4
+
1
5
  // src/translators/shared/utils/find-message-in-locales.ts
2
6
  var findMessageInLocales = ({
3
7
  messages,
@@ -21,18 +25,18 @@ var findMessageInLocales = ({
21
25
  }
22
26
  };
23
27
 
24
- // src/pipeline/hooks/find-message.hook.ts
25
- var findMessageHook = {
26
- name: "findMessage",
27
- order: 200,
28
- run(ctx) {
28
+ // src/pipeline/hooks/find-message.ts
29
+ var findMessage = rura.createHook(
30
+ "findMessage",
31
+ (ctx) => {
29
32
  ctx.rawMessage = findMessageInLocales({
30
33
  messages: ctx.messages,
31
34
  candidateLocales: ctx.candidateLocales,
32
35
  key: ctx.key
33
36
  });
34
- }
35
- };
37
+ },
38
+ 200
39
+ );
36
40
 
37
41
  // src/pipeline/utils/make-handler-context.ts
38
42
  function makeHandlerContext(ctx) {
@@ -50,19 +54,19 @@ function makeHandlerContext(ctx) {
50
54
  });
51
55
  }
52
56
 
53
- // src/pipeline/hooks/format.hook.ts
54
- var formatHook = {
55
- name: "format",
56
- order: 500,
57
- run(ctx) {
57
+ // src/pipeline/hooks/format.ts
58
+ var format = rura.createHook(
59
+ "format",
60
+ (ctx) => {
58
61
  const { config, rawMessage } = ctx;
59
62
  const { formatHandler } = config.handlers || {};
60
63
  if (!formatHandler || rawMessage === void 0) return;
61
64
  ctx.formattedMessage = formatHandler(
62
65
  makeHandlerContext(ctx)
63
66
  );
64
- }
65
- };
67
+ },
68
+ 500
69
+ );
66
70
 
67
71
  // src/translators/shared/utils/replace-values.ts
68
72
  var replaceValues = (message, params) => {
@@ -83,11 +87,10 @@ var replaceValues = (message, params) => {
83
87
  return replaced;
84
88
  };
85
89
 
86
- // src/pipeline/hooks/interpolate.hook.ts
87
- var interpolateHook = {
88
- name: "interpolate",
89
- order: 600,
90
- run(ctx) {
90
+ // src/pipeline/hooks/interpolate.ts
91
+ var interpolate = rura.createHook(
92
+ "interpolate",
93
+ (ctx) => {
91
94
  const { rawMessage, formattedMessage, replacements } = ctx;
92
95
  const message = formattedMessage ?? rawMessage;
93
96
  if (typeof message !== "string" || !replacements) {
@@ -95,51 +98,48 @@ var interpolateHook = {
95
98
  return;
96
99
  }
97
100
  ctx.finalMessage = replaceValues(message, replacements);
98
- }
99
- };
100
-
101
- // src/pipeline/hooks/loading.hook.ts
102
- var loadingHook = {
103
- name: "loading",
104
- order: 300,
105
- run(ctx) {
101
+ },
102
+ 600
103
+ );
104
+ var loading = rura.createHook(
105
+ "loading",
106
+ (ctx) => {
106
107
  const { config, isLoading } = ctx;
107
108
  if (!isLoading) return;
108
109
  const { loadingHandler } = config.handlers || {};
109
110
  if (loadingHandler) {
110
111
  return {
111
- done: true,
112
- value: loadingHandler(makeHandlerContext(ctx))
112
+ early: true,
113
+ output: loadingHandler(makeHandlerContext(ctx))
113
114
  };
114
115
  }
115
116
  const { loadingMessage } = config;
116
117
  if (loadingMessage) {
117
- return { done: true, value: loadingMessage };
118
+ return { early: true, output: loadingMessage };
118
119
  }
119
- }
120
- };
121
-
122
- // src/pipeline/hooks/missing.hook.ts
123
- var missingHook = {
124
- name: "missing",
125
- order: 400,
126
- run(ctx) {
120
+ },
121
+ 300
122
+ );
123
+ var missing = rura.createHook(
124
+ "missing",
125
+ (ctx) => {
127
126
  const { config, key, rawMessage } = ctx;
128
127
  if (rawMessage !== void 0) return;
129
128
  const { missingHandler } = config.handlers || {};
130
129
  if (missingHandler) {
131
130
  return {
132
- done: true,
133
- value: missingHandler(makeHandlerContext(ctx))
131
+ early: true,
132
+ output: missingHandler(makeHandlerContext(ctx))
134
133
  };
135
134
  }
136
135
  const { placeholder } = config;
137
136
  if (placeholder) {
138
- return { done: true, value: placeholder };
137
+ return { early: true, output: placeholder };
139
138
  }
140
- return { done: true, value: key };
141
- }
142
- };
139
+ return { early: true, output: key };
140
+ },
141
+ 400
142
+ );
143
143
 
144
144
  // src/translators/shared/utils/resolve-candidate-locales.ts
145
145
  var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
@@ -148,26 +148,26 @@ var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
148
148
  return [locale, ...filteredFallbacks];
149
149
  };
150
150
 
151
- // src/pipeline/hooks/resolve-locales.hook.ts
152
- var resolveLocalesHook = {
153
- name: "resolveLocales",
154
- order: 100,
155
- run(ctx) {
151
+ // src/pipeline/hooks/resolve-locales.ts
152
+ var resolveLocales = rura.createHook(
153
+ "resolveLocales",
154
+ (ctx) => {
156
155
  ctx.candidateLocales = resolveCandidateLocales(
157
156
  ctx.locale,
158
157
  ctx.config.fallbackLocales
159
158
  );
160
- }
161
- };
159
+ },
160
+ 100
161
+ );
162
162
 
163
- // src/pipeline/hooks/index.ts
163
+ // src/pipeline/index.ts
164
164
  var DEFAULT_HOOKS = [
165
- resolveLocalesHook,
166
- findMessageHook,
167
- loadingHook,
168
- missingHook,
169
- formatHook,
170
- interpolateHook
165
+ resolveLocales,
166
+ findMessage,
167
+ loading,
168
+ missing,
169
+ format,
170
+ interpolate
171
171
  ];
172
172
 
173
173
  // src/translators/base-translator/base-translator.ts
@@ -233,27 +233,16 @@ var hasKey = ({
233
233
  });
234
234
  return !!message;
235
235
  };
236
-
237
- // src/pipeline/run-pipeline.ts
238
- function runPipeline(ctx, hooks) {
239
- for (const hook of hooks) {
240
- const result = hook.run(ctx);
241
- if (result?.done) {
242
- return result.value;
243
- }
244
- }
245
- return ctx.finalMessage ?? ctx.rawMessage;
246
- }
247
-
248
- // src/translators/shared/translate.ts
249
236
  function translate(options) {
250
- const ctx = {
237
+ const context = {
251
238
  ...options,
252
239
  config: options.translateConfig,
253
240
  candidateLocales: [],
254
241
  meta: {}
255
242
  };
256
- return runPipeline(ctx, options.hooks);
243
+ const { early, ctx, output } = rura.run(context, options.hooks);
244
+ if (early === true) return output;
245
+ return ctx.finalMessage;
257
246
  }
258
247
 
259
248
  // src/translators/core-translator/core-translator.ts
@@ -284,6 +273,12 @@ var CoreTranslator = class extends BaseTranslator {
284
273
  }
285
274
  this.sortHooks();
286
275
  }
276
+ /** Outputs a debug overview of the active pipeline. */
277
+ debugHooks() {
278
+ return rura.createPipeline(this.hooks).debugHooks(
279
+ (hooks) => `\u{1F916} Intor Translator pipeline (${hooks.length} hooks)`
280
+ );
281
+ }
287
282
  /** Check if a key exists in the specified locale or current locale. */
288
283
  hasKey = (key, targetLocale) => {
289
284
  return hasKey({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor-translator",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "🤖 A modern, type-safe i18n engine.",
5
5
  "author": "Yiming Liao",
6
6
  "license": "MIT",
@@ -51,26 +51,28 @@
51
51
  "engines": {
52
52
  "node": ">=16.0.0"
53
53
  },
54
- "dependencies": {},
54
+ "dependencies": {
55
+ "rura": "1.0.7"
56
+ },
55
57
  "devDependencies": {
56
- "@types/node": "^24.10.1",
57
- "@vitest/coverage-v8": "4.0.9",
58
- "eslint": "^9.39.1",
59
- "eslint-config-prettier": "^10.1.8",
60
- "eslint-import-resolver-typescript": "^4.4.4",
61
- "eslint-plugin-import": "^2.32.0",
62
- "eslint-plugin-prettier": "^5.5.4",
63
- "eslint-plugin-unicorn": "^62.0.0",
64
- "eslint-plugin-unused-imports": "^4.3.0",
65
- "intl-messageformat": "^10.7.16",
66
- "knip": "^5.69.1",
67
- "prettier": "^3.6.2",
68
- "ts-node": "^10.9.2",
69
- "tsd": "^0.33.0",
70
- "tsup": "^8.4.0",
71
- "typescript": "^5.8.3",
72
- "typescript-eslint": "^8.46.4",
73
- "vite": "^7.2.6",
74
- "vitest": "^4.0.9"
58
+ "@types/node": "24.10.1",
59
+ "@vitest/coverage-v8": "4.0.16",
60
+ "eslint": "9.39.1",
61
+ "eslint-config-prettier": "10.1.8",
62
+ "eslint-import-resolver-typescript": "4.4.4",
63
+ "eslint-plugin-import": "2.32.0",
64
+ "eslint-plugin-prettier": "5.5.4",
65
+ "eslint-plugin-unicorn": "62.0.0",
66
+ "eslint-plugin-unused-imports": "4.3.0",
67
+ "intl-messageformat": "10.7.16",
68
+ "knip": "5.69.1",
69
+ "prettier": "3.6.2",
70
+ "ts-node": "10.9.2",
71
+ "tsd": "0.33.0",
72
+ "tsup": "8.4.0",
73
+ "typescript": "5.8.3",
74
+ "typescript-eslint": "8.46.4",
75
+ "vite": "7.2.6",
76
+ "vitest": "4.0.16"
75
77
  }
76
78
  }