Je me suis cassé la tête ces dernières semaines en essayant de gérer proprement les traductions côté JS sur Hyvä (poke EasierLabs). Knockout, dans l’écosystème Magento classique, supporte facilement des traductions côté client. Hyvä vend la performance et la simplicité, mais laisse ce genre de petites choses derrière. J’ai cherché des recettes, fouillé les forums, tenté des bricolages : la solution la plus fréquente que je trouvais revenait toujours au même pattern un peu moche — coller des x-show
/x-text
avec la traduction déjà résolue dans le .phtml
sinon, passer par une constante window. Ça marche, mais ça force tout le rendu côté serveur et sabote un peu la propreté de l’interface JS quand on veut rester « minimal Alpine ».
<script>
window.WORDING = "<?= $escaper->escapeJs($wording) ?>";
</script>
HTMLPuis
const prefix = (window.WORDING && window.WORDING !== '') ? window.WORDING : '';
const value = saving > 0 ? fmtPrice(saving) : fmtPrice(price);
savingEl.textContent = `${prefix}${value}`;
JavaScriptC’est long et fastidieux.
Je refais mon plus vieux site, creationdeperso.com en ligne depuis le 12/02/2004 et encore en PHP5 sur un serveur en php7 (si, si). Je me suis dit que j’allais demander à mes stagiaires (Mistral, ChatGPT et Copilot) de le mettre au propre. C’était un moyen de voir comment chacun gère la migration de l’existant. J’ai voulu rester raisonnable : PHP pour le back, Twig pour le HTML parce que je ne suis pas totalement taré, et Alpine.js pour les interactions parce que je veux quelque chose de léger, sans bundler, sans pipeline compliqué. Bref : zero drama, max velocity (et pas totalement inconnu).
Le site est multilingue et c’est en essayant de gérer les traductions dans alpinejs avec twig que la lumière m’est apparue. Il existe un petit pattern simple, robuste et réutilisable : produire le JSON de traductions côté Twig (avec json_encode(JSON_UNESCAPED_UNICODE)
), l’échapper pour un attribut HTML, puis le parser côté Alpine (x-init="translations = JSON.parse($el.dataset.translations)"
). Résultat : pas de requêtes supplémentaires, pas de innerHTML
dangereux, et la liberté d’écrire des helpers JS comme translateStat(key)
côté Alpine.
Dans la suite, je te montre exactement comment faire — le code, les pièges à éviter (guillemets, retours à la ligne, double-encodage) et la version Magento/Hyvä adaptée.
Traduction dans Twig
Il faut génèrer ton tableau de traductions côté serveur, transformer en JSON sans échapper les caractères unicode, puis échapper pour un attribut HTML.
{# templates/_translations.twig #}
{% set translations = {
"users": "Utilisateurs",
"welcome": "Bienvenue \"ami\"",
"multiline": "Ligne 1\nLigne 2"
} %}
<div
x-data="translationsComponent()"
x-init="translations = JSON.parse($el.dataset.translations)"
data-translations="{{ translations|json_encode(constant('JSON_UNESCAPED_UNICODE'))|e('html_attr') }}"
>
<p x-text="translateStat('welcome')"></p>
</div>
<script>
function translationsComponent() {
return {
translations: {},
translateStat(key){ return this.translations[key] ?? key; }
}
}
</script>
TwigPoints clés :
json_encode(JSON_UNESCAPED_UNICODE)
→ garde les accents lisibles.|e('html_attr')
→ protège l’attributdata-…
contre les guillemets et XSS.- Côté JS :
JSON.parse($el.dataset.translations)
est simple et sûr.
Traduction dans Hyvä
Il faut préparer les traductions dans un ViewModel.
public function getTranslationsJson(): string
{
$translations = [
'users' => __('Users')->render(),
'welcome' => __('Welcome "%1"', 'ami')->render()
];
return json_encode($translations, JSON_UNESCAPED_UNICODE);
}
PHPPuis dans le phtml, on peut échapper le json
<?php $json = $vm->getTranslationsJson(); ?>
<div
x-data="translationsComponent()"
x-init="translations = JSON.parse($el.dataset.translations)"
data-translations="<?= $block->escapeHtmlAttr($json); ?>"
>
<p x-text="translateStat('welcome')"></p>
</div>
PHPConclusion
C’était pour la logique globale. J’ai conçu un petit module qui permet d’automatiser la récupération des traductions et de permettre l’utilisation de $t(‘chaîne à traduire’) dans le js comme dans x-text.
Laisser un commentaire
Vous devez vous connecter pour publier un commentaire.