A vzk site in several languages
Use this guide when a vzk site speaks more than one language. The site is
written once, in its first language, in its .vzk files, and every other
language is a folder of catalogs that translate those files’ words.
Declare languages
Section titled “Declare languages”Call set_site_languages with the default language and the additional ones.
The default is the site’s first language: the one its files are written in.
This is a site setting, not a draft: it is live when the call returns,
whether or not a catalog exists yet. A text with no translation is drawn as
the file has it, so a site can be translated one text at a time.
language in site.json says what the language of a page goes by:
language |
An address | A link to a page |
|---|---|---|
nothing, or "both" |
/uk/journal is the journal in uk for everyone, and /journal is the journal in the language its visitor reads in |
written under the language on a page asked for under it, and left as written at a plain address |
"address" |
/uk/journal is the journal in uk, and /journal is the journal in the first language for everyone |
written under the language of the page it stands on |
A site in several languages says "address" or nothing. "visitor" is the
word of a site in one language, and a site that says it cannot serve a
second: before set_site_languages adds one, change language in
site.json on a branch and merge it.
A path that starts with the code of one of the other languages belongs to
that language. A page of the site’s own there, such as pages/uk.vzk, is
refused.
Catalogs
Section titled “Catalogs”A catalog is one JSON object at the path of the file it translates, under
locales/<code>/, with .json for .vzk:
pages/journal.vzk the page, in the first languagelocales/uk/pages/journal.json that page's words in Ukrainianlocales/uk/layouts/site.json the words of layouts/site.vzklocales/uk/components/PostCard.json the words of components/PostCard.vzklocales/uk/site.json the fields of site.jsonThe code is two or three lower-case letters and then, if anything, - and
two capitals: uk, en, pt-BR. The first language has no folder. A
catalog is written on a branch and goes live with a merge, like every other
file.
A text is its own key
Section titled “A text is its own key”A text needs no name. A translation is found by the text itself, as a reader
reads it. Part of pages/journal.vzk:
<head> <title>Journal</title></head>
<section id="journal"> <h1>Notes from the bakery</h1> <p>New here? Read <a href="/journal/why-rye" class="link">why we bake with rye</a>.</p> <img src="/files/oven.jpg" alt="The oven at six in the morning"> <p>Page {posts.page} of {posts.pages}</p></section>And locales/uk/pages/journal.json:
{ "Journal": "Журнал", "Notes from the bakery": "Нотатки з пекарні", "New here? Read <a>why we bake with rye</a>.": "Уперше тут? Прочитайте, <a>чому ми печемо з жита</a>.", "The oven at six in the morning": "Піч о шостій ранку", "Page {page} of {pages}": "Сторінка {page} з {pages}"}- One key is one run of text with the inline elements inside it (
a,b,em,strong,spanand the like), so a sentence with a link in it is translated as one sentence. - A tag in a key is its name alone:
<a>stands for the file’s own<a>with every attribute. A translation says where the element goes and what words it holds. {page}stands for the value the file writes there, named by the last name in it:{posts.page}is{page}, and{post.title}is{title}.- A translation holds each tag and placeholder of its key and no other, so it never adds markup to a page.
- The
<title>, the description, and the value ofalt,title,placeholderandaria-labelare texts like the others. - A run with no letter of its own, such as
{post.published_at} · {post.minutes}, has no key and stays as it is. - What
<pre>,<textarea>and<svg>hold, and what an element that saystranslate="no"holds, is not read for texts.
Texts a script holds
Section titled “Texts a script holds”A text written in a script is translated when it reaches the page unchanged, in the catalog of the file that wrote it:
<script server> const links = [ { label: "Home", href: "/" }, { label: "Journal", href: "/journal" }, ]</script>
<nav aria-label="Main"> <a :for={link in links} href={link.href}>{link.label}</a></nav>{ "Main": "Головне меню", "Home": "Головна", "Journal": "Журнал"}A text that is compared, joined or cut is never translated, so a translation
changes the words a visitor reads and nothing a script works out. A text of
a row, and what a visitor typed, are drawn as they are. A page’s
export const name is translated by the page’s own catalog, which is what
site.pages says in each language.
Plurals
Section titled “Plurals”plural(n, forms) answers the form that fits a number, and # is where the
number goes:
<p>{plural(posts.total, { one: "# post", other: "# posts" })}</p>In a catalog a plural is one entry. Its key is the other form, and its
value holds the forms the language has:
{ "# posts": { "one": "# допис", "few": "# дописи", "many": "# дописів" }}One text, two translations
Section titled “One text, two translations”When one text needs two translations, text-key gives the text of an
element a name, and the catalog translates it by that name after @:
<button text-key="open-door">Open</button><p>The bakery is <span text-key="open-now">Open</span></p>{ "@open-door": "Відчинити", "@open-now": "Відчинено"}The fields of site.json and the labels of a table
Section titled “The fields of site.json and the labels of a table”locales/uk/site.json translates the texts among the fields of site.json.
Its keys are @fields.<name>, and it holds no other key:
{ "@fields.motto": "Хліб щоранку"}locales/uk/tables/<handle>.json holds what a table’s fields are called in
that language, under the same keys. A refused form names a field by that
label.
What is missing, stale or wrong
Section titled “What is missing, stale or wrong”- A text with no entry is no finding, and is drawn in the first language.
- An entry whose key is no text of its file is stale, a warning that names
the nearest text the file has: move the translation to the new text, or
remove the entry. Changing a sentence in a
.vzkfile leaves its old entries stale, so update the catalogs in the same write. - A catalog that is not one JSON object, or a translation that does not fit its key (a tag left out, a tag or a placeholder the key does not have), is an error and refuses the write.
Links and the switcher
Section titled “Links and the switcher”A file writes its addresses once, as they are in the first language. On a
page asked for under a language, a link to a page of the site is written
under it: /journal becomes /uk/journal. So are the addresses
page.with(...) answers, a pager’s next and previous, and where a form
is sent. An address of a file, of another site, in src, or under mailto:
and tel: is never rewritten.
An element that says as-written keeps its link as the file writes it:
<a href="/" as-written>Rye and Salt</a>page.locale is the code of the language the page is asked in, and
page.languages lists each language the page is served in, the first one
first, each with its locale, the url this page is switched to it at, and
whether it is current. Use those addresses; do not build one:
<nav aria-label="Languages"> <a :for={language in page.languages} href={language.url} hreflang={language.locale}>{language.locale}</a></nav>A list is never a condition, so ask page.languages.length > 1 before
drawing a switcher. The platform writes the alternate tags of the head.
Dates, numbers and forms
Section titled “Dates, numbers and forms”formatDate writes the names of months and of days in the language of the
page, and formatNumber and formatMoney write a number the way that
language does, so a file writes one pattern for every language. A file that
wants another pattern in another language picks it by page.locale.
The sentences of a refused form (form.message, form.error.<field>) are
held in English and Ukrainian. In any other language they are in English, so
a site in one writes a sentence of its own for each code it reads in
form.errors.
On a site in several languages an <option> of a form says its value:
translated words are not a choice the table knows.
A row is in one language, and no catalog translates a row. Give the table a
choice field with the language role, mark it filterable, and write one
row per language. Give a post’s translations the same slug, each row naming
its own language: the row’s page then shows the row written in the language
being read, then one that names no language. A listing shows every language
unless the page narrows it with a filter on that field, comparing it with
page.locale.