Тема
Мультиязычность — модель
Статус: проектирование («как именно» для Q6: заготовка в ядре, полноценный перевод — модуль под заказ). Здесь — модель хранения, резолв локали, fallback, SEO и граница с мультигородом.
Три слоя перевода
| Слой | Где | Когда |
|---|---|---|
| UI-строки (кнопки, письма, админка) | штатный lang/ + __(); модуль привозит свой lang/ | ядро, всегда |
| Контент (страницы, блоки, типы контента) | модуль мультиязычности — две стратегии ниже | модуль, под заказ |
| Настройки / SEO / виджеты | измерение locale в cms_settings, cms_seo_*, cms_widgets | заготовка в ядре (поля есть, спят) |
Две стратегии контента (модуль выбирает per-проект)
А. Переводимые атрибуты (spatie/laravel-translatable, донор referendum): JSON {ru: ..., en: ...} на поле. Компактно; подходит типам контента и сущностям с полным зеркалом структуры (товар одинаков, отличается текст).
Б. Запись-на-локаль: отдельная запись с locale + translation_group_id (связь переводов между собой). Подходит страницам с блоками: языковые версии страницы могут отличаться структурно (другой набор блоков, другие акценты) — и это норма, а не ошибка. Ревизии (Q7) работают штатно — у каждой языковой записи свои.
Правило по умолчанию: страницы+блоки — стратегия Б; типы контента — А (или Б, если клиенту нужны структурно разные детальные). Ядро нейтрально: поля locale уже в моделях (модель данных), стратегию активирует модуль.
Резолв локали
Middleware ядра (сейчас — заглушка single-locale):
сегмент URL /{locale}/ (или поддомен en.site.ru — выбор на проект)
→ сессия/cookie → Accept-Language → локаль по умолчанию- локаль в URL для индексируемых страниц обязательна (SEO: у каждой версии свой адрес);
- cookie/Accept-Language — только для первого редиректа гостя, не для подмены контента на том же URL (клоакинг).
Fallback
- цепочка fallback конфигурируема:
kk → ru → default(казахская версия без перевода поля показывает русский); - непереведённая страница: 404 или fallback-показ с canonical на исходную локаль — конфиг per-проект;
- переключатель языка ведёт только на существующие переводы (
translation_group_id), иначе — на главную целевой локали; - статус перевода в админке: «переведено / устарело» (исходник изменился позже перевода — сравнение по
updated_atревизий).
SEO
hreflang+x-default— только для языков; версии по городам одного языка — дубли, решаются canonical, не hreflang (SEO);- переводимые slug (у каждой локали свой), карта соответствий для переключателя;
- sitemap per-locale (тиринговый генератор уже умеет разрезы);
- мета/шаблоны SEO — измерение
localeвcms_seo_templates(заготовка есть).
Граница с мультигородом
Город ≠ локаль. Мультигород (universal/gulaev-dev) — то же дерево контента с полевыми оверрайдами и региональными данными; мультиязычность — разные тексты/структуры. Измерения сосуществуют: locale × city (казахская версия сайта тоже мультигородна). Поэтому в моделях ядра оба поля (locale, city_id), и ключ page-cache включает оба (производительность).
Кеш и производительность
- page-cache, кеш настроек, областей, меню — ключ/тег с
locale; - прогрев — по активным локалям;
- словари
lang/— компилируются, БД не участвует в переводе UI-строк.
Админка
- перевод из карточки: табы локалей / действие «создать перевод» (копия структуры → перевод);
- фильтр списка по локали; индикатор непереведённого/устаревшего;
- язык интерфейса админки — штатная локализация Filament, независим от локалей контента.
Чеклист (модуль мультиязычности)
- [ ] Резолвер локали (URL-сегмент/поддомен → сессия → Accept-Language → дефолт).
- [ ] Стратегия А (translatable) и Б (запись-на-локаль + translation_group_id) — выбор per-проект.
- [ ] Fallback-цепочка локалей + политика непереведённых страниц.
- [ ] hreflang/x-default, переводимые slug, sitemap per-locale.
- [ ] Ключи кеша с locale; прогрев по активным локалям.
- [ ] UI: табы локалей, статус «устарело», переключатель по translation_group.
- [ ] Совместимость с мультигородом (locale × city).
Связи
- Решение Q6 — почему заготовка+модуль.
- Модель данных — поля locale/city_id в таблицах ядра.
- SEO — hreflang, региональность; производительность — кеш-ключи.
- Три оси — настройки per-локаль.