Skip to content

Stdlib · extensions

intl

internationalization (i18n)

extensions.md · 69 lines · 2 min read

use intl

In two phases. Phase 1 (now): the useful minimum, with a message catalog, CLDR plural, and hooks for locale-aware formatting reusing the locale that already exists in the core. Phase 2 (sketched): full ICU, with collation, segmentation (grapheme/word/line break), bidi, non-Gregorian calendars, transliteration, formatted ranges/lists. Tier 1.

decl Locale { ... } // "pt-BR", "en-US" (BCP 47); extends the core locale
fn locale_of(tag: string) -> Result[Locale, error{Malformed}]
fn (l: Locale) language() -> string // "pt"
fn (l: Locale) region() -> Optional[string] // "BR"
// message catalog: lookup by key + locale
decl Catalog { ... }
fn (Catalog) load(messages: Map[string, string], locale: Locale) -> Catalog
fn (c: Catalog) get(key: string) -> Optional[string]
fn (c: Catalog) format(key: string, args: Map[string, string]) -> string // interpolates {{name}} (§16)
// plural rules (CLDR): chooses the right category for the number in the locale
decl PluralCategory { Zero; One; Two; Few; Many; Other }
fn (l: Locale) plural(n: i64) -> PluralCategory // pt: 1 to One, rest to Other; ru/ar: rich rules
fn (c: Catalog) plural(key: string, n: i64) -> string // chooses the variant and interpolates
// locale-aware formatting (hooks over the core locale)
fn (l: Locale) format_int(n: i64) -> string // locale thousands/decimal separators
fn (l: Locale) format_float(x: f64, frac_digits: u32) -> string
fn (l: Locale) format_currency(amount: i64, currency: string) -> string // "R$ 1.234,56" / "$1,234.56"
fn (l: Locale) format_date(t: DateTime, style: DateStyle) -> string // named styles (no magic layout)
decl DateStyle { Short; Medium; Long; Full }
use intl
cat := intl.Catalog.load(mensagens_pt, intl.locale_of("pt-BR").or_panic())
msg := cat.plural("itens_no_carrinho", n) // "1 item" / "3 items", correct category per CLDR
preco := intl.locale_of("pt-BR").or_panic().format_currency(123456, "BRL") // "R$ 1.234,56"

Surface foreseen, implementation deferred (each one pulls heavy Unicode/CLDR tables, pure opt-in):

fn (l: Locale) collator() -> Collator // localized alphabetical ordering (collation)
fn (c: Collator) compare(a: string, b: string) -> Order
fn graphemes(s: string) -> Iterator[string] // segmentation by grapheme cluster
fn words(s: string, l: Locale) -> Iterator[string] // segmentation by word (locale-aware)
fn line_breaks(s: string) -> Iterator[usize] // line break points (UAX 14)
fn (s: string) to_bidi(l: Locale) -> string // bidirectional reordering (UAX 9)
fn transliterate(s: string, scheme: string) -> string // "Greek-Latin", etc.
// + non-Gregorian calendars, range/list formatting, etc.
  • Two phases, opt-in: phase 1 covers 90% (catalog + plural + format) reusing the core locale; phase 2 (ICU) is the heavy universe, written as surface now, implemented when needed. The Unicode/CLDR tables only weigh on whoever imports them.
  • Reuses the core locale/unicode: intl is the layer of locale-aware policies; the data and the Unicode mechanism come from below (tier 0), coherent with the mechanism-vs-data split of the tiers (§1).
  • No magic format string: named styles (DateStyle) + interpolation (§16), like time.