intor-translator 1.0.3 → 1.0.5

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
@@ -126,6 +126,12 @@ var hasKey = ({
126
126
  }) => {
127
127
  const messages = messagesRef.current;
128
128
  const locale = localeRef.current;
129
+ if (!messages) {
130
+ throw new Error("[intor-translator] 'messages' is required");
131
+ }
132
+ if (!locale) {
133
+ throw new Error("[intor-translator] 'locale' is required");
134
+ }
129
135
  const localesToTry = resolveLocalesToTry(targetLocale || locale);
130
136
  return findMessageInLocales({ messages, localesToTry, key }) ? true : false;
131
137
  };
@@ -160,6 +166,12 @@ var translate = ({
160
166
  }) => {
161
167
  const messages = messagesRef.current;
162
168
  const locale = localeRef.current;
169
+ if (!messages) {
170
+ throw new Error("[intor-translator] 'messages' is required");
171
+ }
172
+ if (!locale) {
173
+ throw new Error("[intor-translator] 'locale' is required");
174
+ }
163
175
  const isLoading = isLoadingRef.current;
164
176
  const {
165
177
  fallbackLocales,
@@ -200,9 +212,9 @@ var translate = ({
200
212
 
201
213
  // src/translators/base-translator/base-translator.ts
202
214
  var BaseTranslator = class {
203
- constructor(options) {
204
- this.messagesRef = { current: {} };
205
- this.localeRef = { current: "" };
215
+ constructor(options = {}) {
216
+ this.messagesRef = { current: void 0 };
217
+ this.localeRef = { current: void 0 };
206
218
  /** Check if a key exists in the specified locale or current locale. */
207
219
  this.hasKey = (key, targetLocale) => {
208
220
  return hasKey({
@@ -212,15 +224,12 @@ var BaseTranslator = class {
212
224
  targetLocale
213
225
  });
214
226
  };
215
- if (!options.messages) {
216
- throw new Error("[intor-translator] 'messages' is required");
227
+ if (options.messages) {
228
+ this.messagesRef.current = options.messages;
217
229
  }
218
- if (!options.locale) {
219
- throw new Error("[intor-translator] 'locale' is required");
230
+ if (options.locale) {
231
+ this.localeRef.current = options.locale;
220
232
  }
221
- this.options = options;
222
- this.messagesRef.current = options.messages;
223
- this.localeRef.current = options.locale;
224
233
  }
225
234
  /** Get all message data. */
226
235
  get messages() {
@@ -237,7 +246,7 @@ var BaseTranslator = class {
237
246
  }
238
247
  /** Change the active locale if available. */
239
248
  setLocale(newLocale) {
240
- if (newLocale in this.messagesRef.current) {
249
+ if (this.messagesRef.current && newLocale in this.messagesRef.current) {
241
250
  this.localeRef.current = newLocale;
242
251
  return true;
243
252
  }
@@ -260,7 +269,7 @@ var CoreTranslator = class extends BaseTranslator {
260
269
  replacements
261
270
  });
262
271
  };
263
- this.options = options;
272
+ this.options = options || {};
264
273
  }
265
274
  /** Get the current loading state. */
266
275
  get isLoading() {
@@ -311,7 +320,6 @@ var ScopeTranslator = class extends CoreTranslator {
311
320
  }
312
321
  };
313
322
  };
314
- this.options = options;
315
323
  }
316
324
  };
317
325
 
package/dist/index.d.cts CHANGED
@@ -262,6 +262,14 @@ type ResolvePathType<T, P extends string> = P extends `${infer Head}.${infer Tai
262
262
  * ScopedLeafKeys<Messages, "auth.login"> → "success" | "failed"
263
263
  */
264
264
  type ScopedLeafKeys<M extends LocaleNamespaceMessages, K extends string, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends infer ResolvedLocaleMessages ? ResolvedLocaleMessages extends object ? LeafKeys<ResolvePathType<ResolvedLocaleMessages, K>, D> : never : never;
265
+ /**
266
+ * Infer valid key type from locale messages.
267
+ *
268
+ * If `M` is not passed or empty, fallback to `string`.
269
+ */
270
+ type InferTranslatorKey<M extends LocaleNamespaceMessages> = [
271
+ M
272
+ ] extends [never] ? string : UnionLocaleLeafKeys<M>;
265
273
 
266
274
  /**
267
275
  * A ref object holding all localized messages by locale.
@@ -275,7 +283,7 @@ type ScopedLeafKeys<M extends LocaleNamespaceMessages, K extends string, D exten
275
283
  * };
276
284
  */
277
285
  type MessagesRef<M extends LocaleNamespaceMessages> = {
278
- current: Readonly<M>;
286
+ current?: Readonly<M>;
279
287
  };
280
288
  /**
281
289
  * A ref object holding the currently selected locale.
@@ -286,7 +294,7 @@ type MessagesRef<M extends LocaleNamespaceMessages> = {
286
294
  * };
287
295
  */
288
296
  type LocaleRef<M extends LocaleNamespaceMessages> = {
289
- current: LocaleKey<M>;
297
+ current?: LocaleKey<M>;
290
298
  };
291
299
  /**
292
300
  * A ref object indicating whether translation is loading.
@@ -337,43 +345,42 @@ type TranslateContext = {
337
345
  };
338
346
 
339
347
  interface BaseTranslatorOptions<M extends LocaleNamespaceMessages> {
340
- messages: Readonly<M>;
341
- locale: LocaleKey<M>;
348
+ messages?: Readonly<M>;
349
+ locale?: LocaleKey<M>;
342
350
  }
343
351
 
344
- declare class BaseTranslator<M extends LocaleNamespaceMessages> {
345
- protected options: BaseTranslatorOptions<M>;
352
+ declare class BaseTranslator<M extends LocaleNamespaceMessages = never> {
346
353
  protected messagesRef: MessagesRef<M>;
347
354
  protected localeRef: LocaleRef<M>;
348
- constructor(options: BaseTranslatorOptions<M>);
355
+ constructor(options?: BaseTranslatorOptions<M>);
349
356
  /** Get all message data. */
350
- get messages(): M;
357
+ get messages(): M | undefined;
351
358
  /** Replace messages with new ones. */
352
359
  setMessages(messages: M): void;
353
360
  /** Get the current active locale. */
354
- get locale(): LocaleKey<M>;
361
+ get locale(): LocaleKey<M> | undefined;
355
362
  /** Change the active locale if available. */
356
363
  setLocale(newLocale: LocaleKey<M>): boolean;
357
364
  /** Check if a key exists in the specified locale or current locale. */
358
- hasKey: (key: UnionLocaleLeafKeys<M>, targetLocale?: LocaleKey<M>) => boolean;
365
+ hasKey: (key: InferTranslatorKey<M>, targetLocale?: LocaleKey<M>) => boolean;
359
366
  }
360
367
 
361
368
  interface CoreTranslatorOptions<M extends LocaleNamespaceMessages> extends BaseTranslatorOptions<M>, TranslateConfig {
362
369
  }
363
370
 
364
- declare class CoreTranslator<M extends LocaleNamespaceMessages> extends BaseTranslator<M> {
371
+ declare class CoreTranslator<M extends LocaleNamespaceMessages = never> extends BaseTranslator<M> {
365
372
  protected options: CoreTranslatorOptions<M>;
366
373
  protected isLoadingRef: IsLoadingRef;
367
- constructor(options: CoreTranslatorOptions<M>);
374
+ constructor(options?: CoreTranslatorOptions<M>);
368
375
  /** Get the current loading state. */
369
376
  get isLoading(): boolean;
370
377
  /** Set the loading state. */
371
378
  setLoading(state: boolean): void;
372
- t: <Result = string>(key: UnionLocaleLeafKeys<M>, replacements?: Replacement | RichReplacement) => Result;
379
+ t: <Result = string>(key: InferTranslatorKey<M>, replacements?: Replacement | RichReplacement) => Result;
373
380
  }
374
381
 
375
- declare class ScopeTranslator<M extends LocaleNamespaceMessages> extends CoreTranslator<M> {
376
- constructor(options: CoreTranslatorOptions<M>);
382
+ declare class ScopeTranslator<M extends LocaleNamespaceMessages = never> extends CoreTranslator<M> {
383
+ constructor(options?: CoreTranslatorOptions<M>);
377
384
  scoped: <K extends NodeKeys<UnionLocaleMessages<M>> & string, ScopedKeys extends ScopedLeafKeys<M, K> & string>(preKey: K) => {
378
385
  hasKey: (key?: ScopedKeys | undefined, targetLocale?: string) => boolean;
379
386
  t: (key?: ScopedKeys | undefined, replacements?: Replacement | RichReplacement) => string;
package/dist/index.d.ts CHANGED
@@ -262,6 +262,14 @@ type ResolvePathType<T, P extends string> = P extends `${infer Head}.${infer Tai
262
262
  * ScopedLeafKeys<Messages, "auth.login"> → "success" | "failed"
263
263
  */
264
264
  type ScopedLeafKeys<M extends LocaleNamespaceMessages, K extends string, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends infer ResolvedLocaleMessages ? ResolvedLocaleMessages extends object ? LeafKeys<ResolvePathType<ResolvedLocaleMessages, K>, D> : never : never;
265
+ /**
266
+ * Infer valid key type from locale messages.
267
+ *
268
+ * If `M` is not passed or empty, fallback to `string`.
269
+ */
270
+ type InferTranslatorKey<M extends LocaleNamespaceMessages> = [
271
+ M
272
+ ] extends [never] ? string : UnionLocaleLeafKeys<M>;
265
273
 
266
274
  /**
267
275
  * A ref object holding all localized messages by locale.
@@ -275,7 +283,7 @@ type ScopedLeafKeys<M extends LocaleNamespaceMessages, K extends string, D exten
275
283
  * };
276
284
  */
277
285
  type MessagesRef<M extends LocaleNamespaceMessages> = {
278
- current: Readonly<M>;
286
+ current?: Readonly<M>;
279
287
  };
280
288
  /**
281
289
  * A ref object holding the currently selected locale.
@@ -286,7 +294,7 @@ type MessagesRef<M extends LocaleNamespaceMessages> = {
286
294
  * };
287
295
  */
288
296
  type LocaleRef<M extends LocaleNamespaceMessages> = {
289
- current: LocaleKey<M>;
297
+ current?: LocaleKey<M>;
290
298
  };
291
299
  /**
292
300
  * A ref object indicating whether translation is loading.
@@ -337,43 +345,42 @@ type TranslateContext = {
337
345
  };
338
346
 
339
347
  interface BaseTranslatorOptions<M extends LocaleNamespaceMessages> {
340
- messages: Readonly<M>;
341
- locale: LocaleKey<M>;
348
+ messages?: Readonly<M>;
349
+ locale?: LocaleKey<M>;
342
350
  }
343
351
 
344
- declare class BaseTranslator<M extends LocaleNamespaceMessages> {
345
- protected options: BaseTranslatorOptions<M>;
352
+ declare class BaseTranslator<M extends LocaleNamespaceMessages = never> {
346
353
  protected messagesRef: MessagesRef<M>;
347
354
  protected localeRef: LocaleRef<M>;
348
- constructor(options: BaseTranslatorOptions<M>);
355
+ constructor(options?: BaseTranslatorOptions<M>);
349
356
  /** Get all message data. */
350
- get messages(): M;
357
+ get messages(): M | undefined;
351
358
  /** Replace messages with new ones. */
352
359
  setMessages(messages: M): void;
353
360
  /** Get the current active locale. */
354
- get locale(): LocaleKey<M>;
361
+ get locale(): LocaleKey<M> | undefined;
355
362
  /** Change the active locale if available. */
356
363
  setLocale(newLocale: LocaleKey<M>): boolean;
357
364
  /** Check if a key exists in the specified locale or current locale. */
358
- hasKey: (key: UnionLocaleLeafKeys<M>, targetLocale?: LocaleKey<M>) => boolean;
365
+ hasKey: (key: InferTranslatorKey<M>, targetLocale?: LocaleKey<M>) => boolean;
359
366
  }
360
367
 
361
368
  interface CoreTranslatorOptions<M extends LocaleNamespaceMessages> extends BaseTranslatorOptions<M>, TranslateConfig {
362
369
  }
363
370
 
364
- declare class CoreTranslator<M extends LocaleNamespaceMessages> extends BaseTranslator<M> {
371
+ declare class CoreTranslator<M extends LocaleNamespaceMessages = never> extends BaseTranslator<M> {
365
372
  protected options: CoreTranslatorOptions<M>;
366
373
  protected isLoadingRef: IsLoadingRef;
367
- constructor(options: CoreTranslatorOptions<M>);
374
+ constructor(options?: CoreTranslatorOptions<M>);
368
375
  /** Get the current loading state. */
369
376
  get isLoading(): boolean;
370
377
  /** Set the loading state. */
371
378
  setLoading(state: boolean): void;
372
- t: <Result = string>(key: UnionLocaleLeafKeys<M>, replacements?: Replacement | RichReplacement) => Result;
379
+ t: <Result = string>(key: InferTranslatorKey<M>, replacements?: Replacement | RichReplacement) => Result;
373
380
  }
374
381
 
375
- declare class ScopeTranslator<M extends LocaleNamespaceMessages> extends CoreTranslator<M> {
376
- constructor(options: CoreTranslatorOptions<M>);
382
+ declare class ScopeTranslator<M extends LocaleNamespaceMessages = never> extends CoreTranslator<M> {
383
+ constructor(options?: CoreTranslatorOptions<M>);
377
384
  scoped: <K extends NodeKeys<UnionLocaleMessages<M>> & string, ScopedKeys extends ScopedLeafKeys<M, K> & string>(preKey: K) => {
378
385
  hasKey: (key?: ScopedKeys | undefined, targetLocale?: string) => boolean;
379
386
  t: (key?: ScopedKeys | undefined, replacements?: Replacement | RichReplacement) => string;
package/dist/index.js CHANGED
@@ -124,6 +124,12 @@ var hasKey = ({
124
124
  }) => {
125
125
  const messages = messagesRef.current;
126
126
  const locale = localeRef.current;
127
+ if (!messages) {
128
+ throw new Error("[intor-translator] 'messages' is required");
129
+ }
130
+ if (!locale) {
131
+ throw new Error("[intor-translator] 'locale' is required");
132
+ }
127
133
  const localesToTry = resolveLocalesToTry(targetLocale || locale);
128
134
  return findMessageInLocales({ messages, localesToTry, key }) ? true : false;
129
135
  };
@@ -158,6 +164,12 @@ var translate = ({
158
164
  }) => {
159
165
  const messages = messagesRef.current;
160
166
  const locale = localeRef.current;
167
+ if (!messages) {
168
+ throw new Error("[intor-translator] 'messages' is required");
169
+ }
170
+ if (!locale) {
171
+ throw new Error("[intor-translator] 'locale' is required");
172
+ }
161
173
  const isLoading = isLoadingRef.current;
162
174
  const {
163
175
  fallbackLocales,
@@ -198,9 +210,9 @@ var translate = ({
198
210
 
199
211
  // src/translators/base-translator/base-translator.ts
200
212
  var BaseTranslator = class {
201
- constructor(options) {
202
- this.messagesRef = { current: {} };
203
- this.localeRef = { current: "" };
213
+ constructor(options = {}) {
214
+ this.messagesRef = { current: void 0 };
215
+ this.localeRef = { current: void 0 };
204
216
  /** Check if a key exists in the specified locale or current locale. */
205
217
  this.hasKey = (key, targetLocale) => {
206
218
  return hasKey({
@@ -210,15 +222,12 @@ var BaseTranslator = class {
210
222
  targetLocale
211
223
  });
212
224
  };
213
- if (!options.messages) {
214
- throw new Error("[intor-translator] 'messages' is required");
225
+ if (options.messages) {
226
+ this.messagesRef.current = options.messages;
215
227
  }
216
- if (!options.locale) {
217
- throw new Error("[intor-translator] 'locale' is required");
228
+ if (options.locale) {
229
+ this.localeRef.current = options.locale;
218
230
  }
219
- this.options = options;
220
- this.messagesRef.current = options.messages;
221
- this.localeRef.current = options.locale;
222
231
  }
223
232
  /** Get all message data. */
224
233
  get messages() {
@@ -235,7 +244,7 @@ var BaseTranslator = class {
235
244
  }
236
245
  /** Change the active locale if available. */
237
246
  setLocale(newLocale) {
238
- if (newLocale in this.messagesRef.current) {
247
+ if (this.messagesRef.current && newLocale in this.messagesRef.current) {
239
248
  this.localeRef.current = newLocale;
240
249
  return true;
241
250
  }
@@ -258,7 +267,7 @@ var CoreTranslator = class extends BaseTranslator {
258
267
  replacements
259
268
  });
260
269
  };
261
- this.options = options;
270
+ this.options = options || {};
262
271
  }
263
272
  /** Get the current loading state. */
264
273
  get isLoading() {
@@ -309,7 +318,6 @@ var ScopeTranslator = class extends CoreTranslator {
309
318
  }
310
319
  };
311
320
  };
312
- this.options = options;
313
321
  }
314
322
  };
315
323
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor-translator",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A type safe translator that knows what to say and how to handle the rest. Supports custom messages, rich replacements, and async loading.",
5
5
  "author": "Yiming Liao",
6
6
  "license": "MIT",