| Filename | Latest commit message | Latest commit date |
|---|---|---|
The server now holds dictionaries for everyone: `dictionary_entry` and `dictionary_source`, reference data owned by no one, never synced. It loads the dictionary files in its `dictionaries` folder at every start, those whose SHA-256 changed: in the background, each source replaced in one transaction, so searches meanwhile find the old entries; a file it can't read is logged and left out. All of JMdict loads in under half a minute. On an instance the folder is deploy/dictionaries, mounted read-only (compose.yaml); the server's README says how. DictionaryEndpoint (signed in): the dictionaries with their credits; a search (exact key, exact loose key, key starting with the query, loose key starting with it, each in the source's order; katakana as hiragana, macrons written out), some 150-450 ms over all of JMdict; and the entries with a label, counted and a page at a time (all JLPT N5 words). The curator now keeps spellings that aren't quite right apart, as `looseKeys` (romaji with long vowels typed once): "sushi" finds 寿司 before 数詞 (すうし). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me> |
||
| .. | ||
| bin | ||
| lib/src | ||
| test | ||
| analysis_options.yaml | ||
| LICENSE | ||
| pubspec.yaml | ||
| README.md | ||
halkyon_learn_curator
Turns dictionary downloads into the dictionary files a Halkyon Learn server loads. It reads each source with an adapter of its own and writes one format for all of them, so a new source or language needs a new adapter, never a change to the server or the app. It doesn't depend on Serverpod or the server.
Making a dictionary file
JMdict in English, with the JLPT levels on top:
-
Download
jmdict-eng-<version>.json.tgzfrom jmdict-simplified's releases and unpack it. -
Download
original_data/n1.csv…n5.csvfrom yomitan-jlpt-vocab into a folder. -
Convert, in this package:
dart run halkyon_learn_curator:curate jmdict \ --input jmdict-eng-3.6.2.json --jlpt jlpt/ --output jmdict-en.jsonl.gzThe whole of JMdict (about 219,000 entries) takes some 20 seconds and 300 MB of memory: entries are read one at a time.
Put the file into the server's dictionaries folder. The server loads it on
its next start, and again whenever the file changes (see the server's README).
The format (halkyon-dictionary, version 1)
JSON Lines, gzipped when the name ends in .gz.
The first line says what the file holds:
| Field | |
|---|---|
format, formatVersion |
"halkyon-dictionary", 1 |
source, sourceVersion |
The source's name (jmdict) and version (3.6.2 (2026-10-05)). An instance holds one version of a source for each meaning language. |
language, glossLanguage |
BCP 47 tags: the words' language (ja) and the meanings' (en). |
license |
The data's licence, an SPDX identifier (CC-BY-SA-4.0). |
credits |
Everything it is drawn from: name, by, license, url. The app lists them where it credits its data sources. |
Every further line is an entry:
| Field | |
|---|---|
id |
Its id in the source; with the source and meaning language, it names the entry for good. |
headword, reading |
How the word is shown, and how it is read; no reading when the headword is its own (a word written in kana). |
labels |
What it can be picked by: common, jlpt:n5 … jlpt:n1 (later e.g. hsk:3, topik:1). |
rank |
Its order among the source's entries, lower first; JMdict: N5 to N1 in their lists' order, then other common words, then the rest. |
keys |
What a search matches, lower case: written forms, readings in their own script and romanised, meanings. Everything specific to a language happens here, so the server's search knows no language. |
looseKeys |
What a search matches after every keys match: spellings people type that aren't quite right (romaji with long vowels typed once, sushi for すうし). Left out when empty. |
entry |
The entry itself, as cards take it: forms and readings (text, common, the source's tags; for a reading the forms it belongs to), senses (glosses; the source's codes in pos, misc, field, dialect; info; the forms and readings a sense is limited to). Lists are left out when empty. |
Adding a source
Write an adapter in lib/src/sources/ that turns the source into the lines
above, with its credits and a sample of real data in test/fixtures/ (and
where that comes from in test/fixtures/README.md); give it a command in
bin/curate.dart. Check the source's licence first, and that the instance may
pass its data on to the people using it.