kotori 3.0.4 → 3.1.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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Strongly-typed, modular i18n for React. Variables are inferred directly from your strings — no codegen, no JSON, no schema files.
6
6
 
7
7
  ```ts
8
- const { dict } = kotori({
8
+ const { dict, t } = kotori({
9
9
  primaryLanguageTag: 'en',
10
10
  secondaryLanguageTags: ['zh', 'ja', 'ms'],
11
11
  })
@@ -26,16 +26,16 @@ const intro = dict({
26
26
 
27
27
 
28
28
  // ✅ Works
29
- t('intro', { name: 'John', time: '12:25' })
29
+ t(intro, { name: 'John', time: '12:25' })
30
30
 
31
31
  // ❌ TypeScript error: missing { name }
32
- t('intro', { time: '12:25' })
32
+ t(intro, { time: '12:25' })
33
33
 
34
34
  // ❌ TypeScript error: unknown key 'nama'
35
- t('intro', { nama: 'John', time: '12:25' })
35
+ t(intro, { nama: 'John', time: '12:25' })
36
36
 
37
37
  // ❌ TypeScript error: invalid format for 'time'
38
- t('intro', { name: 'John', time: '12-00' })
38
+ t(intro, { name: 'John', time: '12-00' })
39
39
  ```
40
40
 
41
41
  - No codegen
@@ -180,7 +180,7 @@ export const { useT, dict, setLanguage } = kotori({
180
180
  | `primaryLanguageTag` | `BCP47LanguageTag` | The source language. Drives variable inference. |
181
181
  | `secondaryLanguageTags` | `BCP47LanguageTag[]` | Additional supported languages. |
182
182
 
183
- Returns `{ dict, useT, setLanguage }`.
183
+ Returns `{ dict, useT, setLanguage, t }`.
184
184
 
185
185
  ### `dict(translations)<argsType?>`
186
186
 
@@ -203,6 +203,10 @@ const time = dict({ en: '{{hour}}:{{minute}}' })<{
203
203
 
204
204
  Updates the current language and rerenders all active `useT` consumers across all pages. Available directly on the `kotori` instance — useful for calling outside of React (route guards, axios interceptors, etc.).
205
205
 
206
+ ### `t(dict, args?)`
207
+
208
+ Returns the translated string for the current language. `args` is required if the string has variables, omitted if it doesn't. Available directly on the `kotori` instance for non-React usage, but typically accessed via the `useT` hook.
209
+
206
210
  ### `useT()`
207
211
 
208
212
  React hook. Returns `{ t, language, setLanguage }`.
@@ -224,6 +228,7 @@ kotori uses [BCP 47](https://www.iana.org/assignments/language-subtag-registry/l
224
228
  - Pluralization support
225
229
  - Gender support
226
230
  - Value formatting (date, number, currency)
231
+ - Support for non-React frameworks (Vue, Svelte, Angular, etc.)
227
232
 
228
233
  ## Trivial
229
234
 
package/dist/index.cjs CHANGED
@@ -20,17 +20,19 @@ const kotori = (props) => {
20
20
  listeners.delete(listener);
21
21
  };
22
22
  };
23
+ const t = (dict, ...args) => {
24
+ let locale = dict().translation[language] || "unable_to_load_translations";
25
+ for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
26
+ return locale;
27
+ };
23
28
  let snapshot = {
24
29
  language,
25
30
  setLanguage,
26
- t: (dict, ...args) => {
27
- let locale = dict().translation[language] || "unable_to_load_translations";
28
- for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
29
- return locale;
30
- }
31
+ t
31
32
  };
32
33
  return {
33
34
  setLanguage,
35
+ t,
34
36
  dict: (translation) => () => ({ translation }),
35
37
  useT: () => (0, react.useSyncExternalStore)(subscribe, () => snapshot, () => snapshot)
36
38
  };
package/dist/index.d.cts CHANGED
@@ -13,6 +13,10 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
13
13
  secondaryLanguageTags: SecondaryTags[];
14
14
  }) => {
15
15
  setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
16
+ t: <DictCallback extends () => Readonly<{
17
+ translation: Record<PrimaryTag | SecondaryTags, string>;
18
+ [_args]?: Record<string, string | number>;
19
+ }>>(dict: DictCallback, ...args: keyof NonNullable<ReturnType<DictCallback>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallback>[typeof _args]>]) => string;
16
20
  dict: <const PrimaryString extends string, const SecondaryObject extends { [Key in SecondaryTags]: ExtractVariables<PrimaryString> extends infer PrimaryVariables ? ExtractVariables<SecondaryObject[Key] & string> extends infer SecondaryVariables ? PrimaryVariables[] extends SecondaryVariables[] ? SecondaryVariables[] extends PrimaryVariables[] ? SecondaryObject[Key] : "variables not match!" : "variables not match!!" : never : never }>(translation: { [Key in PrimaryTag]: PrimaryString } & SecondaryObject) => <const ArgsType extends Record<ExtractVariables<PrimaryString>, string | number> = Record<ExtractVariables<PrimaryString>, string | number>>() => Readonly<{
17
21
  translation: typeof translation;
18
22
  [_args]?: ArgsType;
package/dist/index.d.mts CHANGED
@@ -13,6 +13,10 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
13
13
  secondaryLanguageTags: SecondaryTags[];
14
14
  }) => {
15
15
  setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
16
+ t: <DictCallback extends () => Readonly<{
17
+ translation: Record<PrimaryTag | SecondaryTags, string>;
18
+ [_args]?: Record<string, string | number>;
19
+ }>>(dict: DictCallback, ...args: keyof NonNullable<ReturnType<DictCallback>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallback>[typeof _args]>]) => string;
16
20
  dict: <const PrimaryString extends string, const SecondaryObject extends { [Key in SecondaryTags]: ExtractVariables<PrimaryString> extends infer PrimaryVariables ? ExtractVariables<SecondaryObject[Key] & string> extends infer SecondaryVariables ? PrimaryVariables[] extends SecondaryVariables[] ? SecondaryVariables[] extends PrimaryVariables[] ? SecondaryObject[Key] : "variables not match!" : "variables not match!!" : never : never }>(translation: { [Key in PrimaryTag]: PrimaryString } & SecondaryObject) => <const ArgsType extends Record<ExtractVariables<PrimaryString>, string | number> = Record<ExtractVariables<PrimaryString>, string | number>>() => Readonly<{
17
21
  translation: typeof translation;
18
22
  [_args]?: ArgsType;
package/dist/index.mjs CHANGED
@@ -19,17 +19,19 @@ const kotori = (props) => {
19
19
  listeners.delete(listener);
20
20
  };
21
21
  };
22
+ const t = (dict, ...args) => {
23
+ let locale = dict().translation[language] || "unable_to_load_translations";
24
+ for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
25
+ return locale;
26
+ };
22
27
  let snapshot = {
23
28
  language,
24
29
  setLanguage,
25
- t: (dict, ...args) => {
26
- let locale = dict().translation[language] || "unable_to_load_translations";
27
- for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
28
- return locale;
29
- }
30
+ t
30
31
  };
31
32
  return {
32
33
  setLanguage,
34
+ t,
33
35
  dict: (translation) => () => ({ translation }),
34
36
  useT: () => useSyncExternalStore(subscribe, () => snapshot, () => snapshot)
35
37
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kotori",
3
3
  "description": "Strongly-typed and composable internationalization library for React",
4
- "version": "3.0.4",
4
+ "version": "3.1.0",
5
5
  "scripts": {
6
6
  "setup": "rm -rf node_modules && npm i && git init && husky",
7
7
  "prepublishOnly": "npm i && npx tsc && npm run build",