yomitan-core 0.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 +485 -0
- package/dist/anki-connect-BQyCGW3O.cjs +513 -0
- package/dist/anki-connect-BQyCGW3O.cjs.map +1 -0
- package/dist/anki-connect-CPPuhyiQ.js +6 -0
- package/dist/anki-connect-DbrQHphS.js +495 -0
- package/dist/anki-connect-DbrQHphS.js.map +1 -0
- package/dist/anki-connect-DcheJrp-.cjs +6 -0
- package/dist/anki.cjs +1758 -0
- package/dist/anki.cjs.map +1 -0
- package/dist/anki.d.cts +751 -0
- package/dist/anki.d.cts.map +1 -0
- package/dist/anki.d.ts +751 -0
- package/dist/anki.d.ts.map +1 -0
- package/dist/anki.js +1751 -0
- package/dist/anki.js.map +1 -0
- package/dist/audio-D9DvYyB7.d.cts +48 -0
- package/dist/audio-D9DvYyB7.d.cts.map +1 -0
- package/dist/audio-DQulUkDM.d.ts +48 -0
- package/dist/audio-DQulUkDM.d.ts.map +1 -0
- package/dist/audio-url-generator-BXvQaqUi.cjs +4 -0
- package/dist/audio-url-generator-Dy2hb2Mm.cjs +414 -0
- package/dist/audio-url-generator-Dy2hb2Mm.cjs.map +1 -0
- package/dist/audio-url-generator-Qi0rfzHz.js +4 -0
- package/dist/audio-url-generator-pFQAB5Nb.js +390 -0
- package/dist/audio-url-generator-pFQAB5Nb.js.map +1 -0
- package/dist/audio.cjs +7 -0
- package/dist/audio.d.cts +86 -0
- package/dist/audio.d.cts.map +1 -0
- package/dist/audio.d.ts +86 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +4 -0
- package/dist/batch-processor-BR-gB3H3.js +84 -0
- package/dist/batch-processor-BR-gB3H3.js.map +1 -0
- package/dist/batch-processor-CSF1acTw.cjs +3 -0
- package/dist/batch-processor-DFqM_L-_.cjs +91 -0
- package/dist/batch-processor-DFqM_L-_.cjs.map +1 -0
- package/dist/batch-processor-Quo9jUyf.js +3 -0
- package/dist/chunk-BCwAaXi7.cjs +31 -0
- package/dist/cjk-util-Dp0ZU0sh.cjs +167 -0
- package/dist/cjk-util-Dp0ZU0sh.cjs.map +1 -0
- package/dist/cjk-util-DubXBGDG.js +94 -0
- package/dist/cjk-util-DubXBGDG.js.map +1 -0
- package/dist/core-BUpclilG.d.cts +102 -0
- package/dist/core-BUpclilG.d.cts.map +1 -0
- package/dist/core-DFUj5GtA.d.ts +102 -0
- package/dist/core-DFUj5GtA.d.ts.map +1 -0
- package/dist/database.cjs +7 -0
- package/dist/database.d.cts +4 -0
- package/dist/database.d.ts +4 -0
- package/dist/database.js +5 -0
- package/dist/dictionary-D7l-qFt1.d.cts +316 -0
- package/dist/dictionary-D7l-qFt1.d.cts.map +1 -0
- package/dist/dictionary-_vzfBLWi.d.ts +316 -0
- package/dist/dictionary-_vzfBLWi.d.ts.map +1 -0
- package/dist/dictionary-data-util-CHnRdYZ9.cjs +378 -0
- package/dist/dictionary-data-util-CHnRdYZ9.cjs.map +1 -0
- package/dist/dictionary-data-util-CfOLfEDE.js +323 -0
- package/dist/dictionary-data-util-CfOLfEDE.js.map +1 -0
- package/dist/dictionary-database-BDC2f9zc.d.ts +58 -0
- package/dist/dictionary-database-BDC2f9zc.d.ts.map +1 -0
- package/dist/dictionary-database-CU4TsvCC.js +393 -0
- package/dist/dictionary-database-CU4TsvCC.js.map +1 -0
- package/dist/dictionary-database-DsOi04Sg.d.cts +58 -0
- package/dist/dictionary-database-DsOi04Sg.d.cts.map +1 -0
- package/dist/dictionary-database-lvFvftnO.cjs +412 -0
- package/dist/dictionary-database-lvFvftnO.cjs.map +1 -0
- package/dist/dictionary-importer-BkQQSBhm.d.ts +237 -0
- package/dist/dictionary-importer-BkQQSBhm.d.ts.map +1 -0
- package/dist/dictionary-importer-Cen1z6co.js +1821 -0
- package/dist/dictionary-importer-Cen1z6co.js.map +1 -0
- package/dist/dictionary-importer-DYmmWmcX.cjs +8 -0
- package/dist/dictionary-importer-Da3AuTZw.d.cts +237 -0
- package/dist/dictionary-importer-Da3AuTZw.d.cts.map +1 -0
- package/dist/dictionary-importer-Dhn75iZ4.cjs +1834 -0
- package/dist/dictionary-importer-Dhn75iZ4.cjs.map +1 -0
- package/dist/dictionary-importer-xWkel0h-.js +8 -0
- package/dist/dictionary-update-checker-BNE4pGTx.js +4 -0
- package/dist/dictionary-update-checker-Byjvifd2.cjs +75 -0
- package/dist/dictionary-update-checker-Byjvifd2.cjs.map +1 -0
- package/dist/dictionary-update-checker-YdpalZ41.cjs +4 -0
- package/dist/dictionary-update-checker-kKukiovj.js +69 -0
- package/dist/dictionary-update-checker-kKukiovj.js.map +1 -0
- package/dist/display-generator-BGVWiI0t.js +746 -0
- package/dist/display-generator-BGVWiI0t.js.map +1 -0
- package/dist/display-generator-BMQmG5Ov.cjs +9 -0
- package/dist/display-generator-BxZ7mBjP.js +9 -0
- package/dist/display-generator-DyP-HNzP.cjs +758 -0
- package/dist/display-generator-DyP-HNzP.cjs.map +1 -0
- package/dist/errors-BSezaJwm.cjs +35 -0
- package/dist/errors-BSezaJwm.cjs.map +1 -0
- package/dist/errors-DuuDSO5N.js +22 -0
- package/dist/errors-DuuDSO5N.js.map +1 -0
- package/dist/frequency-ranking-BXjfhhUQ.js +3 -0
- package/dist/frequency-ranking-Cx1kkIrw.cjs +3 -0
- package/dist/frequency-ranking-DEJMTMdg.js +159 -0
- package/dist/frequency-ranking-DEJMTMdg.js.map +1 -0
- package/dist/frequency-ranking-DVYxTXN-.cjs +166 -0
- package/dist/frequency-ranking-DVYxTXN-.cjs.map +1 -0
- package/dist/furigana-5HK97CY8.js +4 -0
- package/dist/furigana-9bBI9-qe.d.ts +47 -0
- package/dist/furigana-9bBI9-qe.d.ts.map +1 -0
- package/dist/furigana-B3-0y231.js +471 -0
- package/dist/furigana-B3-0y231.js.map +1 -0
- package/dist/furigana-CjOhzvZt.d.cts +47 -0
- package/dist/furigana-CjOhzvZt.d.cts.map +1 -0
- package/dist/furigana-DpZLcues.cjs +609 -0
- package/dist/furigana-DpZLcues.cjs.map +1 -0
- package/dist/furigana-h3v2ub4-.cjs +4 -0
- package/dist/import.cjs +12 -0
- package/dist/import.d.cts +107 -0
- package/dist/import.d.cts.map +1 -0
- package/dist/import.d.ts +107 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +9 -0
- package/dist/index.cjs +275 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +211 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +211 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +238 -0
- package/dist/index.js.map +1 -0
- package/dist/json-DGd-cunA.js +17 -0
- package/dist/json-DGd-cunA.js.map +1 -0
- package/dist/json-DKWp-B7Y.cjs +30 -0
- package/dist/json-DKWp-B7Y.cjs.map +1 -0
- package/dist/language-KN_u-nTR.d.ts +104 -0
- package/dist/language-KN_u-nTR.d.ts.map +1 -0
- package/dist/language-xAbQxgXc.d.cts +104 -0
- package/dist/language-xAbQxgXc.d.cts.map +1 -0
- package/dist/language.cjs +15626 -0
- package/dist/language.cjs.map +1 -0
- package/dist/language.d.cts +959 -0
- package/dist/language.d.cts.map +1 -0
- package/dist/language.d.ts +959 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +15522 -0
- package/dist/language.js.map +1 -0
- package/dist/log-D8KtR3aP.cjs +67 -0
- package/dist/log-D8KtR3aP.cjs.map +1 -0
- package/dist/log-hgSll-dS.js +60 -0
- package/dist/log-hgSll-dS.js.map +1 -0
- package/dist/lookup.cjs +13 -0
- package/dist/lookup.d.cts +161 -0
- package/dist/lookup.d.cts.map +1 -0
- package/dist/lookup.d.ts +161 -0
- package/dist/lookup.d.ts.map +1 -0
- package/dist/lookup.js +10 -0
- package/dist/media-loader-BABA_E4W.js +3 -0
- package/dist/media-loader-Ce9cuANS.cjs +21 -0
- package/dist/media-loader-Ce9cuANS.cjs.map +1 -0
- package/dist/media-loader-qRti-Q6h.js +14 -0
- package/dist/media-loader-qRti-Q6h.js.map +1 -0
- package/dist/media-loader-xlUGaJrx.cjs +3 -0
- package/dist/multi-language-transformer-AlxOM6b3.js +637 -0
- package/dist/multi-language-transformer-AlxOM6b3.js.map +1 -0
- package/dist/multi-language-transformer-MdbQBBOt.cjs +685 -0
- package/dist/multi-language-transformer-MdbQBBOt.cjs.map +1 -0
- package/dist/multi-language-transformer-SEhcJXEB.d.ts +63 -0
- package/dist/multi-language-transformer-SEhcJXEB.d.ts.map +1 -0
- package/dist/multi-language-transformer-Ul9mbRce.d.cts +63 -0
- package/dist/multi-language-transformer-Ul9mbRce.d.cts.map +1 -0
- package/dist/pronunciation-generator-BtBc4q_V.js +397 -0
- package/dist/pronunciation-generator-BtBc4q_V.js.map +1 -0
- package/dist/pronunciation-generator-CBYdXYou.js +4 -0
- package/dist/pronunciation-generator-CFbZlf5J.cjs +445 -0
- package/dist/pronunciation-generator-CFbZlf5J.cjs.map +1 -0
- package/dist/pronunciation-generator-DOz9hEuk.cjs +4 -0
- package/dist/render.cjs +2796 -0
- package/dist/render.cjs.map +1 -0
- package/dist/render.d.cts +424 -0
- package/dist/render.d.cts.map +1 -0
- package/dist/render.d.ts +424 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +2777 -0
- package/dist/render.js.map +1 -0
- package/dist/sentence-parser-BPAJNzqW.js +126 -0
- package/dist/sentence-parser-BPAJNzqW.js.map +1 -0
- package/dist/sentence-parser-BVIOI64h.cjs +132 -0
- package/dist/sentence-parser-BVIOI64h.cjs.map +1 -0
- package/dist/sentence-parser-BoHO3cHn.js +5 -0
- package/dist/sentence-parser-DQVLSW0z.cjs +5 -0
- package/dist/structured-content-generator-BtOApkTW.cjs +4 -0
- package/dist/structured-content-generator-Bx62RYa8.js +4 -0
- package/dist/structured-content-generator-CLnybumI.js +276 -0
- package/dist/structured-content-generator-CLnybumI.js.map +1 -0
- package/dist/structured-content-generator-DrwkB0-k.cjs +282 -0
- package/dist/structured-content-generator-DrwkB0-k.cjs.map +1 -0
- package/dist/text-utilities-B7PIythe.js +8 -0
- package/dist/text-utilities-B7PIythe.js.map +1 -0
- package/dist/text-utilities-Del2Ivkg.cjs +15 -0
- package/dist/text-utilities-Del2Ivkg.cjs.map +1 -0
- package/dist/translator-CRPlPzqi.cjs +1545 -0
- package/dist/translator-CRPlPzqi.cjs.map +1 -0
- package/dist/translator-CWgG5drA.js +1539 -0
- package/dist/translator-CWgG5drA.js.map +1 -0
- package/dist/translator-CaGtJvnQ.cjs +6 -0
- package/dist/translator-Cc6OGxrW.d.ts +180 -0
- package/dist/translator-Cc6OGxrW.d.ts.map +1 -0
- package/dist/translator-CcA-s-W4.d.cts +180 -0
- package/dist/translator-CcA-s-W4.d.cts.map +1 -0
- package/dist/translator-CuJOTK6l.js +6 -0
- package/dist/utilities-C-lbZaJE.cjs +52 -0
- package/dist/utilities-C-lbZaJE.cjs.map +1 -0
- package/dist/utilities-bi3EF-q5.js +33 -0
- package/dist/utilities-bi3EF-q5.js.map +1 -0
- package/package.json +102 -0
package/README.md
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
# yomitan-core
|
|
2
|
+
|
|
3
|
+
Core dictionary lookup, language processing, and rendering engine extracted from the [Yomitan](https://github.com/louismollick/yomitan) browser extension. Use it in Node.js, Electron, or any JavaScript environment with IndexedDB.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install yomitan-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Optional dependencies
|
|
12
|
+
|
|
13
|
+
| Package | Purpose |
|
|
14
|
+
|---------|---------|
|
|
15
|
+
| `linkedom` | Server-side DOM for the rendering module |
|
|
16
|
+
| `hangul-js` | Korean Hangul disassembly/reassembly |
|
|
17
|
+
| `kanji-processor` | Kanji decomposition |
|
|
18
|
+
| `@resvg/resvg-wasm` | SVG rasterization for pitch accent images |
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import YomitanCore from 'yomitan-core';
|
|
24
|
+
|
|
25
|
+
const core = new YomitanCore();
|
|
26
|
+
await core.initialize();
|
|
27
|
+
|
|
28
|
+
// Import a dictionary from a .zip ArrayBuffer
|
|
29
|
+
const archive = await fetch('/jmdict.zip').then((r) => r.arrayBuffer());
|
|
30
|
+
const result = await core.importDictionary(archive, {
|
|
31
|
+
onProgress: (progress) => console.log(progress),
|
|
32
|
+
});
|
|
33
|
+
console.log(`Imported "${result.result.title}" with ${result.result.termCount} terms`);
|
|
34
|
+
|
|
35
|
+
// Look up a term
|
|
36
|
+
const { entries, originalTextLength } = await core.findTerms('食べる', {
|
|
37
|
+
enabledDictionaryMap: new Map([['JMdict', { index: 0, priority: 0 }]]),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log(entries[0].headwords); // [{term: '食べる', reading: 'たべる', ...}]
|
|
41
|
+
|
|
42
|
+
// Clean up
|
|
43
|
+
await core.dispose();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
### `YomitanCore`
|
|
49
|
+
|
|
50
|
+
The main orchestrator. Manages the database, translator, and language processing subsystems.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const core = new YomitanCore({
|
|
54
|
+
databaseName: 'my-dict', // IndexedDB name (default: 'dict')
|
|
55
|
+
initLanguage: true, // auto-init language transformers (default: true)
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await core.initialize();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Dictionary management
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// Import a dictionary zip
|
|
65
|
+
await core.importDictionary(archive: ArrayBuffer, options?)
|
|
66
|
+
|
|
67
|
+
// List installed dictionaries
|
|
68
|
+
await core.getDictionaryInfo(): Promise<Summary[]>
|
|
69
|
+
|
|
70
|
+
// Delete a dictionary by title
|
|
71
|
+
await core.deleteDictionary(name: string, onProgress?)
|
|
72
|
+
|
|
73
|
+
// Check for dictionary updates (fetches remote index URLs)
|
|
74
|
+
await core.checkForUpdates(names?: string[]): Promise<DictionaryUpdateInfo[]>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Term lookup
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Look up terms with deinflection, grouping, and sorting
|
|
81
|
+
await core.findTerms(text, {
|
|
82
|
+
mode: 'group', // 'group' | 'merge' | 'split' | 'simple'
|
|
83
|
+
language: 'ja',
|
|
84
|
+
enabledDictionaryMap: new Map([['JMdict', { index: 0, priority: 0 }]]),
|
|
85
|
+
options: {
|
|
86
|
+
matchType: 'exact', // 'exact' | 'prefix' | 'suffix'
|
|
87
|
+
deinflect: true,
|
|
88
|
+
sortFrequencyDictionary: 'JPDB',
|
|
89
|
+
sortFrequencyDictionaryOrder: 'descending',
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Look up kanji
|
|
94
|
+
await core.findKanji(text, {
|
|
95
|
+
enabledDictionaryMap: new Map([['KANJIDIC', { index: 0, priority: 0 }]]),
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Sentence parsing
|
|
100
|
+
|
|
101
|
+
Sliding-window longest-match parser that splits text into segments with furigana.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const lines = await core.parseText('日本語を勉強する', {
|
|
105
|
+
enabledDictionaryMap: new Map([['JMdict', { index: 0, priority: 0 }]]),
|
|
106
|
+
});
|
|
107
|
+
// Returns ParsedLine[] with segments, readings, and furigana
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Furigana generation
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const segments = await core.generateFurigana('食べる', 'たべる');
|
|
114
|
+
// [{ text: '食', reading: 'た' }, { text: 'べる', reading: '' }]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Batch lookup
|
|
118
|
+
|
|
119
|
+
Look up multiple texts efficiently with shared caches and optional concurrency control.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const results = await core.batchLookup(
|
|
123
|
+
['食べる', '飲む', '走る'],
|
|
124
|
+
{
|
|
125
|
+
enabledDictionaryMap: new Map([['JMdict', { index: 0, priority: 0 }]]),
|
|
126
|
+
concurrency: 4,
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
// Returns Map<string, TermLookupResult>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Frequency ranking
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const ranking = await core.getFrequencyRanking('食べる', ['JPDB', 'Innocent Corpus']);
|
|
136
|
+
// { frequencies: [...], harmonicMean: 1234 }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Audio URLs
|
|
140
|
+
|
|
141
|
+
Generate audio source URLs for a term/reading pair across multiple providers (JapanesePod101, Jisho, Lingua Libre, Wiktionary, custom JSON).
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const urls = await core.getAudioUrls('食べる', 'たべる', [
|
|
145
|
+
{ type: 'jpod101', url: '', voice: '' },
|
|
146
|
+
]);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Factory methods
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// AnkiConnect client
|
|
153
|
+
const anki = await core.createAnkiClient({ server: 'http://127.0.0.1:8765' });
|
|
154
|
+
|
|
155
|
+
// Rendering classes (requires DOM — use linkedom or jsdom in Node.js)
|
|
156
|
+
const { DisplayGenerator, StructuredContentGenerator, PronunciationGenerator } =
|
|
157
|
+
await core.createRenderer();
|
|
158
|
+
|
|
159
|
+
// Standalone audio URL generator
|
|
160
|
+
const audioGen = await core.createAudioUrlGenerator();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### Accessor properties
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
core.isReady // boolean — whether initialize() has been called
|
|
167
|
+
core.database // DictionaryDB — direct access to the Dexie database
|
|
168
|
+
core.language // { summaries, textProcessors, transformer, isTextLookupWorthy }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Tree-shakeable submodule imports
|
|
172
|
+
|
|
173
|
+
Each submodule is a separate entry point. Import only what you need to minimize bundle size.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// Database layer (Dexie-based IndexedDB)
|
|
177
|
+
import { DictionaryDB, YomitanDatabase } from 'yomitan-core/database';
|
|
178
|
+
|
|
179
|
+
// Dictionary import and update checking
|
|
180
|
+
import { DictionaryImporterClass, DictionaryUpdateChecker } from 'yomitan-core/import';
|
|
181
|
+
|
|
182
|
+
// Translator, sentence parsing, batch processing, frequency ranking
|
|
183
|
+
import { Translator, SentenceParser, BatchProcessor, FrequencyRanker } from 'yomitan-core/lookup';
|
|
184
|
+
|
|
185
|
+
// 48 languages: transforms, text processors, CJK utils, furigana, Japanese, Korean, Chinese, ...
|
|
186
|
+
import {
|
|
187
|
+
LanguageTransformer,
|
|
188
|
+
MultiLanguageTransformer,
|
|
189
|
+
distributeFurigana,
|
|
190
|
+
getLanguageSummaries,
|
|
191
|
+
convertKatakanaToHiragana,
|
|
192
|
+
japaneseTransforms,
|
|
193
|
+
koreanTransforms,
|
|
194
|
+
} from 'yomitan-core/language';
|
|
195
|
+
|
|
196
|
+
// AnkiConnect client, note builder, template renderer
|
|
197
|
+
import { AnkiConnect, AnkiNoteBuilder, AnkiTemplateRenderer } from 'yomitan-core/anki';
|
|
198
|
+
|
|
199
|
+
// HTML display rendering (requires DOM)
|
|
200
|
+
import {
|
|
201
|
+
DisplayGenerator,
|
|
202
|
+
StructuredContentGenerator,
|
|
203
|
+
PronunciationGenerator,
|
|
204
|
+
HtmlTemplateCollection,
|
|
205
|
+
} from 'yomitan-core/render';
|
|
206
|
+
|
|
207
|
+
// Audio URL generation
|
|
208
|
+
import { AudioUrlGenerator } from 'yomitan-core/audio';
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Using individual classes directly
|
|
212
|
+
|
|
213
|
+
For more control, use the classes directly instead of the `YomitanCore` wrapper.
|
|
214
|
+
|
|
215
|
+
### Database + Translator
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { DictionaryDB } from 'yomitan-core/database';
|
|
219
|
+
import { Translator } from 'yomitan-core/lookup';
|
|
220
|
+
|
|
221
|
+
const db = new DictionaryDB('my-dict');
|
|
222
|
+
await db.open();
|
|
223
|
+
|
|
224
|
+
const translator = new Translator(db);
|
|
225
|
+
// translator.prepare() loads language transformers internally
|
|
226
|
+
|
|
227
|
+
const { dictionaryEntries, originalTextLength } = await translator.findTerms(
|
|
228
|
+
'group',
|
|
229
|
+
'食べたい',
|
|
230
|
+
{
|
|
231
|
+
matchType: 'exact',
|
|
232
|
+
deinflect: true,
|
|
233
|
+
primaryReading: '',
|
|
234
|
+
mainDictionary: '',
|
|
235
|
+
sortFrequencyDictionary: null,
|
|
236
|
+
sortFrequencyDictionaryOrder: 'descending',
|
|
237
|
+
removeNonJapaneseCharacters: false,
|
|
238
|
+
textReplacements: [null],
|
|
239
|
+
enabledDictionaryMap: new Map([['JMdict', { index: 0, priority: 0 }]]),
|
|
240
|
+
excludeDictionaryDefinitions: null,
|
|
241
|
+
searchResolution: 'letter',
|
|
242
|
+
language: 'ja',
|
|
243
|
+
},
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
db.close();
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Dictionary import
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { DictionaryDB } from 'yomitan-core/database';
|
|
253
|
+
import { DictionaryImporterClass } from 'yomitan-core/import';
|
|
254
|
+
|
|
255
|
+
const db = new DictionaryDB('my-dict');
|
|
256
|
+
await db.open();
|
|
257
|
+
|
|
258
|
+
const importer = new DictionaryImporterClass(
|
|
259
|
+
undefined, // MediaLoader (undefined = NoOpMediaLoader)
|
|
260
|
+
(progress) => console.log(`${progress.index}/${progress.count}`),
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const archive = await fs.readFile('./jmdict.zip');
|
|
264
|
+
const result = await importer.importDictionary(db, archive.buffer, {
|
|
265
|
+
prefixWildcardsSupported: true,
|
|
266
|
+
yomitanVersion: '0.1.0',
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
console.log(result.result.title, result.result.termCount);
|
|
270
|
+
db.close();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Language transforms
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { LanguageTransformer, japaneseTransforms } from 'yomitan-core/language';
|
|
277
|
+
|
|
278
|
+
const transformer = new LanguageTransformer();
|
|
279
|
+
transformer.addDescriptor(japaneseTransforms);
|
|
280
|
+
|
|
281
|
+
const deinflections = transformer.transform('食べたい');
|
|
282
|
+
for (const result of deinflections) {
|
|
283
|
+
console.log(result.text, result.trace);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Furigana
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import { distributeFurigana } from 'yomitan-core/language';
|
|
291
|
+
|
|
292
|
+
const segments = distributeFurigana('食べる', 'たべる');
|
|
293
|
+
// [{ text: '食', reading: 'た' }, { text: 'べる', reading: '' }]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### AnkiConnect
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { AnkiConnect } from 'yomitan-core/anki';
|
|
300
|
+
|
|
301
|
+
const anki = new AnkiConnect({ server: 'http://127.0.0.1:8765' });
|
|
302
|
+
const decks = await anki.getDeckNames();
|
|
303
|
+
const models = await anki.getModelNames();
|
|
304
|
+
const fields = await anki.getModelFieldNames('Basic');
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Server-side rendering with linkedom
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import { parseHTML } from 'linkedom';
|
|
311
|
+
import {
|
|
312
|
+
DisplayGenerator,
|
|
313
|
+
HtmlTemplateCollection,
|
|
314
|
+
DISPLAY_TEMPLATES,
|
|
315
|
+
DISPLAY_CSS,
|
|
316
|
+
} from 'yomitan-core/render';
|
|
317
|
+
|
|
318
|
+
const { document } = parseHTML('<!DOCTYPE html><html><body></body></html>');
|
|
319
|
+
|
|
320
|
+
const templates = new HtmlTemplateCollection();
|
|
321
|
+
templates.loadFromString(DISPLAY_TEMPLATES, document);
|
|
322
|
+
|
|
323
|
+
const generator = new DisplayGenerator(document, templates);
|
|
324
|
+
|
|
325
|
+
// Render a term entry to DOM nodes
|
|
326
|
+
const node = generator.createTermEntry(dictionaryEntry);
|
|
327
|
+
console.log(node.outerHTML);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Development
|
|
331
|
+
|
|
332
|
+
### Prerequisites
|
|
333
|
+
|
|
334
|
+
- Node.js >= 18
|
|
335
|
+
- npm
|
|
336
|
+
|
|
337
|
+
### Setup
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
git clone https://github.com/louismollick/yomitan-core.git
|
|
341
|
+
cd yomitan-core
|
|
342
|
+
npm install
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Scripts
|
|
346
|
+
|
|
347
|
+
| Command | Description |
|
|
348
|
+
|---------|-------------|
|
|
349
|
+
| `npm run build` | Build ESM + CJS + .d.ts with tsdown |
|
|
350
|
+
| `npm run dev` | Watch mode build |
|
|
351
|
+
| `npm run typecheck` | TypeScript type checking (`tsc --noEmit`) |
|
|
352
|
+
| `npm run lint` | Biome lint + format check |
|
|
353
|
+
| `npm run lint:fix` | Auto-fix lint and formatting issues |
|
|
354
|
+
| `npm run format` | Format all files with Biome |
|
|
355
|
+
| `npm run test` | Run tests with vitest |
|
|
356
|
+
| `npm run test:watch` | Watch mode tests |
|
|
357
|
+
|
|
358
|
+
### Automated versioning and releases
|
|
359
|
+
|
|
360
|
+
This repo uses semantic-release on pushes to `main`/`master` to:
|
|
361
|
+
|
|
362
|
+
- determine the next version from commit messages
|
|
363
|
+
- update `package.json` and `package-lock.json`
|
|
364
|
+
- update `CHANGELOG.md`
|
|
365
|
+
- publish to npm
|
|
366
|
+
- create a GitHub release and tag
|
|
367
|
+
|
|
368
|
+
Set the following repository secret in GitHub Actions:
|
|
369
|
+
|
|
370
|
+
- `NPM_TOKEN` (npm automation token with publish access)
|
|
371
|
+
|
|
372
|
+
Use Conventional Commits so version bumps are calculated correctly:
|
|
373
|
+
|
|
374
|
+
- `fix: ...` -> patch release (`x.y.Z`)
|
|
375
|
+
- `feat: ...` -> minor release (`x.Y.0`)
|
|
376
|
+
- `feat!: ...` or a commit body with `BREAKING CHANGE:` -> major release (`X.0.0`)
|
|
377
|
+
|
|
378
|
+
### Testing locally from another project
|
|
379
|
+
|
|
380
|
+
There are two ways to test yomitan-core from another npm project on your machine.
|
|
381
|
+
|
|
382
|
+
#### Option A: `npm link` (recommended)
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# In the yomitan-core directory, build and create a global link
|
|
386
|
+
cd /path/to/yomitan-core
|
|
387
|
+
npm run build
|
|
388
|
+
npm link
|
|
389
|
+
|
|
390
|
+
# In your consuming project, link to it
|
|
391
|
+
cd /path/to/my-app
|
|
392
|
+
npm link yomitan-core
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
You can now import from `yomitan-core` as if it were installed from the registry. Any time you rebuild yomitan-core, the changes are immediately available.
|
|
396
|
+
|
|
397
|
+
To unlink:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
cd /path/to/my-app
|
|
401
|
+
npm unlink yomitan-core
|
|
402
|
+
|
|
403
|
+
cd /path/to/yomitan-core
|
|
404
|
+
npm unlink
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### Option B: `file:` dependency
|
|
408
|
+
|
|
409
|
+
In your consuming project's `package.json`:
|
|
410
|
+
|
|
411
|
+
```json
|
|
412
|
+
{
|
|
413
|
+
"dependencies": {
|
|
414
|
+
"yomitan-core": "file:../yomitan-core"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Then run `npm install`. This creates a symlink to the local package. You need to rebuild yomitan-core and re-run `npm install` in your project when the yomitan-core package structure changes.
|
|
420
|
+
|
|
421
|
+
#### Option C: `npm pack`
|
|
422
|
+
|
|
423
|
+
This simulates a real npm install most closely:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# In yomitan-core
|
|
427
|
+
cd /path/to/yomitan-core
|
|
428
|
+
npm run build
|
|
429
|
+
npm pack
|
|
430
|
+
# Creates yomitan-core-0.1.0.tgz
|
|
431
|
+
|
|
432
|
+
# In your consuming project
|
|
433
|
+
cd /path/to/my-app
|
|
434
|
+
npm install /path/to/yomitan-core/yomitan-core-0.1.0.tgz
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### Verifying the link works
|
|
438
|
+
|
|
439
|
+
Create a test file in your consuming project:
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import YomitanCore from 'yomitan-core';
|
|
443
|
+
|
|
444
|
+
const core = new YomitanCore();
|
|
445
|
+
await core.initialize();
|
|
446
|
+
|
|
447
|
+
const info = await core.getDictionaryInfo();
|
|
448
|
+
console.log('Installed dictionaries:', info);
|
|
449
|
+
|
|
450
|
+
await core.dispose();
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Run it with a runtime that supports IndexedDB (browser, Electron) or with `fake-indexeddb` for Node.js:
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// At the top of your Node.js entry point, before any yomitan-core imports
|
|
457
|
+
import 'fake-indexeddb/auto';
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Project structure
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
yomitan-core/
|
|
464
|
+
src/
|
|
465
|
+
index.ts # YomitanCore class + barrel exports
|
|
466
|
+
types/ # TypeScript type definitions
|
|
467
|
+
util/ # Shared utilities (errors, string, regex, JSON, etc.)
|
|
468
|
+
database/ # Dexie-based IndexedDB dictionary storage
|
|
469
|
+
import/ # Dictionary .zip import + schema validation + update checking
|
|
470
|
+
lookup/ # Translator, sentence parser, batch processor, frequency ranker
|
|
471
|
+
language/ # 48 languages: transforms, text processors, CJK, furigana
|
|
472
|
+
ja/ # Japanese-specific (transforms, kana, wanakana, furigana)
|
|
473
|
+
ko/ # Korean (Hangul processing, transforms)
|
|
474
|
+
zh/ # Chinese (pinyin, character detection)
|
|
475
|
+
ar/ # Arabic
|
|
476
|
+
de/ en/ es/ fr/ ... # Other languages
|
|
477
|
+
anki/ # AnkiConnect client, note builder, template renderer
|
|
478
|
+
audio/ # Audio URL generation (JapanesePod101, Jisho, Wiktionary, etc.)
|
|
479
|
+
render/ # HTML display generation (term/kanji entries, structured content, pitch accent)
|
|
480
|
+
dist/ # Build output (ESM, CJS, .d.ts, sourcemaps)
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## License
|
|
484
|
+
|
|
485
|
+
GPL-3.0-or-later. See [LICENSE](./LICENSE).
|