Skip to content

Languages

Multilingual content lives in three tables: the languages themselves, the translations, and the translators that can fill them in.

Interface strings are a separate matter — those are lexicons, and lang() reads them. This page is about content.

A language

A row in PageBlocks → Languages.

FieldWhat it is
keyShort code used everywhere in the code — en, ru, de
nameName shown to a human
culture_keyMODX culture key
localeSystem locale, for date and number formatting
url_prefixPrefix in the address. Empty for the default language
is_defaultThe fallback language
translator_idWhich translator fills this language in
published_atAn unpublished language does not exist for the front end

One language means no multilingual behaviour at all

Multilingual mode switches on only when there is more than one published language. A single language costs nothing: no prefixes, no resolution, no extra queries.

Prefixes and addresses

The default language has no prefix. That is a deliberate asymmetry: an existing monolingual site keeps every one of its addresses when a second language is added, so nothing has to be redirected.

/about          default language
/en/about       an additional language

The address is resolved from the prefix in the URI; when no prefix matches, the default language wins.

Building an address is done in one place, so there is one rule rather than one per caller: the lang_url() helper and the route modifier both go through the same resolver. It is idempotent — an address that already carries a prefix is not prefixed twice. That matters because a caller usually cannot know: some places hand over a bare URI and others an already-prefixed one.

Translations

Stored per language in pb_translations, keyed by the owner — model_type plus model_id — and the context.

The resource fields are stored explicitly: pagetitle, longtitle, description, introtext, content, menutitle, alias, uri. Constructor fields ride along in the row's data, the same way they do on the object itself.

A missing translation shows the original

A field with no translation falls back to the source text rather than rendering empty. A half-finished translation therefore never blanks a page — which also means an untranslated site looks like it is working, so check the coverage rather than the appearance.

Filling them in

By hand in the manager, or automatically — assign a translator to the language and the component will call the provider's API. Drivers, prompts, costs and the failure behaviour are on the Translators page.

Copying between languages

Blocks can be copied from one language to another — see Copying.

© PageBlocks 2019-present