Усунення несправностей
Кожен запис тут — це збій, з яким хтось справді зіткнувся. Для кожного вказано симптом, причину виникнення та спосіб виправлення. Здебільшого все зводиться до одного з трьох: фрази немає в проєкті, SDK так і не ініціалізувався або заповнювач записано для неправильного контексту.
Нічого не перекладається — усі фрази залишаються мовою оригіналу
Якщо усюди показується вихідний текст, імовірно, SDK не вдалося ініціалізувати. За задумом він збоїть «м’яко» (інтерфейс не має ламатися), тож єдиний явний сигнал — консоль браузера, перевірте її насамперед. Типові причини в порядку ймовірності:
- CORS. Перший запит SDK —
authorize-project; якщо ваш API не додає origin застосунку до списку дозволених, браузер блокує запит, і ініціалізація обривається саме тут. Пам'ятайте, що origin — це точна комбінація схема + хост + порт:localhost:5173іlocalhost:5174є різними origin, а dev-сервери «пливуть» по портах, коли звичний порт зайнятий. Додайте до списку дозволених кожен порт, на якому ви справді розробляєте. - Неправильні облікові дані. Відсутній або помилково введений ідентифікатор проєкту / ключ API призводить до збою того самого виклику авторизації. У консолі показано запит, що завершився помилкою, та URL.
- Ви дивитеся на базову локаль. У базовій локалі «переклад» і є вихідним текстом — нічого помітно не змінюється. Щоб протестувати, перемкніться на цільову локаль.
# The SDK's first call is an authorize-project request.
# If the browser blocks it, NOTHING translates. Check the console for:
Access to fetch at 'https://your-api/api/authorize-project/...'
from origin 'http://localhost:5173' has been blocked by CORS policy
# Fix: allowlist the app's EXACT origin (scheme + host + port) on the API.
CORS_ALLOWED_ORIGINS=http://localhost:5173,https://app.example.com Одна фраза не перекладається (а інші перекладаються)
Фраза у вашому коді є ключем пошуку — фраза і є ключ. Якщо одна фраза відображається вихідним текстом, а сусідні перекладаються, цього ключа немає в каталозі проєкту:
- Її ніколи не було зареєстровано. Реєстрація відбувається через виявлення токенів, і зробити це може лише ключ із правом запису. Якщо фраза з’явилася, коли застосунок працював із ключем лише для читання, її нікуди не було надіслано — один раз відкрийте цей екран у середовищі розробки з ключем запису або додайте фразу в панелі керування.
- Текст змінився. Будь-яка правка — слово, розділовий знак, навіть пробіл — робить фразу новою, і перекладів для неї ще немає. Старі переклади залишаються під старим ключем. Особливо це стосується контентних блоків: блок
<Translate>токенізується з його розмітки, тож зміна тексту чи структури блоку змінює те, що шукається, і блок непомітно повертається до вихідного тексту, доки нову форму не буде зареєстровано й перекладено. - Машинний переклад ще не встиг. Щойно зареєстрована фраза може трохи випереджати свої переклади, а для локалі, якої немає в списку цільових мов проєкту, переклад не з’явиться взагалі. Перевірте фразу в дашборді: чи зареєстрована? чи перекладена для цієї локалі?
Чому відсутні фрази не спричиняють помилку?
Так задумано. У робочому середовищі система перекладу має деградувати до читабельного вихідного тексту, а не до зламаної сторінки — тому незареєстрована фраза відображається вихідним текстом, а SDK мовчить. Зворотний бік: з ключем лише для читання відсутня фраза мовчить. Нічого не логується, нічого не реєструється, і ви дізнаєтеся про це лише тоді, коли користувач побачить англійську. Запобігає цьому розділення ключів: розробляйте з ключем для запису, щоб кожна фраза вашого інтерфейсу була виявлена, а потім випускайте з ключем лише для читання.
# Development — write key: new phrases are discovered,
# registered, and machine-translated as you build.
VITE_LANGSYS_API_KEY=write-key
# Production — read-only key: fetches the finished catalog only.
# Unregistered phrases silently render their source text.
VITE_LANGSYS_API_KEY=read-only-key Мій плейсхолдер відображається буквально — "Hi %name%" або "Hi {name}"
- У викликах
t()заповнювачі записуються в одинарних дужках{name}, а інтерполяція виконується лише тоді, коли ви передаєте параметри:t('Hello, {name}!', 'Greetings', { name }). - У розмітці
<Translate>/<Phrase>під React, Vue або Svelte записуйте плейсхолдери як%name%. Компілятор фреймворку обробляє «голий»{name}як вираз ще до того, як його побачить SDK;%name%переживає компіляцію, і SDK під час захоплення нормалізує його назад у{name}. У звичайному HTML, де немає синтаксису шаблонів, з яким міг би виникнути конфлікт, цілком підійде простий{name}. - Немає параметрів? Якщо
paramsне передано, шаблон відображається як є — це і є той буквальний%name%, який ви бачите.
Усе працює, а потім ламається після того, як я кілька разів перемикаю локалі туди й назад
Оновіть SDK. Реальні виправлені помилки в цій ділянці: повернення до початкової локалі/SSR-локалі залишало активним попередній каталог (виправлено в langsys-js-typescript 0.2.2), а споживачі Translate/Phrase для блоків вмісту могли зависати назавжди на каталозі, заданому сервером (виправлено в 0.2.3). Якщо ви бачите рядки із застарілою локаллю або блоки, що ніколи не завантажуються, перш ніж налагоджувати власний код, порівняйте встановлену версію зі списком змін базового SDK.
На стороні сервера: сторінка повертає помилку 500 замість плавної деградації
Клієнт PHP SDK видає виняток, якщо його створити без облікових даних, тому застосунок на Laravel (або звичайному PHP) із порожнім LANGSYS_API_KEY завершується помилкою під час розв'язання контейнера, ще до початку будь-якого перекладу. Задайте облікові дані (або, якщо застосунок має запускатися без них, прив'яжіть клієнт-заглушку так, як це роблять демозастосунки). Щойно облікові дані задано, збої API під час виконання обробляються м'яко: якщо API недоступний або відхиляє запит, відображається вихідний текст і повідомляється про виняток — сторінка ніколи не зламається.
На стороні сервера: перший запит зависає, а потім усе працює швидко
Тайм-аут HTTP в PHP SDK становить 30 секунд, і екземпляр API, що виходить зі стану простою, може наблизитися до цього значення вже під час першого виклику. Такий запит або завершується повільно (і прогріває кеш каталогу — усе подальше віддається з кешу), або завершується тайм-аутом і відображає вихідний текст. Якщо перше завантаження сторінки після періоду бездіяльності повільне, причина в цьому: це прогрівається API, а не проблема вашої інтеграції.
На сервері: я виконав рендеринг із ключем запису, але фрази немає на панелі керування
Виявлені фрази ставляться в чергу під час запиту й надсилаються після відправлення відповіді — це terminable middleware у Laravel. Оновлюйте панель керування трохи згодом після завантаження сторінки, а не під час нього. У середовищах із довгоживучими воркерами (Octane, FrankenPHP, RoadRunner) переконайтеся, що ви користуєтеся інтеграцією, яку надає SDK: звичайний хук завершення роботи PHP не спрацьовує між запитами воркера.
Серверний рендеринг: переклади з одного запиту потрапляють в інший
Базовий JS SDK зберігає каталог лише однієї локалі одночасно — це синглтон на рівні модуля. Якщо сервер Node рендерить різні локалі для одночасних запитів, виникне гонка. Отримуйте каталог для кожного запиту й ініціалізуйте з нього клієнт — так робиться в посібниках Next.js, Nuxt і SvelteKit — або запускайте по одній локалі на процес.
Усе ще не виходить? Створіть issue в репозиторії SDK — typescript, react, vue, svelte, php або laravel — і додайте вивід консолі (або журнал сервера) для запиту, що завершився помилкою. Або напишіть на [email protected].