Traductions¶
Chaque chaîne visible par l'utilisateur qu'un plugin affiche doit être
traduisible, avec des catalogues pour les quinze langues prises en charge —
en, pl, de, fr, es, pt_PT, pt_BR, nl, sv, nb, da, fi,
it, cs, sk — avant que le plugin ne soit considéré comme terminé. C'est la
même exigence que pour les tests.
Catalogues¶
Chaque plugin qui possède la moindre chaîne porte un catalogue .ts par
langue dans son dossier Translations/ :
Raccordez-les à la compilation via mte_add_plugin :
mte_add_plugin(NAME MyPlugin
SOURCES Src/MyPlugin.cpp
TRANSLATIONS
Translations/MyPlugin_en.ts
Translations/MyPlugin_pl.ts
Translations/MyPlugin_de.ts
Translations/MyPlugin_fr.ts
)
La compilation exécute lrelease pour préparer les fichiers .qm ;
TranslationManager les charge par nom de catalogue à l'exécution (les
catalogues des plugins sous Plugins/Translations/<Plugin>/).
Marquer les chaînes pour la traduction¶
- Préférez
QObject::tr(...)(contexte = la classe) pour les chaînes UI ordinaires. - L'assistant
tr_()enveloppeQCoreApplication::translate("<Context>", s)pour les chaînes situées hors d'unQObject.
tr_() est invisible pour lupdate
lupdate ne peut pas résoudre le contexte à l'intérieur de tr_(), ces
catalogues sont donc maintenus à la main. Gardez le texte <source>
identique octet pour octet à la chaîne d'exécution, sinon la traduction
ne s'appliquera silencieusement pas.
Suivre un changement de langue alors qu'une page est ouverte¶
L'utilisateur peut changer la langue de l'interface dans Préférences ▸
Général sans redémarrer. Qt envoie alors QEvent::LanguageChange à chaque
widget — mais un arbre de widgets dont les chaînes ont été définies une seule
fois, dans le code qui l'a construit, reste dans l'ancienne langue jusqu'à ce
que la boîte de dialogue soit fermée puis rouverte.
PluginApi/Qt/Retranslator.h règle cela sans écrire chaque chaîne deux fois. Il
enregistre comment chaque chaîne a été produite et rejoue l'enregistrement au
changement de langue :
#include <PluginApi/Qt/Retranslator.h>
QWidget* MyPage::createWidget(QWidget* parent)
{
auto* page = new QWidget(parent);
auto& rt = MTE::plugin::Retranslator::installOn(page);
m_watch = new QCheckBox(page);
rt.add([this] { m_watch->setText(tr_("Watch open files")); });
m_size = new QSpinBox(page);
rt.row(form, m_size, [] { return tr_("Font size:"); }); // QFormLayout caption
return page;
}
add()exécute sa lambda immédiatement : le site d'appel se lit exactement comme la ligne « définir le texte » qu'il remplace, et chaque chaîne n'apparaît toujours qu'une fois dans votre source.row()fait de même pour une légende deQFormLayout, autrement inaccessible une fois qu'addRow()l'a consommée.installOn()est idempotent par widget ; l'enregistreur est un enfant de ce widget et meurt avec lui. Si votre page peut survivre à un widget capturé, conservez-le dans unQPointer.
Comme PluginApi/Qt/ISettingsPage.h, c'est un en-tête Qt optionnel : ne
l'incluez que depuis du code qui construit déjà des QWidget (il requiert
Qt6::Widgets). La partie de PluginApi sans Qt reste intacte.
Ce qui n'est pas traduit¶
Deux choses restent, à dessein, dans la langue dans laquelle leur auteur les a écrites :
- Les champs
nameetdescriptionde votre extension dansplugin.json, affichés dans Préférences ▸ Extensions. Le manifeste est lu avant que l'extension ne soit chargée — c'est précisément ce qui permet à la page de lister aussi les extensions désactivées ou compilées contre une autre version de l'API — il n'existe donc à ce moment aucun catalogue où les rechercher. - Les libellés d'une page de réglages ou d'un panneau déclaratif (Python). Ce sont des données que votre worker envoie à l'hôte, et non des chaînes que l'hôte pourrait résoudre dans un catalogue.
Tout ce qu'une extension enregistre à l'exécution — titres de commandes, entrées de menu, titres de panneaux, légendes de page de réglages — est traduit de la manière habituelle décrite ci-dessus.
Trois de ces chaînes sont recherchées par l'hôte, et non par votre code, dans
le contexte partagé PluginMenus : chaque segment d'un menuPath, chaque
title de commande et la category de la commande. Livrez les trois comme des
entrées <source> dans le contexte PluginMenus de vos propres catalogues. La
catégorie est ce que l'utilisateur lit dans la colonne Catégorie de
Préférences ▸ Raccourcis ; quand elle manque au catalogue, la colonne affiche
le mot anglais brut à côté des lignes du cœur traduites. Une catégorie qui est
aussi un titre de menu (Search, Encoding) partage une seule entrée :
conservez-y le mnémonique & pour le menu, l'hôte le retire pour la colonne.
Définition de « terminé »¶
La localisation d'un plugin n'est terminée que lorsque les quinze fichiers
.ts existent, sont raccordés, et que lrelease rapporte 0 chaîne non
finalisée.