January 1, 0001 in

Як ми удвох українізували наш стартап

Cінтра - це TODO стаття про виникнення продукту, та про технічну реалізацію.

локалізація, тобто переклад.

На технічну реалізацію перекладу уйшло 30 годин мого часу. Плюс Александр робив сам переклад.

Локалізація додатка

Перше, що приходить на ум інженера - це локалізація власне кода додатка.

i18next з додаванням react-i18next.

Найбільш проста частина - то перекладання статичних рядків в додатку. Тут достатньо побудувати словник, та позаміняти рядки на виклик функції t:

// TODO example

Інколи рядки містять параметри. Тут теж все прямолінійно.

Інколи локалізований рядок будується не в компоненті React. Найбільш поширений приклад - повідомлення валідації. Тут є два підходи.

Можна замінити рядки на ключи локалізації, а локалізувати вже при відображеннні. Цей підхід мені здається найбільш чистим, але він гарно працює тільки доки рядки не містять параметрів, бо передавати ключ та набір параметрів - це вже суттєве ускладнення.

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

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

// TODO example of i18next helper

Мобільний додаток

Оскільки мобільний додаток у нас написаний на React Native, то його переклад робився буквально так само, як і веб-додатку. Навіть словник у них спільний.

Окрім коду на React Native, довелося перекласти буквально пару системних рядків в додатку iOS. Наприклад, запрошення дозволити повідомлення - воно вказується у файлі Info.plist, і перекладається власними засобами Xcode.

Локалізація бекенда

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

Локалізувати поштові шаблони ми вирішила тією самою бібліотекою i18next. Раніше шаблони були написані на Handlebars, але з найпростішими інтерполяціями. Тож переїзд з Handlebars на i18next пройшов майже без змін.

Цікаво, що переклади тіл листів ми пишемо в окремі файли, а потім вже завантажуємо в структуру словника.

Сайт

Сайт у нас статично генерований, на платформі Hugo. Підтримка локалізації там вбудована. Можна обрати з двох варіантів.

Найбільш очевидний - то перекладати сторінки цілком. Це зручно зі звичайними текстовими сторінками, як-от умови використання.

// example of frontmatter

Але сторінки з більш складним оздобленням так перекладати буде витратно на підтримці, бо треба буде підтримувати форматування. Тому такі сторінки перекладаються зі словником. Так само і сталі елементи дизайну (шапка, підвал тощо.)

// example of hugo template

В будь-якому разі, кожний переклад в Hugo - це окрема статична сторінка з власною адресою.

Сторінки App Store

Коли ви вже думали, що все перекладено, то виявляється, що всі елементи додатка у App Store теж треба перекласти: опис, скріншоти, назви підписок та інше.

Інше

А ще неперекладеним залишилась назва підписки у Paddle. Цей білінг-провайдер не дозволяє перекладати назви товарів. Технічно, мабуть, ми могли б створити окремі підписки для кожної мови. Але покищо просто вказали назву на інтернаціональній англійській. Цю назву клієнти бачать при оформленні підписки, та також у листах з рахунками. У інших місцях нашого сайту та додатку назва локалізована, бо вона береться не з Paddle.

Визначення локалі

Як зрозуміти, яку мову показувати користувачу в перший раз? Є два фундаментальних підхода - можна дивитись на Accept-Language браузера, а можна на географічне розташування. Нам більше сподобався останній, бо нерідко люди ставлять системною мовою англійську.

Виявилось, що Google Cloud та Firebase автоматично визначають геолокацію всіх відвідувачів, та передають у спеціальних заголовках. Тобто нам залишилось просто дивитись на країну відвідувача і виставляти мову.

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

При авторизації поточна мова зберігається у вашому профілі, і далі геолокація не має значення. Та, звісно, мову профіля можна змінити у будь-який час.

Автоматична перевірка (лінтери)

Щоб переконатись, що переклад зроблений повністю, ми додали декілька лінтерів.

TypeScript, TODO i18next linter - для того, щоб знаходити неперекладені рядки в додатку. Без нього процес перекладу був би гірше визначеним, та, мабуть, не вдалося б перекласти все без ретельного тестування.

Самописний лінтер №1 - перевіряє, що словники для кожної мови мають одну й ту саму структуру.

Самописний лінтер №2 - перевіряє, що словники для листів мають однаковий набір ключів для тем та для змісту.

Наступні плани

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

Якщо додаток вже локалізований і має словник, то переклад можна доручити іншим особам, таким чином, отримати переклади хоч на всі мови світу. (А ще можна перекласти автоматично - бачу, що деякі автори так роблять, судячи з кумедних результатів.)

Після локалізації ми ще не додавали суттєвих фіч (хоча це плануємо, та раніше, ніж наступні переклади.) Як я передбачаю, то доповнення вже локалізованого додатка - теж цікава проблема. Сподіваюсь, що лінтери нам в цьому допоможуть.

Цей досвід навчив мене, що локалізація - не така непідйомна справа, як я її вважав раніше. Та зараз вона потрібна, як ніколи. Тож беріть надійні інструменти, заручайтеся уважністю та терпінням, та гайда робити більше українського софту!

Buy me a coffee Liked the post? Treat me to a coffee