Skip to content

Commit b9e768a

Browse files
committed
Document the additional_units and unit parsing migration paths
1 parent fdc3c3c commit b9e768a

2 files changed

Lines changed: 34 additions & 0 deletions

File tree

TODO.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Feature requests from the Intl library (elixir-localize/intl), which maps the JS
44

55
All items are DONE and published as of localize 1.0.0-rc.3 / intl 1.0.0-rc.0 (July 23, 2026), verified against the published packages: the digit-control options (`:minimum_integer_digits`, `:trailing_zero_display`, `:rounding_priority`), relative time `numeric: :always`, `known_collations/0` / `known_timezones/0`, the `:currency_long` fraction-digits/plural semantics, the MF2 digit-control option mapping, fractional-second skeletons, and the complete structured-parts family — `Number.to_parts/2` (including `:currency_long`), `Number.to_range_parts/3`, `Unit.to_parts/2` and `Unit.to_range_string/3`, `Date`/`Time`/`DateTime` `to_parts/2`, `List.to_parts/2`, `Relative.to_parts/2`, and the per-unit `Duration` display options.
66

7+
## Open items
8+
9+
* **`Localize.Unit.parse/2` and `parse_unit_name/2`** (from a user migration question, July 24): ex_cldr_units parses "1kg" / localized "1 tages" into a unit, with `:only`/`:except` category filters disambiguating strings like "2w" (weeks vs watts). Localize has the halves — `Number.Parser.scan/2` for locale-aware number extraction and `Unit.new/1` for canonical identifiers — but no localized unit-name resolution. Needs a display-name-to-unit index per locale (long/short/narrow patterns inverted), category filtering, and custom-unit awareness. The migration guide documents the interim workaround.
10+
711
## Known deviation (accepted)
812

913
* **Compact affix split.** `Number.to_parts/2` tags the whole compact affix as one `:compact` part (`" million"`, leading space included); JS `Intl` splits the leading space into a separate `:literal` part. Callers needing exact JS part boundaries can split leading/trailing whitespace off the `:compact` part.

guides/migration.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,36 @@ iex> Localize.Unit.new!(1_500_000, "byte")
352352
"1.5MB"
353353
```
354354

355+
### Custom units (`:additional_units`)
356+
357+
ex_cldr_units defined custom units at compile time — `:additional_units` in the backend configuration plus a `Cldr.Unit.Additional` module supplying `unit_localization/4` callbacks — and changing a unit meant recompiling the backend. Localize replaces this with a runtime registry: `Localize.Unit.define_unit/2` registers a unit with its conversion (`:base_unit`, `:factor`, optional `:offset`), its `:category`, and its localizations in one definition, and `Localize.Unit.load_custom_units/1` loads a list of definitions from an `.exs` file at application start:
358+
359+
```elixir
360+
# ex_cldr: config :my_app, MyApp.Cldr, providers: [...], additional_units: [...]
361+
# plus a Cldr.Unit.Additional module with unit_localization/4 callbacks
362+
363+
# Localize — at runtime, typically in Application.start/2
364+
iex> Localize.Unit.define_unit("smoot", %{
365+
...> base_unit: "meter",
366+
...> factor: 1.7018,
367+
...> category: "length",
368+
...> display: %{en: %{long: %{one: "{0} smoot", other: "{0} smoots"}}}
369+
...> })
370+
:ok
371+
372+
iex> Localize.Unit.new!(100, "smoot") |> Localize.Unit.to_string!()
373+
"100 smoots"
374+
375+
iex> Localize.Unit.new!(100, "smoot") |> Localize.Unit.convert!("meter") |> Localize.Unit.to_string!()
376+
"170.18 meters"
377+
```
378+
379+
The `:display` map plays the role of the `unit_localization/4` callbacks (locale → style → plural-category patterns), and unlisted locales fall back to the unit identifier. Because registration is runtime, custom units can also come from configuration or a database rather than being baked into a backend module.
380+
381+
### Parsing unit strings (`Cldr.Unit.parse/2`)
382+
383+
`Cldr.Unit.parse/2` and `Cldr.Unit.parse_unit_name/2` — parsing "1kg" or a localized "1 tages" back into a unit, with `:only`/`:except` to disambiguate strings like "2w" (weeks versus watts) — do not yet have a direct Localize equivalent. What exists today covers the two halves separately: `Localize.Unit.new/1` parses any canonical CLDR unit identifier including compounds ("kilometer-per-hour"), and `Localize.Number.Parser.scan/2` performs locale-aware number extraction from mixed text (`scan("1kg")` returns `[1, "kg"]`), leaving the unit-name resolution to the caller. A `Localize.Unit.parse/2` with localized unit-name resolution and `:only`/`:except` disambiguation is on the roadmap; until it lands, applications parsing user input can scan the number and match the remaining token against the inventory from `Localize.Unit.known_units_by_category/0` or their own accepted-units list.
384+
355385
### Lists
356386

357387
```elixir

0 commit comments

Comments
 (0)