Middle: питання на співбесіді з теми «Локалізація»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
2 питання
Файли в lang/ перекладають інтерфейс - кнопки, підписи, помилки. Для контенту з бази - назв категорій, описів товарів - потрібен інший підхід, і вибір між трьома.
1. Колонки на кожну мову - найпростіше:
Schema::table('categories', function (Blueprint $table) {
$table->string('name_uk');
$table->string('name_en');
});
Працює, поки мов дві. Кожна нова - міграція й правка всіх запитів.
2. JSON-колонка:
$table->json('name'); // {"uk": "Вакансії", "en": "Jobs"}
protected function casts(): array
{
return ['name' => 'array'];
}
Нова мова не потребує міграції. Мінус - пошук і сортування за перекладом стають незручними, хоча PostgreSQL і MySQL уміють індексувати JSON-шляхи.
3. Окрема таблиця перекладів - рядок на пару «запис + мова». Найгнучкіше: пошук і сортування звичайні, мов скільки завгодно. Ціна - join у кожному запиті.
Що врахувати незалежно від вибору:
- Запасний варіант. Якщо перекладу немає, показувати мову за замовчуванням, а не порожнє місце.
- URL. Мову зазвичай виносять у шлях (
/en/jobs), бо це дає окремі адреси для індексації - на відміну від зберігання вибору лише в сесії. hreflangу розмітці, щоб пошук розумів звʼязок між версіями.- Не лише текст. Формати дат, чисел і валют теж локальні;
Carbon::setLocale()іNumber::format()це враховують.
Каталог lang у новому Laravel-застосунку відсутній - переклади фреймворку (повідомлення валідації, пагінації, автентифікації) живуть у самому пакеті. Щоб їх змінити чи додати свої:
php artisan lang:publish
Команда створює lang/en/ з файлами auth.php, pagination.php, passwords.php, validation.php. Для української переклади фреймворку зазвичай беруть з пакета спільноти (наприклад, laravel-lang/lang), а не перекладають вручну.
Два формати перекладів.
1. PHP-файли з короткими ключами:
// lang/uk/orders.php
return [
'status' => [
'paid' => 'Оплачено',
'shipped' => 'Відправлено',
],
'empty' => 'Замовлень поки немає',
];
__('orders.status.paid');
- ключі групуються за файлами й вкладеністю;
- зручно для системних рядків: статуси, повідомлення валідації, тексти листів;
- ключ не змінюється, коли змінюється текст.
2. JSON-файли, де ключ - сам текст:
// lang/uk.json
{
"Save changes": "Зберегти зміни",
"Welcome back, :name!": "З поверненням, :name!"
}
__('Save changes');
- у шаблонах видно справжній текст, а не
orders.empty; - якщо перекладу немає, показується сам ключ - англійський текст, а не технічний ідентифікатор;
- зручно для великого інтерфейсу, де вигадувати ключ для кожної кнопки обтяжливо.
Порівняння:
| PHP-файли | JSON | |
|---|---|---|
| ключ | orders.status.paid |
Save changes |
| вкладеність | так | ні |
| без перекладу показується | ключ | англійський текст |
| зміна вихідного тексту | ключ лишається | ключ змінюється, переклади треба переносити |
Пастки:
- конфлікт імен: рядок
__('Orders')за наявності файлуlang/uk/orders.phpі відсутності ключа в JSON поверне весь масив файлу; - запасна мова (
APP_FALLBACK_LOCALE) використовується, коли рядка немає в поточній локалі - зручно, але приховує неперекладені рядки. Знаходити їх допомагаєLang::handleMissingKeysUsing()для логування; - переклади пакетів перевизначаються у
lang/vendor/{пакет}/{локаль}/.
На практиці часто поєднують: PHP-файли - для системних рядків і повідомлень валідації, JSON - для текстів інтерфейсу.
Докладніше в документації: Локалізація: рядки перекладу як ключі