Internationalization preferences

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:

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 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 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 components , use the 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 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 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 in which it is intended to serve, the contents of the internationalization profile may be derived from user settings, 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

In runtimes where the standard library offers access to some default locale, it is the responsibility of the 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 Profiles

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 Profiles.

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 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.

The core product configuration includes 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 and is made available to JavaScript via navigator.languages and navigator.language.

Storing i18n user settings

As with other user settings on Fuchsia, internationalization settings are modified through the fuchsia.settings FIDL protocols.

Specifically, the protocol fuchsia.settings.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 offered through fuchsia.intl.PropertyProvider.

Implementation: setui_service

The protocol fuchsia.settings.Intl is implemented by the setui_service (along with the other protocols under fuchsia.settings). This service serves as the backend for settings UIs in Fuchsia products.