How to translate a PWA app manifest
Tags: javascript, webdev, pwa, tutorial
Published: 2022-10-11 03:38:22

As of October 2022, there's no native way to localize properties of the [web app manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) in multiple languages. Although there's been an [open request for that since 2018](https://github.com/w3c/manifest/issues/676), so far there's no definitive way to achieve this with a conventional static app manifest file.

In this article, I'll tell you about the three methods you can use to localize your PWA manifest, including the one I'm using to provide the localization functionality at [Progressier](https://progressier.com?ref=devtolocalizemanifest).

## Method 1: Static app manifests

If your app has properly scoped language versions hosted at their own URLs, you can simply create different app manifest for each of them.

Say your English app is at `https://example.com/en/` and your French app is at `https://example.com/fr/`, then you can simply host the manifests at `https://example.com/en/manifest.json` and `https://example.com/fr/manifest.json` respectively.

This would work similarly if your English app is at `example.com` and your French app is at `fr.example.com`. You'd then host your manifests at `example.com/manifest.json` and `fr.example.com/manifest.json`

The first drawback of that method is that browsers consider each entity unique PWAs. So when a user installs the English version from `example.com`, they'll be prompted to install the French version when they access `fr.example.com`.

Not great.

Counterintuitively, in this specific case, having [overlapping scopes](https://web.dev/building-multiple-pwas-on-the-same-domain/#overlappingnested-paths) would actually be the better option. 

The second issue is that this method violates [Don't Repeat Yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principles. In the long run, this is harder to manage and tends to lead to errors. It also doesn't scale well — if tomorrow your app is available in 20 different languages, do you really want to modify 20 different manifest files whenever you update your logo?

## Method 2: Server-side dynamic app manifest generation

In general, one PWA = one app manifest. A PWA typically isn't updatable after installation if the URL of the manifest changes. So you should strive to keep the URL of the manifest unchanged as much as possible — even if it might be possible to do things a bit differently now thanks to the new [id](https://developer.chrome.com/blog/pwa-manifest-id/) property.

A more scalable approach is to generate the manifest server-side instead of simply storing it as a static asset. This is the method I use at [Progressier](https://progressier.com?ref=devtolocalizemanifest).

Browsers automatically add a [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header to every `fetch` request. The Accept-Language is determined based on the user's preferred language set in their browser. If you're using Chrome, you can define your own list of preferred languages at `chrome://settings/languages`.

Here is how to translate your manifest server-side:

1. Link to the manifest as usual in your client-side code. Simply add `<link rel="manifest" href="https://example.com/manifest.json">` between the `<head>` and `</head>` tags in your HTML document.
2. In your server-side code, add a GET route for `/manifest.json` 
3. Get the `Accept-Language` header
4. See if you have localized content that matches that header. If so, use it in your app manifest. Else, fall back to your default language.

Here is a complete example using Node/Express:

{% embed https://gist.github.com/kbstt/8d0fe5a0dcf112445fb66a37f6635403 %}

This is a user-level setting, and since the manifest is automatically fetched by the browser based on the meta tag you add to the `<head>` of the HTML document, it's not possible to directly overwrite the `Accept-Language` header. 

In other words, it won't work hand in hand with a dropdown menu that would allow users to select the language themselves — it'll just still use their browser language. 

```
<link rel="manifest" href="https://example.com/manifest.json">
```

The above does not offer any way to overwrite headers added to the `fetch` request for that specific asset.

There's one slightly convoluted way to achieve this: by intercepting the `fetch` request in the service worker, and then manually changing the `Accept-Language`. Since you'll need the service worker to be registered for that to work, the very first fetch request for the manifest might not return a JSON file in the right language. Plus, you'll have to make sure it uses the right caching strategy.

## Method 3: Progressier

If you're using [Progressier](https://progressier.com?ref=devtolocalizemanifest), localizing your app manifest is fairly easy. Since the platform is entirely no-code, all you have to do is click on the _Localize_ button next to any of your manifest's parameters, choose a language, and translate. The rest is automatically taken care of for you.

![Localizing an app manifest in Progressier](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w97s582ls4u5acc9bdio.gif)

In Progressier, you can localize any of the following manifest parameters: `name`, `short_name`, `description`, `start_url`, `screenshots` in any of these 108 languages: _English, Afrikaans, Albanian, Amharic, Arabic, Armenian, Azerbaijani, Basque, Belarusian, Bengali, Bosnian, Bulgarian, Catalan, Cebuano, Chinese, Corsican, Croatian, Czech, Danish, Dutch, Esperanto, Estonian, Finnish, French, Frisian, Galician, Georgian, German, Greek, Gujarati, Haitian Creole, Hausa, Hawaiian, Hebrew, Hindi, Hmong, Hungarian, Icelandic, Igbo, Indonesian, Irish, Italian, Japanese, Javanese, Kannada, Kazakh, Khmer, Kinyarwanda, Korean, Kurdish, Kyrgyz, Lao, Latin, Latvian, Lithuanian, Luxembourgish, Macedonian, Malagasy, Malay, Malayalam, Maltese, Maori, Marathi, Mongolian, Myanmar (Burmese), Nepali, Norwegian, Nyanja (Chichewa), Odia (Oriya), Pashto, Persian, Polish, Portuguese, Punjabi, Romanian, Russian, Samoan, Scots Gaelic, Serbian, Sesotho, Shona, Sindhi, Sinhala (Sinhalese), Slovak, Slovenian, Somali, Spanish, Sundanese, Swahili, Swedish, Tagalog (Filipino), Tajik, Tamil, Tatar, Telugu, Thai, Turkish, Turkmen, Ukrainian, Urdu, Uyghur, Uzbek, Vietnamese, Welsh, Xhosa, Yiddish, Yoruba, Zulu_.

It also works pretty well with the `screenshots` property. Progressier comes with a complete solution for [designing and managing screenshots](https://progressier.com/pwa-screenshots-generator).

Questions? Feedback? Please let me know!