Przejdź do treści

Strony wielojęzyczne w CMS

Aktualizacja: 3 min czytania

Jak tworzyć wielojęzyczne strony w CMS z automatycznym przełączaniem języka i poprawnym SEO.

Architektura

Wielojęzyczność opiera się na trzech elementach:

  1. Master page (PL) z locale-keyed fields
  2. Slave pages (EN, ES, FR…) — puste, dziedziczą content z mastera
  3. Domeny z ustawionym locale (np. mojafirma.pl=pl, mojafirma.com=en)
Site: mojafirma-marketing (multilang: true)
├── Master: path="cennik", locale=pl
│   fields: { "pl": {"hero": "Cennik"}, "en": {"hero": "Pricing"} }
│   content: <h1>{{ hero }}</h1>...
├── Slave EN: path="pricing", locale=en, based_on=master
│   content: "" (pusty — dziedziczy z mastera)
└── Slave FR: path="tarifs", locale=fr, based_on=master
    content: "" (pusty)

Locale-keyed fields

Wszystkie teksty na masterze PL w strukturze per język:

{
  "pl": {
    "hero_title": "Cennik",
    "hero_lead": "Wybierz plan dla siebie"
  },
  "en": {
    "hero_title": "Pricing",
    "hero_lead": "Choose your plan"
  }
}

CMS automatycznie dobiera odpowiedni język na podstawie domeny.

Slave pages — zasady

Slave to strona per język z trzema polami:

  • path — ścieżka w docelowym języku (np. pricing, tarifs)
  • locale — kod języka (en, fr, es)
  • based_on_page_id — ID mastera PL

Content i fields pozostają puste — CMS dziedziczy je z mastera.

Path bez prefixu locale

Slave ma path w docelowym języku, bez prefixu:

  • pricing (nie en/pricing)
  • tarifs (nie fr/tarifs)

Wyjątek: gdy path koliduje z masterem PL (ten sam tekst w obu językach):

  • Master PL: crm → Slave EN: en/crm (bo crm = crm)
  • Master PL: blog → Slave EN: blog-en

Homepage

Homepage (path=””) to jeden master z locale-keyed fields, bez slave’ów.

Strony /en, /fr to puste redirect pages (redirect_to: “/”) — fallback gdy ktoś wejdzie ręcznie.

Layout

Layout używa {{ html_lang }} (nie {{ locale }}) do conditionals:

{% if html_lang == "en" %}
  <a href="/pricing">Pricing</a>
{% else %}
  <a href="/cennik">Cennik</a>
{% endif %}

html_lang jest ustawiany automatycznie z locale domeny.

Zmienne layoutowe dostępne przez {{ layout.nazwa }} (nie {{ nazwa }}).

Blog wielojęzyczny

Tag <cms type="article"> nie filtruje po locale — pokazuje wszystkie artykuły z danej kategorii.

Rozwiązanie: osobny category_code per język + Liquid conditional:

{% if html_lang == "en" %}
<cms type="article" category_code="blog-en" per_page="12" site="current">
  <list><!-- karty artykułów --></list>
  <show><!-- pełny artykuł --></show>
</cms>
{% else %}
<cms type="article" category_code="blog-pl" per_page="12" site="current">
  <list><!-- karty artykułów --></list>
  <show><!-- pełny artykuł --></show>
</cms>
{% endif %}

Ważne: każdy branch musi mieć kompletny blok <cms>...<list>...<show>...</cms>. Nie wolno dzielić otwierającego i zamykającego tagu między branche — CMS zwróci błąd 500.

SEO

  • Canonical: <link rel="canonical" href="{{ url }}"> w layoucie
  • Hreflang: {{ seo_head }} w layoucie generuje hreflang automatycznie (wymaga multilang: true na site)
  • Schema.org: JSON-LD Organization + SoftwareApplication w layoucie

Domeny

Każda domena ma przypisany locale:

Domena locale
mojafirma.pl pl
mojafirma.com en
mojafirma.es es

Ustawienie: Konta → Domeny (Account::Domain z subject_type=Cms::Site).

Locale codes

  • Czech: cs (nie cz)
  • Ukrainian: uk (nie ua)
  • Pozostałe: pl, en, fr, sk, de, es

Checklist

  • Master PL z locale-keyed fields (pl, en, es…)
  • Content z Liquid variables — bez hardkodowanych tekstów
  • Slave per język: path + locale + based_on_page_id, content i fields puste
  • Path slave’a bez prefixu (chyba że koliduje z masterem)
  • Artykuły blogowe z category_code per język
  • Layout z html_lang conditionals
  • multilang: true na site
  • Domeny z locale

Czy ten wpis był pomocny?

Udostępnij

Komentarze