Fuchsia has some conventions for how to communicate i18n preferences, whether
from an end user to components, or among components.

This guide covers the following:

- Use Unicode BCP-47 Locale Identifiers to encode [locale IDs](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#locale-ids).
- Use `fuchsia.intl.PropertyProvider` in components to [read internationalization preferences](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#access). Make sure that the product configuration includes [`intl_services`](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#intl-services) or another implementation of this protocol.
- If implementing a settings UI, use `fuchsia.settings.Intl` to [write internationalization settings](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#store).

## Locale identifiers

The keystone of i18n preferences is the *locale identifier*, which is a string
that concisely conveys information such as:

- Language (e.g. English, French, Arabic)
- Country or region (e.g. United Kingdom, Morocco, South Korea)
- Script (e.g. Latin, Cyrillic, Traditional Chinese, Simplified Chinese)

Locale identifiers can also convey more granular information, such as:

- Calendar (e.g. Gregorian, Japanese, Hebrew)
- First day of week
- Collation (sort order, grouping strings for search)
- Digit style (e.g. "Arabic" 012345, "Eastern Arabic" ٠١٢٣٤٥)
- Number format (decimal separator, digit grouping)
- Currency format
- Time and date formats
- Etc.

Specifying these details is particularly useful when overriding the default
values for a given language and region (see next section).

### Unicode BCP-47 Locale Identifiers

Fuchsia uses the
[Unicode BCP-47 Locale Identifier](http://www.unicode.org/reports/tr35/#BCP_47_Conformance)
standard for locale IDs.

For example, the following locale ID specifies the Serbian language (`sr`) as
spoken in Serbia (`RS`), written in a Cyrillic script (`Cyrl`):

    "sr-Cyrl-RS"

You can use
[Unicode extension subtags](http://unicode.org/reports/tr35/#u_Extension) in the
locale ID to add overrides. Consider the following example:

    "sr-Cyrl-RS-u-ca-hebrew-fw-monday-ms-ussystem-nu-deva-tz-usnyc"

This example specifies the following:

| Subtag(s) | Meaning |
|---|---|
| `sr` | Specifies the Serbian language. |
| `Cyrl` | Specifies the Cyrillic script. |
| `RS` | Specifies Serbia as the country/region. |
| `u` | Marks the start of the Unicode extension data. |
| `ca-hebrew` | Specifies the Hebrew calendar. |
| `fw-monday` | Specifies Monday as the first day of the week. |
| `ms-ussystem` | Specifies the measurement system as "US", e.g. feet, ounces, etc. |
| `nu-deva` | Specifies Devanagari numerals. |
| `tz-usnyc` | Specifies the time zone as `America/New_York`. |

Not all internationalization properties that one might want to express have a
corresponding Unicode extension. For example, there is currently no extension
for temperature units, so there is no way to express "use metric units, but use
Fahrenheit for temperature" in a locale ID.

## Accessing i18n preferences

To send i18n preferences between Fuchsia


[](https://fuchsia.dev/docs/glossary#component)


, use the
[`fuchsia.intl.Profile`](https://fuchsia.dev/reference/fidl/fuchsia.intl#Profile)
FIDL table:

    type Profile = table {
        1: locales vector<LocaleId>;
        2: calendars vector<CalendarId>;
        3: time_zones vector<TimeZoneId>;
        4: temperature_unit TemperatureUnit;
    };

The locale ID is only a building block in the `Profile`. A profile contains a
ranked list of locale IDs (to express relative preference, priority, or degree
of support; see [Locale fallback](https://fuchsia.dev/fuchsia-src/development/internationalization/localization/locale_fallback.md) for a
usage example), as well as other properties that cannot be fully expressed in a
single locale ID. When there is a conflict, explicit settings in the `Profile`
override the values in the locale ID (e.g. specifying US measurement units in
the locale ID but `CELSIUS` in the `temperature_unit` field).

When a component needs to provide i18n preferences to other components, it
should implement the
[`fuchsia.intl.PropertyProvider`](https://fuchsia.dev/reference/fidl/fuchsia.intl#PropertyProvider)
protocol, which serves the `Profile` and notifies of changes:

    closed protocol PropertyProvider {
        strict GetProfile() -> (struct {
            profile Profile;
        });
        strict -> OnChange();
    };

This protocol offers a *read-only* view of an internationalization profile.
Depending on the implementation of the service and the
[realm](https://fuchsia.dev/docs/concepts/components/v2/realms) in which it is intended to
serve, the contents of the internationalization profile may be derived from
[user settings](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#store), a product's factory settings, a specific component's
requirements, or some combination of the above.

### Do not assume an ambient locale

Fuchsia has no ambient or system locale. Locale and other i18n preferences
depend on the context in which a component is running. This is in contrast to
other operating systems, which may have APIs to obtain global or default locale
settings, following Fuchsia's design principle of
[no ambient authority](https://fuchsia.dev/docs/concepts/principles/secure)

In runtimes where the standard library offers access to some default locale, it
is the responsibility of the
[runner](https://fuchsia.dev/docs/concepts/components/v2/capabilities/runner) to retrieve the
needed values from the realm of the component being run. In most cases, the
runner should call `fuchsia.intl.PropertyProvider.GetProfile`.

#### Multiple i18n `Profile`s

Depending on a product's design, it is possible that two component instances
running concurrently on the same machine in different realms are connected to
different `PropertyProvider` instances and receive different `Profile`s.

For example, an encyclopedia component showing a Spanish-language (`es-ES`)
article about Mallorca may choose to launch a map component with an `es-ES` UI,
while at the same time an English-language (`en-US`) article launches the same
map component, but tells it to display an `en-US` UI. This can be accomplished
with two different
[sub-realms](https://fuchsia.dev/docs/concepts/components/v2/realms#definitions) that each
receives a different `PropertyProvider` instance.

### `intl_services` library

A basic C++ library implementing `fuchsia.intl.PropertyProvider` is found at
[`//src/lib/intl/intl_property_provider_impl`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/lib/intl/intl_property_provider_impl).

The
[`core`](https://fuchsia.dev/docs/development/build/software_assembly/build_configuration#key_product_configurations)
product configuration includes [`intl_services`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/intl/intl_services), a
component that wraps this implementation.

### Integrations

#### Web (e.g., Chrome \& WebEngine)

The list of preferred locales from `Profile` is sent to web servers in the HTTP
request header [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) and is made available to
JavaScript via
[`navigator.languages` and `navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages).

## Storing i18n user settings

As with other user settings on Fuchsia, internationalization settings are
modified through the
[`fuchsia.settings`](https://fuchsia.dev/reference/fidl/fuchsia.intl/index) FIDL
protocols.

Specifically, the protocol
[`fuchsia.settings.Intl`](https://fuchsia.dev/reference/fidl/fuchsia.intl/index#Intl)
is used to write and monitor internationalization-related settings.

    closed protocol Intl {
        strict Watch() -> (struct {
            settings IntlSettings;
        });
        strict Set(struct {
            settings IntlSettings;
        }) -> () error Error;
    };

    type IntlSettings = table {
        1: locales vector<fuchsia.intl.LocaleId>:10;
        2: temperature_unit fuchsia.intl.TemperatureUnit;
        3: time_zone_id fuchsia.intl.TimeZoneId;
        4: hour_cycle HourCycle;
    };

This protocol is intended specifically for components that require direct access
to user settings, such as a system control panel, a taskbar locale selector, or
an *implementor* of `fuchsia.intl.PropertyProvider`. In typical Fuchsia product
configurations, this access should be restricted to a narrow allowlist.

Most client components will instead use the [read-only view](https://fuchsia.dev/fuchsia-src/development/internationalization/i18n_preferences#access) offered
through `fuchsia.intl.PropertyProvider`.

### Implementation: `setui_service`

The protocol `fuchsia.settings.Intl` is implemented by the
[`setui_service`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/settings/service) (along with the other protocols under
`fuchsia.settings`). This service serves as the backend for settings UIs in
Fuchsia products.
[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/development/internationalization/i18n_preferences.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/development/internationalization/i18n_preferences.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/development/internationalization/i18n_preferences.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/development/internationalization/i18n_preferences.md "Edit the source code of this page")