Створюємо англо-український словник для Kindle: від Римської імперії до AI

💡 Усі статті, обговорення, новини про AI — в одному місці. Приєднуйтесь до AI спільноти!

Мене звати Павло Ляпін, я CTO у компанії Vault12. Наша українська команда розробляє мобільне рішення для зберігання приватних даних. Але ця стаття про мій мініпроєкт, який почався як «справа на пару вечорів».

Я живу у місті Остін, штат Техас. Переїжджаючи сюди у 2021-му, я уявляв собі центр технологічного всесвіту: Фалькони та Томагавки злітають з кожного подвір’я, а в місцевому АТБ можна привітатися якщо не з Ілоном, то хоча б з яким-небудь подкастером. Реальність виявилася дещо іншою. Без машини тут нікуди — громадського транспорту практично не існує. Єдина технологічна інновація на вулицях — безпілотні таксі, які викликаються довше, ніж їдуть. Зате є невеличка українська IT-спільнота, що гріє душу. Загалом, Остін — це такий собі Житомир без маршруток, і з буріто замість вареників. І він насправді існує.

Одна з переваг США — культура електронних книжок. Читалка тут є майже в кожному домі. Я теж читаю на Kindle, переважно англійською. Але яким би fluent не був English, завжди трапляються слова на кшталт fusiform чи putrefaction, які миттєво вибивають зі стану потоку. Поки не дізнаєшся переклад, далі читати неможливо. Принаймні, з моєю допитливістю.

На щастя, Kindle вміє показувати значення слів з вбудованого словника. На моєму пристрої передвстановленими виявилися тільки English Oxford Dictionary та (чомусь) англо-арабський словник. Англійські синоніми не завжди допомагають зрозуміти точне значення, а українського словника просто не було.

Тож я вирішив зробити його сам. Слова з прикладу, до речі, реальні: зустрівши їх на одній сторінці, я зрозумів, що час діяти. Справа ж на пару днів, що може піти не так?

Пошук сорсу або як знайти голку в стозі сіна

Отже, потрібен словник. Здавалося б: 2024 рік, інтернет, open source, все давно оцифровано. Ну, не зовсім. Англо-українських словників у відкритому доступі практично не існує. Є Google Translate, але він не завжди розуміє контекст і любить перекладати «bank» як «банк», навіть коли мова про берег річки. Є ChatGPT, але він іноді галюцинує українською так, ніби вчив мову за оголошеннями на OLX (що може бути правдою).

Після кількох годин пошуків я натрапив на репозиторій bakustarver/ukr-dictionaries-list-opensource, скарбницю українських офлайн-словників. Там окрім вузько спеціалізованих причаївся Англо-український словник М.І. Балла — 75 000 статей! Саме те, що треба.

Тепер питання авторського права. Видавництво «Освіта», яке випустило цей словник у 1996 році, вже не існує. Автора теж не вдалося знайти — мабуть, у 90-х були вигідніші бізнеси, ніж лексикографія. Слів на кшталт «пітятко» та «кияхи» там немає (перевіряв). Але працювати з тим, що є, цілком можна.

Крок −1. Вибір технології

Грудень 2024-го. Андрей Карпати ще не вжив фразу «vibe coding», але я вже інтуїтивно її практикував. Python здавався логічним вибором для парсингу тексту, хоча я на ньому ніколи не писав. Та й навіщо? Є ж ChatGPT. У тебе інпут, ти знаєш який хочеш аутпут — просто відрізай зайве, як Мікеланджело від мармуру.

У підсумку всі сотні ітерацій написала LLM, а я лише іноді втручався, коли вона робила щось зовсім дивне. Вайб-кодинг до того, як це стало мейнстрімом. До речі, за наступний рік той особливий дофамін здогадуватись, як саме модель вас не зрозуміє, почав притуплятися.

Крок 0. Формат вхідних даних

У репозиторії словник був у кількох форматах. Я вибрав DSL (Dictionary Source Language), бо виглядало найпростіше. Кожен рядок: слово, табуляція, переклад з HTML-розміткою:

fusiform
<div style="margin-left:1em"><i class="p"><font color="green">adj</font></i></div>

<div style="margin-left:1em">веретеноподібний</div>

Виглядає просто. Напевно ж працівники Amazon зробили інтуїтивний спосіб завернути будь-що в словник для їх читалки, щоб продажі книжок серед іноземців постійно зростали. Скоро побачимо.

Крок 1. Зайві метадані

Досить тривіально видалити рядки з кінця і початку файлу, де вказані метадані — вони не знадобляться для фінальної версії словника.

# Видаляємо рядки з "_about" або "##"
if first_column == "_about" or first_column.startswith("##"):
    continue

Також виявилось, що деякі статті містять пояснення у фігурних дужках, наприклад

Tanganyika{, Lake}
Це не особливо допомагає, тому що у англомовній книзі слово не зустрінеться саме у такому форматі. Відрізаємо regexp-ом.

Крок 2. Об’єднання перехресних посилань

Наступне відкриття: багато статей словника — це просто посилання на інші статті:

abnormity

<div><font color="green">див.</font> <<abnormality>></div>

Було б непогано натиснути на посилання і перейти на іншу статтю, правда? От тільки читалки Kindle так не вміють. Навіть найновіші моделі. Тому якщо залишити як є, читач замість перекладу отримає ще одне англійське слово. Не дуже корисно.

Рішення: об’єднуємо такі статті. Скрипт шукає

<font color="green">див.</font>
 і додає синоніми до основної статті.

Крок 3. Британія проти Америки: Colour vs Color

Продивляюсь словник і думаю, що він майже готовий. Перевіряю слово organize, а його немає. Як так? Невже не існувало у 1996-му?

А, ну так. Словник перекладає королівську британську англійську. А американці, як відомо, не дуже дотримуються орфографії з метрополії.

VarCon на допомогу

Розгублена LLM каже, що ніяких вбудованих строкових методів на Python для «суржизації» англійських слів через Атлантичний океан не існує. Що ж, будемо шукати.

Знаходимо VarCon (Variant Conversion Info) — пани Kevin Atkinson та Benjamin Titze підтримують текстовий файл з відмінностями між британською, американською, канадською та австралійською орфографіями. На попередньому кроці ми (а точніше контекст нашої LLM-ки) вже навчилися редагувати окремі статті зі словника. Тепер час додати ще більше аліасів та, можливо, стати першими, хто отримав переклад українською діалектизмів з Небраски та Оклахоми.

Що отримуємо?

На борту тепер:

  • tire на додачу до tyre;
  • enroll замість enrol;
  • smolder замість smoulder;
  • aging замість ageing;
  • ціла плеяда різних -ize на місці -ise;
  • та -er замість -re (center/centre, fiber/fibre).

Якщо є colour, автоматично додаємо color як синонім. Повіримо Кевіну та Бенджаміну на слово, а канадців і австралійців поки пропустимо. Перший у світі австралійсько-український словник залишаємо як вправу для читача.

Крок 4. Іменники: однина, множина та кактуси

Словник скомпільовано, завантажено на Kindle. П’ять хвилин читання — і нова проблема. Виділяю слово books. Kindle каже: «Такого слова не існує». Серйозно?

Нерегулярні множини іменників

Окрім шкільних child/children та mouse/mice, є купа менш очевидних. Словник частково про них знає:

cacti	

<div><font color="green">pl</font> <<cactus>></div>

І ось вона — Римська імперія з клікбейтного заголовку! Англійська запозичила з латини та грецької близько 150-200 слів разом з оригінальною множиною. Тому просимо наш скрипт об’єднати їх в одну статтю:

  • cactus | cacti → одна стаття;
  • aquarium | aquaria → одна стаття;
  • alumnus | alumni → одна стаття;
  • antenna | antennae → одна стаття.

Бонус-факт: деякі слова мають три варіанти множини. Octopus → octopuses (англійська), octopi (псевдо-латина), octopodes (справжня грецька!). А «data» і «media» технічно множини від datum і medium, але сучасна англійська використовує їх як однину. Лінгвістична еволюція в дії.

Регулярні іменники та бібліотека inflect

З рештою іменників теж не все просто — не можна просто додати -s у кінці. Є досить багато виключень. Підключаємо inflect:

import inflect
p = inflect.engine()
p.plural("book")      # → "books"
p.plural("city")      # → "cities"
p.plural("box")       # → "boxes"

Бібліотека знає правила утворення множини: коли додавати -s, коли -es, коли змінювати y на ies.

Цікавий трюк: inflect має метод singular_noun(word), який повертає false для слів в однині, і базову форму для слів у множині. Це дозволяє уникнути неправильних значень типу bookss:

p.singular_noun("books")  # → "book" (це множина)
p.singular_noun("book")   # → False (це однина, не чіпаємо)

Для ваших проєктів: inflect стане у пригоді для:

  • Генерації правильних закінчень у повідомленнях («1 item» vs «5 items»);
  • Роботи з числівниками (перетворення чисел у слова);
  • Визначення артиклів (a/an).

Крок 5. Прикметники: великий, більший, найбільший

Наступний рівень складності — прикметники. В англійській мові є три ступені порівняння:

  • large (positive)
  • larger (comparative)
  • largest (superlative)

І знову проблема: виділяєш на Kindle слово larger, а словник мовчить — у ньому є тільки large. Сам тільки Inflect тут вже не допоможе, тож доводиться шукати інші бібліотеки.

SpaCy + PyInflect

Для генерації форм прикметників використовуємо комбо spaCy + pyinflect:

import spacy
import pyinflect
nlp = spacy.load("en_core_web_sm")
doc = nlp("large")
token = doc[0]
token._.inflect("JJR")  # → "larger" (comparative)
token._.inflect("JJS")  # → "largest" (superlative)

SpaCy — це потужна NLP-бібліотека, яка розуміє структуру мови. PyInflect додає до неї можливість генерувати словоформи.

Для ваших проєктів: SpaCy використовується для:

  • Аналізу тексту (визначення частин мови, іменованих сутностей);
  • Лематизації (знаходження базової форми слова);
  • Машинного перекладу та NLP-задач.

Крок 6. Дієслова: найскладніший бос

Якщо ви думали, що з іменниками та прикметниками було складно — welcome to the verb zone.

В англійській дієслово може мати до 5 різних форм:

  • write (base form)
  • writes (3rd person singular)
  • wrote (past tense)
  • written (past participle)
  • writing (gerund/-ing form)

Нерегулярні дієслова

Знову починаємо з нерегулярних форм. Словник знає базові шкільні варіанти:

wrote	

<div><font color="green">past</font> від <<write>></div>

written	

<div><font color="green">p.p.</font> від <<write>></div>

Збираємо всі такі зв’язки у CSV-файл, а потім об’єднуємо зі статтею основного дієслова:

write | wrote | written | writes | writing

Регулярні дієслова

Для регулярних дієслів знову використовуємо SpaCy + PyInflect:

doc = nlp("walk")
token = doc[0]
token._.inflect("VBD")  # → "walked" (past tense)
token._.inflect("VBN")  # → "walked" (past participle)
token._.inflect("VBG")  # → "walking" (gerund)
token._.inflect("VBZ")  # → "walks" (3rd person)

Penn Treebank POS Tags

Ці загадкові коди (VBD, VBN, VBG, VBZ, JJR, JJS) — це Penn Treebank Part-of-Speech Tags, стандарт маркування частин мови в англійській NLP:

Тег

Значення

Приклад

VB

Base verb

write

VBD

Past tense

wrote, walked

VBN

Past participle

written, walked

VBG

Gerund

writing, walking

VBZ

3rd person singular

writes, walks

JJ

Adjective

large

JJR

Comparative

larger

JJS

Superlative

largest

NN

Noun singular

book

NNS

Noun plural

books

Ймовірно, можна було з цього почати і в попередніх кроках. Але велику частину шляху вже пройдено.

Крок 7. Збірка всіх словоформ

Після всіх етапів у нас є:

  • Нерегулярні множини іменників (з самого словника).
  • Регулярні множини іменників (згенеровані inflect).
  • Всі форми прикметників (згенеровані spacy + pyinflect).
  • Нерегулярні форми дієслів (з самого словника).
  • Регулярні форми дієслів (згенеровані spacy + pyinflect).

Об’єднуємо всі CSV-файли та додаємо до основного словника:

csv_paths = [
    "temp/nouns-regular.csv",
    "temp/adjectives.csv",
    "temp/regular.csv"
]

На виході маємо словник, де кожна стаття містить всі можливі форми слова.

Крок 8. Чистка розмітки

Оригінальний словник містить специфічну для свого формату HTML-розмітку:

<i class="p"><font color="green">n</font></i>
<font color="green">юр.</font>
<font color="darkred"><b>1.</b></font>
<div style="margin-left:1em">...</div>

На чорно-білому Kindle кольори не відображаються. Замінюємо на курсив, підкреслення тощо. Деякі кольори так і не вдалося розшифрувати — просто видаляємо:

# Видаляємо зайве
content = re.sub(r'<font color="green">(.*?)</font>', r'\1', content)

# Замінюємо <i class="p"> на <em>, який коректно відображається на Kindle
content = re.sub(r'<i class="p">(.*?)</i>', r'<em>\1</em>', content)

# Конвертуємо внутрішні посилання
content = re.sub(r"<<(.*?)>>", r'<a href="#\1">\1</a>', content)

Крок 9. Фінальна конверсія в XHTML

Kindle використовує специфічний формат для словників — XHTML з особливими тегами:

<idx:entry name="default" scriptable="yes" spell="yes">

<h5><dt>
  <idx:orth value="book">book
    <idx:infl>
      <idx:iform value="books" />

    </idx:infl>
  </idx:orth></dt></h5>
  <dd>книга, книжка</dd>
</idx:entry>

Що тут що:

  • <idx:entry> — стаття словника;
  • <idx:orth> — основне слово (headword);
  • <idx:infl> — альтернативні форми (inflections);
  • <idx:iform> — кожна окрема форма.

Офіційної документації немає. Єдиний спосіб — шукати інші саморобні словники на GitHub і розбиратися по їхньому коду.

Оскільки словник величезний (75 000+ статей), розбиваємо на кілька файлів по 15 000 записів. Інакше конвертер задихається, принаймні на моєму девайсі.

Крок 10. Повний пайплайн

Запускаємо python main.py — і 14 скриптів виконуються послідовно:

scripts = [
    "00.sanitize.py",        # Чистка метаданих
    "01.crosslinks.py",      # Об'єднання перехресних посилань
    "02.varcon-csv.py",      # Парсинг британсько-американських варіантів
    "03.variants.py",        # Застосування варіантів
    "04.irregular-nouns.py", # Екстракція нерегулярних множин іменників
    "05.filter-irregular-nouns.py",  # Мерж нерегулярних множин іменників
    "06.regular-nouns.py",   # Генерація регулярних множин
    "07.adjectives.py",      # Генерація ступенів порівняння прикметників
    "08.filter-irregular-verbs.py",  # Мерж нерегулярних форм дієслів
    "09.irregular-verbs.py", # Екстракція нерегулярних форм дієслів
    "10.regular-verbs.py",   # Генерація регулярних дієслівних форм
    "11.all-inflections.py", # Об'єднання всіх словоформ
    "12.clean-markup.py",    # Чистка HTML-розмітки
    "13.convert-to-xhtml.py",# Конверсія в XHTML для Kindle
]

Як зростає словник на кожному етапі:

Етап

Словоформ

Початок (сирі дані)

79 355

Після об’єднання посилань

79 300

Після британсько-американських варіантів

80 700

Після всіх словоформ

155 622

Майже вдвічі більше слів, ніж на старті. Залишається скомпілювати в MOBI через Kindle Previewer — і готово.

Підсумки

Отже, що вийшло? Фінальний словник містить понад 75 000 статей та 155 тисяч словоформ — це з урахуванням усіх множин, дієслівних форм, ступенів порівняння та британсько-американських варіантів. Працює на всіх моделях Kindle, від найстаріших до Scribe.

Щодо бібліотек: inflect виявився незамінним для роботи з іменниками, а комбо spaCy + pyinflect закрило всі потреби з дієсловами та прикметниками. Якщо колись будете працювати з англійською морфологією, раджу почати саме з них.

Окрема подяка Jake McCrary за статтю про формат словників Kindle та авторам English-Persian Dictionary за робочі скрипти, з яких я багато чого підгледів.

Словник можна завантажити і користуватися. Просто скиньте файл на Kindle через Calibre, виберіть його як словник за замовчуванням — і вперед читати. Код відкритий, тож якщо хочете адаптувати для іншої мови або інших читалок — форкайте.

Якщо ви володієте правами на цей словник — напишіть мені, і я або видалю проєкт, або (що було б значно краще) отримаю дозвіл і вкажу коректну ліцензію. Тим часом маємо що маємо: видавництво не існує, автора не знайти, ліцензія невідома.

А якщо ви представник держави і чомусь дочитали до цього місця — підтримка офіційного open-source словника звучить як задача для профільного міністерства. Трохи дивно, що у 2025 році це має робити хтось невідомий з інтернету у вільний час.

Буду радий фідбеку в коментарях!

P.S. Fusiform — веретеноподібний. Putrefaction — гниття. Тепер ви знаєте.

P.P.S. Справа на «пару днів» зайняла три тижні. Але воно того варте.

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось25
До обраногоВ обраному10
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Jesus Christ, хто ти воїне?!
Безмежно дякую! Багато читаю на англійському на Kindle, хоча я і не в Остіні, а в Кропивницькому, тим не менш, подякував ще раз, за разом зі словником, який зараз встановлю, цікаво було почитати про «вайб-кодинг» та нові бібліотеки, про які знав, але лише частково. Нехай квітне український Kindle :-)
P.S. за іронією долі, прочитав цю статтю на iOS Kindle xD

Безмежне будь ласка! Сам регулярно користуюся словником.

UPD: встановив, працює, що потрібно =)

Класний проект. Підтримую що то робота профільних державних інституцій підтримувати таке. Особливо дякую за просте та конкретне пояснення як це відбувалось.

Крута робота! Обов’язково спробую словник.

Валідне зауваження, що українська мова має популяризуватися. А по факту kindle не підтримує її як мову інтерфейсу. Схожа ситуація з телефонами Samsung та AI, в останніх релізах не можна перекласти текст через контекстне меню на українську, хоча переклад робиться через Google.

Варіанти які були доступні раніше:
1. Є платний словник «Англійсько-український словник для Kindle» на Amazon $10
2. Безкоштовний від 2018 року «Словники української мови для Amazon kindle 3-4» на toloka
3. Інтернет переклад (навіть цілих речень) через інтернет на останніх версіях Kindle, але там немає української мови

Дякую!

Я купував той словник за $10 — він зроблений з того ж джерела, яке я взяв за основу. Але там автор не попрацював з форматом, все просто сліпо зконвертовано в plain text: без розмітки, без структури, все в одному рядку. Читати й користуватись максимально незручно.

І так, справді дивно, що у вбудованому Translate така обмежена кількість мов.

Дякую. Можливо, згодитися для мого тренажера слів — WordDolphin. Хоча я пішов іншим шляхом, використовував wiktionary і вручну зробив близько 1000 англо-українських перекладів

Так. Дуже цікаво. Правда так і не зміг локально переглянути. Kindle Viewer зависає на «Loading book, please wait»

Якщо ви маєте на увазі Kindle Previewer — це нормально. Він може висіти хвилин 10, бо працює дуже повільно. Через це під час розробки я тестував словник лише на букві A, інакше стаття вийшла б років за два :)

Ви зробили дуже корисний проєкт. Дякую!

Підписатись на коментарі