Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Питання на співбесіді: Локалізація

Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів

3 питання

Локалізація дає багатомовність. Рядки перекладів лежать у lang/{locale} (наприклад, lang/uk/messages.php або JSON-файли).

// lang/uk/messages.php
return ['welcome' => 'Ласкаво просимо, :name'];
{{ __('messages.welcome', ['name' => $user->name]) }}
  • app()->setLocale('uk') перемикає мову (зазвичай у middleware).
  • trans_choice() обирає форму за кількістю (1 яблуко / 2 яблука / 5 яблук).

Докладніше в документації: Локалізація

Файли в 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() це враховують.

Докладніше в документації: Локалізація

Мову зазвичай визначає middleware - з URL, налаштувань користувача чи заголовка браузера:

class SetLocale
{
    public function handle(Request $request, Closure $next): Response
    {
        $locale = $request->route('locale')
            ?? $request->user()?->locale
            ?? $request->getPreferredLanguage(['uk', 'en']);

        App::setLocale($locale);

        return $next($request);
    }
}

Де це стикається з кешем - три різні місця:

1. Кеш застосунку. Значення, покладене під ключем nav.items, буде віддане й іншій мові. Ключ має включати локаль:

Cache::remember('nav.items.'.app()->getLocale(), 3600, fn () => ...);

2. Кеш HTTP і CDN. Якщо мова визначається заголовком Accept-Language, а не URL, то одна адреса віддає різний вміст - і проксі роздасть усім ту версію, яка потрапила в кеш першою. Рятує або Vary: Accept-Language, або мова в URL.

3. Кеш маршрутів. route:cache фіксує маршрути один раз, тож локаль не може бути частиною визначення маршруту - лише параметром.

Чому мову краще тримати в URL. Окремі адреси на кожну мову - це єдиний варіант, який нормально індексується: у пошуку зʼявляються обидві версії, hreflang їх звʼязує, а посилання веде туди, куди вело в того, хто ним поділився. Мова в сесії всього цього не дає.

Дрібниця, яку часто пропускають: App::setLocale() не змінює локаль Carbon - для дат потрібен окремий Carbon::setLocale().

Докладніше в документації: Локалізація