+
+ `*_localized` members
+
+
+ A localizable member is a [=manifest=] member that can be
+ localized. Each [=localizable member=] of the [=manifest=] has a
+ corresponding *_localized
member, where `*` represents the
+ member name.
+
+
+
+ For example, the [=manifest/name=] member is a [=localizable
+ member=], and `name_localized` is its corresponding
+ [=manifest/*_localized=] member.
+
+
+
+ A language map is an [=ordered map=] whose key is a
+ [=language tag=] and whose value is a [=localized value=]. The
+ localized value is content localized in the language given
+ by the key.
+
+
+
+ {
+ "lang": "en-US",
+ "dir": "ltr",
+ "name": "Color Picker",
+ "name_localized": {
+ "de": "Farbwähler",
+ "en": {"value": "Color Picker"},
+ "en-GB": {"value": "Colour Picker", "dir": "ltr"},
+ "fr": {"value": "Sélecteur de Couleur", "lang": "fr-CA", "dir": "ltr"},
+ "ar": {"value": "منتقي الألوان", "dir": "rtl"}
+ }
+ }
+
+
+
+ The value assigned to the [=localizable member=] is the
+ default representation .
+ [=manifest/*_localized=] members contain a [=language map=] that
+ defines [=localized values=] for the given [=localizable member=] in
+ the application. The user agent SHOULD use the user's localization
+ settings to select the [=localized value=] whose [=language tag=] key
+ best matches the user's preference. When no such [=localized value=]
+ is available, the [=localizable member/default representation=] is
+ used.
+
+
+
+ Localizing text values
+
+
+ A localized text object is an [=ordered map=] with the
+ following properties:
+
+
+
+ value
+
+
+ The localized [=string=].
+
+
+ dir
(optional)
+
+
+ The [=text-direction=].
+
+
+ lang
(optional)
+
+
+ A [=language tag=].
+
+
+
+ For [=localizable members=] that accept [=strings=], the
+ [=manifest/*_localized=] member's [=language map=] accepts either a
+ [=string=] or a [=localized text object=] as the [=localized
+ value=].
+
+
+ When a [=string=] is used, or when the [=manifest/*_localized/dir=]
+ member of the [=localized text object=] is missing, the [=default
+ direction=] ([=manifest/dir=] member of the [=manifest=]) is
+ applied.
+
+
+ The [=manifest/*_localized/dir=] member of the [=localized text
+ object=] needs to be present if the direction of a localized string
+ differs from the [=default direction=] set in the manifest
+ ([=manifest/dir=] member). Right-to-left text will require specific
+ direction settings if the manifest's default direction is
+ left-to-right, and vice versa.
+
+
+ When a [=string=] is used, or when the
+ [=manifest/*_localized/lang=] member of the [=localized text
+ object=] is missing, the [=language tag=] of the [=language map=]
+ key is applied.
+
+
+ To support multilingual content and ensure optimal display and
+ accessibility, it is possible to specify a different language for a
+ [=localized text object=]. This is needed for situations where a
+ term or text needs to be presented in a language different from the
+ user's set locale.
+
+
+
+ For example, brand names might need to be pronounced in a
+ language different from the user's locale:
+
+
+ {
+ "lang": "fr",
+ "name": "Superbes biscuits",
+ "name_localized": {
+ "de-DE": {"value": "Super Cookies", "lang": "en"}
+ }
+ }
+
+
+
+ To process a `*_localized` text member , given [=ordered
+ map=] |json:ordered map|, [=ordered map=] |map:ordered map|,
+ [=string=] |member:string|, and [=text-direction=]
+ |defaultDirection:string|:
+
+
+ If |member| does not [=map/exist=] in |json|, return.
+
+ Let |languageMap| be |json|[|member|].
+
+ If |languageMap| is not an [=ordered map=], return.
+
+ Let |languageTags:ordered set| be the [=map/keys=] of
+ |languageMap:ordered map|.
+
+ Set |map|[|member|] to a new [=ordered map=].
+
+ [=Set/For each=] |languageTag:string| of |languageTags|, run
+ [=process a localized text object=], passing
+ |languageMap|[|languageTag|], |languageTag|, |map|, |member|, and
+ |defaultDirection|.
+
+
+
+ To process a localized text object , given [=string=] or
+ [=ordered map=] |localizedValue|, [=string=]
+ |defaultLanguageTag:string|, [=ordered map=] |map:ordered map|,
+ [=string=] |member:string|, and [=text-direction=]
+ |defaultDirection:string|:
+
+
+ Let |normalizedValue:ordered map| be an [=ordered map=].
+
+ If |localizedValue| is a [=string=], [=strip leading and
+ trailing ASCII whitespace=] from |localizedValue:string| and
+ [=map/set=] |normalizedValue|["value"] to |localizedValue|.
+
+ If |localizedValue:ordered map| is an [=ordered map=]:
+
+ If "value" [=map/exists=] in |localizedValue| and
+ |localizedValue|["value"] is a [=string=], [=strip leading and
+ trailing ASCII whitespace=] from |localizedValue|["value"] and
+ [=map/set=] |normalizedValue|["value"] to
+ |localizedValue|["value"].
+
+ If "lang" [=map/exists=] in |localizedValue| and
+ |localizedValue|["lang"] is a [=string=], [=strip leading and
+ trailing ASCII whitespace=] from |localizedValue|["lang"] and
+ [=map/set=] |normalizedValue|["lang"] to
+ |localizedValue|["lang"].
+
+ If "dir" [=map/exists=] in |localizedValue| and
+ |localizedValue|["dir"] is a [=string=]:
+
+ [=Strip leading and trailing ASCII whitespace=] from
+ |localizedValue|["dir"].
+
+ If [=text-direction list=] [=list/contains=]
+ |localizedValue|["dir"], [=map/set=]
+ |normalizedValue|["dir"] to |localizedValue|["dir"].
+
+
+
+
+
+ If "value" does not [=map/exist=] in |normalizedValue|, return.
+
+ If "lang" does not [=map/exist=] in |normalizedValue|,
+ [=map/set=] |normalizedValue|["lang"] to |defaultLanguageTag|.
+
+ If "dir" does not [=map/exist=] in |normalizedValue|,
+ [=map/set=] |normalizedValue|["dir"] to |defaultDirection|.
+
+ If calling IsStructurallyValidLanguageTag
+ with |normalizedValue|["lang"] or calling IsStructurallyValidLanguageTag
+ with |defaultLanguageTag| returns `false`, return.
+
+ [=Map/Set=] |map|[|member|][|defaultLanguageTag|] to
+ |normalizedValue|.
+
+
+
+ The [=process a localized text object=] algorithm takes both a
+ [=string=] or a [=localized text object=] for the [=localized
+ value=] parameter, but the processed result will be normalized into
+ a [=localized text object=] with the
+ [=manifest/*_localized/value=], [=manifest/*_localized/lang=], and
+ [=manifest/*_localized/dir=] members set.
+
+
+
+
+ Localizing image resources
+
+
+ For [=localizable members=] that accept a [=list=] of [=image
+ resources=], the [=manifest/*_localized=] member's [=language map=]
+ accepts a [=list=] of [=image resources=] as the [=localized
+ value=].
+
+
+
+ {
+ "lang": "en-US",
+ "icons": [
+ { "src": "icon/lowres.png", "sizes": "64x64" },
+ { "src": "icon/hires.png", "sizes": "256x256" }
+ ],
+ "icons_localized": {
+ "fr": [
+ { "src": "icon/lowres_fr.png", "sizes": "64x64" },
+ { "src": "icon/hires_fr.png", "sizes": "256x256" }
+ ]
+ }
+ }
+
+
+
+ To process a `*_localized` image resource member , given
+ [=ordered map=] |json:ordered map|, [=ordered map=] |map:ordered
+ map|, [=string=] |member:string|, and [=URL=] |manifest URL:URL|:
+
+
+ If |member| does not [=map/exist=] in |json|, return.
+
+ Let |languageMap| be |json|[|member|].
+
+ If |languageMap| is not an [=ordered map=], return.
+
+ Let |languageTags:ordered set| be the [=map/keys=] of
+ |languageMap:ordered map|.
+
+ [=Map/Set=] |map|[|member|] to a new [=ordered map=].
+
+ [=List/For each=] |languageTag:string| of |languageTags|:
+
+ If calling IsStructurallyValidLanguageTag
+ with |languageTag| returns `false`, [=iteration/continue=].
+
+ Run [=process image resources=], passing
+ |languageMap|[|languageTag|] as the [=list=] of [=image
+ resources=], |map|[|member|], |manifest URL|, and |languageTag|
+ as the member.
+
+
+
+
+
+
Manifest life-cycle
@@ -1328,9 +1607,15 @@
[=Process a text member=] passing |json|, |manifest|, and
"name".
+ [=Process a `*_localized` text member=] passing |json|,
+ |manifest|, "name_localized", and |manifest|["dir"].
+
[=Process a text member=] passing |json|, |manifest|, and
"short_name".
+ [=Process a `*_localized` text member=] passing |json|,
+ |manifest|, "short_name_localized", and |manifest|["dir"].
+
[=Process the `start_url` member=] passing |json|, |manifest|,
|manifest URL|, and |document URL|.
@@ -1354,6 +1639,9 @@
[=Process image resources=] passing |json|["icons"],
|manifest|, |manifest URL|, and "icons".
+ [=Process a `*_localized` image resource member=] passing
+ |json|, |manifest|, "icons_localized", and |manifest URL|.
+
[=Process the `orientation` member=] passing |json|,
|manifest|.
@@ -1540,13 +1828,21 @@
installation and on launch surfaces:
- [=manifest/short_name=],
+ [=manifest/short_name=] and localized representations in
+ `short_name_localized`,
- [=manifest/icons=]
+ [=manifest/icons=] and localized representations in
+ `icons_localized`,
- [=manifest/name=],
+ [=manifest/name=] and localized representations in
+ `name_localized`.
+
+ [=Security-sensitive members=] SHOULD be displayed in a
+ bidirectionally isolated way as described in [[UTS55]], regardless
+ of their direction.
+
User agents SHOULD NOT automatically apply changes to
[=security-sensitive members=] without [=express permission=] from
@@ -1561,6 +1857,13 @@
The user agent MAY automatically apply the changes if the update
does not contain changes to [=security-sensitive members=].
+
+ If a user changes localization settings, the user agent MAY
+ automatically adjust the [=security-sensitive members=] visible on
+ launch surfaces to their localized representations specified in the
+ [=manifest/`*_localized`=] members. These changes SHOULD be
+ presented to users the next time they open the web application.
+
@@ -2098,7 +2413,8 @@
To process a shortcut , given [=ordered map=] |item:ordered
- map| and |scope:URL|,:
+ map|, [=URL=] |manifest URL:URL|, [=URL=] |scope:URL|, and
+ [=text-direction=] |defaultDirection:string|:
Return failure if it's the case that:
@@ -2126,9 +2442,29 @@
Let |shortcut:ordered map| be |ordered map| «[ "url" → |url|,
"name" → |item|["name"] ]».
+ [=Process a `*_localized` text member=] passing |item|,
+ |shortcut|, "name_localized", and |defaultDirection|.
+
+ If "short_name" [=map/exists=] in |item|, and
+ |item|["short_name"] is a [=string=], [=map/set=]
+ |shortcut|["short_name"] to |item|["short_name"].
+
+ [=Process a `*_localized` text member=] passing |item|,
+ |shortcut|, "short_name_localized", and |defaultDirection|.
+
+ If "description" [=map/exists=] in |item|, and
+ |item|["description"] is a [=string=], [=map/set=]
+ |shortcut|["description"] to |item|["description"].
+
+ [=Process a `*_localized` text member=] passing |item|,
+ |shortcut|, "description_localized", and |defaultDirection|.
+
[=Process image resources=] passing |item|["icons"], |shortcut|,
|manifest URL|, and "icons".
+ [=Process a `*_localized` image resource member=] passing |item|,
+ |shortcut|, "icons_localized", and |manifest URL|.
+
Return |shortcut|.
@@ -2316,7 +2652,9 @@
The application's name is derived from either the
- [=manifest/name=] member or [=manifest/short_name=] member.
+ [=manifest/name=] member or [=manifest/short_name=] member. The user
+ agent SHOULD first resolve the localized values from their
+ corresponding [=manifest/`*_localized`=] members.
When either the [=manifest/name=] member or the
@@ -3303,7 +3641,8 @@