Чому українська?
Цей проєкт обслуговує студентів природничих наук по всьому світу. Після англійської найбільшою аудиторією, яка недостатньо забезпечена ресурсами STEM-освіти рідною мовою, виявилась українська. Це рішення було й особистим: супроводжувачі проєкту — українці.
Питання полягало не в тому, чи варто це робити, а в тому, як керувати 293 HTML-файлами на статичному сайті без інструментів збірки, не перетворюючи підтримку англійських версій на кошмар.
Архітектурне рішення
Розглядалися три підходи:
-
Визначення мови на стороні сервера —
перенаправлення на основі
Accept-Language. Відхилено: сайт — це чистий статичний HTML, що подається як статичні файли з нашого CDN. Жодної серверної логіки. - JavaScript i18n на одній сторінці (i18next тощо) — один HTML-файл, JS підміняє рядки. Відхилено: жахливо для SEO, вимагає JS-бандла на кожній сторінці, а кожна симуляція вже завантажує Three.js — додавання бібліотеки i18n до 225 сторінок симуляцій було неприйнятним.
-
Паралельне дерево статичних файлів у
/uk/— точне дзеркало англійської структури з перекладеним HTML. Кожна сторінка має власну URL-адресу, власні метадані, власний hreflang, що вказує назад на англійський канонічний URL. Саме це ми й побудували.
Компроміс: паралельні дерева подвоюють кількість файлів. 293 українські сторінки на додачу до 326 англійських = 619 загалом. Але URL-адреси стабільні, SEO чисте, і немає жодних JS-залежностей для перекладу. Того варте.
День 1 — Побудова структури файлів
Першим завданням було написати Python-скрипт, який дублював кожну
папку симуляції під /uk/ і коригував усі відносні
шляхи. Складна частина: шляхи на кшталт
../../shared/theme.css (2 рівні вгору від
/categories/) перетворюються на
../../../../shared/theme.css (4 рівні вгору від
/uk/categories/). Помилка тут непомітно ламає кожен
файл стилів.
import os, re, shutil
def fix_paths(html: str, extra_depth: int) -> str:
prefix = '../' * extra_depth
# Виправляємо відносні src/href, що починаються з ../../, але не з //
return re.sub(
r'((?:src|href)=["\'])(?!https?://|//|#)(\.\./)',
lambda m: m.group(1) + prefix + m.group(2),
html
)
День 2 — Робочий процес перекладу
Кожна сторінка симуляції має три ключові текстові блоки для
перекладу: <title> сторінки, meta description та
панель опису симуляції (розділ «Що це показує / Як користуватися /
Чи знали ви?»). Усе інше — елементи керування інтерфейсом, підписи
осей, фрагменти коду — залишається англійською.
Переклад виконувався вручну за допомогою мовних інструментів для вичитки, з пріоритетом природної української мови над дослівним перекладом. Наукова термінологія відповідає українському академічному стандарту там, де існують усталені відповідники, а в інших випадках англійський термін наводиться в дужках.
Вимога щодо hreflang
Кожна англійська сторінка мала отримати
<link rel="alternate" hreflang="uk">, що вказує
на її український відповідник. Кожна українська сторінка
потребувала зворотного посилання на англійську версію. І обидві
потребували hreflang="x-default", що вказує на
англійський канонічний URL. Без зворотної пари Google повністю
ігнорує hreflang.
<!-- У /boids/index.html (англійська) -->
<link rel="alternate" hreflang="en" href="https://www.mysimulator.uk/algorithms/boids/">
<link rel="alternate" hreflang="uk" href="https://www.mysimulator.uk/uk/algorithms/boids/">
<link rel="alternate" hreflang="x-default" href="https://www.mysimulator.uk/algorithms/boids/">
<!-- У /uk/boids/index.html (українська) -->
<link rel="alternate" hreflang="en" href="https://www.mysimulator.uk/algorithms/boids/">
<link rel="alternate" hreflang="uk" href="https://www.mysimulator.uk/uk/algorithms/boids/">
<link rel="alternate" hreflang="x-default" href="https://www.mysimulator.uk/algorithms/boids/">
Скрипт валідації перевіряв кожну сторінку за регулярним виразом: усі три теги hreflang мають існувати та відповідати шляху файлу. Жодна сторінка не публікувалася, доки аудит не показував 0 помилок.
День 3 — Компонент перемикача мов
Перемикач мов — це єдиний тег <a>, що
вставляється components.js у навігаційну панель. Він
зчитує поточний URL і формує URL альтернативної мови так:
-
Якщо шлях починається з
/uk/→ видалити його (перейти до англійської версії) -
Інакше → додати
/uk/на початок (перейти до української версії)
function buildLangUrl(base) {
const path = window.location.pathname;
if (path.startsWith('/uk/')) {
return base + path.slice(3); // прибираємо префікс /uk
}
return base + 'uk' + path; // додаємо префікс /uk
}
Це крихко рівно в одному випадку: сторінки, які існують англійською, але ще не мають української версії. Перемикач все одно показується, посилаючись на 404. Крок попередньої обробки генерує JSON-маніфест усіх наявних українських шляхів, і перемикач перевіряє його перед показом кнопки.
День 4 — Мапа сайту, Robots, Розгортання
Мапа сайту мала містити як англійські, так і українські
URL-адреси з відповідними альтернативами hreflang
<xhtml:link> у кожному записі. Python-скрипт, що
генерує sitemap.xml, оновили, щоб він обходив дерева
EN та UK разом і видавав правильні альтернативи.
Фінальне розгортання додало 293 нові файли та змінило 326 наявних англійських файлів (щоб додати hreflang). Загальний diff: ~1 500 змінених файлів у репозиторії. Веб-сервер обслуговував їх без жодних змін конфігурації — статичний HTML просто працює.
Що нас здивувало
-
Аудит hreflang зайняв більше часу, ніж переклад.
Дрібні невідповідності — кінцева коса риска в одному посиланні,
але не в іншому, розбіжність
/uk/проти/uk— непомітно ламають інтерпретацію Google. Скрипт валідатора виявив 47 таких помилок до розгортання. - Українська STEM-термінологія виявилася багатшою, ніж ми очікували. Для більшості понять фізики та математики існують усталені українські терміни. Складність полягала в послідовності — використанні того самого терміна на кожній сторінці, а не того, що спершу спав на думку.
- Органічний український трафік з'явився протягом 2 тижнів після запуску. Жодної реклами — лише чистий hreflang, правильні канонічні посилання та контент, недоступний українською більше ніде.