Softanza
StartFrançais
Softanza
Language & intelligence

Internationalization

A deliberate bet against ICU: broad data and solid datetime, but no collation, plural rules or time zones.

0 Strong · 4 Solid · 4 Partial · 4 Emerging

Measured against: ICU/CLDR · Luxon · Babel · Folders: base/i18n(opens in a new tab) · base/culture(opens in a new tab) · base/datetime(opens in a new tab) · For programmers: this area's reference

nine languages naming themselves in their own script
nine languages naming themselves in their own script. rendered on 2026-10-01 at 04:00 by the site's render script tools/areas.ring, run inside the library at commit 0e72e2e2c · the source(opens in a new tab)

Rethought from first principles

What Softanza kept from what works, and what it rethought, as the library wrote it down in its design documents and narrations.

The Softanza wayA locale says how a value is written down; a culture says how it will be read, and no meaning may be inferred from a locale code alone.

Kept from the best practice

  • Standard identifiers: locales are created from IETF language tags such as ar-TN, and currencies are keyed by their ISO codes. source(opens in a new tab)
  • ISO 8601 for data exchange and logs, and a 24-hour clock by default, for precision and international clarity. source(opens in a new tab)
  • Unicode normalization in all four standard forms and script detection come from the shared Unicode library rather than home-made tables. source(opens in a new tab)

Rethought

  • No ICU: the locale data the library actually answers is generated offline and committed with its source stamped, avoiding tens of megabytes of dependency. source(opens in a new tab)
  • A locale formats; a culture interprets: a meaning such as red-for-loss is never derived from a locale code, since red means gain in some financial cultures. (planned) source(opens in a new tab)
  • No facades: an operation honours the culture it was given or refuses, because ignoring a locale silently looks like success and returns wrong text. (planned) source(opens in a new tab)
  • Time is modelled, not just measured: one timeline object holds events, spans and blocked zones, checks them on insertion and draws them, instead of stitched-together tools. source(opens in a new tab)

A deliberate bet against ICU: rather than vendor tens of MB of C++ and CLDR data, Softanza ships broad hand-tables (261 countries, 323 languages, 143 scripts, Qt-sourced), a solid engine-backed datetime core with rich Haro-side formatting, and a distinctive business/holiday calendar. That same choice leaves the CLDR crown jewels absent: no locale collation, no ICU MessageFormat or plural rules, no translation catalog, no locale-aware number/currency formatting, no timezone database (ToUTC is a no-op), and no non-Gregorian calendars.

What a crafter does with it, and what stands out

  • Reference tables whose row coverage rivals CLDR (261 countries, 323 languages, 143 scripts)
  • A business/holiday calendar with sprint and capacity planning that most i18n libraries lack
  • An engine-backed datetime core with validated construction
  • Natural-language epoch parsing (FromNaturalEpoch)

What is owed

  • A timezone database (IANA/Olson zones, offset math, DST)
  • Locale-aware number and currency formatting over the hint tables that already ship
  • Fix the datetime / date / calendar / currency C22 test-runner collision (~450 assertions)
  • Locale-aware collation, CLDR plural rules and a translation catalog

The Softanza way, run

What Softanza does differently in this area, shown by code taken from its narrations and guards, and run for this page.

A locale knows both its currency's ISO code and the sign people actually write, from one table the engine owns.

Softanza
oFr = new stzLocale("fr_FR")
Then("the ISO code is the ISO code", oFr.CurrencyISOSymbol(), "EUR")
Then("...and the symbol is the euro sign", oFr.CurrencySymbol(), "€")
Output
  THEN  the ISO code is the ISO code  [PASS]
  THEN  ...and the symbol is the euro sign  [PASS]

run on 2026-10-01 21:17 inside the library at commit 0e72e2e2c; taken from base/test/locale/02_currencysymbol_narrated.ring(opens in a new tab)

An Iranian locale starts its week on Saturday and names that day in Persian.

Softanza
oFa = new stzLocale("fa_IR")
Then("the language itself resolves", oFa.LanguageName(), "persian")
Then("...and its first day is Saturday, as Iran counts it", oFa.NthDayOfWeek(1), "saturday")
Then("...named in Persian, not English", oFa.NativeNthDayOfWeek(1), "شنبه")
Output
  THEN  the language itself resolves  [PASS]
  THEN  ...and its first day is Saturday, as Iran counts it  [PASS]
  THEN  ...named in Persian, not English  [PASS]

run on 2026-10-01 21:17 inside the library at commit 0e72e2e2c; taken from base/test/locale/01_languagename_narrated.ring(opens in a new tab)

A timeline refuses an event placed inside a blocked maintenance window, at the moment it is added.

Softanza
oTimeline = new stzTimeLine("2024-01-01", "2024-12-31")
oTimeline.AddBlockedSpan("MAINTENANCE", "2024-06-15 09:00:00", "2024-06-15 17:00:00")
oTimeline.AddPoint("EVENT1", "2024-06-15 08:00:00")  # OK
oTimeline.AddPoint("EVENT2", "2024-06-15 12:00:00")  # Error: blocked
Output
Point 'EVENT2' falls within a blocked span or blocked point

run on 2026-10-01 21:17 inside the library at commit 0e72e2e2c; taken from base/test/timeline/47_simple_blocked_maintenance_period.ring(opens in a new tab)

The articles of this area (1)

The lanes, one by one

Lanes and their notes are quoted as they were read at the source, on Read from the source on 2026-09-16.

Locale identity and reference data
Solid
261 countries, 323 languages, 143 scripts, 495 locale abbreviations, mirrored into engine SQLite (ref_data.zig / i18n.db); Qt-sourced, native names romanizedref_data.zig / i18n.db
Date / time types and arithmetic
Solid
stzDate/stzTime/stzDateTime engine-backed (datetime.zig): components, leap, add-days, diff, compare, ISO/Unix round-trips; month/year add is Haro-side; naivedatetime.zig
Date / time formatting and parsing
Solid
~40 named formats over Qt/Unicode tokens, multi-format and natural-language epoch parsing; all Haro-side, the engine stz_date_format always emits ISO
Business and holiday calendar
Solid
stzCalendar: quarters, weeks, working-day arithmetic, holidays, capacity and sprint planning, heat-map; plus engine-backed stzTimeLine; pure Haro, GregorianstzCalendar; test/timeline (54 assertions)
Currency
Partial
Engine-backed (the L1 cutover) stz_locale_currency_iso / _symbol over 143 rows with a property test; symbol / ISO lookup only, no amount formattingstz_locale_currency_iso / _symbol property test
Number formatting
Partial
StzFormatNumber groups and rounds; Haro holds per-locale separator hints (~30 languages) but the engine formatter hardcodes US separators and never reads themStzFormatNumber
Native names and per-locale text
Partial
Native day and month names for 11 languages via NamesOfDaysIn / NamesOfMonthsIn; all else falls back to English; engine day_name takes no locale (L3 work)NamesOfDaysIn / NamesOfMonthsIn
Calendar systems
Partial
Proleptic Gregorian only, hardcoded in datetime.zig (gregorianToJulian); no Hijri, Persian, Hebrew, Buddhist or Japanese calendarsdatetime.zig gregorianToJulian
Timezones
Emerging
None: datetimes are naive wall-clock; ToUTC() and ToLocalTime() are no-ops that copy the components unchanged
Collation (locale-aware sorting)
Emerging
None: the only collate in the tree is SQLite COLLATE NOCASE (ASCII case-insensitive), not linguistic collation
Message formatting and pluralization
Emerging
None: the only plural handling is an English singular/plural pair in stzDuration; no ICU MessageFormat, no CLDR plural rules, no gender/select
Translation / message catalog
Emerging
None: no gettext, no .po / .mo, no message catalog anywhere in the group