How does the Locale type work in EK9 and how do I format values for different regions?
← Getting Started · Ref: Q44
Locale is EK9's unified formatting type for presenting values according to regional conventions. One type handles formatting for Integer, Float, Date, Time, DateTime, Money, Boolean, and Dimension.
CONSTRUCTION
enGB <- Locale("en_GB") single string skSK <- Locale("sk", "SK") language, country
FORMATTING
Unified API: locale.format(value) for all types. Four named levels for Date/Time/Money: shortFormat(), mediumFormat(), longFormat(), fullFormat(). Day of week: enGB.dayOfWeek(date).
Use 'ek9 -h Locale' to see the full API.
See Q31 for Date/Time/DateTime. See Q35 for Money. See Q36 for Dimension. See Q37 for string interpolation. See Q39 for Integer/Float formatting.
Example
defines module qa.locale defines program LocaleDemo() stdout <- Stdout() // === LOCALE CONSTRUCTION === // Single string with underscore separator enGB <- Locale("en_GB") // Dash separator also works enUS <- Locale("en-US") // Two-argument form: language, country deutsch <- Locale("de_DE") skSK <- Locale("sk", "SK") // Access language and country parts stdout.println(`Language: ${enGB.language()}, Country: ${enGB.country()}`) // === INTEGER FORMATTING === bigNumber <- 675807 negative <- -92208 // Thousand separators differ by locale stdout.println(`GB: ${enGB.format(bigNumber)}`) stdout.println(`DE: ${deutsch.format(bigNumber)}`) stdout.println(`SK: ${skSK.format(negative)}`) // === FLOAT FORMATTING === pi <- 3.14159265358979 bigFloat <- -1.797693134862395E12 // Decimal separators differ by locale stdout.println(`GB pi: ${enGB.format(pi)}`) stdout.println(`DE pi: ${deutsch.format(pi)}`) // Control decimal places with second argument stdout.println(`GB pi (2dp): ${enGB.format(pi, 2)}`) stdout.println(`DE big (1dp): ${deutsch.format(bigFloat, 1)}`) // === DATE FORMATTING — four named levels === wedding <- 2020-10-03 stdout.println(`GB short: ${enGB.shortFormat(wedding)}`) stdout.println(`US medium: ${enUS.mediumFormat(wedding)}`) stdout.println(`SK long: ${skSK.longFormat(wedding)}`) stdout.println(`DE full: ${deutsch.fullFormat(wedding)}`) // === TIME FORMATTING === lunchTime <- 12:00:01 stdout.println(`GB short: ${enGB.shortFormat(lunchTime)}`) stdout.println(`DE medium: ${deutsch.mediumFormat(lunchTime)}`) // === DATETIME FORMATTING === event <- 2020-10-03T12:00:00Z stdout.println(`US short: ${enUS.shortFormat(event)}`) stdout.println(`GB medium: ${enGB.mediumFormat(event)}`) stdout.println(`DE long: ${deutsch.longFormat(event)}`) stdout.println(`SK full: ${skSK.fullFormat(event)}`) // === MONEY FORMATTING === tenPounds <- 10#GBP thirtyDollars <- 30.89#USD // Default format — symbol + full amount stdout.println(`GB: ${enGB.format(tenPounds)}`) stdout.println(`DE: ${deutsch.format(tenPounds)}`) stdout.println(`SK: ${skSK.format(thirtyDollars)}`) // Named levels for money stdout.println(`Medium (no fraction): ${enGB.mediumFormat(tenPounds)}`) stdout.println(`Short (no symbol/fraction): ${enGB.shortFormat(thirtyDollars)}`) stdout.println(`Long (no symbol): ${deutsch.longFormat(tenPounds)}`) // Custom control: format(money, withSymbol, withFraction) stdout.println(`Symbol, no fraction: ${enGB.format(arg0: thirtyDollars, showSymbol: true, showFractionalPart: false)}`) stdout.println(`No symbol, with fraction: ${enGB.format(arg0: thirtyDollars, showSymbol: false, showFractionalPart: true)}`) // === BOOLEAN FORMATTING === stdout.println(`True in GB: ${enGB.format(true)}`) stdout.println(`True in DE: ${deutsch.format(true)}`) // === DIMENSION FORMATTING === dist <- 42.5km stdout.println(`Dimension GB: ${enGB.format(dist)}`) stdout.println(`Dimension GB (1dp): ${enGB.format(dist, 1)}`) // === DAY OF WEEK === stdout.println(`Day: ${enGB.dayOfWeek(wedding)}`) stdout.println(`Tag: ${deutsch.dayOfWeek(wedding)}`) // === LOCALE OPERATORS === // Comparison require enGB <> deutsch require enGB < enUS stdout.println(`GB <=> US: ${enGB <=> enUS}`) // Hashcode stdout.println(`Hash: ${#? enGB}`) // To-string and to-JSON stdout.println(`String: ${enGB}`) stdout.println(`JSON: ${$enGB}`) // Copy copied <- Locale() copied :=: enGB require copied == enGB // Unset unsetLocale <- Locale() require ~unsetLocale? stdout.println(`Unset isSet: ${unsetLocale?}`) // Matches matchResult <- enGB matches /en.*/ stdout.println(`Matches /en.*/: ${matchResult}`) // === USING LOCALE WITH INTERPOLATION === // Locale formatting combines naturally with string interpolation stdout.println(`The wedding was on ${enGB.longFormat(wedding)} at ${enGB.shortFormat(lunchTime)}`) stdout.println(`Cost: ${enGB.format(tenPounds)} (${deutsch.format(tenPounds)} in German format)`)
Common mistakes
E50060 — EK9 Locale uses short method names: language(), country() not getLanguage(), getCountry(). Triggers E50060 — method not resolved. See ek9 -h Locale for the full API.
Incorrect:
enGB.getLanguage()
Correct:
enGB.language()
E50060 — EK9 Locale uses short method names: language(), country() not getLanguage(), getCountry(). Triggers E50060 — method not resolved. See ek9 -h Locale for the full API.
Incorrect:
enGB.getCountry()
Correct:
enGB.country()
Other ways to ask this
- How do I format numbers, dates, and currency for different locales in EK9?
- What is the difference between shortFormat, mediumFormat, longFormat, and fullFormat in EK9?
- How do I display money amounts with locale-specific formatting in EK9?
- How does EK9 handle internationalization and localization?
Coming from another language?
Java: separate NumberFormat/DateTimeFormatter/Currency classes. Python: locale module with global state. Rust/Go: no built-in locale. EK9: unified locale.format(value) for all types, named format levels.
Keywords: country, date, longFormat, first, shortFormat, language, time, beginner, localization, locale, migrate, mediumFormat, fullFormat, format, start, currency, number, money, internationalization, region, intro