guides/localized-html-helpers.md

# Localized HTML Helpers

This guide covers the HTML form helpers provided by `localize_web` for generating `<select>` tags and option lists with localized display names.

## Overview

The HTML helpers generate `<select>` tags for currencies, territories, locales, units of measure, and months. Display names are localized according to the current or specified locale using CLDR data from the [Localize](https://hex.pm/packages/localize) library.

Each helper module provides two public functions:

* `select/3` — generates a complete `<select>` tag for use with Phoenix forms.

* `*_options/1` — returns a list of `{display_name, value}` tuples for use with `Phoenix.HTML.Form.options_for_select/2` or custom `<datalist>` elements.

All helpers are also available through the `Localize.HTML` facade module with prefixed names (e.g., `Localize.HTML.territory_select/3`).

## Territory Select

Displays territories with their Unicode flag emoji and localized name:

```elixir
iex> Localize.HTML.Territory.select(:my_form, :territory, selected: :AU)
```

### Options

* `:territories` — a list of territory codes to include. The default is all known territories from `Localize.Territory.territory_codes/0`.

* `:style` — the format of the territory name. Options are `:standard` (default), `:short`, and `:variant`.

* `:locale` — the locale used to localize territory names. The default is `Localize.get_locale/0`.

* `:selected` — the territory code to pre-select. The default is `nil`.

* `:prompt` — a prompt string displayed at the top of the select box.

* `:collator` — a function to sort territories. The default sorts alphabetically by name. Receives a list of `%{territory_code: atom, name: string, flag: string}` maps and returns the sorted list.

* `:mapper` — a function to produce the display text for each territory. The default is `&({&1.flag <> " " <> &1.name, &1.territory_code})`.

### Restricting the Territory List

```elixir
iex> Localize.HTML.Territory.select(:my_form, :territory,
...>   territories: [:US, :GB, :AU, :CA, :NZ],
...>   selected: :AU
...> )
```

### Changing the Display Style

```elixir
# Short names (e.g., "US" instead of "United States")
iex> Localize.HTML.Territory.select(:my_form, :territory, style: :short)
```

### Displaying in a Different Locale

```elixir
# Territory names in French
iex> Localize.HTML.Territory.select(:my_form, :territory, locale: "fr")
```

### Getting Options Without the Select Tag

```elixir
iex> Localize.HTML.Territory.territory_options(
...>   territories: [:US, :GB, :AU],
...>   locale: "fr"
...> )
[{"🇦🇺 Australie", :AU}, {"🇬🇧 Royaume-Uni", :GB}, {"🇺🇸 États-Unis", :US}]
```

## Currency Select

Displays currencies with their code and localized name:

```elixir
iex> Localize.HTML.Currency.select(:my_form, :currency, selected: :USD)
```

### Options

* `:currencies` — a list of currency codes to include. The default is all known currencies from `Localize.Currency.known_currency_codes/0`.

* `:locale` — the locale used to localize currency names. The default is `Localize.get_locale/0`.

* `:selected` — the currency code to pre-select. The default is `nil`.

* `:prompt` — a prompt string displayed at the top of the select box.

* `:collator` — a function to sort currencies. The default sorts alphabetically by name.

* `:mapper` — a function to produce the display text for each currency. The default is `&({&1.code <> " - " <> &1.name, &1.code})`.

### Restricting the Currency List

```elixir
iex> Localize.HTML.Currency.select(:my_form, :currency,
...>   currencies: [:USD, :EUR, :GBP, :JPY],
...>   selected: :USD
...> )
```

### Getting Options Without the Select Tag

```elixir
iex> Localize.HTML.Currency.currency_options(
...>   currencies: [:USD, :EUR, :GBP],
...>   locale: "de"
...> )
```

## Locale Select

Displays locales with their localized display name:

```elixir
iex> Localize.HTML.Locale.select(:my_form, :locale, selected: "en")
```

### Options

* `:locales` — a list of locale identifiers to include. The default is `Localize.all_locale_ids/0` with meta locales excluded.

* `:locale` — the locale used to localize display names. The default is `Localize.get_locale/0`. The special value `:identity` renders each locale's name in its own language.

* `:selected` — the locale identifier to pre-select. The default is `nil`.

* `:prompt` — a prompt string displayed at the top of the select box.

* `:collator` — a function to sort locales. The default sorts alphabetically by display name.

* `:mapper` — a function to produce the display text for each locale. Receives a map with `:display_name`, `:locale`, and `:language_tag` keys. The default is `&{&1.display_name, &1.locale}`.

### Identity Mode

The `:identity` locale renders each option in its own language. This is useful for language-picker UIs where users should see their own language name regardless of the current page locale:

```elixir
iex> Localize.HTML.Locale.select(:my_form, :locale,
...>   locale: :identity,
...>   locales: [:en, :fr, :de, :ja],
...>   selected: "en"
...> )
```

This renders "English", "Français", "Deutsch", and "日本語" each in their respective language. Each `<option>` also receives a `lang` attribute set to its locale for proper browser rendering of non-Latin scripts.

### Restricting the Locale List

```elixir
iex> Localize.HTML.Locale.select(:my_form, :locale,
...>   locales: [:en, :fr, :de, :es, :pt],
...>   selected: "en"
...> )
```

### Getting Options Without the Select Tag

```elixir
iex> Localize.HTML.Locale.locale_options(
...>   locales: [:en, :fr, :de],
...>   locale: :identity
...> )
```

## Unit Select

Displays units of measure with their localized name:

```elixir
iex> Localize.HTML.Unit.select(:my_form, :unit, selected: :kilogram)
```

### Options

* `:units` — a list of unit identifiers to include. The default is all known units grouped by category.

* `:style` — the style of unit name to display. Options are `:long` (default), `:short`, and `:narrow`.

* `:locale` — the locale used to localize unit names. The default is `Localize.get_locale/0`.

* `:selected` — the unit to pre-select. The default is `nil`.

* `:prompt` — a prompt string displayed at the top of the select box.

* `:collator` — a function to sort units. The default sorts alphabetically by display name.

* `:mapper` — a function to produce the display text for each unit. Receives a `{display_name, unit_code}` tuple. The default is the identity function.

### Different Display Styles

```elixir
# Long: "Kilograms"
iex> Localize.HTML.Unit.select(:my_form, :unit, style: :long, selected: :kilogram)

# Short: "kg"
iex> Localize.HTML.Unit.select(:my_form, :unit, style: :short, selected: :kilogram)

# Narrow: "kg"
iex> Localize.HTML.Unit.select(:my_form, :unit, style: :narrow, selected: :kilogram)
```

### Getting Options Without the Select Tag

```elixir
iex> Localize.HTML.Unit.unit_options(style: :short, locale: "fr")
```

## Month Select

Displays month names from CLDR calendar data:

```elixir
iex> Localize.HTML.Month.select(:my_form, :month, selected: 1)
```

### Options

* `:months` — a list of month numbers to include. The default is `1..12`.

* `:style` — the format of the month name. Options are `:wide` (default), `:abbreviated`, and `:narrow`.

* `:calendar` — the calendar from which month names are derived. The default is `Calendar.ISO`.

* `:year` — the year from which the number of months is derived. The default is the current year.

* `:locale` — the locale used to localize month names. The default is `Localize.get_locale/0`.

* `:selected` — the month number to pre-select. The default is `nil`.

* `:prompt` — a prompt string displayed at the top of the select box.

* `:collator` — a function to sort months. The default preserves month order.

* `:mapper` — a function to produce the display text for each month. Receives a `{month_name, month_number}` tuple. The default is the identity function.

### Different Display Styles

```elixir
# Wide: "January", "February", ...
iex> Localize.HTML.Month.select(:my_form, :month, style: :wide)

# Abbreviated: "Jan", "Feb", ...
iex> Localize.HTML.Month.select(:my_form, :month, style: :abbreviated)

# Narrow: "J", "F", ...
iex> Localize.HTML.Month.select(:my_form, :month, style: :narrow)
```

### Getting Options Without the Select Tag

```elixir
iex> Localize.HTML.Month.month_options(style: :abbreviated, locale: "de")
```

## Customizing Display with Mapper and Collator

All select helpers accept `:mapper` and `:collator` options for full control over display text and sort order.

### Custom Mapper

The mapper function transforms each item into a `{display_text, value}` tuple for the select options:

```elixir
# Territory: show only the name without the flag
iex> Localize.HTML.Territory.select(:my_form, :territory,
...>   mapper: fn territory ->
...>     {territory.name, territory.territory_code}
...>   end
...> )
```

### Custom Collator

The collator function receives the full list of items and returns them in the desired order:

```elixir
# Territory: sort by territory code instead of name
iex> Localize.HTML.Territory.select(:my_form, :territory,
...>   collator: fn territories ->
...>     Enum.sort_by(territories, & &1.territory_code)
...>   end
...> )
```

### Combining Mapper and Collator

```elixir
# Currency: show symbol + name, sorted by code
iex> Localize.HTML.Currency.select(:my_form, :currency,
...>   currencies: [:USD, :EUR, :GBP],
...>   mapper: fn currency ->
...>     {"#{currency.code} - #{currency.name}", currency.code}
...>   end,
...>   collator: fn currencies ->
...>     Enum.sort_by(currencies, & &1.code)
...>   end
...> )
```

## Using with Phoenix Forms

The select helpers work with both Phoenix form structs and atom-based form names:

```elixir
# With an atom form name
Localize.HTML.Territory.select(:my_form, :territory, selected: :AU)

# With a Phoenix.HTML.Form struct in a template
<.form let={f} for={@changeset} action={@action}>
  <%= Localize.HTML.Territory.select(f, :territory, selected: :AU) %>
</.form>
```

## Using the Facade Module

The `Localize.HTML` facade module provides all helpers with prefixed names:

```elixir
Localize.HTML.territory_select(form, field, options)
Localize.HTML.territory_options(options)
Localize.HTML.currency_select(form, field, options)
Localize.HTML.currency_options(options)
Localize.HTML.locale_select(form, field, options)
Localize.HTML.locale_options(options)
Localize.HTML.unit_select(form, field, options)
Localize.HTML.unit_options(options)
```