# TR35 Conformance

This document maps the features defined in [Unicode Technical Standard #35 (LDML)](https://www.unicode.org/reports/tr35/) version 49 against the implementation status of the Localize library.

Two areas are explicitly out of scope:

* **Part 7 — Keyboards.** Not relevant to a formatting library.

* **Part 8 — Person Names.** Implemented as the separate [localize_person_names](https://hex.pm/packages/localize_person_names) package, which uses Localize's person-name locale data (stored under the `:person_names` key in each locale ETF) and implements the full TR35 Part 8 formatting algorithm.

## Legend

* **Implemented** — feature is present and tested.
* **Partial** — core functionality exists but some sub-features are missing.
* **Not implemented** — feature is absent.

---

## Part 1 — Core (tr35.html)

### Unicode Language and Locale Identifiers

| Feature | Status | Notes |
|---------|--------|-------|
| BCP 47 / RFC 5646 language tag parsing | Implemented | `Localize.Rfc5646.Parser`, pre-compiled NimbleParsec grammar. |
| Unicode locale extensions (`-u-`) | Implemented | Calendar (`ca`), collation (`co`), currency (`cu`), number system (`nu`), hour cycle (`hc`), first day (`fw`), region override (`rg`), measurement system (`ms`), and others. |
| Transformed extensions (`-t-`) | Implemented | Parser and struct support in `Localize.LanguageTag`. |
| Private use subtags (`-x-`) | Implemented | |
| Grandfathered and irregular tags | Implemented | |
| Locale ID canonicalization | Partial | Alias resolution via supplemental data. Full Annex C canonicalization algorithm not independently verified. |

### Locale Inheritance and Matching

| Feature | Status | Notes |
|---------|--------|-------|
| Parent locale chain | Implemented | `Localize.Locale.parent/1` uses CLDR parent locale data. |
| Likely subtags | Implemented | `Localize.LanguageTag.add_likely_subtags/1` and `remove_likely_subtags/2`, including both the favor-script (default) and favor-region removal variants, verified against the CLDR likely-subtags test data. |
| Locale matching / best match | Implemented | `Localize.LanguageTag.best_match/3` using CLDR language matching data. |
| Default content locales | Not implemented | |
| Locale inheritance for data lookup | Partial | `Locale.get/3` supports `:fallback` option to walk parent chain. Not all data accessors use it consistently. |

### Validity Data

| Feature | Status | Notes |
|---------|--------|-------|
| Language validity | Implemented | Subtags are checked against the CLDR validity data by `Localize.validate_locale/1` and the other `Localize.validate_*` functions. |
| Script validity | Implemented | |
| Territory validity | Implemented | |
| Variant validity | Implemented | |
| Unit validity | Implemented | |
| Subdivision validity | Implemented | |
| U and T extension validity | Implemented | |

---

## Part 2 — General (tr35-general.html)

### Display Names

| Feature | Status | Notes |
|---------|--------|-------|
| Language display names | Implemented | `Localize.Language.display_name/2` with `:standard`, `:short`, `:long`, `:menu`, and `:variant` styles. |
| Script display names | Implemented | `Localize.Script.display_name/2` with `:prefer` values `:standard`, `:short`, `:stand_alone`, `:variant`. |
| Territory display names | Implemented | `Localize.Territory.display_name/2` with `:prefer` values `:standard`, `:short`, `:variant`. |
| Variant display names | Implemented | Rendered as a subtag by `Localize.Locale.LocaleDisplay.display_name/2` — `de-1901` is "German (Traditional German orthography)", `en-US-posix` is "English (United States, Computer)". |
| Key/type display names | Implemented | Drives `Localize.Locale.LocaleDisplay.display_name/2` — `en-u-kn-true` renders "English (Sort Digits Numerically)". `type_value_name/2` returns the localized name of a boolean keyword value ("On"/"Off"), and `key_name/2` and `type_name/3` return the key and type names on their own for menu use. |
| Locale display names | Implemented | `Localize.Locale.LocaleDisplay.display_name/2` implements the CLDR locale display name algorithm. |

### Layout

| Feature | Status | Notes |
|---------|--------|-------|
| Character order (LTR/RTL) | Partial | Data ships and is readable — `Localize.Locale.get(:ar, [:layout])` gives `%{character_order: :rtl, line_order: :ttb}` — but there is no dedicated accessor and nothing in the library consumes it. |
| Line order | Partial | Same `:layout` map; `:ttb` for every locale CLDR records. |

### Character Elements

| Feature | Status | Notes |
|---------|--------|-------|
| Exemplar characters | Not implemented | |
| Ellipsis patterns | Implemented | `Localize.ellipsis/2` with `:initial`, `:medial`, `:final`, `:word_initial`, `:word_medial`, `:word_final` styles. |
| Parse lenient characters | Implemented | Consumed by `Localize.Number.Parser`, which accepts the locale's lenient sets for the date, general and number scopes when parsing. |

### Delimiters

| Feature | Status | Notes |
|---------|--------|-------|
| Quotation marks | Implemented | `Localize.quote/2` with locale-appropriate primary and alternate quotation marks. |

### Measurement System Data

| Feature | Status | Notes |
|---------|--------|-------|
| Measurement system per territory | Implemented | `Localize.validate_measurement_system/1` and supplemental data. |
| Paper size per territory | Implemented | `Localize.Unit.measurement_system_for_territory(:US, :paper_size)` returns `:us_letter`, `:FR` returns `:a4`. |

### Unit Elements

| Feature | Status | Notes |
|---------|--------|-------|
| Unit identifiers (simple, compound) | Implemented | `Localize.Unit.Parser` parses full CLDR unit identifier syntax including SI prefixes, powers, per-units. |
| Unit formatting with plural patterns | Implemented | `Localize.Unit.to_string/2` with `:long`, `:short`, `:narrow` styles. |
| Compound unit formatting | Implemented | Multiplication, division, and power patterns. |
| Mixed/sequence units | Partial | `Localize.Unit` struct supports mixed units; formatting coverage not fully verified. |
| Duration unit patterns (hms) | Implemented | `Localize.Duration.to_time_string/2` formats durations as `"hh:mm:ss"` with unbounded hours. `to_string/2` formats as localized unit list (e.g., "11 months, 30 days"). |
| Coordinate units (N/S/E/W) | Not implemented | |
| Unit conversion | Implemented | `Localize.Unit.Conversion` with factor/offset mappings to base units. |
| Unit preferences by territory | Implemented | Territory and usage-based unit selection from supplemental data. |
| Grammatical case in units | Partial | `:grammatical_case` option supported in formatter with `:nominative` default. Full case/gender/definiteness coverage depends on locale data. |
| Grammatical gender in units | Partial | Data structures present; not all locales exercised. |

### Transforms

| Feature | Status | Notes |
|---------|--------|-------|
| General character transforms | Separate library | [unicode_transform](https://github.com/elixir-unicode/unicode_transform) implements the CLDR transform rules engine. |
| Script-to-script transliteration | Separate library | Provided by `unicode_transform`. |
| Number digit transliteration | Implemented | `Localize.Number.Transliterate` for numeric digit systems (e.g., Latin → Arabic-Indic). |

### List Patterns

| Feature | Status | Notes |
|---------|--------|-------|
| Conjunction lists ("a, b, and c") | Implemented | `Localize.List.to_string/2` with `:and`, `:and_short` styles. |
| Disjunction lists ("a, b, or c") | Implemented | `:or` style. |
| Unit lists ("3 ft, 7 in") | Implemented | `:unit`, `:unit_short`, `:unit_narrow` styles. |

### Context Transforms

| Feature | Status | Notes |
|---------|--------|-------|
| Capitalization by context | Not implemented | No context-dependent capitalization for display names. |

### Segmentation

| Feature | Status | Notes |
|---------|--------|-------|
| Grapheme cluster boundaries | Separate library | [unicode_string](https://github.com/elixir-unicode/unicode_string) implements Unicode text segmentation. |
| Word boundaries | Separate library | Provided by `unicode_string`. |
| Sentence boundaries | Separate library | Provided by `unicode_string`. |
| Line break boundaries | Separate library | Provided by `unicode_string`. |

### Annotations

| Feature | Status | Notes |
|---------|--------|-------|
| Character/emoji labels | Not implemented | |
| Typographic names | Not implemented | |

### POSIX Elements

| Feature | Status | Notes |
|---------|--------|-------|
| Yes/no strings | Implemented | `Localize.affirmative_responses/1` and `negative_responses/1` return CLDR's POSIX `yesstr` / `nostr` forms; `affirmative?/2` and `negative?/2` match a response, folding case. |
| POSIX locale identifier conversion | Implemented | `Localize.Locale` handles POSIX-style identifiers (e.g., `en_US.UTF-8`). |

---

## Part 3 — Numbers (tr35-numbers.html)

### Number Systems

| Feature | Status | Notes |
|---------|--------|-------|
| Numeric systems (digit mapping) | Implemented | `Localize.Number.System` with 97 systems loaded from ETF. |
| Algorithmic systems (RBNF) | Implemented | `Localize.Number.Rbnf` for Roman numerals, CJK, spellout, etc. |
| Number system per locale | Implemented | `:default`, `:native`, `:traditional`, `:finance` types resolved per locale. |

### Number Formatting

| Feature | Status | Notes |
|---------|--------|-------|
| Decimal format patterns | Implemented | `Localize.Number.to_string/2` with full pattern support. |
| Percent formatting | Implemented | `format: :percent` option. |
| Currency formatting | Implemented | `format: :currency` with symbol placement, spacing. |
| Accounting format | Implemented | `format: :accounting` for parenthesized negatives. |
| Compact/short formats ("1.2M") | Implemented | `format: :decimal_short`, `:decimal_long`, `:currency_short`, `:currency_long`. |
| Scientific notation | Implemented | Exponent formatting with configurable digits. |
| Significant digits | Implemented | `@` pattern character for significant digit control. |
| Number padding | Implemented | `*` pattern character for fixed-width padding. |
| Grouping separators | Implemented | Primary and secondary grouping sizes. |
| Rounding | Implemented | Pattern-specified increments, half-even default. |
| Special values (NaN, Infinity) | Implemented | |
| Number symbols per locale | Implemented | Decimal, grouping, percent, minus, plus, exponential, etc. |

### Number Parsing

| Feature | Status | Notes |
|---------|--------|-------|
| String to number parsing | Implemented | `Localize.Number.Parser` with locale-aware digit transliteration. |
| Lenient parsing | Not implemented | |

### Number Ranges

| Feature | Status | Notes |
|---------|--------|-------|
| Number range formatting | Implemented | `Localize.Number.to_range_string/3` using locale-specific range patterns. |
| Approximate number formatting | Implemented | `Localize.Number.to_approximately_string/2`, also `to_at_least_string/2` and `to_at_most_string/2`. |

### Rational Numbers

| Feature | Status | Notes |
|---------|--------|-------|
| Fraction formatting | Implemented | `Localize.Number.to_ratio_string/2`. |

### Currencies

| Feature | Status | Notes |
|---------|--------|-------|
| Currency codes and validation | Implemented | `Localize.Currency.validate_currency/1` with ISO 4217. |
| Currency display names (plural) | Implemented | `Localize.Currency.display_name/2`, `pluralize/3`. |
| Currency symbols | Implemented | Via locale data. |
| Currency digits/rounding | Implemented | Supplemental currency data. |
| Territory currency history | Implemented | `Localize.Currency.territory_currencies/1` with date ranges. |
| Current currency for territory | Implemented | `Localize.Currency.current_currency_for_territory/1`. |

### Plural Rules

| Feature | Status | Notes |
|---------|--------|-------|
| Cardinal plural rules | Implemented | `Localize.Number.PluralRule.Cardinal` with all CLDR operands (n, i, f, t, v, w, c, e). |
| Ordinal plural rules | Implemented | `Localize.Number.PluralRule.Ordinal`. |
| Plural ranges | Implemented | `Localize.Number.PluralRule.Range`. |
| Minimal pairs | Implemented | `Localize.MinimalPairs` exposes the short phrases that demonstrate a locale's plural, ordinal, case and gender forms; `format/3` picks the one a number selects. |
| Explicit 0 and 1 | Partial | Standard plural categories used; explicit 0/1 override not independently verified. |

### Rule-Based Number Formatting (RBNF)

| Feature | Status | Notes |
|---------|--------|-------|
| Spellout rules | Implemented | `Localize.Number.Rbnf` with locale-specific rule sets. |
| Ordinal rules | Implemented | |
| Numbering system rules | Implemented | Roman numerals, CJK, etc. via algorithmic number systems. |

---

## Part 4 — Dates (tr35-dates.html)

### Calendar Elements

| Feature | Status | Notes |
|---------|--------|-------|
| Month names (format/standalone, wide/abbreviated/narrow) | Implemented | `Localize.Calendar.months/2`. |
| Day names (format/standalone, wide/abbreviated/narrow) | Implemented | `Localize.Calendar.days/2`. |
| Quarter names | Implemented | `Localize.Calendar.quarters/2`. |
| Era names | Implemented | `Localize.Calendar.eras/2`. |
| Day period names (AM/PM, flexible) | Implemented | `Localize.Calendar.day_periods/2`. |
| Cyclic name sets (Chinese/Dangi) | Implemented | `Localize.Calendar.cyclic_years/2`; `U` formats and parses the cyclic year name, `y` the year's place in the sixty-year cycle and `G` the cycle's number, which TR35 leaves open and ICU writes. |
| Month patterns (leap months) | Implemented | `Localize.Calendar.month_patterns/2`; a leap month formats and parses in the locale's pattern. |

### Date/Time Formatting

| Feature | Status | Notes |
|---------|--------|-------|
| Date format patterns (:short/:medium/:long/:full) | Implemented | `Localize.Date.to_string/2`. |
| Time format patterns (:short/:medium/:long/:full) | Implemented | `Localize.Time.to_string/2`. |
| DateTime combined patterns | Implemented | `Localize.DateTime.to_string/2`. |
| All date format pattern symbols (y, M, d, E, G, etc.) | Implemented | Full symbol set in `Localize.DateTime.Formatter`. |
| Invalid pattern fields | Implemented | A symbol at a width the Date Field Symbol Table does not list formats as U+FFFD; an undefined letter is an error. |
| Hour cycle (h, H, k, K) | Implemented | Including territory and locale preferences (`hi_IN` allows `hB`), the `-u-hc-` override, and the skeleton symbols `j`, `J` and `C`. |
| Day periods (a, b, B) | Implemented | `a` renders AM/PM; `b` renders noon/midnight at the exact points and AM/PM otherwise; `B` selects flexible day periods ("in the morning", "mittags") from the CLDR day-period rules, falling back to AM/PM for languages without rules. Noon and midnight are judged at the precision the pattern shows, so "h B" renders 12:05 as "12 noon". |
| Available formats (skeletons) | Implemented | `Localize.DateTime.Format.Match` for skeleton matching. |
| Interval formats | Implemented | `Localize.Interval.to_string/3` for date/time/datetime intervals, in the formats of the endpoints' calendar, with an era difference shown as ICU shows it. |
| Append items (missing fields) | Implemented | `Localize.DateTime.Format.AppendItems` matches the closest format that is a subset of the request and appends the fields it lacks, so `en` renders `:yMMMdQ` as "Jul 6, 2024 (quarter: 3)". |

### Date/Time Parsing

| Feature | Status | Notes |
|---------|--------|-------|
| String to date/time parsing | Implemented | `Localize.Date.parse/2`, `Localize.Time.parse/2`, `Localize.DateTime.parse/2` and `Localize.Interval.parse/2` read the locale's patterns in any calendar module, and ISO 8601. A week 53 the year does not have is an error, where TR35's note on week data recommends reading it as week 1 of the next year; see [ICU divergences](icu_divergences.md#date-parsing). |

### Calendar Fields

| Feature | Status | Notes |
|---------|--------|-------|
| Relative date/time formatting | Implemented | `Localize.DateTime.Relative` — "yesterday", "in 3 days", etc. |
| Calendar field display names | Partial | Data accessible via locale data; no dedicated public function for field names. |

### Supplemental Date Data

| Feature | Status | Notes |
|---------|--------|-------|
| Calendar preferences per territory | Implemented | Supplemental data loaded from ETF. |
| Week data (firstDay, minDays) | Implemented | `Localize.Calendar.first_day_for_locale/1` and `Localize.Calendar.min_days_for_locale/1`, by TR35's first day algorithm: `-u-fw-`, `-u-rg-`, `-u-ca-iso8601`, the region, `-u-sd-`, likely subtags, the world. |
| Weekend data | Implemented | Via week data. |
| Time data (preferred hour cycle) | Implemented | Time preferences data from ETF. |
| Day period rules | Implemented | The CLDR day-period rule sets (format and selection) are part of the supplemental data pipeline; the `b` and `B` format symbols select periods from them. |

### Time Zones

| Feature | Status | Notes |
|---------|--------|-------|
| Timezone format symbols (z, Z, O, v, V, X, x) | Implemented | `Localize.DateTime.Formatter` handles all timezone symbols. |
| GMT offset formatting | Implemented | `gmtFormat` with `hourFormat` for every known offset, zero included ("GMT+00:00", "GMT+0"), with a two-digit hour in the long format and the seconds of an offset that has them ("GMT-07:52:58"), and `gmtUnknownFormat` ("GMT+?") when the offset is unknown — the two styles TR35 defines. `gmtZeroFormat` is still in the data but no TR35 formatting rule uses it. |
| UTC designation (CLDR 49) | Implemented | CLDR 49's `gmtFormat` and `gmtUnknownFormat` `alt="utc"` forms, which spell the unambiguous designation for Coordinated Universal Time where `gmtFormat` may spell the London zone's "GMT". `designation: :utc` on `Localize.DateTime.Timezone.gmt_format/3` writes them — "UTC+01:00" and "UTC+?" in `en`, "التوقيت العالمي+1:00" in `ar` against its "غرينتش+1:00" — and `non_location_format/3` passes it to its GMT fallback. Both spellings read back through `parse_offset/2`. The pattern symbols (`O`, `OOOO`, `ZZZZ`) write the locale's `gmtFormat`, which is the designation TR35 gives them. |
| Dual offset format (CLDR 49) | Implemented | CLDR 49's `dualOffsetFormat`, joining the two offsets a zone keeps so the localized GMT format describes a zone that moves between them: `offsets: :dual` on `Localize.DateTime.Timezone.gmt_format/3` writes Los Angeles as "GMT-8/-7" and Denver as "GMT-7/-6", where Phoenix keeps one offset and stays "GMT-7". The pair comes from the configured time zone database, sampled across the year around the value's time, so a value with no zone writes its single offset. It names a zone rather than a time, so it does not read back through `parse_offset/2` and no pattern symbol writes it — TR35 defines none. |
| Metazone names | Implemented | The `z` and `v` symbols render the metazone's names — "Eastern Daylight Time" and "EDT", "Eastern Time" and "ET". Both formats qualify a metazone name with the zone's country or city unless the zone is the metazone's preferred zone for the locale's country, as TR35's steps for the non-location formats give it: "Pacific Time (Canada)" and "Pacific Standard Time (Canada)" for Vancouver in `en`. A zone's first metazone period that CLDR gives no beginning begins with 1970, as ICU begins it, and a zone is written by its offset and its location before it. |
| Exemplar cities | Implemented | `VVV` renders the exemplar city ("New York") and `VVVV` the generic location format ("New York Time"), which names the country of a zone that is the only one, or the primary one, in its country ("Italy Time"): by its short name where the locale has one, and by its code where the locale does not name it ("CU"). |
| Timezone fallback formatting | Implemented | The generic format falls back from the zone's or metazone's name to the generic location format and then the localized GMT format, taking a standard name for a zone that keeps one offset for 184 days either side; the specific format falls back to the localized GMT format. |
| Time zone parsing | Implemented | `Localize.DateTime.Timezone.parse_zone/2` and `resolve/3` read every form TR35's parsing lists, in the order of its sample process, with the GMT format matched as leniently as it asks. Two departures from the sample, which TR35 calls only a sample: a country or city in parentheses is read only after a name the locale writes, where the sample reads "xxx (Italy)" as Rome whatever xxx is, and a country with several zones stands for its primary zone, which the sample leaves out. |

### Semantic Skeletons

| Feature | Status | Notes |
|---------|--------|-------|
| Semantic skeleton support | Partial | `Localize.DateTime.SemanticSkeleton` builds a skeleton from meaning (`"YMDE"`, `"MDTZ"`) with `:length`, `:year_style`, `:zone_style`, `:hour_cycle`, `:time_precision` and `:alignment`, taking the widths from the locale's date formats. It matches CLDR on all 240 conformance cases and rejects the field sets, and the options without their fields, that TR35 rules out; TR35's `Auto` zone style, which its mapping table leaves undefined, is not offered. |

### Supported Calendars

| Feature | Status | Notes |
|---------|--------|-------|
| Gregorian | Implemented | Primary calendar. |
| Japanese | Implemented | Era data and formatting. |
| Chinese | Implemented | Calendar data present. |
| Persian | Implemented | Calendar data present. |
| Coptic | Implemented | Calendar data present. |
| Ethiopic | Implemented | Including Amete Alem variant. |
| Dangi (Korean) | Implemented | Calendar data present. |
| Buddhist | Implemented | Era (BE), month, and day data tested. |
| Hebrew | Implemented | Era (AM), 13-month calendar with leap year variant tested. |
| Islamic variants | Implemented | `:islamic`, `:islamic_civil`, `:islamic_rgsa`, `:islamic_tbla`, `:islamic_umalqura` — eras (AH) and month names (Muharram, Ramadan, etc.) tested. |
| ROC (Minguo) | Implemented | Era names (B.R.O.C., Minguo) tested. |
| Indian (Saka) | Implemented | Calendar data present and included in `known_calendars/0`. |

---

## Part 5 — Collation (tr35-collation.html)

### Core Collation

| Feature | Status | Notes |
|---------|--------|-------|
| UCA (Unicode Collation Algorithm) | Implemented | `Localize.Collation` with DUCET-based sort key generation. |
| CLDR root collation | Implemented | Uses `allkeys_CLDR` data. |
| Multi-level comparison (L1-L4) | Implemented | Primary through quaternary levels. |
| Variable weighting (shifted) | Implemented | `alternate: :shifted` option. |
| Normalization (NFD) | Implemented | Automatic NFD when tailoring requires it. |
| French secondary sorting | Implemented | `backwards: :level2` / `[backwards 2]` directive. |

### Collation Options (BCP 47 keys)

| Feature | Status | Notes |
|---------|--------|-------|
| Strength (ks) | Implemented | Levels 1-4 and identical. |
| Alternate (ka) | Implemented | `noignore` and `shifted`. |
| Backwards (kb) | Implemented | Level 2 reversal. |
| Normalization (kk) | Implemented | |
| Case level (kc) | Implemented | |
| Case first (kf) | Implemented | `upper` and `lower`. |
| Numeric collation (kn) | Implemented | Number-aware sorting via the `:numeric` option to `Localize.Collation.sort/3` and `compare/3`, or the `-u-kn` locale extension. |
| Reorder (kr) | Implemented | Script reordering with weight remapping. |
| Max variable (kv) | Implemented | `space`, `punct`, `symbol`, `currency`. |
| Hiragana quaternary (kh) | Not implemented | Deprecated in recent UCA. |

### Collation Tailoring

| Feature | Status | Notes |
|---------|--------|-------|
| Locale-specific tailoring rules | Implemented | 110 locale/type pairs covering 97 languages, extracted from CLDR XML. |
| Relation operators (`<`, `<<`, `<<<`, `<<<<`, `=`) | Implemented | |
| Contractions (multi-character) | Implemented | |
| Expansions (slash notation) | Implemented | e.g., `ccs/cs` in Hungarian. |
| Star syntax (`<*`) | Implemented | Used for CJK and other large character sets. |
| Context before (`\|`) | Not implemented | |
| `[before N]` positioning | Not implemented | |
| `[suppressContractions]` | Implemented | Used by cu, sr, mk. |
| `[optimize]` | Not applicable | Advisory hint; intentionally ignored. |
| `[import]` | Implemented | Resolved at extraction time — imported rules are inlined into the ETF. Supports BCP47 tags (e.g., `und-u-co-search`, `de-u-co-phonebk`) and short locale tags (e.g., `hr`). |
| `[strength]` directive | Not implemented | Used by ja:private-kana only. |

### Collation Types

| Feature | Status | Notes |
|---------|--------|-------|
| Standard collation | Implemented | Default type for all locales. |
| Search collation | Implemented | Root search rules (Arabic form equivalences, Korean jamo decomposition, `[suppressContractions]`) extracted from CLDR XML. 20 locale-specific search types with resolved imports. Accessed via `type: :search` option. |
| Phonebook (de), Pinyin (zh), etc. | Partial | Some non-standard types extracted; not all verified. |

### Collation Features

| Feature | Status | Notes |
|---------|--------|-------|
| Alphabetic index characters | Not implemented | No UI bucketing support. |
| Collation type fallback chain | Partial | Falls back to standard; full 7-step chain not verified. |

---

## Part 6 — Supplemental (tr35-info.html)

### Territory Data

| Feature | Status | Notes |
|---------|--------|-------|
| Territory containment | Implemented | `Localize.Territory.territory_containers/0`, `territory_containment/0`. |
| Subdivision containment | Implemented | `Localize.Territory.territory_subdivision_containment/0`. |
| Territory information (GDP, population) | Implemented | `Localize.Territory.info/1`. |
| Language population data | Implemented | Via territory info. |
| Emoji flags | Implemented | `Localize.Territory.unicode_flag/1`. |

### Supplemental Language Data

| Feature | Status | Notes |
|---------|--------|-------|
| Scripts per language | Not implemented | Data not exposed as a public API. |
| Language grouping (families) | Not implemented | |

### Code Mappings

| Feature | Status | Notes |
|---------|--------|-------|
| Territory code mappings (alpha-2/3, FIPS, numeric) | Implemented | `Localize.Territory.territory_codes/1`. |
| Currency code mappings | Implemented | ISO 4217 via `Localize.Currency`. |

### Aliases

| Feature | Status | Notes |
|---------|--------|-------|
| Language aliases | Implemented | Supplemental alias data loaded from ETF. |
| Territory aliases | Implemented | |
| Script aliases | Implemented | |
| Variant aliases | Implemented | |

### Parent Locales

| Feature | Status | Notes |
|---------|--------|-------|
| CLDR parent locale data | Implemented | `Localize.Locale.parent/1`. |

### Unit Data (Supplemental)

| Feature | Status | Notes |
|---------|--------|-------|
| Unit conversion factors | Implemented | Extracted from CLDR XML via `scripts/extract_unit_data.exs`. |
| Unit preferences per territory | Implemented | |
| Unit quantities and base units | Implemented | |
| SI and binary prefixes | Implemented | `Localize.Unit.Parser` handles all CLDR prefixes. |

### Coverage Levels

| Feature | Status | Notes |
|---------|--------|-------|
| Coverage level assessment | Not implemented | |

---

## Part 9 — MessageFormat (tr35-messageFormat.html)

### MF2 Syntax

| Feature | Status | Notes |
|---------|--------|-------|
| Simple messages | Implemented | `Localize.Message.Parser` with pre-compiled NimbleParsec grammar. |
| Complex messages | Implemented | |
| Quoted patterns (`{{...}}`) | Implemented | |
| Text and escape sequences | Implemented | |
| Declarations (`.input`, `.local`) | Implemented | All declaration types are handled by `Localize.Message.format/3`. |
| Pattern selection (`.match`) | Implemented | With selector resolution and variant ranking. |
| Expressions (literal, variable, function) | Implemented | |
| Options on functions | Implemented | |
| Markup (open, close, standalone) | Implemented | Parsed and emitted in interpreter output. |
| Attributes | Implemented | Parsed; treated as metadata per spec. |

### MF2 Default Functions

| Feature | Status | Notes |
|---------|--------|-------|
| `:string` | Implemented | |
| `:number` | Implemented | Delegates to `Localize.Number.to_string/2`. All numeric functions support `signDisplay`, `minimumIntegerDigits`, the significant-digit options, `trailingZeroDisplay` and `roundingPriority`; an unannotated numeric operand formats with the locale-aware `:number` default. |
| `:integer` | Implemented | |
| `:percent` | Implemented | |
| `:currency` | Implemented | |
| `:unit` | Implemented | Delegates to `Localize.Unit.to_string/2`. |
| `:date` | Implemented | Draft. `fields` and `length` choose a semantic skeleton; the override options `timeZone` and `calendar` are supported, `calendar` through `calendrical`. |
| `:time` | Implemented | Draft. `precision` and `timeZoneStyle` choose a semantic skeleton; the override options `timeZone`, `hour12` and `calendar` are supported. |
| `:datetime` | Implemented | Draft. `dateFields`, `dateLength`, `timePrecision` and `timeZoneStyle` choose a semantic skeleton; the override options are supported and inherited on re-annotation. |
| `:offset` | Implemented | Adjusts a numeric operand with the required `add` or `subtract` option (a non-negative integer) for both formatting and selection, per the MF2 `:offset` function. Used for patterns like "you and N other people". |

### Localize-specific MF2 functions (not in the spec)

| Function | Notes |
|----------|-------|
| `:list` | Formats a list operand by delegating to `Localize.List.to_string/2`. Each element is itself formatted via `Localize.Chars`, so a list of dates, numbers, units, etc. picks up the message's locale and forwarded options. Supports a `style` (or `type`) option whose values map to CLDR list styles: `"and"`, `"and-short"`, `"and-narrow"`, `"or"`, `"or-short"`, `"or-narrow"`, `"unit"`, `"unit-short"`, `"unit-narrow"`. Default is `"and"`. |

### MF2 Error Handling

| Feature | Status | Notes |
|---------|--------|-------|
| Syntax errors | Implemented | Parser returns `{:error, reason}`. |
| Resolution errors (unknown function, unresolved variable) | Implemented | Unresolved variables error per spec; an unknown function is a `Localize.FormatError` with reason `:unknown_function`. |
| Data model errors | Implemented | All six rules are checked by `Localize.Message.Validator.validate/1`: duplicate declarations (including implicit-use-then-declare and self-reference), duplicate option names, duplicate variants (NFC-normalized keys), missing selector annotation, variant key mismatch, and missing fallback variant. `Localize.Message.Parser.parse/1` checks syntax only; everything that formats or serializes a message runs both passes, reporting syntax errors first. |
| Function option and operand validation | Implemented | The `select` option must be a literal set directly on the expression; digit size options must be non-negative integers; string operands of the numeric functions must match the `number-literal` production; `:currency`, `:unit` and the date/time functions are rejected as selectors. |

### MF2 Data Model

| Feature | Status | Notes |
|---------|--------|-------|
| JSON interchange format | Implemented | `Localize.Message.JSON.to_json/2` and `from_json/1` for round-trip serialization to the TR35 §8 data model. |
| Literal code points and key normalization | Implemented | Literals keep all their code points; keys and a `:string` selector's value are compared in NFC (TR35 NormalizeKey), and names are compared as if normalized. |
| Bidirectional text handling | Partial | `:bidi` option (`:none`, `:isolate`, `:auto`) wraps placeholder output in Unicode isolate characters (FSI/PDI), and the `@u:dir` expression *attribute* overrides direction per expression. The `u:dir` / `u:id` expression *options* are not implemented, and the `:isolate` strategy isolates every placeholder where the WG default strategy leaves known-LTR placeholders unisolated. |

### MF2 known conformance gaps

The MessageFormat working group conformance suite — including the WG `:test:function` / `:test:format` / `:test:select` registry functions it uses to exercise selection mechanics — runs against both the parser and the formatter (`test/localize/message/formatter_conformance_test.exs`). The few cases the implementation cannot yet satisfy are excluded there, each with a documented reason:

* The `u:dir` / `u:id` expression *options* are not implemented (the `@u:dir` attribute form is).

* The `:isolate` bidi strategy isolates every placeholder where the WG default strategy leaves known-LTR placeholders unisolated (three cases).

---

## Summary

### Implemented (core functionality present and tested)

* Language tag parsing and validation (BCP 47 / RFC 5646)
* Locale management (get/put/default/with_locale)
* Likely subtags and locale matching
* Number formatting (decimal, percent, currency, accounting, compact, scientific, RBNF)
* Number parsing
* Date, time, and datetime formatting
* Date, time, datetime and interval parsing
* Interval formatting
* Relative date/time formatting
* Unit formatting, conversion, and preferences (also include basic math functions)
* List formatting
* Currency data and validation
* Territory data and display names
* Language display names
* Locale display names
* Plural rules (cardinal, ordinal, ranges)
* Collation with locale tailoring (97 languages)
* MessageFormat 2 parsing and interpretation
* Quotation marks and ellipsis formatting

### Separate libraries

* General character transforms/transliteration — [unicode_transform](https://github.com/elixir-unicode/unicode_transform)
* Text segmentation (grapheme/word/sentence/line) — [unicode_string](https://github.com/elixir-unicode/unicode_string)

### Not implemented

* Context-dependent capitalization
* Collation alphabetic index (UI bucketing)
* Coordinate unit formatting (N/S/E/W)
* Layout direction data
* Coverage level assessment

### Not in scope for Localize

* Emoji/character annotations and labels
* Keyboards

