Skip to content

Мультиязычность — модель

Статус: проектирование («как именно» для 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).

Связи

Внутренняя база знаний студии