C&C Docs
Log in
Platform services

$t

Welcome to the translation tour. Every string in the examples below is a _Translation row the docs seed (English, French and Spanish), looked up by key with $t or x-t.

This request resolved to en-US from your language cookie or your browser's Accept-Language . Try ?lang=fr or ?lang=es.

A key becomes a sentence

x-t sets an element's text from a key; $t(key, vars) answers the string, with each {name} filled from vars. The controller and the template call the same function. A key with no row in your language falls back to English, and a key nobody wrote shows the key itself, never a blank.

// blocks/translations.mjs
async $update() {
  if (this.$req.query.lang) await $t.lang(this.$req.query.lang)
  this.fromController = $t('tour.welcome')
}

<!-- blocks/translations.html -->
<span x-t="tour.welcome"></span>
<span x-text="$t('tour.hello', { name })"></span>

// seeds/_Translation.json
{ "locale": "fr", "key": "tour.hello", "value": "Bonjour {name}" }
controller
Welcome to the translation tour
x-t
Welcome to the translation tour
with a var
Hello Ada
English only
This sentence has no French yet, so French readers get it in English
nobody wrote it
tour.nobody.wrote.this

In the browser

The browser holds the catalogue too, so a count the server never saw fills in with no request, and a key built in the browser still resolves. Switch language and the whole page switches; the choice is kept in a cookie for the next request.

<span x-text="$t('tour.cart', { count })"></span>
<span x-text="$t('tour.status.' + status)"></span>
<button @click="switchTo('fr')">Français</button>

// a plain method: it runs in the browser
async switchTo(tag) {
  await $t.lang(tag)
}
2 You have 2 item(s) in your cart
→ Open
switch language:

Dates and numbers follow the same locale

The locale that picks a string also formats dates, numbers and money in the same response, so a French page never shows March 3, 2026. The controller passes no locale to Intl; it gets the request's. The browser formats the same way, so the text does not change when the page comes alive.

// No locale argument: the request's own.
new Date(instant).toLocaleDateString(undefined,
  { year: 'numeric', month: 'long', day: 'numeric' })
new Intl.NumberFormat().format(1234567.89)
new Intl.NumberFormat(undefined,
  { style: 'currency', currency: 'EUR' }).format(1234.5)
$t('tour.date', { date })
a date
March 3, 2026
in a sentence
Today is March 3, 2026
a number
1,234,567.89
money
€1,234.50