Формат словаря для импорта 辞書形式
od-dict/1 · контракт импорта пользовательских словарей
Приложение «Обычный японский словарь» умеет подключать ваши собственные словари. Один словарь — это
один JSON-файл в формате od-dict/1. Вы готовите такой файл, конвертируя
существующий словарь (например, словарь Yomitan) — вручную или с помощью LLM, — а приложение строит
из него свою базу.
Формат — это надмножество jmdict-simplified
(scriptin/jmdict-simplified): корректное
слово из jmdict-simplified уже валидно здесь, так что при таком источнике конвертация почти не нужна.
docs/od-dict-format.md.
1. Файл целиком
{
"format": "od-dict/1", // обязательно, точная строка
"source": "custom", // обязательно; id этого словаря (§2)
"metadata": { // необязательно; только для отображения/происхождения
"title": "My Dictionary",
"license": "CC BY-SA 4.0",
"url": "https://…"
},
"tags": { "v1": "Ichidan verb" }, // необязательно; НЕ используется (§6)
"words": [
{
"id": "1259420", // обязательно; УНИКАЛЕН в пределах файла (§3)
"kanji": ["食べる"], // необязательно; опустите для слов только из каны
"kana": ["たべる"], // хотя бы одна форма (kanji или kana) обязана быть
"sense": [ // обязательно; ≥1
{
"partOfSpeech": ["v1"], // необязательно; ТОЛЬКО коды POS, не текст (§4)
"misc": ["transitive"], // необязательно; свободные подписи, показываются как есть
"gloss": [ // переводы
{ "lang": "ru", "text": "есть; кушать" },
"пожирать" // голая строка = { lang: "ru", origin: "original" }
],
"examples": [ ["ご飯を食べる", "есть рис"] ], // необязательно; пары [японский, перевод]
"references": [] // необязательно; перекрёстные ссылки (§5)
}
]
}
]
}
2. Верхний уровень
| поле | обяз. | значение |
|---|---|---|
format | да | Ровно "od-dict/1". |
source | да | Строка-id всего словаря. Стабильный слаг ("custom", "jitendex"). Это пространство имён для id и перекрёстных ссылок. Неизвестный источник просто ранжируется после встроенных словарей — никогда не отвергается. |
metadata | нет | Свободный объект (title, license, url). Хранится только для отображения; сборщик его не читает. |
tags | нет | Карта код → подпись для совместимости с jmdict-simplified. Не используется (§6). Нужные подписи кладите прямо в misc. |
words | да | Массив статей. |
Безопасность: задумано принудительно выставлять source = "custom" при импорте, чтобы файл не выдал себя за "warodai"/"jmdict". Это пока не реализовано — считайте source рекомендательным до появления проверяющего импортёра.
3. Слова и идентичность
{
"id": "1259420",
"homograph": "II", // необязательно; различитель, если head+чтение совпадают
"label": "colloquial", // необязательно; тег уровня статьи, показывается на карточке
"isExpression": true, // необязательно; фраза из нескольких слов
"common": true, // необязательно; высокочастотная статья
"kanji": ["食べる", "喰べる"], // 0…n письменных форм
"kana": ["たべる"], // 0…n чтений
"sense": [ /* … */ ]
}
Идентичность — это (source, id), и она UNIQUE.
idобязан быть уникальным в файле. Таблица пишется обычнымINSERTс ограничениемUNIQUE(source, source_entry_id), поэтому дубликатidроняет и прерывает весь батч импорта — не молча. Берите собственный id источника; если его нет — синтезируйте стабильный (счётчик или сам заголовок).- Элементы
kanji/kana— голая строка (норма) или объект jmdict-simplified{ "text": "…" }; читается толькоtext, остальное принимается, но отбрасывается. Голая строка предпочтительнее. - У слова обязана быть хотя бы одна форма. Для японского давайте
kana; для слов только из каны опускайтеkanji.
Группировка. Приложение показывает одну карточку на группу
(заголовок + чтение), объединяя словари. В своём файле выдавайте
одно слово на статью — все письменные формы в kanji, все чтения в
kana, все значения в sense. Если источник разбивает статью на строки
(Yomitan — через общий sequence), сначала слейте их в одно слово, иначе получите
несколько карточек на одну статью.
4. partOfSpeech — единственное поле, тихо ломающее поиск
Это единственное поле, где неверное значение убирает слово из поиска без всякой ошибки.
POS не влияет на поиск по словарной форме или чтению — 食べる и
たべる находятся всегда. POS используется ровно в одном месте: ворота
деинфлексии — нахождение слова по словоформе, которую набрал пользователь
(食べた, 静かな).
| POS статьи | вердикт | эффект |
|---|---|---|
| отсутствует / не класс спряжения | weak | всё равно находится, чуть ниже в ранге |
| класс спряжения, который совпал | confirmed | находится, обычный ранг |
| класс спряжения, который не совпал | rejected | выбрасывается — не находится из этой словоформы |
Не уверены в классе спряжения — опускайте partOfSpeech целиком.
Отсутствие безопасно (weak), ошибка фатальна (rejected). Опустить лучше, чем угадать.
Правила:
- Только коды, никогда свободный текст. Читаемые подписи («verb», «honorific»)
кладите в
misc— там они показываются дословно. - Значимы только классы спряжения. Прочие коды (
n,exp,vt,adv…) поиском игнорируются — безвредны, но бесполезны. - Ловушка Yomitan: никогда не копируйте схлопнутый
v5. У движка нет классаv5— нужен конкретный (v5k,v5r…). Голый"v5"не совпадает ни с чем →rejected, то есть хуже, чем без тега. Берите конкретный код изdefinitionTags, либо разворачивайте по последней кане словарной формы, либо опускайте.
Классы спряжения, которые понимает движок:
v1 ичидан (-ru): 食べる, 見る
v5u v5k v5g v5s v5t v5n v5b v5m v5r годан, по финальной кане словарной формы
vk 来る (kuru)
vs vs-i vs-s する-глаголы
adj-i い-прилагательные: 高い, 良い
adj-na な-прилагательные: 静か, 綺麗
5. Глоссы, языки и перекрёстные ссылки
"гулять" // голая строка = { "lang": "ru", "origin": "original" }
{ "lang": "en", "text": "to take a walk" }
{ "lang": "ru", "text": "то же, что {0}", "origin": "original" }
- Голая строка — это русский (
lang: "ru"). Для любого другого языка нужен объект сlang. origin—"original"(по умолчанию) или"machine"(создано ИИ); только отображение.- Как
langвлияет на поиск: глосс сlang: "ru"попадает в русский поисковый канал, любой другойlang— в английский. Канал выбирается по письменности запроса: кириллица → ru, латиница → en. Поэтому для японско-русского словаря глоссы должны бытьlang: "ru", иначе кириллический поиск их не найдёт. Одноязычный японский глосс (lang: "ja") попадает в en-канал и фактически становится только отображаемым — слово всё ещё находится по заголовку и чтению, но не по тексту определения.
Перекрёстные ссылки — ICU-плейсхолдеры {0}, {1} … в тексте
глосса, разрешаемые через массив references:
{
"gloss": [ { "lang": "ru", "text": "вежливая форма {0}" } ],
"references": [ { "label": "", "to": "1234567", "text": "言う" } ]
}
{0}заменяется на месте наreferences[0].textкак нажимаемая ссылка.to— этоidцелевого слова в этом же файле; ссылка открывает{ source: <этот словарь>, id: to }. Несуществующийtoпросто ничего не открывает.label— маркер связи ("see","cf."), для ссылок без{n}(рендерятся после глосса). Литеральная{в тексте пишется как'{'(ICU-экранирование).
6. Чего формат НЕ несёт
Эти данные приложение добавляет само, по поверхности/чтению, чтобы все словари были согласованы —
их не нужно задавать: тоновое ударение, фуригана, ромадзи/Поливанов,
частотность/«common», аудио/TTS, уровни JLPT/WaniKani, разбор кандзи. Также не используются (хотя
принимаются ради совместимости): верхнеуровневый tags и пер-форменные/пер-глоссовые
extras. Карточка рендерит misc/field/dialect как
свободные строки дословно — раскрытия кодов нет, кладите туда читаемые подписи.
7. Минимальные примеры
Самое маленькое слово — только кана и один русский глосс:
{ "id": "w1", "kana": ["ありがとう"], "sense": [ { "gloss": ["спасибо"] } ] }
// (a) JA→EN годан. POS — КОНКРЕТНЫЙ класс v5k, а не "v5" из Yomitan.
{ "id": "1578850", "kanji": ["書く"], "kana": ["かく"],
"sense": [ { "partOfSpeech": ["v5k", "vt"],
"gloss": [ { "lang": "en", "text": "to write; to compose; to pen" } ] } ] }
// (b) JA→RU с внутренней перекрёстной ссылкой.
{ "id": "敷衍", "kanji": ["敷衍", "敷延"], "kana": ["ふえん"],
"sense": [ { "gloss": [ { "lang": "ru", "text": "развёртывание мысли (ср. {0})" } ],
"references": [ { "label": "", "to": "演繹", "text": "演繹" } ] } ] }
// (c) な-прилагательное только из каны. adj-na — класс деинфлексии, тег уместен.
{ "id": "1000230", "kana": ["きれい"],
"sense": [ { "partOfSpeech": ["adj-na"], "gloss": ["красивый; чистый; опрятный"] } ] }
8. POS-allowlist
Помещайте код в partOfSpeech, только если он один из этих (или подкласс jmdict,
начинающийся с одного из них). Всё прочее — человеческую подпись в misc, а здесь опустить.
v1
v5u v5k v5g v5s v5t v5n v5b v5m v5r
vk
vs vs-i vs-s
adj-i
adj-na
Схлопнутый Yomitan "v5" → развернуть по финальной кане:
う→v5u く→v5k ぐ→v5g す→v5s つ→v5t ぬ→v5n ぶ→v5b む→v5m る→v5r.
Не уверены — опускайте.