Date formatting and i18n
Metanorma renders dates through a single extended strftime-style formatter
shipped in the isodoc-i18n gem (IsoDoc::ExtendedDateFormatter) [added in https://github.com/metanorma/isodoc-i18n/releases/tag/v1.5.1].
The formatter supports POSIX %E* / %O* modifiers for era years and
alternative numbering systems on top of locale-aware month and day names, so a
single format string can express anything from a plain Gregorian date to a
Japanese regnal-year colophon or a Continental-European bibliographic date with
a Roman-numeral month.
This page documents:
-
the format-string grammar accepted by
IsoDoc::ExtendedDateFormatter, -
how it is reached from the
<date value="…" format="…"/>presentation-XML element and from thedate_i18nLiquid filter, -
the per-flavour YAML keys that hold the canonical format strings for each locale and rendering mode.
Format string grammar
Most strftime conversions work as in Ruby’s Date#strftime — %Y, %m, %d,
%-m, %-d, %H, %M, etc. — and pass through to the underlying date. On
top of that, the formatter recognises three families of extended tokens:
| Token family | Meaning | Backed by |
|---|---|---|
|
Era year. |
|
|
Alternative numbering for date components. The script of the digits is controlled by an optional argument (see below) rather than the underlying month/day value, which is unchanged. |
|
|
Localised month / weekday / am-pm names, sourced from CLDR for the active locale. |
|
The %E* and %O* tokens take an optional square-bracket-delimited
argument naming the numbering system or calendar:
| Argument | Effect |
|---|---|
|
Plain Arabic numerals ( |
|
CLDR spellout: locale-appropriate spelled-out form (Japanese kanji
|
|
Han ideographic digits ( |
|
Roman numerals ( |
|
For |
Arguments can be combined comma-separated, e.g. %EY{spellout, cal=japanese}.
The first non-key=value argument is treated as the numbering system.
Calendar selection
The era family (%EY / %Ey / %EC) dispatches to a calendar backend selected
via cal=. Currently implemented:
-
cal=japanese— Japanese era (Reiwa, Heisei, Shōwa, …), backed by thejapanese_calendargem. Returns the Gregorian year if the date predates Meiji. -
cal=gregorian— Gregorian year (%EYreturns the year as a number,%ECreturns an empty string).
The following CLDR calendar identifiers are reserved as extension points and
will raise NotImplementedError when used today: roc (Republic of China /
Minguo), buddhist (Thai), persian (Solar Hijri), islamic (Hijri),
indian (Saka), hebrew. The framework dispatches on them so they can be
implemented later without API changes.
If cal= is omitted, the default calendar is japanese when the active
locale is ja and gregorian otherwise.
Worked examples
| Format string | Locale | Output (for 2024-09-30) |
|---|---|---|
|
(any) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<date> element
Inside the presentation XML, the <date value="ISO-DATE" format="FMT"/>
element renders by passing value and format to IsoDoc::I18n#date,
which delegates to IsoDoc::ExtendedDateFormatter. The active locale and
script come from the IsoDoc::I18n instance for the document being rendered,
so <date value="2024-09-30" format="%EY[numeric]年%-m月%-d日"/> in a ja
document produces 令和6年9月30日 automatically.
date_i18n Liquid filter
For Liquid templates inside flavour gems and Liquid snippets in authored
documents, the same formatter is exposed as the date_i18n filter,
registered globally on Liquid::Environment.default by IsoDoc::I18n.
Signature:
{{ value | date_i18n: format }}
{{ value | date_i18n: format, lang }}
{{ value | date_i18n: format, lang, calendar }}
-
value— an ISO 8601 date string (YYYY-MM-DD,YYYY-MM, orYYYY). Returned unchanged ifnilor empty. -
format— the extended strftime format string. -
lang(optional) — override the active locale just for this call. When omitted, the locale is inherited from theIsoDoc::I18ninstance. -
calendar(optional) — override the calendar ("japanese","gregorian", …). When omitted, the calendar is derived from the locale.
Format strings inline cleanly inside Liquid string literals because
the %E*[…] / %O*[…] argument syntax uses square brackets, which do
not clash with Liquid’s {{…}} template delimiters:
{{ revdate | date_i18n: "%-d.%Om[roman].%Y" }}
{{ revdate | date_i18n: "%EY[numeric]年%-m月%-d日", "ja" }}
For non-trivial format strings, the convention in metanorma flavour gems is to centralise them in a YAML key and reference by name — see the per-flavour YAML keys section below.
Per-flavour YAML keys
Each Metanorma flavour gem ships a lib/isodoc/<flavour>/i18n-<lang>.yaml
file with localisation data. Date format strings live under a date_format
key with two branches keyed by rendering mode:
# Example: metanorma-jis/lib/isodoc/jis/i18n-ja.yaml
date_format:
default: # standalone rendering: kanji year, Arabic month/day
year: "%EY[spellout]年"
year_month: "%EY[spellout]年%-m月"
full: "%EY[spellout]年%-m月%-d日"
japanese_numbering: # autonumbering-style: japanese — full kanji
year: "%EY[spellout]年"
year_month: "%EY[spellout]年%Om[spellout]月"
full: "%EY[spellout]年%Om[spellout]月%Od[spellout]日"
The inner year / year_month / full keys correspond to the three input
arities (year only, year + month, full year-month-day).
The flavour’s i18n class picks the right format based on the date arity and the
active rendering mode, then calls IsoDoc::ExtendedDateFormatter.format(…).
Downstream flavours can override individual sub-trees via Ruby’s
Hash#deep_merge — for example, metanorma-plateau extends metanorma-jis
and overrides only date_format.default to switch from the "spellout" kanji
year (令和六年) to numeric Arabic year (令和6年), while inheriting the
japanese_numbering sub-tree from JIS unchanged.
See also
-
Localization — how
lib/isodoc/i18n-*.yamlfiles are loaded and merged across flavours. -
Metadata and predefined text — how
revdateand other date-bearing metadata fields reach the rendering pipeline.