From 1c3574a7e5324e07163a74f3d261a26142fed6dd Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Thu, 27 Jun 2024 10:15:06 -0700 Subject: [PATCH 01/16] Various edits --- .../language-negotiation.md | 79 +++++++++++-------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 17262497..a7e6d833 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -1,15 +1,57 @@ # Language and Locale Negotiation on the Web One challenge faced by websites and services on the Web is how to present -users with the most appropriate language and [=locale=] to use when presenting +users with the most appropriate language and [locale](https://www.w3.org/TR/i18n-glossary#locale) to use when presenting information to users. -This tutorial outlines some of the considerations and best practices when +This article outlines some of the considerations and best practices when deciding how to choose, set, and store a user's locale preference. It is not a complete recipe: different users will have different preferences and there are choices that developers need to make when implementing locale negotiation. +## What is locale negotiation? + +Sites perform language negotiation in order to provide the user +with an experience that they understand. + +In the most general terms, locale negotiation is the process that internationalized +software uses to match a user's [international preferences](https://www.w3.org/TR/i18n-glossary/#dfn-international-preferences) +to the internationalized functionality and localized resources available +in a given piece of software (such as a website). + +On the one hand, this entails selecting the best set of translated (localized) set of resources +for the user's needs. +For example, a site consistent of static files might just choose between different +language versions of each page, while another site might load text into a blank template +from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). + +On the other hand, locale negotiation is also needed to allow systems to call internationalized APIs, +used for operations such as by formatting dates and numbers or for sorting lists. + +The negotiated locale is used to select resources (static pages, resource files, +etc.) and to set the locale for internationalization (I18N) APIs such as +`Intl.DateFormat` or `Intl.Collator` in JavaScript. + +## Inputs + +Language negotiation generally uses a hierarchy of "signals". +Depending on the type of user and the user's authentication state there +can be different hierarchies used by the language negotiation process. + +These signals can include: +- the HTTP `Accept-Language` header +- the user's geographic location (often determined from their IP address) +- the site's configuration +- values stored in a cookie +- values stored in the user's profile on the site +- values in the URL; these might be: + - a subdomain (`en.example.com` vs. `fr.example.com`) + - a path element (`example.com/en/index.html` vs. `example.com/fr/index.html`) + - a part of the filename (`index.en.html` vs. `index.fr.html`) + - a query parameter (`example.com?lang=en` vs. `example.com?lang=fr`) +- application specific information + ## Types of User The simplest use case is a site or service that does not persist the user's @@ -43,39 +85,6 @@ The effect might be similar to having a "recognized authenticated user", except that, of course, that the site can't generate offline interactions and might "forget" the user's preferences between sessions or browsers. -## Language/Locale Negotiation - -The reason sites perform language negotiation is to provide the user -with an experience that they understand. -Such an experience should be consistent throughout. -Since many sites are assembled by multiple services or processes, -all parts of the site experience need to get the same, consistent "answer" -for a given request. -The locale identifier also needs to allow systems to produce a fully localized -experience, such as by formatting numbers or sorting lists. -These variations require "fully qualified" locales to produce the best results, -that is, locales that include the region, not just the language and script code. -The user's locale identifier is then used to select resources (static pages, resource files, -etc.) and to set the locale for internationalization (I18N) APIs such as -`Intl.DateFormat` or `Intl.Collator` in JavaScript. - -Language negotiation generally uses a hierarchy of "signals". -Depending on the type of user and the user's authentication state there -can be different hierarchies used by the language negotiation process. - -These signals can include: -- the HTTP `Accept-Language` header -- the user's geographic location (often determined from their IP address) -- the site's configuration -- values stored in a cookie -- values stored in the user's profile on the site -- values in the URL; these might be: - - a subdomain (`en.example.com` vs. `fr.example.com`) - - a path element (`example.com/en/index.html` vs. `example.com/fr/index.html`) - - a part of the filename (`index.en.html` vs. `index.fr.html`) - - a query parameter (`example.com?lang=en` vs. `example.com?lang=fr`) -- application specific information - ## Site Configuration A site cannot support every language in the world nor can it support From 99ec8ba14a69842be5b0138c10a8bc1e8f03b19a Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Thu, 27 Jun 2024 10:21:01 -0700 Subject: [PATCH 02/16] Correct typos --- articles/language-negotiation/language-negotiation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index a7e6d833..f61c0f96 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -22,7 +22,7 @@ in a given piece of software (such as a website). On the one hand, this entails selecting the best set of translated (localized) set of resources for the user's needs. -For example, a site consistent of static files might just choose between different +For example, a site consisting of static files might just choose between different language versions of each page, while another site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). @@ -68,20 +68,20 @@ have three types of user profile: - **Unrecognized User** - the user does not have a profile or the site does not maintain one on the user's behalf. There are no cookies or other cross-session indicators of the user's preference. -- **Recognized but Not Authenticated User** - the user has a profile on +- **Recognized User** - the user has a profile on this site and there is some cross-session or other indication to associate the request with a specific user profile. However, the user has not authenticated themselves. Users in this state can have a measure of personalization done for them, but should not be given access to account secrets (such as the password, payment information, and the like). -- **Recognized and Authenticated User** - the user has a profile on this site +- **Authenticated User** - the user has a profile on this site and has authenticated themselves (by logging in or through some other mechanism) An important special case is that of recognized users for sites that don't maintain a server-side profile or account: user state, including language preference, can be stored in the cookies or browser local storage. -The effect might be similar to having a "recognized authenticated user", +The effect might be similar to having an "authenticated user", except that, of course, that the site can't generate offline interactions and might "forget" the user's preferences between sessions or browsers. From 9ac6994475d12459c5dc56bef400e0c3bc226d9a Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Thu, 27 Jun 2024 11:31:37 -0700 Subject: [PATCH 03/16] Add locale examples --- .../language-negotiation.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index f61c0f96..e5a871ae 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -33,6 +33,29 @@ The negotiated locale is used to select resources (static pages, resource files, etc.) and to set the locale for internationalization (I18N) APIs such as `Intl.DateFormat` or `Intl.Collator` in JavaScript. +> **_Example_** +> Consider a web site operated by a non-profit `example.org`. +> They want to offer different language experiences to meet user needs. +> This organization decides that their site experience will serve users +> in North America, so initially, they offer three languages: +> `en` (English), `es` (Spanish), and `fr` (French). +> +> Using `en`, `es`, or `fr` as the locale in software, however, does not +> produce complete results. +> For example, regional variations in formatting will affect how the software +> presents values such as dates, times, numbers, and so forth: +> +> | Locale | Locale Description | Formatted Value | +> |===|===|===| +> | en-US | US English | Jun 27, 2024, 1:17:36 PM | +> | en-CA | Canadian English | Jun 27, 2024, 1:17:36 p.m. | +> | en-GB | UK English | 27 Jun 2024, 13:17:36 | +> | fr-CA | Canadian French | 27 juin 2024, 13 h 17 min | +> | fr-FR | French (France) | 27 juin 2024, 13:17:36 | +> | es-419 | Latin American Spanish | 1,234.56 | +> | es-ES | Iberian Spanish | 1234,56 | + + ## Inputs Language negotiation generally uses a hierarchy of "signals". From b6c7b1f666673d1fc8bcefbef072a71973b3c520 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Thu, 27 Jun 2024 11:34:31 -0700 Subject: [PATCH 04/16] Fix table --- .../language-negotiation/language-negotiation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index e5a871ae..536ead2c 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -45,15 +45,15 @@ etc.) and to set the locale for internationalization (I18N) APIs such as > For example, regional variations in formatting will affect how the software > presents values such as dates, times, numbers, and so forth: > -> | Locale | Locale Description | Formatted Value | -> |===|===|===| -> | en-US | US English | Jun 27, 2024, 1:17:36 PM | +> | Locale | Locale Description | Formatted Value | +> |--------|--------------------|----------------------------| +> | en-US | US English | Jun 27, 2024, 1:17:36 PM | > | en-CA | Canadian English | Jun 27, 2024, 1:17:36 p.m. | -> | en-GB | UK English | 27 Jun 2024, 13:17:36 | -> | fr-CA | Canadian French | 27 juin 2024, 13 h 17 min | -> | fr-FR | French (France) | 27 juin 2024, 13:17:36 | -> | es-419 | Latin American Spanish | 1,234.56 | -> | es-ES | Iberian Spanish | 1234,56 | +> | en-GB | UK English | 27 Jun 2024, 13:17:36 | +> | fr-CA | Canadian French | 27 juin 2024, 13 h 17 min | +> | fr-FR | French (France) | 27 juin 2024, 13:17:36 | +> | es-419 | Latin American Spanish | 1,234.56 | +> | es-ES | Iberian Spanish | 1234,56 | ## Inputs From 817c32fb6c283f8952903e5345c68b6e7426a00d Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 28 Jun 2024 09:48:25 -0700 Subject: [PATCH 05/16] Improve locale example --- .../language-negotiation.md | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 536ead2c..974a25c8 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -41,19 +41,27 @@ etc.) and to set the locale for internationalization (I18N) APIs such as > `en` (English), `es` (Spanish), and `fr` (French). > > Using `en`, `es`, or `fr` as the locale in software, however, does not -> produce complete results. -> For example, regional variations in formatting will affect how the software -> presents values such as dates, times, numbers, and so forth: +> produce complete results +> or these locales may produce unexpected results compared to more-specific +> locales that include, for example, region subtags. +> Such regional variations in formatting affect how the software +> presents values such as dates, times, numbers, and so forth, +> which, in turn, affects how users experience the localization: > -> | Locale | Locale Description | Formatted Value | -> |--------|--------------------|----------------------------| -> | en-US | US English | Jun 27, 2024, 1:17:36 PM | -> | en-CA | Canadian English | Jun 27, 2024, 1:17:36 p.m. | -> | en-GB | UK English | 27 Jun 2024, 13:17:36 | -> | fr-CA | Canadian French | 27 juin 2024, 13 h 17 min | -> | fr-FR | French (France) | 27 juin 2024, 13:17:36 | -> | es-419 | Latin American Spanish | 1,234.56 | -> | es-ES | Iberian Spanish | 1234,56 | +> | Locale | Locale Description | Formatted Date | Number | Currency | +> |--------|--------------------|-----------------|--------|----------| +> | en | English | Jun 28, 2024, 1:24:45 PM | 1,234.56 |$1,234.56 | +> | en-US | English (United States) | Jun 28, 2024, 1:24:45 PM | 1,234.56 |$1,234.56 | +> | en-CA | English (Canada) | Jun 28, 2024, 1:24:45 p.m. | 1,234.56 |US$1,234.56 | +> | en-GB | English (United Kingdom) | 28 Jun 2024, 13:24:45 | 1,234.56 |US$1,234.56 | +> | fr | French | 28 juin 2024, 13:24:45 | 1 234,56 |1 234,56 $US | +> | fr-CA | French (Canada) | 28 juin 2024, 13 h 24 min 45 s | 1 234,56 |1 234,56 $ US | +> | fr-FR | French (France) | 28 juin 2024, 13:24:45 | 1 234,56 |1 234,56 $US | +> | es-419 | Spanish (Latin America) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |USD 1,234.56 | +> | es | Spanish | 28 jun 2024, 13:24:45 | 1234,56 |1.234,56 US$ | +> | es-MX | Spanish (Mexico) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |USD 1,234.56 | +> | es-ES | Spanish (Spain) | 28 jun 2024, 13:24:45 | 1234,56 |1.234,56 US$ | +> | es-US | Spanish (United States) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |$1,234.56 | ## Inputs From 759536c7aa93e87238231a3c13f026bd6a5acc26 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 28 Jun 2024 10:17:53 -0700 Subject: [PATCH 06/16] Improving the text - Retitling the headers - Making the core flow better - Remove redundant information about why locales --- .../language-negotiation.md | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 974a25c8..0389c6fb 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -64,34 +64,51 @@ etc.) and to set the locale for internationalization (I18N) APIs such as > | es-US | Spanish (United States) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |$1,234.56 | -## Inputs - -Language negotiation generally uses a hierarchy of "signals". -Depending on the type of user and the user's authentication state there -can be different hierarchies used by the language negotiation process. - -These signals can include: +## Determining the User's International Preferences + +The first problem in locale negotiation is: +how do we know what the user's preferences are? + +If an application knows exactly who a user is, +it can often use stored data to know exactly what the preferences are. +Otherwise, locale negotiation depends on whatever information is available +in the session or request. + +Determining the user's international preferences, thus, often +depends on a hierarchy of "signals". +Some signals are directly related to the user's international preferences +(such as storing the specific locale to use!) +while others are open to interpretation +(such as the user's geographic location). +These can include: +- values stored in the user's profile on the site +- values stored in a cookie +- vaules stored in the browser, sesssion, or application - the HTTP `Accept-Language` header - the user's geographic location (often determined from their IP address) - the site's configuration -- values stored in a cookie -- values stored in the user's profile on the site - values in the URL; these might be: - a subdomain (`en.example.com` vs. `fr.example.com`) - a path element (`example.com/en/index.html` vs. `example.com/fr/index.html`) - a part of the filename (`index.en.html` vs. `index.fr.html`) - a query parameter (`example.com?lang=en` vs. `example.com?lang=fr`) -- application specific information +- or application specific information ## Types of User +Locale negotiation is more reliable if the user's has provided a strong signal +(such as choosing their locale from a menu). +Once the locale has been determined, it is usually a good idea to store the result +for future use (including for offline interactions, such as push notifications). + The simplest use case is a site or service that does not persist the user's information between sessions, has no offline experience, and does not maintain a user profile. -Such a site might even negotiate the locale with every request. +Such a site might need to negotiate the locale with every request. -Towards the other end of the spectrum is a site or service that maintains a user profile -(account), has an offline experience (such as sending emails to the user), +Towards the other end of the spectrum is a site or service that +maintains a user profile (account), +has an offline experience (such as sending emails to the user), and attempts to maintain the user's locale preference between sessions. In general, these use cases (and ones in-between these two extremes) @@ -168,9 +185,15 @@ For example, a site might make `es-419` the default for users whose geoIP location indicates Latin America but use the site default for users outside that region. -## Locale Negotiation +Notice that there is a tension between providing a long list of supported locales +(to give users the ability to tailor API-based formatting presentation) +and providing a short list of available languages. +In our example above, where the site is available in English, French, and Spanish, +there might only be three localizations, but twenty or more locales. + +## Constructing the Algorithm -Hierarchical negotiation is one mechanism for performing language negotiation. +Hierarchical negotiation is the most common mechanism for performing language negotiation. One way to implement this is to work from the least specific signal to the most specific one and then return the result. @@ -198,7 +221,8 @@ and leaves out mapping of values, either of which might affect the outcome. When a user authenticates (logs in), the user's preferences need to be checked. If the user's profile contains a language preference different from the one -currently negotiated with the user-agent, it may need to be updated: +currently negotiated with the user-agent, the stored preference may need to be updated +or the user's preference changed: - optionally query the user if they want to change their language (did the currently negotiated language meet their need?) - update the session with the value in their profile @@ -225,25 +249,13 @@ linked from. This can help users of non-default languages who are unrecognized users get the right experience. -### Why locale and not just language negotiation? - -The user's locale influences display and processing with more detail than -just a language. -The ability to format numbers, dates, and messages or the ability to sort -lists depends on the user's locale. - -This also explains why many sites provide a mapping from a more general -form of a language to a specific locale (such as the `es-CR` vs. `es-419` -example given earlier). -It must always be possible to create a _consistent_ user experience. - ### What's not included in the locale? There are a number of values that might be inferred from a locale identifier but which should be separately maintained. These include the user's preferred currency (or the currency of a given transaction), the user's time zone, -and the user's country. +and the user's country/jurisdiction (where they actually live, for example). While locales often contain a country code, this code does not mean that the user is located in that country From 4454690304fa52fae83db8e7bdf409afc10e0bfd Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 28 Jun 2024 16:57:10 -0700 Subject: [PATCH 07/16] Fix list of signals - group the list by type of signal - rephrase helpfully - add a note about not inferring locale from region etc. --- .../language-negotiation.md | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 0389c6fb..282b663f 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -81,19 +81,40 @@ Some signals are directly related to the user's international preferences while others are open to interpretation (such as the user's geographic location). These can include: -- values stored in the user's profile on the site -- values stored in a cookie -- vaules stored in the browser, sesssion, or application -- the HTTP `Accept-Language` header -- the user's geographic location (often determined from their IP address) +- values directly indicated by the user, such as: + - locale preferences stored in the user's profile on the site + - locale preferences stored in a cookie + - locale preferences stored in the browser, sesssion, or application +- values from the user's runtime environment, such as: + - the HTTP `Accept-Language` header (which often matches the user's + operating system runtime locale) + - the browser's localization or locale, such as `navigator.language` + or `navigator.languages` +- values that imply the user's locale preferences, such as: + - the user's geographic location (often determined from their IP address, + often refered to as "geoIP") - the site's configuration -- values in the URL; these might be: +- values in the URL; such as: - a subdomain (`en.example.com` vs. `fr.example.com`) - a path element (`example.com/en/index.html` vs. `example.com/fr/index.html`) - a part of the filename (`index.en.html` vs. `index.fr.html`) - a query parameter (`example.com?lang=en` vs. `example.com?lang=fr`) - or application specific information +> [!NOTE] +> Be careful about making assumptions based on regional or locale information. +> +> For example, knowing that someone's IP address might be located in a specific +> country (via geoIP detection) does not mean that the person speaks the most +> common languages of that country, or that they prefer local formatting +> conventions of that country. +> It's possible, too, that the location is being spoofed, such as via +> a VPN. +> +> Similarly, a locale should not be used to imply unrelated values, +> such as the currency of a transaction or the time zone of the user. + + ## Types of User Locale negotiation is more reliable if the user's has provided a strong signal From aeef1cf3a699f9801495b9d9ad57eca00981013c Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 28 Jun 2024 17:06:19 -0700 Subject: [PATCH 08/16] Move note under list to make it easier to read --- .../language-negotiation/language-negotiation.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 282b663f..49dec288 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -163,10 +163,12 @@ To ensure a consistent experience, sites need these concepts: - **Available Locales** The list of locales that the site will support. Only locales appearing in this list can be selected by the language negotiation process. - + - **Default Locale**. If none of the user's signals match the available + list of locales on the site, there needs to be some language chosen. + This default is the "ultimate fallback" for the site. + > [!NOTE] -> Note that sites may have some locales that are available only to a -> specific set of users. +> Sites sometimes have different configurations for different sets of users. > For example, a site might "stage" a new locale or language and need > testers to have access to the language prior to making the language > available to other users. @@ -177,10 +179,6 @@ To ensure a consistent experience, sites need these concepts: > more languages available to users with a non-USA shipping address > than to domestic users.) -- **Default Locale**. If none of the user's signals match the available - list of locales on the site, there needs to be some language chosen. - This default is the "ultimate fallback" for the site. - Sites also sometimes need to manage more detailed preferences. For example, suppose a site supports two variations of Spanish: From 8a968d7dd23f8abf9aa7598b0444dddf4d56f0df Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 28 Jun 2024 17:08:11 -0700 Subject: [PATCH 09/16] Fix formatting - fix badly indented bullet item - remove note/example formatting --- .../language-negotiation.md | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 49dec288..45e17cc4 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -163,21 +163,18 @@ To ensure a consistent experience, sites need these concepts: - **Available Locales** The list of locales that the site will support. Only locales appearing in this list can be selected by the language negotiation process. - - **Default Locale**. If none of the user's signals match the available +- **Default Locale**. If none of the user's signals match the available list of locales on the site, there needs to be some language chosen. This default is the "ultimate fallback" for the site. -> [!NOTE] -> Sites sometimes have different configurations for different sets of users. -> For example, a site might "stage" a new locale or language and need -> testers to have access to the language prior to making the language -> available to other users. -> Or a site might make a language available only to users from certain -> geographies. -> (As of 2024, an example of this is the [US Amazon website](https://www.amazon.com), -> which makes -> more languages available to users with a non-USA shipping address -> than to domestic users.) +Sites sometimes have different configurations for different sets of users. +For example, a site might "stage" a new locale or language and need +testers to have access to the language prior to making the language +available to other users. +Or a site might make a language available only to users from certain geographies. +(As of 2024, an example of this is the [US Amazon website](https://www.amazon.com), +which makes more languages available to users with a non-USA shipping address +than to domestic users.) Sites also sometimes need to manage more detailed preferences. From 5950acd2ab552c6bb268a69f58088d92945dbcf7 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 9 Jul 2024 10:08:37 -0700 Subject: [PATCH 10/16] Address consistency of locale vs. language negotiation --- .../language-negotiation.md | 105 ++++++++++-------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 45e17cc4..40c2c1e7 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -6,28 +6,38 @@ information to users. This article outlines some of the considerations and best practices when deciding how to choose, set, and store a user's locale preference. -It is not a complete recipe: different users will have different -preferences and there are choices that developers need to make when +It is not a complete recipe: not only will different users will have different +preferences but there are choices that developers need to make when implementing locale negotiation. -## What is locale negotiation? +## What are language and locale negotiation? How are they the same/different? -Sites perform language negotiation in order to provide the user -with an experience that they understand. +**_Language negotiation_** is the process of using various inputs to select between different language +pieces of content for a given request, session, or user experience. +Web sites perform language negotiation in order to provide the user with an experience that they understand. -In the most general terms, locale negotiation is the process that internationalized -software uses to match a user's [international preferences](https://www.w3.org/TR/i18n-glossary/#dfn-international-preferences) -to the internationalized functionality and localized resources available -in a given piece of software (such as a website). - -On the one hand, this entails selecting the best set of translated (localized) set of resources +Language negotiation allows software to select the best set of translated (localized) set of resources for the user's needs. For example, a site consisting of static files might just choose between different language versions of each page, while another site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). -On the other hand, locale negotiation is also needed to allow systems to call internationalized APIs, -used for operations such as by formatting dates and numbers or for sorting lists. +Language negotiation also provides the locale, +which is needed by software when calling internationalized APIs +used for operations such as by formatting dates and numbers, sorting lists, +and many other operations. + +A [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) is: +> An identifier (such as a language tag) for a set of international preferences. +> Usually this identifier indicates the preferred language of the user and +> possibly includes other information, such as a geographic region (such as a country). +> A locale is passed in APIs or set in the operating environment to obtain culturally-affected behavior within a system or process. + +As a result, language negotiation should really be called **_locale negotiation_**, +because it includes the process that internationalized software uses to match a +user's [international preferences](https://www.w3.org/TR/i18n-glossary/#dfn-international-preferences) +to the internationalized functionality and localized resources available +in a given piece of software (such as a website). The negotiated locale is used to select resources (static pages, resource files, etc.) and to set the locale for internationalization (I18N) APIs such as @@ -70,9 +80,14 @@ The first problem in locale negotiation is: how do we know what the user's preferences are? If an application knows exactly who a user is, -it can often use stored data to know exactly what the preferences are. +it can often use stored data to know exactly what the user prefers. Otherwise, locale negotiation depends on whatever information is available -in the session or request. +in the session or request to guess at the user's intent. + +Guessing at the user's intention might vary depending on many different things. +For example, user's might expect a different default currency on a website +intended for use in Germany than on one intended for use in Switzerland, +even if both are localized into German. Determining the user's international preferences, thus, often depends on a hierarchy of "signals". @@ -161,17 +176,17 @@ all of the potential variations of a given language/locale. To ensure a consistent experience, sites need these concepts: - **Available Locales** The list of locales that the site will support. - Only locales appearing in this list can be selected by the language + Only locales appearing in this list can be selected by the locale negotiation process. - **Default Locale**. If none of the user's signals match the available - list of locales on the site, there needs to be some language chosen. + list of locales on the site, there needs to be some locale chosen. This default is the "ultimate fallback" for the site. Sites sometimes have different configurations for different sets of users. -For example, a site might "stage" a new locale or language and need -testers to have access to the language prior to making the language -available to other users. -Or a site might make a language available only to users from certain geographies. +For example, a site might be preparing to release a new localization (language) and need +testers to have access to the locale prior to making the locale +available to regular users. +Or a site might make a locale available only to users from certain geographies. (As of 2024, an example of this is the [US Amazon website](https://www.amazon.com), which makes more languages available to users with a non-USA shipping address than to domestic users.) @@ -203,26 +218,29 @@ outside that region. Notice that there is a tension between providing a long list of supported locales (to give users the ability to tailor API-based formatting presentation) -and providing a short list of available languages. +and providing a short list of available locales (to aid in selection). In our example above, where the site is available in English, French, and Spanish, -there might only be three localizations, but twenty or more locales. +there might only be three localizations, but twenty or more locales that the site _could_ +make available. +Deciding which combinations of language and locale to expose to users and how to represent these +depends on many factors. ## Constructing the Algorithm -Hierarchical negotiation is the most common mechanism for performing language negotiation. +Hierarchical negotiation is the most common mechanism for performing locale negotiation. One way to implement this is to work from the least specific signal to the most specific one and then return the result. > For example: > > 1. Let the return value be the site default. -> 2. If the user's geographic region has a default let return value be that language. +> 2. If the user's geographic region has a default let return value be that locale. > 3. If the user has an Accept-Language header -> i. For each language in the A-L header -> a. if the language matches an available language, let return value be that language -> 4. If the user has a cookie with a language preference, let return value be that language -> 5. If the URL contains a language, let return value be that language -> 6. If the user is recognized, let return value be the language in the user's profile +> i. For each language range in the A-L header +> a. if the language range matches an available locale's language tag, let return value be that locale +> 4. If the user has a cookie with a locale preference, let return value be that locale +> 5. If the URL contains a (recognized, permitted) locale identifier, let return value be that locale +> 6. If the user is recognized, let return value be the locale in the user's profile > > Return the return value. @@ -236,33 +254,33 @@ and leaves out mapping of values, either of which might affect the outcome. ### What happens when the user logs in? When a user authenticates (logs in), the user's preferences need to be checked. -If the user's profile contains a language preference different from the one +If the user's profile contains a locale preference different from the one currently negotiated with the user-agent, the stored preference may need to be updated or the user's preference changed: - - optionally query the user if they want to change their language - (did the currently negotiated language meet their need?) + - optionally query the user if they want to change their locale + (did the currently negotiated locale meet their need?) - update the session with the value in their profile (either the value currently negotiated or what they had previously) Updating the user's profile helps ensure, for example, that offline communications, -such as push notifications, emails, or SMS messages, are in the user's preferred language) +such as push notifications, emails, or SMS messages, are in the user's preferred locale) ### Why provide locale overrides via the URL? -There are a number of reasons why the URL might need to encode the language/locale -to use. +There are a number of reasons why the URL might need to encode the locale to use. -One important use is to allow testing of the site in a given language. +One important use is to allow testing of the site in a given locale. This is useful in reproducing issues that only appear in specific locales without having to change the customer support account's preference. It is also useful when the locale is not yet available to end users but it being prepared for production. Another is that URLs can be shared or used for marketing materials. -By encoding the language into the URL, you can guarantee that the site -shown is in the same language as (for example) a display ad or email being -linked from. -This can help users of non-default languages who are unrecognized users +By encoding the locale into the URL, you can guarantee that the site +shown is in the same language as some external resource. +For example, if the user was brought to the site by clicking on a display ad in a specific language +or clicked on a link in an email they received from the site. +This can help users of a non-default locale who might also be unrecognized users to get the right experience. ### What's not included in the locale? @@ -294,8 +312,7 @@ But user overrides of the value sometimes need to be propagated separately. When a site offers multiple languages or offers multiple locales for a given language (or both), -the result of language negotiation might not be what the user would have -chosen. +the result of locale negotiation might not be what the user would have chosen. When this happens, the user should be provided a convenient control in a predictable, visible location to choose the locale for herself. @@ -303,7 +320,7 @@ The result of choosing a locale should be sticky. Any offline hints (such as cookies) as well as any server-side user profile should be updated. In addition, if the site uses URL elements, the page should redirect with -the language preference added/substituted in the URL. +the locale preference added/substituted in the URL. Sites that "don't remember" a user's choice can be frustrating to use, as the user might need to navigate a foreign language experience to reach one From 354eb35bf3fc9d66deb8bff1f3b33c2831db86ee Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 13 Jul 2024 11:42:41 -0700 Subject: [PATCH 11/16] Remove stray apostrophes --- articles/language-negotiation/language-negotiation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 40c2c1e7..31743eaf 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -85,7 +85,7 @@ Otherwise, locale negotiation depends on whatever information is available in the session or request to guess at the user's intent. Guessing at the user's intention might vary depending on many different things. -For example, user's might expect a different default currency on a website +For example, users might expect a different default currency on a website intended for use in Germany than on one intended for use in Switzerland, even if both are localized into German. @@ -132,7 +132,7 @@ These can include: ## Types of User -Locale negotiation is more reliable if the user's has provided a strong signal +Locale negotiation is more reliable if the user has provided a strong signal (such as choosing their locale from a menu). Once the locale has been determined, it is usually a good idea to store the result for future use (including for offline interactions, such as push notifications). @@ -150,7 +150,7 @@ and attempts to maintain the user's locale preference between sessions. In general, these use cases (and ones in-between these two extremes) have three types of user profile: - **Unrecognized User** - the user does not have a profile or the site - does not maintain one on the user's behalf. There are no cookies or other + does not maintain one on the users behalf. There are no cookies or other cross-session indicators of the user's preference. - **Recognized User** - the user has a profile on this site and there is some cross-session or other indication to From 1168920e10aa3b034886a9a91a4df69005e039f5 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 13 Jul 2024 11:46:58 -0700 Subject: [PATCH 12/16] Clarify localization and example about language choice --- articles/language-negotiation/language-negotiation.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 31743eaf..b4b81bdc 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -16,8 +16,10 @@ implementing locale negotiation. pieces of content for a given request, session, or user experience. Web sites perform language negotiation in order to provide the user with an experience that they understand. -Language negotiation allows software to select the best set of translated (localized) set of resources +Language negotiation allows software to select the best set of set of resources for the user's needs. +Sometimes there is different content available in various languages, but most often +these resources are translated ("localized") from content in a specific source language. For example, a site consisting of static files might just choose between different language versions of each page, while another site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). @@ -47,7 +49,8 @@ etc.) and to set the locale for internationalization (I18N) APIs such as > Consider a web site operated by a non-profit `example.org`. > They want to offer different language experiences to meet user needs. > This organization decides that their site experience will serve users -> in North America, so initially, they offer three languages: +> in North America. +> While other languages are spoken in this region, initially they decide to offer three languages: > `en` (English), `es` (Spanish), and `fr` (French). > > Using `en`, `es`, or `fr` as the locale in software, however, does not From dde0ea9e75b002b010897c1b5977140e36a81845 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 13 Jul 2024 11:48:02 -0700 Subject: [PATCH 13/16] Update language-negotiation.md --- articles/language-negotiation/language-negotiation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index b4b81bdc..759210c0 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -20,6 +20,8 @@ Language negotiation allows software to select the best set of set of resources for the user's needs. Sometimes there is different content available in various languages, but most often these resources are translated ("localized") from content in a specific source language. + +Localization of content can take different forms. For example, a site consisting of static files might just choose between different language versions of each page, while another site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). From c1b11aea78cb93830f83fae30422fa5315eefbb0 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 27 Jul 2024 11:11:36 -0700 Subject: [PATCH 14/16] Address some of @kleinsin's comments --- .../language-negotiation.md | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 759210c0..9140236e 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -1,35 +1,37 @@ # Language and Locale Negotiation on the Web -One challenge faced by websites and services on the Web is how to present -users with the most appropriate language and [locale](https://www.w3.org/TR/i18n-glossary#locale) to use when presenting +One challenge faced by websites and services on the Web is how to decide on +the most appropriate language and [locale](https://www.w3.org/TR/i18n-glossary#locale) to use when presenting information to users. This article outlines some of the considerations and best practices when deciding how to choose, set, and store a user's locale preference. -It is not a complete recipe: not only will different users will have different +It is not a complete recipe: not only will different users have different preferences but there are choices that developers need to make when implementing locale negotiation. ## What are language and locale negotiation? How are they the same/different? **_Language negotiation_** is the process of using various inputs to select between different language -pieces of content for a given request, session, or user experience. +experiences for a given request, session, or user experience. Web sites perform language negotiation in order to provide the user with an experience that they understand. -Language negotiation allows software to select the best set of set of resources -for the user's needs. -Sometimes there is different content available in various languages, but most often -these resources are translated ("localized") from content in a specific source language. +Language negotiation allows software to select the best experience for the user's needs. +Sometimes different languages will have different content or experiences, +but most often a site or software will have a consistent experience +that is translated ("localized") from a specific source language to support users +with different linguistic or cultural needs. Localization of content can take different forms. For example, a site consisting of static files might just choose between different language versions of each page, while another site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). -Language negotiation also provides the locale, -which is needed by software when calling internationalized APIs -used for operations such as by formatting dates and numbers, sorting lists, -and many other operations. +One aspect of language negotiation is that the result is usually a +[language tag](https://www.w3.org/TR/i18n-glossary/#dfn-language-tag) +that identifies the user's locale. +The language tags used on the Web (and by most software) are defined by +[BCP47](https://rfc-editor.org/bcp/bcp47). A [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) is: > An identifier (such as a language tag) for a set of international preferences. @@ -37,6 +39,12 @@ A [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) is: > possibly includes other information, such as a geographic region (such as a country). > A locale is passed in APIs or set in the operating environment to obtain culturally-affected behavior within a system or process. +Developers pass the locale (or set it in the operating environment) when calling +internationalized APIs used for operations such as loading the localized resources mentioned above. +But they are also use APIs that make the content or data in a system appear or +work in a localized way, such as by formatting dates and numbers, sorting lists, +and many other operations that vary by language or culture. + As a result, language negotiation should really be called **_locale negotiation_**, because it includes the process that internationalized software uses to match a user's [international preferences](https://www.w3.org/TR/i18n-glossary/#dfn-international-preferences) @@ -111,8 +119,8 @@ These can include: - the browser's localization or locale, such as `navigator.language` or `navigator.languages` - values that imply the user's locale preferences, such as: - - the user's geographic location (often determined from their IP address, - often refered to as "geoIP") + - the user's geographic location (perhaps determined from signals + such as the user's IP address or other networking information) - the site's configuration - values in the URL; such as: - a subdomain (`en.example.com` vs. `fr.example.com`) @@ -142,7 +150,7 @@ Locale negotiation is more reliable if the user has provided a strong signal Once the locale has been determined, it is usually a good idea to store the result for future use (including for offline interactions, such as push notifications). -The simplest use case is a site or service that does not persist the user's +The simplest use case is a site or service that does not preserve the user's information between sessions, has no offline experience, and does not maintain a user profile. Such a site might need to negotiate the locale with every request. From 9462ee09eb7ece42bd65c89ae722b03113962b92 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 2 Nov 2024 08:38:48 -0700 Subject: [PATCH 15/16] Address comment by @xfq --- articles/language-negotiation/language-negotiation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 9140236e..176d80c5 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -41,7 +41,7 @@ A [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) is: Developers pass the locale (or set it in the operating environment) when calling internationalized APIs used for operations such as loading the localized resources mentioned above. -But they are also use APIs that make the content or data in a system appear or +But they are also used in APIs that make the content or data in a system appear or work in a localized way, such as by formatting dates and numbers, sorting lists, and many other operations that vary by language or culture. From 100eb51779d47d777bff9ff8b4d0e05782e9baf0 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 2 Nov 2024 09:16:00 -0700 Subject: [PATCH 16/16] Improvements --- .../language-negotiation.md | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/articles/language-negotiation/language-negotiation.md b/articles/language-negotiation/language-negotiation.md index 176d80c5..3a089edd 100644 --- a/articles/language-negotiation/language-negotiation.md +++ b/articles/language-negotiation/language-negotiation.md @@ -24,16 +24,16 @@ with different linguistic or cultural needs. Localization of content can take different forms. For example, a site consisting of static files might just choose between different -language versions of each page, while another site might load text into a blank template +language versions of each page, while a different site might load text into a blank template from resource bundles (such those employed by GNU gettext or Java's `java.util.ResourceBundle`). -One aspect of language negotiation is that the result is usually a +Usually the outcome of the language negotiation process is a [language tag](https://www.w3.org/TR/i18n-glossary/#dfn-language-tag) that identifies the user's locale. The language tags used on the Web (and by most software) are defined by [BCP47](https://rfc-editor.org/bcp/bcp47). -A [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) is: +The W3C Internationalization Glossary defines as [locale](https://www.w3.org/TR/i18n-glossary/#dfn-locale) as: > An identifier (such as a language tag) for a set of international preferences. > Usually this identifier indicates the preferred language of the user and > possibly includes other information, such as a geographic region (such as a country). @@ -45,7 +45,7 @@ But they are also used in APIs that make the content or data in a system appear work in a localized way, such as by formatting dates and numbers, sorting lists, and many other operations that vary by language or culture. -As a result, language negotiation should really be called **_locale negotiation_**, +Thus, language negotiation should really be called **_locale negotiation_**, because it includes the process that internationalized software uses to match a user's [international preferences](https://www.w3.org/TR/i18n-glossary/#dfn-international-preferences) to the internationalized functionality and localized resources available @@ -64,24 +64,24 @@ etc.) and to set the locale for internationalization (I18N) APIs such as > `en` (English), `es` (Spanish), and `fr` (French). > > Using `en`, `es`, or `fr` as the locale in software, however, does not -> produce complete results -> or these locales may produce unexpected results compared to more-specific +> produce complete results. +> Such generic locales produce unexpected results compared to more-specific > locales that include, for example, region subtags. > Such regional variations in formatting affect how the software > presents values such as dates, times, numbers, and so forth, > which, in turn, affects how users experience the localization: > > | Locale | Locale Description | Formatted Date | Number | Currency | -> |--------|--------------------|-----------------|--------|----------| -> | en | English | Jun 28, 2024, 1:24:45 PM | 1,234.56 |$1,234.56 | +> |:-------|:------------------:|:----------------|:-------|:---------| +> | **en** | English | Jun 28, 2024, 1:24:45 PM | 1,234.56 |$1,234.56 | > | en-US | English (United States) | Jun 28, 2024, 1:24:45 PM | 1,234.56 |$1,234.56 | > | en-CA | English (Canada) | Jun 28, 2024, 1:24:45 p.m. | 1,234.56 |US$1,234.56 | > | en-GB | English (United Kingdom) | 28 Jun 2024, 13:24:45 | 1,234.56 |US$1,234.56 | -> | fr | French | 28 juin 2024, 13:24:45 | 1 234,56 |1 234,56 $US | +> | **fr** | French | 28 juin 2024, 13:24:45 | 1 234,56 |1 234,56 $US | > | fr-CA | French (Canada) | 28 juin 2024, 13 h 24 min 45 s | 1 234,56 |1 234,56 $ US | > | fr-FR | French (France) | 28 juin 2024, 13:24:45 | 1 234,56 |1 234,56 $US | +> | **es** | Spanish | 28 jun 2024, 13:24:45 | 1234,56 |1.234,56 US$ | > | es-419 | Spanish (Latin America) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |USD 1,234.56 | -> | es | Spanish | 28 jun 2024, 13:24:45 | 1234,56 |1.234,56 US$ | > | es-MX | Spanish (Mexico) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |USD 1,234.56 | > | es-ES | Spanish (Spain) | 28 jun 2024, 13:24:45 | 1234,56 |1.234,56 US$ | > | es-US | Spanish (United States) | 28 jun 2024, 1:24:45 p.m. | 1,234.56 |$1,234.56 | @@ -148,7 +148,7 @@ These can include: Locale negotiation is more reliable if the user has provided a strong signal (such as choosing their locale from a menu). Once the locale has been determined, it is usually a good idea to store the result -for future use (including for offline interactions, such as push notifications). +for future use (including for offline interactions, such as push notifications or emails). The simplest use case is a site or service that does not preserve the user's information between sessions, has no offline experience, and does not maintain @@ -166,7 +166,7 @@ have three types of user profile: does not maintain one on the users behalf. There are no cookies or other cross-session indicators of the user's preference. - **Recognized User** - the user has a profile on - this site and there is some cross-session or other indication to + this site or there is some cross-session or other indication to associate the request with a specific user profile. However, the user has not authenticated themselves. Users in this state can have a measure of personalization done for them, but should not be given access to @@ -236,29 +236,42 @@ In our example above, where the site is available in English, French, and Spanis there might only be three localizations, but twenty or more locales that the site _could_ make available. Deciding which combinations of language and locale to expose to users and how to represent these -depends on many factors. +is a local decision that the site will need to make. +A couple of best practices to briefly mention: +* Avoid using national or regional flags as a proxy for language. +* Present the locale in its own language. + Chinese speakers are more readily able to recognize `简体中文` than `Simplified Chinese` + just as English speakers are more readily able to recognize `English` than `英语` ## Constructing the Algorithm -Hierarchical negotiation is the most common mechanism for performing locale negotiation. +There is no one precise mechanism that applies to every site or organization's +locale negotiation needs. +Different factors have to be weighed by the developer to get the right result. +These include what information is available about the user, both in terms of +profile information and passively collected info. + +In most cases, the result of this will be a hierarchical negotiation mechanism +that uses different site configuration details and different user signals to arrive +at the specific result. One way to implement this is to work from the least specific signal to the -most specific one and then return the result. +most specific one and then return the result, such as the following: -> For example: -> -> 1. Let the return value be the site default. -> 2. If the user's geographic region has a default let return value be that locale. +> 1. Let `return_value` be the site default. +> 2. If the user's geographic region has a default let `return_value` be that locale. > 3. If the user has an Accept-Language header > i. For each language range in the A-L header -> a. if the language range matches an available locale's language tag, let return value be that locale -> 4. If the user has a cookie with a locale preference, let return value be that locale -> 5. If the URL contains a (recognized, permitted) locale identifier, let return value be that locale -> 6. If the user is recognized, let return value be the locale in the user's profile +> a. if the language range matches an available locale's language tag, let `return_value` be that locale +> 4. If the user has a cookie with a locale preference, let `return_value` be that locale +> 5. If the URL contains a (recognized, permitted) locale identifier, let `return_value` be that locale +> _Note: this might be in the path, domain name, file name, or a query parameter... or more than one of these_ +> 7. If the user is recognized, let `return_value` be the locale in the user's profile > -> Return the return value. +> Return `return_value`. Notice how the above algorithm might be tailored to weight one item higher (or lower) in the hierarchy. +Notice too that the algorithm never fails (it always returns a valid result). The above short description leaves out checking if each language tag is in the list of supported locales