User preferences are often system-wide settings (such as in Android, macOS, or Windows). Operating systems allow the user to specify custom overrides for settings such as:
- Hour cycle (24-hour or 12-hour time)
- Calendar system
- Measurement unit preferences (metric or imperial)
- Date/time patterns
- Number separators (comma or period)
However, there’s currently no reliable way to access this information from the Web Platform to help craft better user experiences. Allowing web developers to access this information would allow them to improve the accessibility and usability of their websites, and bring the user experience of web applications closer to that of native applications.
To allow web applications to get access to higher quality user preferences to assist Internationalization.
Client and server-side applications should access and share consistently locale user preferences that will help solve cases like:
Alice, an end user, reads en-US but prefers using a 24-hour clock. She has set that preference in her operating system settings. Native apps are able to respect her preference. However, web apps cannot access OS user preferences, so on the Web Platform, Alice sees a 12-hour clock, the default for en-US.
other use cases: NodeJS programs that want to respect the user's hourCycle preference by passing it in to Intl.DateTimeFormat, Other non browser environments.
For client side applications, the best way to get them would be through a browser API that fetches this information from the different platform-specific OS APIs.
For server-side applications, one way to get access to this information would be via HTTP headers on the request.
We propose to address the above use cases by using a pair of Client Hints
headers and a homologous Javascript API. Both will be responsible for exposing and negotiating the exchange of user preferences from the OS to the required environment.
We use Unicode Extensions for BCP 47 or compatible as the main reference for the base mechanism for delivering user locale preferences. The goal is to allow the handling of user preferences consistently across the industry.
We define new standard Locale-Preferences
Client Hints and navigator.localePreferences
, that map the user locale preferences using the following steps:
- Validate if there is any fingerprinting mechanism and if OS preferences are allowed to be exposed
- Read the available OS preferences
- Return values
The following table suggests common user preferences #416 to be used, and does the correlation from Locale-Preferences
Client Hints and navigator.localePreferences
to extension keys if they exist, or other values in case table is extended by user demand.
Locale Preferences Name | Extension Key/Unicode Source | Example Values | Description |
---|---|---|---|
"calendar" | ca |
buddhist, chinese... | Calendar system / Calendar algorithm |
"currencyFormat" | cf |
standard, account | Currency Format style, whether to use accounting currency format |
"collation" | co |
standard, search, phonetic... | Collation type, sort order |
"currencyCode" | cu |
ISO 4217 codes | Currency type |
"emojiStyle" | em |
emoji , text, default | Emoji presentation style |
"firstDayOfTheWeek" | fw |
"sun", "mon" ... "sat" | First day of week |
"hourCycle" | hc |
h12 , h23, h11, h24 | Hour cycle, i.e., 12-hour or 24-hour clock |
"measurementSystem" | ms |
metric , ussystem , uksystem | Measurement system |
"measurementUnit" | mu |
celsius , kelvin , fahrenhe | Measurement units currently only temperature |
"numberingSystem" | nu |
Unicode script subtag(arabext...) |
Numbering system |
"timeZone" | tz |
Unicode short time zone IDs | Time zone |
"region" | rg |
Unicode Region Subtag | Region override |
Other user preferences that might be included based on user research about OS preferences inputs and #1308329, most of them don't have a 1:1 match with BCP47 extension keys, however, they are available in ICU/CLDR
- number separator (grouping/decimal)
- date formats short/medium/long/full
- time formats short/medium/long/full
- dayperiod names
- time display with/without seconds
- flash the time separators
- show dayPeriod
- show the day of the week
- show date
Note: The preferences ultimately included need to be validated and agreed to by security teams and stakeholders. For this proposal, we consider a subset of possible preferences, sorted into two categories: DateTime and LanguageRegion.
A HTTP Client Hint is a request header field that is used by HTTP clients to indicate configuration data that can be used by the server to select an appropriate response. It defines an Accept-CH
response header that servers can use to advertise their use of request headers for proactive content negotiation. Each new client hint conveys a list of user locale preferences that the server can use to adapt and optimize responses.
Servers will receive no information about the user's locale preferences. Servers can instead opt-into receiving such information via a new Locale-Preferences
Client Hints.
To accomplish this, Browsers should introduce a pair of new Client Hint
header fields as part of a Structured Header sent over request whose value is a list of defined user locale preferences.
Sec-CH-Locale-Preferences-*
The following table represents the list of headers returning individual opted-in Locale-Preferences
. For example:
Client Hint | Example output |
---|---|
Sec-CH-Locale-Preferences-DateTime | `Sec-CH-Locale-Preferences-DateTime : hourCycle="h24"; timeZone="CET"; ... |
Sec-CH-Locale-Preferences-LanguageRegion | calendar="buddhist"; measurementSystem="metric"; ... |
- The client makes an initial request to the server:
GET / HTTP/1.1
Host: example.com
- The server responds, telling the client via an
Accept-CH
header (Section 2.2.1 of [[!RFC8942]]) along with the initial response withSec-CH-Locale-Preferences-DateTime
and theSec-CH-Locale-Preferences-LanguageRegion
Client Hints:
HTTP/1.1 200 OK
Content-Type: text/html
Accept-CH: Sec-CH-Locale-Preferences-DateTime, Sec-CH-Locale-Preferences-LanguageRegion
- Subsequent requests to https://example.com will include the following request headers in case the user sets
numberingSystem
andtimeZone
values:
GET / HTTP/1.1
Host: example.com
Sec-CH-Locale-Preferences-DateTime: timeZone="CET"
Sec-CH-Locale-Preferences-LanguageRegion: numberingSystem="jpan"
- The server can then tailor the response to the client's preferences accordingly.
These client hints should also be exposed as JavaScript APIs via navigator.locales
as suggested in #68 or by creating a new navigator.localePreferences
that exposes Locale-Preferences
information as below.
dictionary LocalePreferencesLanguageRegion {
DOMString calendar;
DOMString measurementSystem;
DOMString measurementUnit;
DOMString numberingSystem;
DOMString region;
};
dictionary LocalePreferencesDateTime {
DOMString dateFormat;
DOMString timeFormats;
DOMString timeZone;
DOMString hourCycle;
DOMString firstDayOfTheWeek;
};
interface mixin NavigatorLocalePreferences {
readonly attribute LocalePreferencesLocaleRegion localeRegion;
readonly attribute LocalePreferencesDateTime dateTime;
};
Navigator includes NavigatorLocalePreferences;
WorkerNavigator includes NavigatorLocalePreferences;
This might be written like so by web developers:
// languageAndRegion
navigator.localePreferences['languageRegion'];
navigator.localePreferences.languageRegion;
self.navigator.localePreferences.languageRegion;
// Output => => {calendar: "buddhist", measurementSystem: "metric", ... }
// languageAndRegion
navigator.localePreferences['dateTime'];
navigator.localePreferences.dateTime;
self.navigator.localePreferences.dateTime;
// Output => { dateFormat: "EEE, d MMM yyyy HH:mm:ss Z", ... }
// Window or WorkerGlobalScope event
window.onlocalepreferences = (event) => {
console.log('localepreferences event detected!');
};
// Or
window.addEventListener('localepreferences', () => {
console.log('localepreferences event detected!');
});
Use the navigator.localePreferences
to populate data with user preferences
// User set locale preferences for calendar , region and hourCycle
navigator.localePreferences['languageRegion'];
navigator.localePreferences['dateTime'];
const preferences = (...iterate over needed navigator.localePreferences )
new Intl.Locale('es' , preferences ).maximize();
// => Locale {..., calendar:"gregory" , region:"GB" , hourCycle:"h11" }
new Intl.DateTimeFormat('es', preferences ).resolvedOptions();
// => {locale: 'es', calendar: 'gregory', numberingSystem: 'latn', timeZone: 'Europe/London', ...}
There are some concerns that exposing this information would give trackers, advertisers and malicious web services another fingerprinting vector. That said, this information may or may not already be available to a certain extent to such services, based on the host and the user’s settings. The use of Sec-CH-
prefix is to forbid access to these headers containing Locale Preferences
information from JavaScript, and demarcate them as browser-controlled client hints so they can be documented and included in requests without triggering CORS preflights.
Client Hints provides a powerful content negotiation mechanism that enables us to adapt content to users' needs without compromising their privacy. It does that by requiring server opt-in, which guarantees that access to the information requires active and tracable action on the server's side. As such, the mechanism does not increase the web's current active fingerprinting surface. The Security Considerations of HTTP Client Hints and the Security Considerations of Client Hint Reliability likewise apply to this proposal.
- Brave :
- Chrome :
- Edge :
- Firefox :
- Safari :
Q: Does this proposal support non Unicode Extension Key compatible options?
- A: The first approach used a
-u
compatible syntax that could match 1:1 Unicode Extension Keys, which would ease the interoperability, but at the same time limit future extensibility and scalability when non-BCP47 data would be available as user preference, so the table maps user preferences to BCP-47 compatible keys and future other sources.
Q: Aren’t you adding a lot of new headers? Isn’t that going to bloat requests?
- A: It’s true this proposal adds multiple new headers per request. But we don’t expect every site to use or need all the hints for every request, and the
Sec-CH-Locale-Preferences
single header is able to provide most of the needed information. [in response to privacy concerns, proposal modified to add only two new headers]
Q: How about en-Latn-US-u-ca-gregory-cu-EUR-hc-h24-ms-uksystem
?
- A: At the moment there is no support to convert to or from the Unicode format
Q: How about a header that gives access to all user local preferences Sec-CH-Locale-Preferences-all
Sec-CH-Locale-Preferences-: calendar="gregory"; timeZone="Europe/London" ...
?
- A: There are use cases to simplify how to access this data but at the same time this would add significant new fingerprinting vectors
- Design Doc - User Preferences on the Web
- The Lang Client Hint
- Expose datetime formatting user preferences · Issue #38
- Add navigator.locales for user preferences · Issue #68
- Allow for implementations to retrieve settings from host environment · Issue #109
- RFC: Add user preferences to HTTP header · Issue #416
- Region Override Support · Issue #370
- [Proposal] Make an API for locale negotiation · Issue #513 (
Intl.LocaleMatcher
)
[1] - To be discussed - related issues (#3, #6, #38, #68, #580)