/translation — Customiser les traductions Sylius
Tu aides à redéfinir un libellé traduit (label de form, texte de bouton, message flash, message de validation) dans un projet Sylius sans patcher le vendor. Le pattern officiel : créer / éditer translations/<domaine>.<locale>.yaml à la racine du projet (ou du plugin) en reprenant la même clé que celle déclarée par le bundle Sylius concerné. Symfony merge les catalogues et l'override applicatif gagne.
Référence officielle : docs.sylius.com/the-customization-guide/customizing-translations.
Détection préalable (obligatoire)
- Lire
composer.jsonà la racine. - Vérifier
sylius/syliusdans les dépendances.- Présent → OK.
- Absent → « Ce skill cible Sylius (override du catalogue
translations/appliqué par le Translator Symfony). Je ne trouve passylius/sylius. On continue quand même ou on bascule sur/symfony:translationpour un projet Symfony générique ? »
- Si la demande est « ajouter des champs multilingues à une entité » (pas surcharger un libellé UI) → basculer sur
/sylius:translation-entity: c'est un pattern Doctrine (TranslatableTrait,*Translation), rien à voir avec le catalogue de messages. - Si la demande concerne un message d'erreur de contrainte Symfony (
#[Assert\Length], etc.) → la clé vit en général sous le domainevalidatorset la contrainte elle-même se redéfinit via/sylius:validation. Revenir ici seulement pour traduire la clé dans les locales.
Règles fondamentales
- Un fichier par locale, par domaine : la convention Symfony est
<domaine>.<locale>.<format>. Sylius utilise principalement quatre domaines :messages→ libellés UI, titres, boutons, labels de form (domaine par défaut).validators→ messages d'erreur de contraintes Symfony / Sylius.flashes→ messages flash après action (sylius.product.create, etc.).security→ messages liés à l'authentification (Symfony Security). Ne pas mélanger : un libellé de bouton sousvalidators.en.yamlne sera jamais chargé par le form qui regardemessages.
- L'override reprend exactement la même clé que le vendor. Le Translator Symfony merge les catalogues avec un ordre de priorité application > plugins > bundles vendor : la dernière source qui déclare la clé gagne. Pas besoin de redéclarer les clés voisines — seule la clé override est écrite dans le fichier applicatif, le reste continue de venir du vendor.
- Les clés Sylius sont structurées en YAML imbriqué, mais référencées à plat dans le code (
sylius.form.customer.email). Respecter l'arborescence exacte du vendor, sinon la clé n'est pas matchée :sylius: form: customer: email: Username # override de sylius.form.customer.email - Une clé par locale à maintenir : si le projet supporte
en,fr,pl, et que tu overridesylius.form.customer.email, il faut écrire l'override dans chaquemessages.<locale>.yamlque tu veux voir affecté. Sinon seuls les visiteurs de la locale modifiée voient le libellé custom ; les autres retombent sur la traduction vendor (ou lafallback_localesi la locale n'est pas couverte du tout). - Fallback locale (
translator.fallbacksdansconfig/packages/translation.yaml, ouframework.default_locale) s'applique clé par clé : simessages.pl.yamln'a pas la clé et que le fallback esten, Symfony remonte laen. Utile en dev, piège en prod : une clé oubliée en polonais s'affichera en anglais sans warning. - Cache obligatoire après toute modif des fichiers
translations/enprod:php bin/console cache:clear. Endev, le Translator recharge automatiquement (watcher sur le dossier) — mais si rien ne change à l'écran, vider quand même. - Override dans un plugin : un plugin Sylius qui embarque des traductions les place dans
src/<Plugin>/Resources/translations/<domaine>.<locale>.yaml(outranslations/à la racine du bundle selon la version). Depuis l'application, on peut re-override les clés du plugin danstranslations/de l'app — l'ordre de priorité resteapp > plugin > core. - Clés introuvables dans le YAML vendor : certaines chaînes viennent du code PHP (exceptions, messages flash construits à la volée, attributs
#[Groups]). Elles sont toujours repérables via le Profiler ; ne pas les chercher dans les sources YAML du bundle.
Déroulement
1 — Cadrer le besoin
Demander (ou confirmer si déjà fourni) :
- Chaîne source à remplacer (ex.
"Email","Add to cart","Last name"). - Nouvelle chaîne à afficher (ex.
"Username","Buy now","Surname"). - Locale(s) concernée(s) :
en,fr,pl, etc. Lister toutes les locales actives du projet (voirconfig/packages/translation.yaml→framework.enabled_localesouframework.translator.fallbacks). - Portée : shop, admin, ou les deux ? (Certaines clés sont partagées —
sylius.form.address.streetvit des deux côtés — d'autres sont scoped sur un bundle.) - Domaine probable : label / bouton →
messages. Erreur de validation →validators. Message flash post-action →flashes. Message de login →security.
2 — Repérer la clé exacte via Symfony Profiler
Le chemin rapide, imposé par la doc Sylius :
- Lancer le serveur de dev :
symfony serve -d(ousymfony server:start). - Ouvrir la page qui affiche le libellé à changer.
- Cliquer sur la toolbar Symfony en bas → onglet Translations (icône globe).
- Filtrer la colonne « Message » sur le texte à modifier → lire la clé et le domaine exacts dans les colonnes de gauche.
Alternative ligne de commande, utile pour valider qu'une clé est bien déclarée :
# Chercher une clé dans tous les catalogues chargés pour une locale
php bin/console debug:translation en --domain=messages | grep -i "email"
# Lister les clés manquantes dans une locale (par rapport au fallback)
php bin/console debug:translation pl --only-missing
Alternative repository : grep direct dans les YAML vendor du bundle concerné.
# Pour une clé shop/checkout/customer form
grep -r "Email" vendor/sylius/sylius/src/Sylius/Bundle/CustomerBundle/Resources/translations/
3 — Créer (ou éditer) le fichier translations/<domaine>.<locale>.yaml
Exemple : remplacer "Email" par "Username" sur le form client, en anglais.
# translations/messages.en.yaml
sylius:
form:
customer:
email: Username
Puis, pour couvrir le français :
# translations/messages.fr.yaml
sylius:
form:
customer:
email: Nom d'utilisateur
Points de vigilance :
- Respecter l'indentation YAML à 4 espaces comme les fichiers Sylius — un désalignement d'un niveau casse le merge (la clé ne matche pas).
- Ne pas copier tout le catalogue vendor dans le fichier applicatif. Seule la clé override est nécessaire. Laisser le reste venir du vendor évite de rater les nouvelles traductions ajoutées aux updates Sylius.
- Apostrophes / caractères spéciaux : quoter la valeur si elle contient
:,#, ou commence par-/?. YAML peut sinon mal parser :some_key: "Ajouter au panier : c'est parti" - Placeholders Symfony (
{{ limit }},%count%) : conserver exactement les mêmes placeholders que la version vendor — sinon la chaîne s'affiche avec le placeholder brut.
4 — Cas domaine validators
Exemple : override du message « This value is too short » sur la longueur min d'un Product.name.
# translations/validators.en.yaml
sylius:
product:
name:
min_length: 'The product name is too short. It must be at least {{ limit }} characters long.'
La clé doit correspondre à ce qui est déclaré dans la contrainte côté config/validator/ProductTranslation.yaml. Si tu viens de créer la contrainte avec /sylius:validation, la clé est probablement app.product.name.min_length — mets-la dans le même domaine validators.<locale>.yaml.
5 — Cas domaine flashes
Les messages flash Sylius suivent la convention sylius.<resource>.<action> (ex. sylius.product.create, sylius.customer.update). Override :
# translations/flashes.en.yaml
sylius:
product:
create: Product successfully registered!
Pour vérifier la clé exacte, inspecter la réponse HTTP après l'action ou grep FlashHelper / FlashBag dans le controller concerné.
6 — Override depuis un plugin Sylius
Si tu livres la customisation dans un plugin (pas dans config/ applicatif) :
src/MyPluginBundle/Resources/translations/messages.en.yaml
src/MyPluginBundle/Resources/translations/messages.fr.yaml
- Le Translator charge automatiquement les catalogues d'un bundle enregistré. Pas de configuration supplémentaire nécessaire.
- L'application peut toujours re-override : si
my_pluginchangesylius.form.customer.email: "Login"et que l'app veut"User ID", écriresylius.form.customer.email: "User ID"danstranslations/messages.en.yaml(applicatif) suffit. L'app gagne.
7 — Vérifier
# Vider le cache (obligatoire en prod, recommandé en dev)
php bin/console cache:clear
# Recharger la page dans le navigateur et confirmer le nouveau libellé
# Optionnel : dumper tous les catalogues pour la locale
php bin/console debug:translation en
Si le libellé n'a pas changé :
- la clé ou le domaine est faux → vérifier via le Profiler, pas deviner ;
- l'indentation YAML diverge du vendor → la clé ne matche pas ;
- mauvaise locale visitée → l'override ciblait
fr, mais le visiteur est enen; - cache non vidé en
prod→cache:clearpuiscache:warmupsi déploiement ; - le texte vient d'un template Twig hardcodé (pas un
{{ 'sylius.form...' | trans }}) → l'override YAML ne peut rien, il faut override le template via/sylius:template.
8 — Clôture
Afficher :
- Fichiers créés/modifiés :
translations/<domaine>.<locale>.yamlpour chaque locale couverte. - Clé(s) override et domaine(s).
- Ce qui reste : couvrir les autres locales actives, répercuter côté admin et shop si la clé est partagée, pousser l'override dans le plugin ou le garder applicatif, ajouter un test smoke (ouvrir la page et asserter le libellé) si la chaîne est critique.
Pièges fréquents
- Mauvais domaine : déclarer
sylius.form.customer.email: Usernamedansvalidators.en.yaml. Le form litmessagespar défaut → la chaîne vendor reste affichée. Toujours confirmer le domaine via le Profiler. - Clé plate au lieu d'imbriquée : écrire
sylius.form.customer.email: Usernamecomme clé littérale (avec les points). YAML stocke alors la clé entière comme chaîne et Symfony ne la matche pas. Respecter l'arborescence YAML ou préfixer la clé plate avec!/''selon le format attendu (le YAML imbriqué est toujours plus sûr). - Override partiel sur une seule locale : les visiteurs
frvoient le libellé vendor, les visiteursenle nouveau. Soit assumé (locale-specific branding), soit bug — toujours lister les locales actives avant de boucler. - Placeholder supprimé : retirer
{{ limit }}duminMessage→ la chaîne s'affiche avec le nombre manquant, ou pire, le placeholder littéral{{ limit }}. Toujours conserver les mêmes placeholders que le vendor. - Modifier le fichier
vendor/sylius/…/translations/*.yamldirectement : saute aucomposer updatesuivant. Toujours écrire côtétranslations/applicatif ou plugin. - Template Twig avec texte hardcodé :
<button>Add to cart</button>au lieu de<button>{{ 'sylius.ui.add_to_cart' | trans }}</button>. Aucun override YAML ne changera ça — passer par/sylius:template(Twig hook ou overridetemplates/bundles/). - Cache non vidé en
prod: la modif reste invisible après déploiement.cache:clear+cache:warmupsystématiques. - Conflit app vs plugin : l'app et un plugin custom déclarent la même clé avec des valeurs différentes. L'app gagne (ordre de priorité) — le mainteneur du plugin ne comprend pas pourquoi son libellé ne passe pas. Documenter l'override applicatif pour éviter la confusion.
Argument optionnel
/sylius:translation sylius.form.customer.email Username en — override de la clé sylius.form.customer.email en anglais, domaine messages par défaut.
/sylius:translation sylius.ui.add_to_cart "Buy now" en,fr — override sur plusieurs locales en une passe.
/sylius:translation sylius.product.name.min_length "..." en --domain=validators — override dans le domaine validators.
/sylius:translation sans argument — demande la clé, la valeur, les locales, le domaine, et guide la détection via Symfony Profiler.