Log inGet started

i18n

Updated October 16, 2026

The player's language, and which of your world's languages to show them. i18n.pick({"en", "pt", "es"}) answers which of the languages your content has text for this player reads; i18n.preferred() is the languages their platform says they read (OS, browser or Android settings), most preferred first; i18n.onChange reports every change while they play; i18n.emulate(tags) stands a visitor's language list in to try content under it. i18n.locale() is the locale the engine's own text is in, one of i18n.offered(); i18n.choose(tag) is the player's own choice, kept for their account. The same surface in every VM. The engine picks the locale from one chain: the player's choice, then the language ZeroMind shows them, then the platform's list, then en, each matched against the offered locales (same tag, then the tag truncated, then the same language). i18n.sources() shows every link and which one decided.

require("@builtin::modules.api.engine.i18n") -- i18n (also available as global 'i18n')

The i18n namespace: 33 functions.

globals/i18n/choice

i18n.choice() -> string?

The locale the player chose for themselves, or nil when they chose none and the chain decides.

Returns string? — The player's choice.

globals/i18n/choose

i18n.choose(tag: string?) -> ChooseResult

Choose tag as the player's locale, kept on this device for their ZeroMind account (or for the signed-out player), so it wins the chain from now on and on every later boot. nil clears the choice and the chain decides again. A tag no offered locale matches is refused, naming the offered tags.

Parameters

  • tag string (optional) — A tag from i18n.offered(), or nil to clear the choice.

Returns ChooseResult — { ok, locale?, decidedBy?, reason?, offered? }.

local r = i18n.choose("pt-BR")
if not r.ok then log.warn(r.reason) end

globals/i18n/emulate

i18n.emulate(tags: { string }?) -> { ok: boolean, locale: string?, platform: { string }?, reason: string? }

Stand tags in for the platform's preferred languages, the way a visitor whose device or browser reads them would arrive, and negotiate again: i18n.preferred(), i18n.pick, i18n.locale() and i18n.onChange all answer as they would for that visitor. nil reads the platform's own list again. A report the platform makes afterwards (a language change, a desktop window regaining focus) replaces it. The player's own choice (i18n.choose) still comes first in the chain, so clear it with i18n.choose(nil) to see the list decide.

Parameters

  • tags { string } (optional) — BCP 47 tags, most preferred first, or nil for the platform's own list.

Returns { ok: boolean, locale: string?, platform: { string }?, reason: string? } — { ok, locale?, platform?, reason? }: the locale and list now in force.

i18n.emulate({ "pt-BR", "en" })   -- try the world as a Brazilian visitor
i18n.emulate(nil)                  -- back to this machine's own languages

globals/i18n/fallback

i18n.fallback() -> { string }

The chosen locale's fallback chain: the locales a string missing from its catalog is looked up in, in order.

Returns { string } — The fallback locales, en last; empty for en itself.

globals/i18n/locale

i18n.locale() -> string

The locale the engine chose for the player for its own text, a BCP 47 tag such as en or pt-BR. It is always one of i18n.offered(); en, the engine's source language, until a negotiation states another. To choose among your own content's languages, use i18n.pick.

Returns string — The chosen locale.

if i18n.locale() == "pt-BR" then label.text = "Olá" end

globals/i18n/offChange

i18n.offChange(id: number) -> boolean

Remove an i18n.onChange subscriber by its watcher id. Returns true when a live watcher carried that id (false for one already removed, or ended with the component that made it).

Parameters

  • id number — Watcher id returned by i18n.onChange.

Returns boolean

globals/i18n/offered

i18n.offered() -> { Locale }

The locales the engine offers for its own text, sorted by tag. Only an offered locale can be chosen or negotiated. Content picks among its own languages with i18n.pick.

Returns { Locale } — One { tag, name, nativeName, fallback } per offered locale.

globals/i18n/onChange

i18n.onChange(callback: (string, { string }) -> ()) -> number

Run callback each time the player's language changes: the platform's preferred list changes (the player changed their OS, browser or device language while the engine runs, or i18n.emulate stood a list in), the player chooses or clears a choice, the ZeroMind language moves, or the offered locales change. Called as (locale, preferred), after the engine renegotiated, so i18n.pick inside it answers for the new state. A change i18n.emulate or i18n.choose makes reaches this VM's subscribers before that call returns; one the platform reports reaches them within a tenth of a second. A subscription made from a component ends with that component. Returns a watcher id for i18n.offChange.

Parameters

  • callback (string, { string }) -> () — Function invoked as (locale: string, preferred: {string}).

Returns number — The watcher id.

local id = i18n.onChange(function(locale, preferred)
log.info(("locale %s, platform %s"):format(locale, table.concat(preferred, ",")))
end)

globals/i18n/pick

i18n.pick(available: { string }) -> string

Which of available, the languages your content has text for, this player reads: the tag the engine's chain picks from the player's own choice, the language ZeroMind shows them and their platform's list, matched by the same rules (same tag, the tag truncated, the same language). The first of available when none of them matches, so list your fallback first. Call it again (or from i18n.onChange) to follow a change while they play.

Parameters

  • available { string } — BCP 47 tags your content has text for, fallback first.

Returns string — One of available, exactly as written there.

local lang = i18n.pick({ "en", "pt", "es" })
label.text = ({ en = "Welcome!", pt = "Bem-vindo!", es = "¡Bienvenido!" })[lang]

globals/i18n/preferred

i18n.preferred() -> { string }

The languages the player's platform says they read, as BCP 47 tags, most preferred first: the OS language list on Linux, Windows and macOS, navigator.languages in a browser, the device (or per-app) language list on Android. Empty when the platform states none.

Returns { string } — The platform's preferred languages.

local first = i18n.preferred()[1]

globals/i18n/sources

i18n.sources() -> Sources

Every link of the chain the locale was chosen from: the player's choice, the zeromind language, the platform list, and which link decided (decidedBy: choice, zeromind, platform or default) with the tag it matched.

Returns Sources — { locale, decidedBy, matched, choice?, zeromind?, platform, signedIn }.

modules/i18n/choice

choice(): string?

The locale the player chose for themselves, or nil when they chose none and the chain decides.

modules/i18n/choose

choose(tag: string?): ChooseResult

Choose tag as the player's locale, kept on this device for their ZeroMind account (or for the signed-out player), so it wins the chain from now on and on every later boot. nil clears the choice and the chain decides again. A tag no offered locale matches is refused, naming the offered tags.

Parameters

  • tag string? (optional) — A tag from i18n.offered(), or nil to clear the choice.
local r = i18n.choose("pt-BR")
if not r.ok then log.warn(r.reason) end

modules/i18n/emulate

emulate(tags: { string }?): { ok: boolean, locale: string?, platform: { string }?, reason: string? }

Stand tags in for the platform's preferred languages, the way a visitor whose device or browser reads them would arrive, and negotiate again: i18n.preferred(), i18n.pick, i18n.locale() and i18n.onChange all answer as they would for that visitor. nil reads the platform's own list again. A report the platform makes afterwards (a language change, a desktop window regaining focus) replaces it. The player's own choice (i18n.choose) still comes first in the chain, so clear it with i18n.choose(nil) to see the list decide.

Parameters

  • tags { string }? (optional) — BCP 47 tags, most preferred first, or nil for the platform's own list.
i18n.emulate({ "pt-BR", "en" })   -- try the world as a Brazilian visitor
i18n.emulate(nil)                  -- back to this machine's own languages

modules/i18n/fallback

fallback(): { string }

The chosen locale's fallback chain: the locales a string missing from its catalog is looked up in, in order.

modules/i18n/locale

locale(): string

The locale the engine chose for the player for its own text, a BCP 47 tag such as en or pt-BR. It is always one of i18n.offered(); en, the engine's source language, until a negotiation states another. To choose among your own content's languages, use i18n.pick.

if i18n.locale() == "pt-BR" then label.text = "Olá" end

modules/i18n/offChange

offChange(id: number): boolean

Remove an i18n.onChange subscriber by its watcher id. Returns true when a live watcher carried that id (false for one already removed, or ended with the component that made it).

Parameters

  • id number — Watcher id returned by i18n.onChange.

modules/i18n/offered

offered(): { Locale }

The locales the engine offers for its own text, sorted by tag. Only an offered locale can be chosen or negotiated. Content picks among its own languages with i18n.pick.

modules/i18n/onChange

onChange(callback: (string, { string }) -> ()): number

Run callback each time the player's language changes: the platform's preferred list changes (the player changed their OS, browser or device language while the engine runs, or i18n.emulate stood a list in), the player chooses or clears a choice, the ZeroMind language moves, or the offered locales change. Called as (locale, preferred), after the engine renegotiated, so i18n.pick inside it answers for the new state. A change i18n.emulate or i18n.choose makes reaches this VM's subscribers before that call returns; one the platform reports reaches them within a tenth of a second. A subscription made from a component ends with that component. Returns a watcher id for i18n.offChange.

Parameters

  • callback (string, { string }) -> () — Function invoked as (locale: string, preferred: {string}).
local id = i18n.onChange(function(locale, preferred)
log.info(("locale %s, platform %s"):format(locale, table.concat(preferred, ",")))
end)

modules/i18n/pick

pick(available: { string }): string

Which of available, the languages your content has text for, this player reads: the tag the engine's chain picks from the player's own choice, the language ZeroMind shows them and their platform's list, matched by the same rules (same tag, the tag truncated, the same language). The first of available when none of them matches, so list your fallback first. Call it again (or from i18n.onChange) to follow a change while they play.

Parameters

  • available { string } — BCP 47 tags your content has text for, fallback first.
local lang = i18n.pick({ "en", "pt", "es" })
label.text = ({ en = "Welcome!", pt = "Bem-vindo!", es = "¡Bienvenido!" })[lang]

modules/i18n/preferred

preferred(): { string }

The languages the player's platform says they read, as BCP 47 tags, most preferred first: the OS language list on Linux, Windows and macOS, navigator.languages in a browser, the device (or per-app) language list on Android. Empty when the platform states none.

local first = i18n.preferred()[1]

modules/i18n/sources

sources(): Sources

Every link of the chain the locale was chosen from: the player's choice, the zeromind language, the platform list, and which link decided (decidedBy: choice, zeromind, platform or default) with the tag it matched.

typed/builtin//modules/api/engine/i18n/i18n/choice

i18n.choice() -> string?

The locale the player chose for themselves, or nil when they chose none and the chain decides.

Returns string? — The player's choice.

typed/builtin//modules/api/engine/i18n/i18n/choose

i18n.choose(tag: string?) -> ChooseResult

Choose tag as the player's locale, kept on this device for their ZeroMind account (or for the signed-out player), so it wins the chain from now on and on every later boot. nil clears the choice and the chain decides again. A tag no offered locale matches is refused, naming the offered tags.

Parameters

  • tag string (optional) — A tag from i18n.offered(), or nil to clear the choice.

Returns ChooseResult — { ok, locale?, decidedBy?, reason?, offered? }.

local r = i18n.choose("pt-BR")
if not r.ok then log.warn(r.reason) end

typed/builtin//modules/api/engine/i18n/i18n/emulate

i18n.emulate(tags: { string }?) -> { ok: boolean, locale: string?, platform: { string }?, reason: string? }

Stand tags in for the platform's preferred languages, the way a visitor whose device or browser reads them would arrive, and negotiate again: i18n.preferred(), i18n.pick, i18n.locale() and i18n.onChange all answer as they would for that visitor. nil reads the platform's own list again. A report the platform makes afterwards (a language change, a desktop window regaining focus) replaces it. The player's own choice (i18n.choose) still comes first in the chain, so clear it with i18n.choose(nil) to see the list decide.

Parameters

  • tags { string } (optional) — BCP 47 tags, most preferred first, or nil for the platform's own list.

Returns { ok: boolean, locale: string?, platform: { string }?, reason: string? } — { ok, locale?, platform?, reason? }: the locale and list now in force.

i18n.emulate({ "pt-BR", "en" })   -- try the world as a Brazilian visitor
i18n.emulate(nil)                  -- back to this machine's own languages

typed/builtin//modules/api/engine/i18n/i18n/fallback

i18n.fallback() -> { string }

The chosen locale's fallback chain: the locales a string missing from its catalog is looked up in, in order.

Returns { string } — The fallback locales, en last; empty for en itself.

typed/builtin//modules/api/engine/i18n/i18n/locale

i18n.locale() -> string

The locale the engine chose for the player for its own text, a BCP 47 tag such as en or pt-BR. It is always one of i18n.offered(); en, the engine's source language, until a negotiation states another. To choose among your own content's languages, use i18n.pick.

Returns string — The chosen locale.

if i18n.locale() == "pt-BR" then label.text = "Olá" end

typed/builtin//modules/api/engine/i18n/i18n/offChange

i18n.offChange(id: number) -> boolean

Remove an i18n.onChange subscriber by its watcher id. Returns true when a live watcher carried that id (false for one already removed, or ended with the component that made it).

Parameters

  • id number — Watcher id returned by i18n.onChange.

Returns boolean

typed/builtin//modules/api/engine/i18n/i18n/offered

i18n.offered() -> { Locale }

The locales the engine offers for its own text, sorted by tag. Only an offered locale can be chosen or negotiated. Content picks among its own languages with i18n.pick.

Returns { Locale } — One { tag, name, nativeName, fallback } per offered locale.

typed/builtin//modules/api/engine/i18n/i18n/onChange

i18n.onChange(callback: (string, { string }) -> ()) -> number

Run callback each time the player's language changes: the platform's preferred list changes (the player changed their OS, browser or device language while the engine runs, or i18n.emulate stood a list in), the player chooses or clears a choice, the ZeroMind language moves, or the offered locales change. Called as (locale, preferred), after the engine renegotiated, so i18n.pick inside it answers for the new state. A change i18n.emulate or i18n.choose makes reaches this VM's subscribers before that call returns; one the platform reports reaches them within a tenth of a second. A subscription made from a component ends with that component. Returns a watcher id for i18n.offChange.

Parameters

  • callback (string, { string }) -> () — Function invoked as (locale: string, preferred: {string}).

Returns number — The watcher id.

local id = i18n.onChange(function(locale, preferred)
log.info(("locale %s, platform %s"):format(locale, table.concat(preferred, ",")))
end)

typed/builtin//modules/api/engine/i18n/i18n/pick

i18n.pick(available: { string }) -> string

Which of available, the languages your content has text for, this player reads: the tag the engine's chain picks from the player's own choice, the language ZeroMind shows them and their platform's list, matched by the same rules (same tag, the tag truncated, the same language). The first of available when none of them matches, so list your fallback first. Call it again (or from i18n.onChange) to follow a change while they play.

Parameters

  • available { string } — BCP 47 tags your content has text for, fallback first.

Returns string — One of available, exactly as written there.

local lang = i18n.pick({ "en", "pt", "es" })
label.text = ({ en = "Welcome!", pt = "Bem-vindo!", es = "¡Bienvenido!" })[lang]

typed/builtin//modules/api/engine/i18n/i18n/preferred

i18n.preferred() -> { string }

The languages the player's platform says they read, as BCP 47 tags, most preferred first: the OS language list on Linux, Windows and macOS, navigator.languages in a browser, the device (or per-app) language list on Android. Empty when the platform states none.

Returns { string } — The platform's preferred languages.

local first = i18n.preferred()[1]

typed/builtin//modules/api/engine/i18n/i18n/sources

i18n.sources() -> Sources

Every link of the chain the locale was chosen from: the player's choice, the zeromind language, the platform list, and which link decided (decidedBy: choice, zeromind, platform or default) with the tag it matched.

Returns Sources — { locale, decidedBy, matched, choice?, zeromind?, platform, signedIn }.

  • api
  • reference