The languages a site publishes in, and what the runtime makes of a path segment that names one.
The site's list
site.languages is a setting a site may override — see MishkaCmsCore.Settings — holding codes:
["en", "fa", "ar"]. A site that sets none reads the global value, and a global that sets none
reads default/0.
What a master allows, and what a master requires
Two master-only global settings bound every site's list — see allowed/0 and required/0. A
site may list only allowed languages (all of them, while none is set), and every required one is
part of every site's list whether the site listed it or not. site/1 answers with both applied, so
every reader — routing, the language plug, t/1, the translations admin — sees the same list.
A capture named lang
A page stored at /:lang/about answers /fa/about only when fa is one of its site's languages.
Without that check the capture takes anything — /xyz/about, /favicon.ico/about — and the page
renders as though it had been written in a language nobody wrote it in. So
MishkaCmsCore.Runtime.States.WebRunTimeMetaDataState asks admits?/3 before it keeps a match,
and a request whose lang is not the site's falls through to the next pattern, or to the 404.
Wherever the capture sits: /docs/:lang/:section and /shop/:category/:lang are checked the same
way, and so is a *lang rest capture. No other capture name is ever checked against languages.
Failing safe
A list that cannot be read — no such site, a value that is not a list, a cache that is not there —
is default/0. So is one with nothing usable left in it, because a site that answers no language
at all would 404 every page that has a lang in its path. Each code is trimmed and downcased, and
anything that is not a language code is dropped rather than admitted. The settings page refuses to
store such a list (valid?/1); this is for one that reached the store some other way.
Public addresses
site.language_urls decides how an address names its language — see url_mode/1. Every public
address the CMS builds comes out of url/3, and a request whose first segment names no language
is read through implied/2. A stored path is the same in both modes, so switching modes rewrites
no page.
Names
name/1 and names/1 put a code into a sentence a person reads, in the locale of the calling
process: "fa" is "Persian", and ["fa", "fr"] is "French and Persian". The names, their
alphabetical order and the "and" are Unicode CLDR's, through MishkaCmsCore.Localized; nothing
is translated by hand.
See MishkaCmsCore.Runtime.PageEditions for what a page does with its language.