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.
- Use
fuchsia.intl.PropertyProvider
in components to read internationalization preferences. Make sure that the product configuration includesintl_services
or another implementation of this protocol. - If implementing a settings UI, use
fuchsia.settings.Intl
to write internationalization settings.
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 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 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.