intor-translator 1.3.1 → 1.4.0

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/dist/index.cjs CHANGED
@@ -11,19 +11,19 @@ var findMessageInLocales = ({
11
11
  key
12
12
  }) => {
13
13
  for (const locale of candidateLocales) {
14
- const localeMessages = messages[locale];
15
- if (!localeMessages) continue;
16
- let candidate = localeMessages;
14
+ const messagesForLocale = messages[locale];
15
+ if (!messagesForLocale) continue;
16
+ let candidate = messagesForLocale;
17
17
  const keys = key.split(".");
18
- for (const k of keys) {
19
- if (candidate && typeof candidate === "object" && k in candidate) {
20
- candidate = candidate[k];
18
+ for (const key2 of keys) {
19
+ if (candidate !== null && typeof candidate === "object" && key2 in candidate) {
20
+ candidate = candidate[key2];
21
21
  } else {
22
22
  candidate = void 0;
23
23
  break;
24
24
  }
25
25
  }
26
- if (typeof candidate === "string") return candidate;
26
+ if (candidate !== void 0) return candidate;
27
27
  }
28
28
  };
29
29
 
@@ -31,11 +31,15 @@ var findMessageInLocales = ({
31
31
  var findMessage = rura.rura.createHook(
32
32
  "findMessage",
33
33
  (ctx) => {
34
- ctx.rawMessage = findMessageInLocales({
34
+ ctx.rawValue = void 0;
35
+ ctx.rawString = void 0;
36
+ const message = findMessageInLocales({
35
37
  messages: ctx.messages,
36
38
  candidateLocales: ctx.candidateLocales,
37
39
  key: ctx.key
38
40
  });
41
+ ctx.rawValue = message;
42
+ if (typeof message === "string") ctx.rawString = message;
39
43
  },
40
44
  200
41
45
  );
@@ -50,7 +54,8 @@ function makeHandlerContext(ctx) {
50
54
  key: ctx.key,
51
55
  replacements: ctx.replacements,
52
56
  candidateLocales: ctx.candidateLocales,
53
- rawMessage: ctx.rawMessage,
57
+ rawValue: ctx.rawValue,
58
+ rawString: ctx.rawString,
54
59
  formattedMessage: ctx.formattedMessage,
55
60
  meta: ctx.meta
56
61
  });
@@ -60,9 +65,9 @@ function makeHandlerContext(ctx) {
60
65
  var format = rura.rura.createHook(
61
66
  "format",
62
67
  (ctx) => {
63
- const { config, rawMessage } = ctx;
68
+ const { config, rawString } = ctx;
64
69
  const { formatHandler } = config.handlers || {};
65
- if (!formatHandler || rawMessage === void 0) return;
70
+ if (!formatHandler || rawString === void 0) return;
66
71
  ctx.formattedMessage = formatHandler(
67
72
  makeHandlerContext(ctx)
68
73
  );
@@ -93,8 +98,8 @@ var replaceValues = (message, params) => {
93
98
  var interpolate = rura.rura.createHook(
94
99
  "interpolate",
95
100
  (ctx) => {
96
- const { rawMessage, formattedMessage, replacements } = ctx;
97
- const message = formattedMessage ?? rawMessage;
101
+ const { rawString, formattedMessage, replacements } = ctx;
102
+ const message = formattedMessage ?? rawString;
98
103
  if (typeof message !== "string" || !replacements) {
99
104
  ctx.finalMessage = message;
100
105
  return;
@@ -116,7 +121,7 @@ var loading = rura.rura.createHook(
116
121
  };
117
122
  }
118
123
  const { loadingMessage } = config;
119
- if (loadingMessage) {
124
+ if ("loadingMessage" in config) {
120
125
  return { early: true, output: loadingMessage };
121
126
  }
122
127
  },
@@ -125,8 +130,8 @@ var loading = rura.rura.createHook(
125
130
  var missing = rura.rura.createHook(
126
131
  "missing",
127
132
  (ctx) => {
128
- const { config, key, rawMessage } = ctx;
129
- if (rawMessage !== void 0) return;
133
+ const { config, key, rawString } = ctx;
134
+ if (rawString !== void 0) return;
130
135
  const { missingHandler } = config.handlers || {};
131
136
  if (missingHandler) {
132
137
  return {
@@ -134,9 +139,9 @@ var missing = rura.rura.createHook(
134
139
  output: missingHandler(makeHandlerContext(ctx))
135
140
  };
136
141
  }
137
- const { placeholder } = config;
138
- if (placeholder) {
139
- return { early: true, output: placeholder };
142
+ const { missingMessage } = config;
143
+ if ("missingMessage" in config) {
144
+ return { early: true, output: missingMessage };
140
145
  }
141
146
  return { early: true, output: key };
142
147
  },
@@ -229,20 +234,31 @@ var hasKey = ({
229
234
  }) => {
230
235
  const candidateLocales = resolveCandidateLocales(targetLocale || locale);
231
236
  const message = findMessageInLocales({ messages, candidateLocales, key });
232
- return !!message;
237
+ return message !== void 0;
233
238
  };
234
- function translate(options) {
239
+ function runTranslate(options) {
235
240
  const context = {
236
241
  ...options,
237
242
  config: options.translateConfig,
238
243
  candidateLocales: [],
239
244
  meta: {}
240
245
  };
241
- const { early, ctx, output } = rura.rura.run(context, options.hooks);
246
+ return rura.rura.run(context, options.hooks);
247
+ }
248
+
249
+ // src/translators/methods/translate.ts
250
+ function translate(options) {
251
+ const { early, ctx, output } = runTranslate(options);
242
252
  if (early === true) return output;
243
253
  return ctx.finalMessage;
244
254
  }
245
255
 
256
+ // src/translators/methods/translate-raw.ts
257
+ function translateRaw(options) {
258
+ const { ctx } = runTranslate(options);
259
+ return ctx.rawValue;
260
+ }
261
+
246
262
  // src/translators/core-translator/core-translator.ts
247
263
  var CoreTranslator = class extends BaseTranslator {
248
264
  /** User-provided options including messages, locale, and config. */
@@ -298,6 +314,18 @@ var CoreTranslator = class extends BaseTranslator {
298
314
  replacements
299
315
  });
300
316
  };
317
+ /** Get the raw message value for a key without formatting or interpolation. */
318
+ tRaw = (key, replacements) => {
319
+ return translateRaw({
320
+ hooks: this.hooks,
321
+ messages: this._messages,
322
+ locale: this._locale,
323
+ isLoading: this._isLoading,
324
+ translateConfig: this.translateConfig,
325
+ key,
326
+ replacements
327
+ });
328
+ };
301
329
  };
302
330
 
303
331
  // src/translators/scope-translator/utils/get-full-key.ts
package/dist/index.d.cts CHANGED
@@ -1,30 +1,24 @@
1
1
  import { RuraHook } from 'rura';
2
2
 
3
+ type MessagePrimitive = string | number | boolean | null;
4
+ type MessageArray = readonly MessageValue[];
5
+ interface MessageObject {
6
+ [key: string]: MessageValue;
7
+ }
8
+ /** A message value in the locale message tree. */
9
+ type MessageValue = MessagePrimitive | MessageObject | MessageArray;
3
10
  /**
4
- * A nested message structure or a simple string message.
5
- *
6
- * - Used to represent either a plain message or an object containing more nested messages.
11
+ * A non-traversable message value.
7
12
  *
8
- * @example
9
- * ```ts
10
- * const greeting: NestedMessage = "Hello";
11
- * const userMessages: NestedMessage = {
12
- * profile: {
13
- * greeting: "Hello, user!",
14
- * farewell: "Goodbye!"
15
- * }
16
- * };
17
- * ```
13
+ * Leaf values represent the end of a message path.
18
14
  */
19
- type NestedMessage = string | {
20
- [key: string]: NestedMessage;
21
- };
15
+ type MessageLeaf = MessagePrimitive | MessageArray;
22
16
  /**
23
17
  * Messages grouped by locale.
24
18
  * Used to structure all available messages for multiple locales.
25
19
  *
26
20
  * - The root-level keys are locale identifiers, e.g., "en" or "zh-TW".
27
- * - Each value is a `NestedMessage`, allowing for deeply nested message objects.
21
+ * - Each value is a `MessageObject`, allowing for deeply nested message objects.
28
22
  *
29
23
  * @example
30
24
  * ```ts
@@ -37,22 +31,11 @@ type NestedMessage = string | {
37
31
  * failure: "Login failed"
38
32
  * }
39
33
  * }
40
- * },
41
- * "zh-TW": {
42
- * welcome: "歡迎",
43
- * auth: {
44
- * login: {
45
- * success: "登入成功",
46
- * failure: "登入失敗"
47
- * }
48
- * }
49
34
  * }
50
35
  * };
51
36
  * ```
52
37
  */
53
- type LocaleMessages = Record<string, {
54
- [x: string]: NestedMessage;
55
- }>;
38
+ type LocaleMessages = Record<string, MessageObject>;
56
39
  /**
57
40
  * Merges messages from all locales into a single unified structure,
58
41
  * or extracts messages for a specific locale if `L` is provided.
@@ -144,7 +127,7 @@ type DefaultDepth = 15;
144
127
  /** Countdown tuple for limiting recursive depth (up to 15 levels). */
145
128
  type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
146
129
  /**
147
- * Gets all dot-separated keys (including non-leaf nodes) from a nested object.
130
+ * Gets all dot-separated keys of a nested object, stopping at message leaf values.
148
131
  *
149
132
  * @example
150
133
  * ```ts
@@ -152,10 +135,10 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
152
135
  * ```
153
136
  */
154
137
  type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
155
- [K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K], Prev[D]>}` : never;
138
+ [K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}` | `${K & string}.${NodeKeys<M[K], Prev[D]>}` : never;
156
139
  }[keyof M] : never;
157
140
  /**
158
- * Gets dot-separated keys to string leaf nodes in a nested object.
141
+ * Gets dot-separated keys that resolve to message leaf values in a nested object.
159
142
  *
160
143
  * @example
161
144
  * ```ts
@@ -163,7 +146,7 @@ type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
163
146
  * ```
164
147
  */
165
148
  type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
166
- [K in keyof M]: M[K] extends string ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
149
+ [K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
167
150
  }[keyof M] : never;
168
151
 
169
152
  /**
@@ -246,7 +229,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
246
229
  * ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
247
230
  * ```
248
231
  */
249
- type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer messages ? messages extends NestedMessage ? LeafKeys<MessagesAtPreKey<messages, PK>, D> : never : never : string;
232
+ type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer Messages ? Messages extends MessageValue ? MessagesAtPreKey<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
250
233
 
251
234
  /**
252
235
  * Configuration options for translation behavior.
@@ -258,8 +241,8 @@ type TranslateConfig<M = unknown> = {
258
241
  fallbackLocales?: FallbackLocalesMap<Locale<M>>;
259
242
  /** Optional message to display while translations are still loading. */
260
243
  loadingMessage?: string;
261
- /** Optional placeholder to use when a message cannot be found. */
262
- placeholder?: string;
244
+ /** Optional message used when a translation is missing. */
245
+ missingMessage?: string;
263
246
  /** Optional set of handler functions for customizing translation behavior. */
264
247
  handlers?: TranslateHandlers;
265
248
  };
@@ -278,7 +261,7 @@ type LoadingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
278
261
  type MissingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
279
262
  /** Function to format a resolved message. */
280
263
  type FormatHandler<Result = unknown> = (ctx: HandlerContext & {
281
- rawMessage: string;
264
+ rawString: string;
282
265
  }) => Result;
283
266
  /**
284
267
  * Snapshot of the translate pipeline context exposed to handlers.
@@ -310,8 +293,10 @@ interface TranslateContext<Result = unknown> {
310
293
  replacements?: Replacement;
311
294
  /** Ordered list of locales to try, including fallbacks */
312
295
  candidateLocales: string[];
313
- /** Raw message string found in the messages map, before formatting */
314
- rawMessage?: string;
296
+ /** Raw message value resolved from the message tree. */
297
+ rawValue?: MessageValue;
298
+ /** Raw string message before formatting. */
299
+ rawString?: string;
315
300
  /** Message after formatting (e.g. ICU, custom formatters) */
316
301
  formattedMessage?: unknown;
317
302
  /** Final value produced by the pipeline */
@@ -416,6 +401,8 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
416
401
  hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
417
402
  /** Get the translated message for a key, with optional replacements. */
418
403
  t: <Result = string, K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => Result;
404
+ /** Get the raw message value for a key without formatting or interpolation. */
405
+ tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => MessageValue | undefined;
419
406
  }
420
407
 
421
408
  type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
@@ -496,4 +483,4 @@ interface Renderer<Output> {
496
483
  */
497
484
  declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
498
485
 
499
- export { type ASTNode, type Attributes, 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 };
486
+ export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MessageObject, type MessageValue, type MissingHandler, 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
@@ -1,30 +1,24 @@
1
1
  import { RuraHook } from 'rura';
2
2
 
3
+ type MessagePrimitive = string | number | boolean | null;
4
+ type MessageArray = readonly MessageValue[];
5
+ interface MessageObject {
6
+ [key: string]: MessageValue;
7
+ }
8
+ /** A message value in the locale message tree. */
9
+ type MessageValue = MessagePrimitive | MessageObject | MessageArray;
3
10
  /**
4
- * A nested message structure or a simple string message.
5
- *
6
- * - Used to represent either a plain message or an object containing more nested messages.
11
+ * A non-traversable message value.
7
12
  *
8
- * @example
9
- * ```ts
10
- * const greeting: NestedMessage = "Hello";
11
- * const userMessages: NestedMessage = {
12
- * profile: {
13
- * greeting: "Hello, user!",
14
- * farewell: "Goodbye!"
15
- * }
16
- * };
17
- * ```
13
+ * Leaf values represent the end of a message path.
18
14
  */
19
- type NestedMessage = string | {
20
- [key: string]: NestedMessage;
21
- };
15
+ type MessageLeaf = MessagePrimitive | MessageArray;
22
16
  /**
23
17
  * Messages grouped by locale.
24
18
  * Used to structure all available messages for multiple locales.
25
19
  *
26
20
  * - The root-level keys are locale identifiers, e.g., "en" or "zh-TW".
27
- * - Each value is a `NestedMessage`, allowing for deeply nested message objects.
21
+ * - Each value is a `MessageObject`, allowing for deeply nested message objects.
28
22
  *
29
23
  * @example
30
24
  * ```ts
@@ -37,22 +31,11 @@ type NestedMessage = string | {
37
31
  * failure: "Login failed"
38
32
  * }
39
33
  * }
40
- * },
41
- * "zh-TW": {
42
- * welcome: "歡迎",
43
- * auth: {
44
- * login: {
45
- * success: "登入成功",
46
- * failure: "登入失敗"
47
- * }
48
- * }
49
34
  * }
50
35
  * };
51
36
  * ```
52
37
  */
53
- type LocaleMessages = Record<string, {
54
- [x: string]: NestedMessage;
55
- }>;
38
+ type LocaleMessages = Record<string, MessageObject>;
56
39
  /**
57
40
  * Merges messages from all locales into a single unified structure,
58
41
  * or extracts messages for a specific locale if `L` is provided.
@@ -144,7 +127,7 @@ type DefaultDepth = 15;
144
127
  /** Countdown tuple for limiting recursive depth (up to 15 levels). */
145
128
  type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
146
129
  /**
147
- * Gets all dot-separated keys (including non-leaf nodes) from a nested object.
130
+ * Gets all dot-separated keys of a nested object, stopping at message leaf values.
148
131
  *
149
132
  * @example
150
133
  * ```ts
@@ -152,10 +135,10 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
152
135
  * ```
153
136
  */
154
137
  type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
155
- [K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K], Prev[D]>}` : never;
138
+ [K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}` | `${K & string}.${NodeKeys<M[K], Prev[D]>}` : never;
156
139
  }[keyof M] : never;
157
140
  /**
158
- * Gets dot-separated keys to string leaf nodes in a nested object.
141
+ * Gets dot-separated keys that resolve to message leaf values in a nested object.
159
142
  *
160
143
  * @example
161
144
  * ```ts
@@ -163,7 +146,7 @@ type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
163
146
  * ```
164
147
  */
165
148
  type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
166
- [K in keyof M]: M[K] extends string ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
149
+ [K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
167
150
  }[keyof M] : never;
168
151
 
169
152
  /**
@@ -246,7 +229,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
246
229
  * ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
247
230
  * ```
248
231
  */
249
- type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer messages ? messages extends NestedMessage ? LeafKeys<MessagesAtPreKey<messages, PK>, D> : never : never : string;
232
+ type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer Messages ? Messages extends MessageValue ? MessagesAtPreKey<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
250
233
 
251
234
  /**
252
235
  * Configuration options for translation behavior.
@@ -258,8 +241,8 @@ type TranslateConfig<M = unknown> = {
258
241
  fallbackLocales?: FallbackLocalesMap<Locale<M>>;
259
242
  /** Optional message to display while translations are still loading. */
260
243
  loadingMessage?: string;
261
- /** Optional placeholder to use when a message cannot be found. */
262
- placeholder?: string;
244
+ /** Optional message used when a translation is missing. */
245
+ missingMessage?: string;
263
246
  /** Optional set of handler functions for customizing translation behavior. */
264
247
  handlers?: TranslateHandlers;
265
248
  };
@@ -278,7 +261,7 @@ type LoadingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
278
261
  type MissingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
279
262
  /** Function to format a resolved message. */
280
263
  type FormatHandler<Result = unknown> = (ctx: HandlerContext & {
281
- rawMessage: string;
264
+ rawString: string;
282
265
  }) => Result;
283
266
  /**
284
267
  * Snapshot of the translate pipeline context exposed to handlers.
@@ -310,8 +293,10 @@ interface TranslateContext<Result = unknown> {
310
293
  replacements?: Replacement;
311
294
  /** Ordered list of locales to try, including fallbacks */
312
295
  candidateLocales: string[];
313
- /** Raw message string found in the messages map, before formatting */
314
- rawMessage?: string;
296
+ /** Raw message value resolved from the message tree. */
297
+ rawValue?: MessageValue;
298
+ /** Raw string message before formatting. */
299
+ rawString?: string;
315
300
  /** Message after formatting (e.g. ICU, custom formatters) */
316
301
  formattedMessage?: unknown;
317
302
  /** Final value produced by the pipeline */
@@ -416,6 +401,8 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
416
401
  hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
417
402
  /** Get the translated message for a key, with optional replacements. */
418
403
  t: <Result = string, K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => Result;
404
+ /** Get the raw message value for a key without formatting or interpolation. */
405
+ tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => MessageValue | undefined;
419
406
  }
420
407
 
421
408
  type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
@@ -496,4 +483,4 @@ interface Renderer<Output> {
496
483
  */
497
484
  declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
498
485
 
499
- export { type ASTNode, type Attributes, 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 };
486
+ export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MessageObject, type MessageValue, type MissingHandler, 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
@@ -9,19 +9,19 @@ var findMessageInLocales = ({
9
9
  key
10
10
  }) => {
11
11
  for (const locale of candidateLocales) {
12
- const localeMessages = messages[locale];
13
- if (!localeMessages) continue;
14
- let candidate = localeMessages;
12
+ const messagesForLocale = messages[locale];
13
+ if (!messagesForLocale) continue;
14
+ let candidate = messagesForLocale;
15
15
  const keys = key.split(".");
16
- for (const k of keys) {
17
- if (candidate && typeof candidate === "object" && k in candidate) {
18
- candidate = candidate[k];
16
+ for (const key2 of keys) {
17
+ if (candidate !== null && typeof candidate === "object" && key2 in candidate) {
18
+ candidate = candidate[key2];
19
19
  } else {
20
20
  candidate = void 0;
21
21
  break;
22
22
  }
23
23
  }
24
- if (typeof candidate === "string") return candidate;
24
+ if (candidate !== void 0) return candidate;
25
25
  }
26
26
  };
27
27
 
@@ -29,11 +29,15 @@ var findMessageInLocales = ({
29
29
  var findMessage = rura.createHook(
30
30
  "findMessage",
31
31
  (ctx) => {
32
- ctx.rawMessage = findMessageInLocales({
32
+ ctx.rawValue = void 0;
33
+ ctx.rawString = void 0;
34
+ const message = findMessageInLocales({
33
35
  messages: ctx.messages,
34
36
  candidateLocales: ctx.candidateLocales,
35
37
  key: ctx.key
36
38
  });
39
+ ctx.rawValue = message;
40
+ if (typeof message === "string") ctx.rawString = message;
37
41
  },
38
42
  200
39
43
  );
@@ -48,7 +52,8 @@ function makeHandlerContext(ctx) {
48
52
  key: ctx.key,
49
53
  replacements: ctx.replacements,
50
54
  candidateLocales: ctx.candidateLocales,
51
- rawMessage: ctx.rawMessage,
55
+ rawValue: ctx.rawValue,
56
+ rawString: ctx.rawString,
52
57
  formattedMessage: ctx.formattedMessage,
53
58
  meta: ctx.meta
54
59
  });
@@ -58,9 +63,9 @@ function makeHandlerContext(ctx) {
58
63
  var format = rura.createHook(
59
64
  "format",
60
65
  (ctx) => {
61
- const { config, rawMessage } = ctx;
66
+ const { config, rawString } = ctx;
62
67
  const { formatHandler } = config.handlers || {};
63
- if (!formatHandler || rawMessage === void 0) return;
68
+ if (!formatHandler || rawString === void 0) return;
64
69
  ctx.formattedMessage = formatHandler(
65
70
  makeHandlerContext(ctx)
66
71
  );
@@ -91,8 +96,8 @@ var replaceValues = (message, params) => {
91
96
  var interpolate = rura.createHook(
92
97
  "interpolate",
93
98
  (ctx) => {
94
- const { rawMessage, formattedMessage, replacements } = ctx;
95
- const message = formattedMessage ?? rawMessage;
99
+ const { rawString, formattedMessage, replacements } = ctx;
100
+ const message = formattedMessage ?? rawString;
96
101
  if (typeof message !== "string" || !replacements) {
97
102
  ctx.finalMessage = message;
98
103
  return;
@@ -114,7 +119,7 @@ var loading = rura.createHook(
114
119
  };
115
120
  }
116
121
  const { loadingMessage } = config;
117
- if (loadingMessage) {
122
+ if ("loadingMessage" in config) {
118
123
  return { early: true, output: loadingMessage };
119
124
  }
120
125
  },
@@ -123,8 +128,8 @@ var loading = rura.createHook(
123
128
  var missing = rura.createHook(
124
129
  "missing",
125
130
  (ctx) => {
126
- const { config, key, rawMessage } = ctx;
127
- if (rawMessage !== void 0) return;
131
+ const { config, key, rawString } = ctx;
132
+ if (rawString !== void 0) return;
128
133
  const { missingHandler } = config.handlers || {};
129
134
  if (missingHandler) {
130
135
  return {
@@ -132,9 +137,9 @@ var missing = rura.createHook(
132
137
  output: missingHandler(makeHandlerContext(ctx))
133
138
  };
134
139
  }
135
- const { placeholder } = config;
136
- if (placeholder) {
137
- return { early: true, output: placeholder };
140
+ const { missingMessage } = config;
141
+ if ("missingMessage" in config) {
142
+ return { early: true, output: missingMessage };
138
143
  }
139
144
  return { early: true, output: key };
140
145
  },
@@ -227,20 +232,31 @@ var hasKey = ({
227
232
  }) => {
228
233
  const candidateLocales = resolveCandidateLocales(targetLocale || locale);
229
234
  const message = findMessageInLocales({ messages, candidateLocales, key });
230
- return !!message;
235
+ return message !== void 0;
231
236
  };
232
- function translate(options) {
237
+ function runTranslate(options) {
233
238
  const context = {
234
239
  ...options,
235
240
  config: options.translateConfig,
236
241
  candidateLocales: [],
237
242
  meta: {}
238
243
  };
239
- const { early, ctx, output } = rura.run(context, options.hooks);
244
+ return rura.run(context, options.hooks);
245
+ }
246
+
247
+ // src/translators/methods/translate.ts
248
+ function translate(options) {
249
+ const { early, ctx, output } = runTranslate(options);
240
250
  if (early === true) return output;
241
251
  return ctx.finalMessage;
242
252
  }
243
253
 
254
+ // src/translators/methods/translate-raw.ts
255
+ function translateRaw(options) {
256
+ const { ctx } = runTranslate(options);
257
+ return ctx.rawValue;
258
+ }
259
+
244
260
  // src/translators/core-translator/core-translator.ts
245
261
  var CoreTranslator = class extends BaseTranslator {
246
262
  /** User-provided options including messages, locale, and config. */
@@ -296,6 +312,18 @@ var CoreTranslator = class extends BaseTranslator {
296
312
  replacements
297
313
  });
298
314
  };
315
+ /** Get the raw message value for a key without formatting or interpolation. */
316
+ tRaw = (key, replacements) => {
317
+ return translateRaw({
318
+ hooks: this.hooks,
319
+ messages: this._messages,
320
+ locale: this._locale,
321
+ isLoading: this._isLoading,
322
+ translateConfig: this.translateConfig,
323
+ key,
324
+ replacements
325
+ });
326
+ };
299
327
  };
300
328
 
301
329
  // src/translators/scope-translator/utils/get-full-key.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor-translator",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "🤖 A modern, type-safe i18n engine.",
5
5
  "author": {
6
6
  "name": "Yiming Liao",
@@ -50,13 +50,14 @@
50
50
  "node": ">=16.0.0"
51
51
  },
52
52
  "scripts": {
53
- "build": "tsup",
54
- "prepublishOnly": "yarn build",
55
- "test": "vitest",
56
53
  "type": "tsc --noEmit",
57
54
  "lint": "eslint",
58
55
  "lint:debug": "eslint --debug",
56
+ "test": "vitest",
57
+ "test:types": "tsx scripts/test-types.ts",
59
58
  "knip": "knip --config .config/knip.config.ts",
59
+ "build": "tsup",
60
+ "prepublishOnly": "yarn build",
60
61
  "examples:html": "vite --config examples/html/basic/vite.config.ts",
61
62
  "examples:html:rich-message": "vite --config examples/html/rich-message/vite.config.ts"
62
63
  },