Pourquoi un texte généré par un modèle de langage, syntaxiquement irréprochable en apparence, peut-il malgré tout produire un rendu incorrect une fois passé dans esc_html__() ? La réponse tient souvent à la typographie choisie par le modèle, qui privilégie spontanément des guillemets courbes ou des tirets longs, des caractères qui survivent à l’échappement HTML sans poser de problème de sécurité, mais qui détonnent visuellement dans une interface qui utilise par ailleurs une typographie différente.
Le vrai risque ne se situe pas dans la casse mais dans les caractères qui interagissent avec l’échappement lui-même : une esperluette isolée, un chevron non accompagné de son symétrique, ou une apostrophe qui perturbe un test de correspondance de chaîne réalisé en aval du texte.
Ce que fait esc_html__ et ce qu’il ne fait pas
La fonction esc_html__() combine deux opérations : une traduction via le domaine de texte fourni, puis un échappement des caractères spéciaux HTML via esc_html(). Elle protège contre l’injection de balises, mais elle ne reformule jamais le texte source, qu’il vienne d’un traducteur humain ou d’un modèle de langage.
echo esc_html__( $texte_genere, 'mon-plugin' );
Si $texte_genere contient déjà un caractère & isolé, non suivi d’une entité valide, esc_html() le transforme en &, ce qui affiche littéralement « & » à l’écran plutôt que l’esperluette attendue. Le problème ne vient pas de la fonction, mais du texte source qui contenait déjà une esperluette brute là où une entité aurait dû figurer, ou inversement.
Formuler une consigne qui anticipe l’échappement
La consigne envoyée au modèle gagne à préciser explicitement le format de sortie attendu, plutôt que de laisser le modèle choisir librement sa ponctuation :

Consigne :
« Rédige ce texte en français courant, sans balise HTML, sans entité HTML.
Utilise des guillemets droits ("...") plutôt que des guillemets typographiques.
N'utilise jamais le symbole & seul : écris "et" en toutes lettres. »
Pourquoi préférer « et » à l’esperluette
Demander explicitement d’éviter l’esperluette élimine une source récurrente de textes mal échappés en sortie, sans complexifier la consigne outre mesure. Ce choix reste spécifique au contexte : un texte destiné à une liste de tags peut légitimement conserver le symbole, à condition que le code d’affichage gère correctement l’échappement à ce niveau.
Valider malgré tout le texte reçu
Une consigne bien formulée réduit la fréquence des cas problématiques, elle ne les élimine pas. Une fonction de validation, appliquée systématiquement avant tout usage du texte, reste la seule garantie fiable :
function preparer_texte_genere( string $texte ): string {
$texte = wp_strip_all_tags( $texte );
$texte = html_entity_decode( $texte, ENT_QUOTES, 'UTF-8' );
$texte = str_replace( array( '“', '”', '‘', '’' ), array( '"', '"', "'", "'" ), $texte );
return trim( $texte );
}
echo esc_html__( preparer_texte_genere( $texte_genere ), 'mon-plugin' );
Le décodage préalable des entités, suivi d’un nouvel échappement via esc_html__(), évite le double échappement, un défaut fréquent qui affiche littéralement des séquences comme & lorsque le texte source contenait déjà des entités encodées par le modèle.
Le cas des chaînes utilisées comme identifiants de traduction
Un texte généré ne devrait jamais servir directement de chaîne source à traduire via __() : les fonctions de traduction du cœur attendent des chaînes littérales, connues à l’analyse statique par les outils d’extraction comme wp i18n make-pot. Un texte variable, généré dynamiquement, doit rester un simple texte affiché avec esc_html(), sans passer par le mécanisme de traduction du cœur.
- Chaîne fixe du plugin :
esc_html__( 'Résumé généré :', 'mon-plugin' ) - Contenu variable généré :
esc_html( $texte_genere ), sans domaine de texte - Ne jamais mélanger les deux dans un seul appel
Un texte généré dynamiquement n’est pas une chaîne à traduire, c’est un contenu à afficher : la distinction évite bien des confusions dans l’usage des fonctions d’internationalisation du cœur.
Ce qu’il faut retenir
Anticiper le format attendu dans la consigne envoyée au modèle réduit les cas problématiques, mais une validation systématique du texte reçu, avant tout échappement, reste indispensable. La distinction entre chaîne de traduction fixe et contenu variable généré évite par ailleurs un usage incorrect des fonctions d’internationalisation du cœur.