Skip to content

Technical review: Document web app manifest localization#44609

Open
chrisdavidmills wants to merge 11 commits into
mdn:mainfrom
chrisdavidmills:manifest-localization
Open

Technical review: Document web app manifest localization#44609
chrisdavidmills wants to merge 11 commits into
mdn:mainfrom
chrisdavidmills:manifest-localization

Conversation

@chrisdavidmills

Copy link
Copy Markdown
Contributor

Description

Chrome and Edge 148 desktop have added support for *_localized members, aka localizable web app manifests. See https://chromestatus.com/feature/5090807862394880.

This PR adds reference documentation for *_localized members and the dir and lang members, as well as a how-to guide covering how to localize a web app manifest.

Motivation

Additional details

Related issues and pull requests

@chrisdavidmills chrisdavidmills requested review from a team as code owners June 30, 2026 15:58
@chrisdavidmills chrisdavidmills requested review from dipikabh and hamishwillee and removed request for a team June 30, 2026 15:58
@github-actions github-actions Bot added Content:PWA Progressive Web Apps content size/l [PR only] 501-1000 LoC changed labels Jun 30, 2026
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@chrisdavidmills chrisdavidmills changed the title Document web app manifest localization Technical review: Document web app manifest localization Jun 30, 2026
Comment thread files/en-us/web/progressive_web_apps/manifest/reference/lang/index.md Outdated

in this example, the app's default `lang` is `en-US`, and its default `dir` is `ltr`. Its default `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

The French variant is specified as French Canadian (`fr-CA`) in its `lang` property, with a direction (`dir`) of `ltr`, while the Arabic variant has its `dir` specified as `rtl`. The German variant doesn't need its `lang` or `dir` specified, so its value is a string containing the localized text.

@hamishwillee hamishwillee Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't quite work because the French Canadian version doesn't need its direction set either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've chatted to @kyerebo about the dir and lang members' involvement in manifest localization, and ... they are confusingly not involved at all. I've therefore made quite a few changes to the articles.

In this particular case (and on the dir page), I've cut the example right down, removing all this stuff.

"name": "Color Picker",
"name_localized": {
"de": "Farbwähler",
"fr": { "value": "Sélecteur de Couleur", "lang": "fr-CA", "dir": "ltr" },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work - i.e this is fr, but you also have a lang that is "fr-CA". However I know lang sets the default language.

My guess is that this should omit lang and fix up the key.

    "fr-CA": { "value": "Sélecteur de Couleur", "dir": "ltr" },

Further, in the intro it says "will see the app's name displayed in a more suitable language for them."

I would like to understand the fallback here. If my language is set to fr, will it choose "fr-CA" or will it choose English ? Can I declare both "fr" and "fr-CA", and so on. The example could show a case or two.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't speak to the standards approach to this, but for the Chromium implementation, the localized member's lang field, if specified, doesn't currently have an effect on what the user sees.
The primary criteria for localization selection is if there exists a language tag that matches or partly matches the user's current browser language setting.

So if we had something like:

"fr": { "value": "Color Selector, "lang": "en" },

The end result for a browser set to French is that we'd see Color Selector.
The lang field is effectively acting as a "heads up, this value is this language rather than the one specified by the language tag."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I've cut this right down. In other places, I've made the text more understandable.

In the particular case of the lang property being different from the main object property key, I've removed the fr-CA example and used a much more obvious one; see the Howto guide's short_name_localized example.

Comment thread files/en-us/web/progressive_web_apps/manifest/reference/dir/index.md Outdated
---

The `lang` manifest member is used to specify a default language for your web application, which will be used unless overriden by a different `lang` value found in a [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) member.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a default lang assumed?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think including the manifest-level dir and lang as part of this conversation can be confusing.
In the Chromium implementation, the language selection is independent of the manifest-level lang specification, and is solely based on the user's browser language.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this. The chosen language has nothing to do with lang. When localized members are included (e.g. name_localized), the browser chooses the variant that matches the user's browser language setting.

If no variant matches the user's browser language setting, the value in the non-localized member is used instead (e.g. name). I've explained this in the *_localized reference and the Howto.

Comment thread files/en-us/web/progressive_web_apps/manifest/reference/dir/index.md Outdated

in this example, the app's default `lang` is `en-US`, and its default `dir` is `ltr`. Its default `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

The French variant is specified as French Canadian (`fr-CA`) in its `lang` property, with a direction (`dir`) of `ltr`, while the Arabic variant has its `dir` specified as `rtl`. The German variant doesn't need its `lang` or `dir` specified, so its value is a string containing the localized text.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as for the lang case.

Note also that this is a dir topic. I'd show a screen shot or explicitly state at least somewhere that the text will be drawn LTR and show it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is all now cut down and changed around.

page-type: how-to
sidebar: pwasidebar
---

@hamishwillee hamishwillee Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I localise the rest of the app? We should at least mention that (or if it can't be done, state that too). I assume perhaps we can specify a key for the default language entry point?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Localizing the rest of the app is a huge topic and out of scope for this article. How you would go about localizing it depends on what kind of app it is, what stack you've used, etc.

https://github.com/oh-jon-paul/awesome-i18n gives you an idea of what's available.

Comment thread files/en-us/web/progressive_web_apps/how_to/localize_an_app_manifest/index.md Outdated
Comment thread files/en-us/web/progressive_web_apps/how_to/localize_an_app_manifest/index.md Outdated

## Set a default language and direction

The [`lang`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/lang) and [`dir`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/dir) members define a default language and language direction for the app. These will be assumed by the browser if no language and direction more suitable for the user's preferences are found in the [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) variants. In such cases, the non-prefixed members are used (for example, `name`).

@hamishwillee hamishwillee Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. What if I don't set a default language or dir, what is used?

  2. While I understand exactly what you mean, this doesn't feel quite right

    These will be assumed by the browser if no language and direction more suitable for the user's preferences are found in the *_localized variants.

    It's because the languages will be used but it isn't lang and dir that will be used. What will be used is the other non-localized members. You clarify this in the next sentence, but "These" still grates.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. At least in the Chromium implementation, if no dir is specified for a localized member, it uses the direction of the browser's currently set language. Localizations are selected based off of the browser's currently set language at all times.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comments.

Comment thread files/en-us/web/progressive_web_apps/how_to/localize_an_app_manifest/index.md Outdated
sidebar: pwasidebar
---

The `lang` manifest member is used to specify a default language for your web application, which will be used unless overriden by a different `lang` value found in a [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) member.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm nearing the end of my review, and I realize that this first doc that I read in the review is confusing:

overriden by a different lang value found in a *_localized member.

If it specifies the default language for my web application, what sense does it make to override?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comments.

},
```

The French (`fr`) `short_name` translation shows typical usage of the object value form being used to specify a `lang` property. In this case, our French audience knows our app by its English brand name — "SuperSausage" — and we want to specify that this should be handled as English rather than French (for example, for the purposes of pronounciation).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://github.com/mdn/content/pull/44609/changes#r3517481036 - lang in a translation needs additional explanation there. I think I get it now, finally on this the second last doc - this allows you to specify that the value from some other language key should be used for a translation, instead of providing your own, or using the default?

Typo too

Suggested change
The French (`fr`) `short_name` translation shows typical usage of the object value form being used to specify a `lang` property. In this case, our French audience knows our app by its English brand name — "SuperSausage" — and we want to specify that this should be handled as English rather than French (for example, for the purposes of pronounciation).
The French (`fr`) `short_name` translation shows typical usage of the object value form being used to specify a `lang` property. In this case, our French audience knows our app by its English brand name — "SuperSausage" — and we want to specify that this should be handled as English rather than French (for example, for the purposes of pronunciation).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reading it as clarification that although the localized object is under the French language tag, the value of the object is presented in English rather than French.

From the web application manifest spec:

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the typo

Comment thread files/en-us/web/progressive_web_apps/how_to/localize_an_app_manifest/index.md Outdated

## Finished manifest

Putting this all together, the complete manifest looks like this:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need your shortcuts - I want to know how to select my language version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean you want me to include a shortcuts example?


Localized text field properties have values equal to objects or strings.

in this example, the app's default `en-US` language `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
in this example, the app's default `en-US` language `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.
In this example, the app's default `en-US` language `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But also see my other comment on lang - this could be better worded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is changed now


in this example, the app's default `en-US` language `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

The French variant is specified as French Canadian (`fr-CA`) in its `lang` property, with a direction (`dir`) of `ltr`, while the Arabic variant has its `dir` specified as `rtl`. The German variant doesn't need its `lang` or `dir` specified, so its value is a string containing the localized text.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't clear why the French version needs a lang and dir and the german version does not - same thing as https://github.com/mdn/content/pull/44609/changes#r3517444725

Somewhere else, perhaps in the how to, you indicate that lange in a localized member takes a language from somewhere else. So here you're saying that for French ou take your language from "fr-CA". But then there are two more questions:

  • If you are taking it from fr-CA, where is your fr-CA definition?
  • If you are taking it from fr-CA, why do you have a value?

I suspect the answer might be "take it from fr-CA if defined and otherwise fall back to the specified value. But that feels like poor design to me.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, neither of these actually need dir or lang specified, those are always optional fields.

The manifest spec is actually pretty loose on what lang for localized members should do beyond "specifying when it should be presented as another language".
At least in the Chromium implementation, for current cases that make localized members user-visible, it seems to ignore the lang field if provided.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed this for a more obvious example


The `lang` and `dir` members define a default language and language direction that will be assumed by the browser if no language more suitable for the user's preferences is found in the `name_localized` variants. In such cases, the `name` member is used.

### Localized images

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it icons or image or both? If it can only be icons we should say that. If icons and other images are different we should say that. We should also note "somewhere" whether the localised set can have diferrent sets of icons or must match the same sizes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 let's change this to "Localized icons"

The localized set can have different sets of icons; each localization is treated independently as if the other localizations didn't exist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed it to "icons"

chrisdavidmills and others added 7 commits July 3, 2026 08:59
…ndex.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…dex.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…dex.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…nifest/index.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…nifest/index.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…nifest/index.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
…nifest/index.md

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>

@kyerebo kyerebo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly comments about clarifying the effect of manifest-level lang and dir, thanks!

sidebar: pwasidebar
---

[Progressive Web App (PWA)](/en-US/docs/Web/Progressive_web_apps) manifests can be localized using a combination of localizable members, which have the suffix [`_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized), and the [`lang`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/lang) and [`dir`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/dir) members.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Touched upon this in email with Chris, reposting here in more detail.
The dir and lang manifest-level members are somewhat independent of the localization feature.
*_localized members are selected based off of the browser's language setting, not off of the other manifest members.
This is definitely a bit confusing in the spec, as it says the manifest-level dir/lang set the default value of localized members, but the section on localized members clarifies that the default representation is the manifest member without *_localized and localizations should be selected based off of the user's language setting.
The manifest-level dir is defined in the spec as applying a default text direction for localized members that are missing a dir field, but the Chromium implementation only prioritizes whatever direction is specified by the localized member.
The manifest-level lang field isn't actually used when calculating which localized value to show.

In practice (or at least how it works right now in Chromium), this means that the manifest-level lang and dir don't have implications for the localized value that ends up getting chosen. Perhaps we can remove or edit the references to these manifest level members to avoid confusing developers?
The suggested instructions for working with localizable manifests on the chrome developer blog don't mention manifest-level dir or lang as any sort of fallback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've captured this all in my updates, except maybe this bit:

The manifest-level dir is defined in the spec as applying a default text direction for localized members that are missing a dir field, but the Chromium implementation only prioritizes whatever direction is specified by the localized member.

But I'm not sure if there is really much worth saying.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's probably not worth specifying. LGTM.


The [`lang`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/lang) and [`dir`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/dir) members define a default language and language direction for the app. These will be assumed by the browser if no language and direction more suitable for the user's preferences are found in the [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) variants. In such cases, the non-prefixed members are used (for example, `name`).

Set a suitable default language and direction like so:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider removing/editing this section as part of comment above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


## Set a default language and direction

The [`lang`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/lang) and [`dir`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/dir) members define a default language and language direction for the app. These will be assumed by the browser if no language and direction more suitable for the user's preferences are found in the [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) variants. In such cases, the non-prefixed members are used (for example, `name`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. At least in the Chromium implementation, if no dir is specified for a localized member, it uses the direction of the browser's currently set language. Localizations are selected based off of the browser's currently set language at all times.

},
```

The French (`fr`) `short_name` translation shows typical usage of the object value form being used to specify a `lang` property. In this case, our French audience knows our app by its English brand name — "SuperSausage" — and we want to specify that this should be handled as English rather than French (for example, for the purposes of pronounciation).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reading it as clarification that although the localized object is under the French language tag, the value of the object is presented in English rather than French.

From the web application manifest spec:

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.

The exact properties contained within each object will be the same as the properties contained within the objects included with the non-localized versions of the members:

- For `icons_localized`, the objects can have the same properties as the [`icons`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons) member: `src`, `sizes`, `type`, and `purpose`.
- For `shortcuts_localized`, the objects can have the same properties as the [`shortcuts`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/shortcuts) member: `name`, `short_name`, `description`, `url`, and [`icons`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it makes sense to break out shortcut localization to its own section. Localization of shortcuts looks a little different than described here. Rather than shortcuts having a corresponding *_localized version, it's that shortcut fields can be localized.

An example from this test site:

 "shortcuts": [
    {
      "name": "Open Dashboard",
      "name_localized": {
        "en": { "value": "Open Dashboard", "lang": "en", "dir": "ltr" },
        "de": { "value": "Dashboard öffnen", "lang": "de", "dir": "ltr" },
        "ar": { "value": "فتح لوحة المعلومات", "lang": "ar", "dir": "rtl" }
      },
      "short_name": "Dashboard",
      "short_name_localized": {
        "en": { "value": "Dashboard", "lang": "en", "dir": "ltr" },
        "de": { "value": "Dashboard", "lang": "de", "dir": "ltr" },
        "ar": { "value": "لوحة", "lang": "ar", "dir": "rtl" }
      },
      "description": "Go to your dashboard.",
      "description_localized": {
        "en": { "value": "Go to your dashboard.", "lang": "en", "dir": "ltr" },
        "de": { "value": "Zum Dashboard wechseln.", "lang": "de", "dir": "ltr" },
        "ar": { "value": "انتقل إلى لوحتك.", "lang": "ar", "dir": "rtl" }
      },
      "url": "./dashboard",
      "icons": [
        { "src": "./icons/shortcut-dashboard.png", "sizes": "96x96", "type": "image/png", "purpose": "any" }
      ],
      "icons_localized": {
        "en": [
          { "src": "./icons/icon-128.png", "sizes": "128x128", "type": "image/png", "purpose": "any" }
        ],
        "de": [
          { "src": "./icons/localized_icons/de/Iconka-Meow-Cat-purr.128.png", "sizes": "128x128", "type": "image/png", "purpose": "any" }
        ],
        "ar": [
          { "src": "./icons/localized_icons/ar/black_cat-128.png", "sizes": "128x128", "type": "image/png", "purpose": "any" }
        ]
      }
    }
  ],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I think I've made all the updates I need, except for more coverage of shortcuts. I'll work on that tomorrow.


in this example, the app's default `en-US` language `name` is "Color picker", but we've also specified localized variants in the `name_localized` member. Users that have their primary language preference set to German (`de`), French (`fr`), or Arabic (`ar`) will see the app's name displayed in a more suitable language for them.

The French variant is specified as French Canadian (`fr-CA`) in its `lang` property, with a direction (`dir`) of `ltr`, while the Arabic variant has its `dir` specified as `rtl`. The German variant doesn't need its `lang` or `dir` specified, so its value is a string containing the localized text.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, neither of these actually need dir or lang specified, those are always optional fields.

The manifest spec is actually pretty loose on what lang for localized members should do beyond "specifying when it should be presented as another language".
At least in the Chromium implementation, for current cases that make localized members user-visible, it seems to ignore the lang field if provided.


The `lang` and `dir` members define a default language and language direction that will be assumed by the browser if no language more suitable for the user's preferences is found in the `name_localized` variants. In such cases, the `name` member is used.

### Localized images

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 let's change this to "Localized icons"

The localized set can have different sets of icons; each localization is treated independently as if the other localizations didn't exist.

---

The `dir` manifest member is used to specify a default language directionality for your web application, which will be used unless overriden by a different `dir` value found in a [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) member.
If not specifies, the default direction is inferred from the default language, as specfiied using [`lang`].

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "specfiied"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all changed now.

---

The `lang` manifest member is used to specify a default language for your web application, which will be used unless overriden by a different `lang` value found in a [`*_localized`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/*_localized) member.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think including the manifest-level dir and lang as part of this conversation can be confusing.
In the Chromium implementation, the language selection is independent of the manifest-level lang specification, and is solely based on the user's browser language.

"name": "Color Picker",
"name_localized": {
"de": "Farbwähler",
"fr": { "value": "Sélecteur de Couleur", "lang": "fr-CA", "dir": "ltr" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't speak to the standards approach to this, but for the Chromium implementation, the localized member's lang field, if specified, doesn't currently have an effect on what the user sees.
The primary criteria for localization selection is if there exists a language tag that matches or partly matches the user's current browser language setting.

So if we had something like:

"fr": { "value": "Color Selector, "lang": "en" },

The end result for a browser set to French is that we'd see Color Selector.
The lang field is effectively acting as a "heads up, this value is this language rather than the one specified by the language tag."

@kyerebo

kyerebo commented Jul 9, 2026

Copy link
Copy Markdown

Thanks for making those changes, the new technical descriptions LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Content:PWA Progressive Web Apps content size/l [PR only] 501-1000 LoC changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants