kotori 0.0.1 → 0.0.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 +26 -11
- package/dist/index.cjs +51 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +50 -1
- package/package.json +72 -65
package/README.md
CHANGED
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
Strongly-typed, modular i18n for React. Variables are inferred directly from your strings — no codegen, no JSON, no schema files.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
const
|
|
6
|
+
const { dict } = kotori({
|
|
7
|
+
primaryLanguageTag: 'en',
|
|
8
|
+
secondaryLanguageTags: ['zh', 'ja', 'ms'],
|
|
9
|
+
})
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
// ❌ compile error: missing japanese translation
|
|
12
|
+
const intro = dict({
|
|
13
|
+
en: 'Hello {{name}}, is it {{time}} now?', // base string drives the type contract
|
|
14
|
+
zh: '你好,现在是 {{time}} 吗?', // ❌ compile error: missing key 'nam'
|
|
15
|
+
ms: 'Hai {{nam}}, adakah pukul {{time}} sekarang?' // ❌ compile error: unknown key 'nam'
|
|
16
|
+
})<{name: string; time: `${number}:${number}`}> // optional: type your arguments, by default it's `Record<'name'|'time', string>` in this example
|
|
17
|
+
|
|
18
|
+
t('intro', { name: 'John', time: '12:25' }) // ✅
|
|
19
|
+
t('intro', { time: '12:25' }) // ❌ compile error: missing { name }
|
|
20
|
+
t('intro', { nama: 'John', time: '12:25' }) // ❌ compile error: unknown key 'nama'
|
|
21
|
+
t('intro', { name: 'John', time: '12-00' }) // ❌ compile error: invalid format for 'time'
|
|
11
22
|
```
|
|
12
23
|
|
|
13
24
|
- No codegen
|
|
14
25
|
- No JSON
|
|
15
26
|
- No dependencies
|
|
16
|
-
- 0.
|
|
27
|
+
- 0.39kb gzipped
|
|
17
28
|
- Modular and tree-shakeable
|
|
18
29
|
- Language change in one page rerenders all pages
|
|
19
30
|
- Variables typed and inferred from string literals
|
|
@@ -55,7 +66,7 @@ const time = dict({
|
|
|
55
66
|
zh: '时间 {{time}}',
|
|
56
67
|
ja: '時間 {{time}}',
|
|
57
68
|
ms: 'waktu {{time}}',
|
|
58
|
-
// type your arguments, by default it's `Record<
|
|
69
|
+
// optional: type your arguments, by default it's `Record<time, string>` in this example
|
|
59
70
|
})<{ time: `${number}:${number}:${number}` }>
|
|
60
71
|
|
|
61
72
|
const { useTranslations } = createTranslations({
|
|
@@ -139,11 +150,13 @@ export const Page2 = () => {
|
|
|
139
150
|
|
|
140
151
|
## How It Works
|
|
141
152
|
|
|
153
|
+

|
|
154
|
+
|
|
142
155
|
### One `kotori` instance per app
|
|
143
156
|
|
|
144
157
|
`kotori` holds the language state. All `createTranslations` calls share that state — changing the language anywhere rerenders everywhere.
|
|
145
158
|
|
|
146
|
-
### One `createTranslations` per page/feature
|
|
159
|
+
### One `createTranslations` per page/component/feature
|
|
147
160
|
|
|
148
161
|
Translations are colocated with the component that uses them. Bundlers naturally code-split them, so each page only loads what it needs.
|
|
149
162
|
|
|
@@ -179,16 +192,18 @@ const time = dict({ en: '{{hour}}:{{minute}}' })<{
|
|
|
179
192
|
Creates a scoped i18n instance.
|
|
180
193
|
|
|
181
194
|
| option | type | description |
|
|
182
|
-
|
|
195
|
+
| --- | --- | --- |
|
|
183
196
|
| `primaryLanguageTag` | `AllTags` | The source language. Drives variable inference. |
|
|
184
197
|
| `secondaryLanguageTags` | `AllTags[]` | Additional supported languages. |
|
|
185
198
|
|
|
186
199
|
Returns `{ dict, createTranslations }`.
|
|
187
200
|
|
|
188
|
-
### `dict(translations)
|
|
201
|
+
### `dict(translations)<argsType?>`
|
|
189
202
|
|
|
190
203
|
Defines a translation unit. Takes one string per language. Optionally takes a generic to type the interpolated variables.
|
|
191
204
|
|
|
205
|
+
Returns `() => { translations: Record<string, string> }`.
|
|
206
|
+
|
|
192
207
|
### `createTranslations(dicts)`
|
|
193
208
|
|
|
194
209
|
Registers a set of dicts and returns `{ useTranslations }`. Call once per page or feature module.
|
|
@@ -198,7 +213,7 @@ Registers a set of dicts and returns `{ useTranslations }`. Call once per page o
|
|
|
198
213
|
React hook. Returns `{ t, getLanguage, setLanguage }`.
|
|
199
214
|
|
|
200
215
|
| return | description |
|
|
201
|
-
|
|
216
|
+
| --- | --- |
|
|
202
217
|
| `t(key, args?)` | Returns the translated string for the current language. `args` is required if the string has variables, omitted if it doesn't. |
|
|
203
218
|
| `getLanguage()` | Returns the current language tag. |
|
|
204
219
|
| `setLanguage(tag)` | Updates the language and rerenders all active `useTranslations` consumers. |
|
|
@@ -211,4 +226,4 @@ kotori uses [BCP 47](https://www.iana.org/assignments/language-subtag-registry/l
|
|
|
211
226
|
|
|
212
227
|
There are already a lot of i18n libraries, and the good names are mostly taken. The original plan was *kotoba* (言葉), the Japanese word for "words" — also taken. Claude suggested *kotori* as an alternative, and it stuck.
|
|
213
228
|
|
|
214
|
-
*Kotori* (小鳥) means "small bird" in Japanese. No deeper relevance to the library — it just sounds nice.
|
|
229
|
+
*Kotori* (小鳥) means "small bird" in Japanese. No deeper relevance to the library — it just sounds nice.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1,51 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let react = require("react");
|
|
3
|
+
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
const kotori = (props) => {
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
let languageTag = props.primaryLanguageTag;
|
|
8
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
9
|
+
const languageTagMethod = {
|
|
10
|
+
getLanguage: () => languageTag,
|
|
11
|
+
setLanguage: (tag) => {
|
|
12
|
+
languageTag = tag;
|
|
13
|
+
snapshots.forEach((snapshot, key) => {
|
|
14
|
+
snapshots.set(key, { ...snapshot });
|
|
15
|
+
});
|
|
16
|
+
listeners.forEach((listener) => {
|
|
17
|
+
listener();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
dict: (translation) => () => ({ translation }),
|
|
23
|
+
createTranslations: (dictCallbacks) => {
|
|
24
|
+
const s = Symbol();
|
|
25
|
+
let refCount = 0;
|
|
26
|
+
const snapshot = {
|
|
27
|
+
...languageTagMethod,
|
|
28
|
+
t: (key, ...args) => {
|
|
29
|
+
let locale = dictCallbacks[key]?.().translation[languageTag];
|
|
30
|
+
if (!locale) return;
|
|
31
|
+
for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
|
|
32
|
+
return locale;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
snapshots.set(s, snapshot);
|
|
36
|
+
return { useTranslations: () => (0, react.useSyncExternalStore)((listener) => {
|
|
37
|
+
if (refCount === 0) snapshots.set(s, snapshot);
|
|
38
|
+
refCount++;
|
|
39
|
+
listeners.add(listener);
|
|
40
|
+
return () => {
|
|
41
|
+
refCount--;
|
|
42
|
+
if (refCount === 0) snapshots.delete(s);
|
|
43
|
+
listeners.delete(listener);
|
|
44
|
+
};
|
|
45
|
+
}, () => snapshots.get(s)) };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
exports.kotori = kotori;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region node_modules/bcp47-language-tags/dist/zh.d.ts
|
|
2
2
|
type BCP47LanguageTagName = "zh-CN" | "zh-TW" | "zh-HK" | "zh-MO" | "zh-SG" | "zh-CHS" | "zh-CHT" | "en-US" | "en-GB" | "en-CA" | "en-AU" | "en-IN" | "en-ZA" | "en-NZ" | "en-IE" | "en-PH" | "en-ZW" | "en-BZ" | "en-CB" | "en-JM" | "en-TT" | "hi-IN" | "es-ES" | "es-MX" | "es-AR" | "es-CO" | "es-PE" | "es-VE" | "es-CL" | "es-EC" | "es-GT" | "es-CU" | "es-BO" | "es-DO" | "es-HN" | "es-PY" | "es-SV" | "es-NI" | "es-PR" | "es-UY" | "es-PA" | "es-CR" | "ar-EG" | "ar-SA" | "ar-DZ" | "ar-MA" | "ar-IQ" | "ar-SD" | "ar-YE" | "ar-SY" | "ar-TN" | "ar-LY" | "ar-JO" | "ar-LB" | "ar-KW" | "ar-AE" | "ar-BH" | "ar-QA" | "ar-OM" | "pt-BR" | "pt-PT" | "ru-RU" | "ja-JP" | "de-DE" | "de-AT" | "de-CH" | "fr-FR" | "fr-CA" | "fr-BE" | "fr-CH" | "fr-LU" | "fr-MC" | "ko-KR" | "it-IT" | "it-CH" | "tr-TR" | "th-TH" | "el-GR" | "cs-CZ" | "sv-SE" | "sv-FI" | "hu-HU" | "fi-FI" | "da-DK" | "nb-NO" | "nn-NO" | "he-IL" | "id-ID" | "ms-MY" | "ms-BN" | "ro-RO" | "bg-BG" | "uk-UA" | "sk-SK" | "sl-SI" | "hr-HR" | "ca-ES" | "lt-LT" | "lv-LV" | "et-EE" | "sq-AL" | "mk-MK" | "be-BY" | "is-IS" | "gl-ES" | "eu-ES" | "af-ZA" | "sw-KE" | "ta-IN" | "te-IN" | "kn-IN" | "mr-IN" | "gu-IN" | "pa-IN" | "kok-IN" | "sa-IN" | "ur-PK" | "fa-IR" | "syr-SY" | "div-MV" | "ka-GE";
|
|
3
3
|
//#endregion
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/index.d.ts
|
|
5
5
|
type Tags = BCP47LanguageTagName;
|
|
6
6
|
type SubTags = BCP47LanguageTagName extends `${infer SubTag}-${string}` ? SubTag : never;
|
|
7
7
|
type AllTags = Tags | SubTags;
|
|
@@ -21,11 +21,11 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
|
|
|
21
21
|
[_args]?: Record<string, string | number>;
|
|
22
22
|
}>>>(dictCallbacks: DictCallbacks) => {
|
|
23
23
|
useTranslations: () => {
|
|
24
|
+
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
24
25
|
getLanguage: () => PrimaryTag | SecondaryTags;
|
|
25
26
|
setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
|
|
26
|
-
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
//#endregion
|
|
31
|
-
export { AllTags,
|
|
31
|
+
export { AllTags, SubTags, Tags, kotori };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region node_modules/bcp47-language-tags/dist/zh.d.ts
|
|
2
2
|
type BCP47LanguageTagName = "zh-CN" | "zh-TW" | "zh-HK" | "zh-MO" | "zh-SG" | "zh-CHS" | "zh-CHT" | "en-US" | "en-GB" | "en-CA" | "en-AU" | "en-IN" | "en-ZA" | "en-NZ" | "en-IE" | "en-PH" | "en-ZW" | "en-BZ" | "en-CB" | "en-JM" | "en-TT" | "hi-IN" | "es-ES" | "es-MX" | "es-AR" | "es-CO" | "es-PE" | "es-VE" | "es-CL" | "es-EC" | "es-GT" | "es-CU" | "es-BO" | "es-DO" | "es-HN" | "es-PY" | "es-SV" | "es-NI" | "es-PR" | "es-UY" | "es-PA" | "es-CR" | "ar-EG" | "ar-SA" | "ar-DZ" | "ar-MA" | "ar-IQ" | "ar-SD" | "ar-YE" | "ar-SY" | "ar-TN" | "ar-LY" | "ar-JO" | "ar-LB" | "ar-KW" | "ar-AE" | "ar-BH" | "ar-QA" | "ar-OM" | "pt-BR" | "pt-PT" | "ru-RU" | "ja-JP" | "de-DE" | "de-AT" | "de-CH" | "fr-FR" | "fr-CA" | "fr-BE" | "fr-CH" | "fr-LU" | "fr-MC" | "ko-KR" | "it-IT" | "it-CH" | "tr-TR" | "th-TH" | "el-GR" | "cs-CZ" | "sv-SE" | "sv-FI" | "hu-HU" | "fi-FI" | "da-DK" | "nb-NO" | "nn-NO" | "he-IL" | "id-ID" | "ms-MY" | "ms-BN" | "ro-RO" | "bg-BG" | "uk-UA" | "sk-SK" | "sl-SI" | "hr-HR" | "ca-ES" | "lt-LT" | "lv-LV" | "et-EE" | "sq-AL" | "mk-MK" | "be-BY" | "is-IS" | "gl-ES" | "eu-ES" | "af-ZA" | "sw-KE" | "ta-IN" | "te-IN" | "kn-IN" | "mr-IN" | "gu-IN" | "pa-IN" | "kok-IN" | "sa-IN" | "ur-PK" | "fa-IR" | "syr-SY" | "div-MV" | "ka-GE";
|
|
3
3
|
//#endregion
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/index.d.ts
|
|
5
5
|
type Tags = BCP47LanguageTagName;
|
|
6
6
|
type SubTags = BCP47LanguageTagName extends `${infer SubTag}-${string}` ? SubTag : never;
|
|
7
7
|
type AllTags = Tags | SubTags;
|
|
@@ -21,11 +21,11 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
|
|
|
21
21
|
[_args]?: Record<string, string | number>;
|
|
22
22
|
}>>>(dictCallbacks: DictCallbacks) => {
|
|
23
23
|
useTranslations: () => {
|
|
24
|
+
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
24
25
|
getLanguage: () => PrimaryTag | SecondaryTags;
|
|
25
26
|
setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
|
|
26
|
-
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
//#endregion
|
|
31
|
-
export { AllTags,
|
|
31
|
+
export { AllTags, SubTags, Tags, kotori };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1,50 @@
|
|
|
1
|
-
import{useSyncExternalStore
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
const kotori = (props) => {
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
let languageTag = props.primaryLanguageTag;
|
|
7
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
8
|
+
const languageTagMethod = {
|
|
9
|
+
getLanguage: () => languageTag,
|
|
10
|
+
setLanguage: (tag) => {
|
|
11
|
+
languageTag = tag;
|
|
12
|
+
snapshots.forEach((snapshot, key) => {
|
|
13
|
+
snapshots.set(key, { ...snapshot });
|
|
14
|
+
});
|
|
15
|
+
listeners.forEach((listener) => {
|
|
16
|
+
listener();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
dict: (translation) => () => ({ translation }),
|
|
22
|
+
createTranslations: (dictCallbacks) => {
|
|
23
|
+
const s = Symbol();
|
|
24
|
+
let refCount = 0;
|
|
25
|
+
const snapshot = {
|
|
26
|
+
...languageTagMethod,
|
|
27
|
+
t: (key, ...args) => {
|
|
28
|
+
let locale = dictCallbacks[key]?.().translation[languageTag];
|
|
29
|
+
if (!locale) return;
|
|
30
|
+
for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
|
|
31
|
+
return locale;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
snapshots.set(s, snapshot);
|
|
35
|
+
return { useTranslations: () => useSyncExternalStore((listener) => {
|
|
36
|
+
if (refCount === 0) snapshots.set(s, snapshot);
|
|
37
|
+
refCount++;
|
|
38
|
+
listeners.add(listener);
|
|
39
|
+
return () => {
|
|
40
|
+
refCount--;
|
|
41
|
+
if (refCount === 0) snapshots.delete(s);
|
|
42
|
+
listeners.delete(listener);
|
|
43
|
+
};
|
|
44
|
+
}, () => snapshots.get(s)) };
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { kotori };
|
package/package.json
CHANGED
|
@@ -1,65 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "kotori",
|
|
3
|
-
"description": "Strongly-typed and composable internationalization library for React",
|
|
4
|
-
"version": "0.0.
|
|
5
|
-
"scripts": {
|
|
6
|
-
"setup": "rm -rf node_modules && npm i && git init && husky",
|
|
7
|
-
"prepublishOnly": "npm run build",
|
|
8
|
-
"build": "tsdown",
|
|
9
|
-
"test": "vitest",
|
|
10
|
-
"lint": "npx @biomejs/biome check --write",
|
|
11
|
-
"dev": "vite --host"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"dist"
|
|
15
|
-
],
|
|
16
|
-
"lint-staged": {
|
|
17
|
-
"*": [
|
|
18
|
-
"npm run lint"
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
"type": "module",
|
|
22
|
-
"main": "./dist/index.cjs",
|
|
23
|
-
"types": "./dist/index.d.cts",
|
|
24
|
-
"exports": {
|
|
25
|
-
".": {
|
|
26
|
-
"require": {
|
|
27
|
-
"types": "./dist/index.d.cts",
|
|
28
|
-
"default": "./dist/index.cjs"
|
|
29
|
-
},
|
|
30
|
-
"import": {
|
|
31
|
-
"types": "./dist/index.d.mts",
|
|
32
|
-
"default": "./dist/index.mjs"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"react": "^19.2.
|
|
47
|
-
"react-dom": "^19.2.
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
},
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "kotori",
|
|
3
|
+
"description": "Strongly-typed and composable internationalization library for React",
|
|
4
|
+
"version": "0.0.6",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"setup": "rm -rf node_modules && npm i && git init && husky",
|
|
7
|
+
"prepublishOnly": "npm run build",
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"lint": "npx @biomejs/biome check --write",
|
|
11
|
+
"dev": "vite --host"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"lint-staged": {
|
|
17
|
+
"*": [
|
|
18
|
+
"npm run lint"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/index.d.cts",
|
|
28
|
+
"default": "./dist/index.cjs"
|
|
29
|
+
},
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
32
|
+
"default": "./dist/index.mjs"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"i18n",
|
|
38
|
+
"internationalization",
|
|
39
|
+
"react",
|
|
40
|
+
"typescript",
|
|
41
|
+
"strongly-typed"
|
|
42
|
+
],
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@biomejs/biome": "^2.4.12",
|
|
45
|
+
"@types/node": "^25.6.0",
|
|
46
|
+
"@types/react": "^19.2.14",
|
|
47
|
+
"@types/react-dom": "^19.2.3",
|
|
48
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
49
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
50
|
+
"bcp47-language-tags": "^1.1.0",
|
|
51
|
+
"husky": "^9.1.7",
|
|
52
|
+
"lint-staged": "^16.4.0",
|
|
53
|
+
"react": "^19.2.5",
|
|
54
|
+
"react-dom": "^19.2.5",
|
|
55
|
+
"tsdown": "^0.21.10",
|
|
56
|
+
"tsx": "^4.21.0",
|
|
57
|
+
"typescript": "^6.0.3",
|
|
58
|
+
"vitest": "^4.1.5"
|
|
59
|
+
},
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "git+https://github.com/tylim88/kotori.git"
|
|
63
|
+
},
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/tylim88/kotori/issues"
|
|
66
|
+
},
|
|
67
|
+
"author": "tylim88",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"react": ">=19.2.5"
|
|
71
|
+
}
|
|
72
|
+
}
|