Aller au contenu principal
Site en cours de refonte — quelques pages peuvent bouger ou évoluer.
13 mai 2026

Localiser le manifest de ta PWA : bonne idée… jusqu’au moment où ton app a 3 noms différents

Localiser le nom et les shortcuts d’une PWA, c’est super… tant que tu ne crées pas une app incohérente selon l’écran. Voilà comment le faire proprement, et quoi tester.

11 min de lecture
161 vues
réactions
Partager :
Localiser le manifest de ta PWA : bonne idée… jusqu’au moment où ton app a 3 noms différents

Tu as une PWA multi-langue. Ton UI est déjà traduite. Et pourtant, au moment le plus “produit” de ton expérience, l’installation, ton app s’appelle en anglais, avec une description en français, et des shortcuts mi-traduits. Ça fait cheap. Et le pire, c’est que ça arrive vite, même sur des équipes sérieuses, parce que le Web App Manifest a longtemps été pensé comme un fichier “technique”, pas comme une surface UX.

Bonne nouvelle : le manifest peut maintenant embarquer des variantes localisées. Mauvaise nouvelle : si tu le fais à moitié, tu fabriques un flou produit très visible sur Android et desktop. On va donc parler implémentation, mais surtout cohérence et QA terrain.

Manifest PWA localisé : ce que ça change vraiment côté expérience “home screen”

Quand un utilisateur installe ta PWA, il ne “bookmark” pas une page. Il ajoute une app à son launcher, à son dock, à son menu démarrer. Et à ce moment-là, ton manifest devient ton packaging. Le name devient un libellé dans des UI système. Le short_name se retrouve tronqué sous une icône. Les shortcuts deviennent des entrées accessibles en appui long. Même la description peut être affichée dans des écrans d’installation ou de gestion.

Donc oui, pouvoir localiser tout ça, c’est une vraie amélioration. Mais ce n’est pas “un détail i18n”. Tu touches à l’identité visible de ton produit, en dehors de ton DOM, avec des comportements qui varient selon plateformes. C’est exactement le genre de truc qui, s’il est incohérent, fait perdre confiance sans que l’utilisateur sache l’expliquer.

Ce qui est localisable dans le Web App Manifest (et ce qui doit rester cohérent)

Le support de la localisation vise les champs qui sont, par nature, du texte produit et de l’UX writing : name, short_name, description, mais aussi des éléments plus piégeux comme les shortcuts (leurs noms, leurs descriptions) et, selon le support, certains sous-objets associés. L’idée n’est pas juste de traduire une string. C’est de pouvoir fournir une version “complète” du manifest par langue, avec un fallback propre vers une langue par défaut.

Le premier réflexe que je recommande : considère ces champs comme un contrat de cohérence. Si tu localises name mais pas short_name, tu crées très vite un mismatch : un nom en français dans la boîte d’installation, puis un libellé en anglais sous l’icône. Si tu localises les shortcuts mais que tes routes ne sont pas cohérentes avec ton routing i18n, tu envoies des gens sur des pages dans une autre langue depuis un menu système. Ça ne “bug” pas, mais ça fait amateur.

Un exemple de manifest avec traductions (et un fallback qui tient debout)

Le modèle introduit côté Chrome repose sur une langue par défaut et un dictionnaire de traductions par locale (tags BCP 47 du style fr, fr-FR, en, en-GB). Ce qui compte, ce n’est pas de mémoriser le nom exact de chaque champ, c’est de retenir l’intention : tu déclares une base + des overrides par langue, au même endroit, et tu laisses le navigateur choisir la meilleure variante.

{
  "name": "Devmy App",
  "short_name": "Devmy",
  "description": "A demo PWA.",
  "lang": "en",
  "start_url": "/",
  "display": "standalone",
  "shortcuts": [
    {
      "name": "New post",
      "url": "/new"
    }
  ],
  "translations": {
    "fr": {
      "name": "Appli Devmy",
      "short_name": "Devmy",
      "description": "Une PWA de démo.",
      "shortcuts": [
        {
          "name": "Nouveau post",
          "url": "/fr/new"
        }
      ]
    }
  }
}

Deux remarques de terrain. D’abord, ne sur-spécifie pas 12 variantes si tu n’as pas une vraie stratégie fr vs fr-FR vs fr-CA. Ça se transforme vite en dette, et le jour où tu changes une accroche marketing, tu oublies une langue et c’est reparti pour du flou. Ensuite, fais attention aux URLs dans les shortcuts : localiser le libellé sans localiser la destination, ça crée des expériences “bizarres” à base de menu en français qui ouvre une page en anglais.

Organiser tes locales : une seule source de vérité, sinon tu vas diverger

Le piège classique, c’est d’avoir trois systèmes qui vivent chacun leur vie : tes JSON i18n côté app, tes meta SEO, et ton manifest. Au début, ça va. Puis tu renames une feature, tu changes un terme produit, tu ajustes un tone of voice, et tu oublies le manifest. Résultat : l’app “s’installe” avec un vocabulaire ancien. Et comme cette UI est en dehors de ton app, personne ne le voit pendant les reviews.

Ce que je fais quand je veux que ça reste propre dans le temps : je choisis une source de vérité pour les libellés “produit” qui doivent exister aussi dans le manifest. Pas forcément toutes tes traductions, juste celles qui impactent l’installation et les shortcuts. Et je génère le manifest à partir de ça.

Build-time vs runtime : mon choix est (presque) toujours “build-time”

Techniquement, tu peux servir ton manifest de plusieurs façons. Certains veulent un endpoint dynamique qui renvoie un JSON selon Accept-Language. Ça marche… jusqu’au moment où tu mets un CDN devant, où tu oublies de varier correctement le cache, ou où tu découvres que tes outils (Lighthouse, audits, intégrations) n’aiment pas les comportements “magiques”.

Dans la vraie vie, je préfère une approche simple : un manifest “principal” stable, avec ses traductions embarquées, produit au build. Tu maîtrises le diff, tu peux reviewer, et tu peux tester localement comme en prod. Si tu as déjà un pipeline i18n, c’est facile de brancher une étape qui injecte les valeurs “manifest” depuis tes fichiers de traduction.

// Exemple volontairement simple : générer un manifest à partir de messages i18n.
import fs from "node:fs";

const fr = JSON.parse(fs.readFileSync("./locales/fr.json", "utf8"));
const en = JSON.parse(fs.readFileSync("./locales/en.json", "utf8"));

const manifest = {
  name: en.app_name,
  short_name: en.app_short_name,
  description: en.app_description,
  lang: "en",
  start_url: "/",
  display: "standalone",
  translations: {
    fr: {
      name: fr.app_name,
      short_name: fr.app_short_name,
      description: fr.app_description
    }
  }
};

fs.writeFileSync("./public/manifest.webmanifest", JSON.stringify(manifest, null, 2));

Le point important n’est pas le script, c’est la discipline : si tu acceptes que le manifest soit un artefact généré, tu réduis fortement les incohérences. Et tu peux imposer des garde-fous, par exemple une longueur max pour short_name (sinon tu te fais tronquer), ou l’interdiction de “pseudo-locales” qui se retrouvent en prod.

Le piège produit : éviter 3 noms différents selon l’écran

Sur Android et desktop, tu vas vite croiser des endroits différents où le nom apparaît. L’invite d’installation peut afficher name. Sous l’icône, c’est souvent short_name. Dans certains écrans de gestion, tu peux revoir un autre champ. Si tu traduis “à l’instinct”, tu finis avec des variations qui ont l’air minimes côté dev, mais énormes côté user.

Mon avis est assez tranché : pour une app grand public, short_name doit être pensé comme un label d’icône, pas comme un champ “au cas où”. Donc court, stable, pas de gimmick marketing. Et surtout, cohérent entre langues. Si ta marque est « Devmy », ne t’amuse pas à traduire en « Mon Devmy » dans une langue, puis à garder « Devmy » ailleurs. C’est exactement comme changer le nom d’un package dans un store : tu perds des repères.

Shortcuts : le détail qui te trahit (URLs, wording, et promesses)

Les shortcuts, c’est super… et c’est aussi une façon très rapide de créer de la confusion. Déjà parce que tu vas les traduire, et que certaines langues explosent naturellement en longueur. Ensuite parce que les shortcuts sont des promesses : si tu appelles un shortcut « Nouveau post » et qu’il ouvre un écran qui commence par te demander de te connecter dans une autre langue, tu as raté ton coup.

Le truc que je teste systématiquement : est-ce que chaque shortcut reste vrai après installation, après logout, et après changement de langue. Et est-ce que l’URL est la bonne selon ton routing i18n. Si ton app bascule la langue via un cookie ou du localStorage, mais que tes URLs sont neutres, ça peut aller. Si tes URLs sont préfixées (/fr, /en), alors tes shortcuts doivent l’être aussi, sinon tu envoies l’utilisateur dans un mélange étrange.

QA terrain : ce que je teste, parce que c’est là que ça part en vrille

Sur le papier, localiser le manifest est simple. En QA, c’est plus sport, parce que tu testes une interaction entre le navigateur, l’OS, l’état “installé”, et ton déploiement. Je fais toujours au moins ces vérifications sur Chrome Android et sur desktop Chrome.

D’abord, je teste l’installation avec l’OS en français puis en anglais, sur un profil propre. Pas sur mon téléphone de dev rempli de caches et d’anciennes installations. Je vérifie le nom dans la UI d’installation, le libellé sous l’icône, et les shortcuts. Ensuite, je teste le comportement après mise à jour : je déploie une nouvelle version qui change le texte du manifest, et j’observe ce qui se met réellement à jour côté app installée. Selon les plateformes, tout ne se rafraîchit pas comme tu l’imagines. Donc évite de compter sur une “renommage” immédiat en prod pour corriger une erreur.

Enfin, et c’est le point qui surprend souvent : je change la langue après installation. L’utilisateur change la langue système, ou change la langue dans ton app. Est-ce que le nom affiché par l’OS suit ? Pas toujours. Et c’est logique : l’icône sur le launcher n’est pas ton DOM. Donc ton objectif n’est pas de promettre un changement parfait en live. Ton objectif est d’éviter un mix incohérent, et d’avoir une stratégie de fallback claire.

Aligner manifest, <html lang>, routing i18n et SEO : sinon tu envoies des signaux contradictoires

Le manifest localisé ne remplace pas ton i18n web classique. Il s’ajoute. Et si tu veux un produit propre, il faut que ça raconte la même histoire : le lang du document, tes hreflang (si tu en as), ta structure d’URLs, et les textes “produit” dans le manifest.

Un cas que je vois : des équipes qui ont une pseudo-locale en interne (genre du texte volontairement accentué pour repérer les oublis) et qui la laissent traîner dans un fichier de build. Si tu embarques ça dans le manifest, tu peux te retrouver avec une PWA installable dont le nom ressemble à un test. Ça fait rire en staging, beaucoup moins en prod. Même logique pour les traductions “placeholder” : si elles vivent dans ton manifest, elles vivent sur l’écran d’accueil des gens.

Compat et limites : ne vends pas une promesse cross-browser que tu ne tiens pas

Le support de la localisation du manifest est porté côté Chrome, et il faut être lucide : l’écosystème PWA n’est pas homogène. Entre Chrome Android, Chrome desktop, et d’autres navigateurs, les comportements diffèrent déjà sur l’installation elle-même. Donc traite la localisation comme un progressive enhancement : ça doit améliorer l’expérience quand c’est supporté, sans casser ton installation quand ça ne l’est pas.

Concrètement, garde une base propre en langue par défaut. Considère tes traductions comme des overrides. Et ne fais pas dépendre une logique critique d’une locale côté manifest. Le manifest, c’est de l’affichage et du packaging. Ton app doit rester robuste sans lui.

Conclusion : localiser le manifest, c’est bien. Localiser le produit, c’est mieux.

Je suis content de voir la localisation arriver dans le Web App Manifest, parce que c’était un angle mort évident. Mais c’est aussi un nouveau terrain de bugs “soft” : pas des crashs, des incohérences. Des petits trucs qui donnent l’impression que ton app n’est pas finie.

Si tu dois retenir une seule règle : traite ton manifest comme une surface UX au même titre que ton header ou ton onboarding. Une PWA installée, c’est une app. Et une app avec un nom bancal et des shortcuts incohérents, ça se désinstalle vite.

Sources

Cet article vous a plu ?

Commentaires

Laisser un commentaire

Entre 10 et 2000 caractères

Les commentaires sont modérés avant publication.

Aucun commentaire pour le moment.

Soyez le premier à donner votre avis !