Übersetzungen¶
Jeder für Benutzer sichtbare String, den ein Plugin anzeigt, muss übersetzbar
sein, mit Katalogen für alle fünfzehn unterstützten Sprachen — en, pl, de,
fr, es, pt_PT, pt_BR, nl, sv, nb, da, fi, it, cs, sk —,
bevor das Plugin als fertig gilt. Das ist dieselbe Messlatte wie bei Tests.
Kataloge¶
Jedes Plugin, das irgendeinen String hat, führt einen .ts-Katalog pro
Sprache in seinem Ordner Translations/:
Binden Sie sie über mte_add_plugin in den Build ein:
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
)
Der Build führt lrelease aus, um .qm-Dateien bereitzustellen;
TranslationManager lädt sie zur Laufzeit anhand des Katalognamens
(Plugin-Kataloge unter Plugins/Translations/<Plugin>/).
Strings zur Übersetzung markieren¶
- Bevorzugen Sie
QObject::tr(...)(Kontext = die Klasse) für normale UI-Strings. - Der Helfer
tr_()umhülltQCoreApplication::translate("<Context>", s)für Strings außerhalb einesQObject.
tr_() ist für lupdate unsichtbar
lupdate kann den Kontext innerhalb von tr_() nicht auflösen, daher
werden diese Kataloge von Hand gepflegt. Halten Sie den
<source>-Text byte-identisch zum Laufzeit-String, sonst greift die
Übersetzung stillschweigend nicht.
Einer Sprachumschaltung bei geöffneter Seite folgen¶
Die Sprache der Benutzeroberfläche lässt sich in Einstellungen ▸ Allgemein
ohne Neustart ändern. Qt sendet dann QEvent::LanguageChange an jedes Widget —
aber ein Widget-Baum, dessen Strings einmal im aufbauenden Code gesetzt wurden,
bleibt bei der alten Sprache, bis der Dialog geschlossen und wieder geöffnet
wird.
PluginApi/Qt/Retranslator.h löst das, ohne jeden String zweimal zu schreiben.
Es zeichnet auf, wie jeder String entstanden ist, und spielt die Aufzeichnung
bei einem Sprachwechsel erneut ab:
#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()führt sein Lambda sofort aus, die Aufrufstelle liest sich also genau wie die ersetzte „Text setzen"-Zeile, und jeder String steht weiterhin einmal im Quelltext.row()tut dasselbe für eineQFormLayout-Beschriftung, die sonst nicht mehr erreichbar ist, sobaldaddRow()sie übernommen hat.installOn()ist pro Widget idempotent; der Rekorder ist ein Kind dieses Widgets und stirbt mit ihm. Kann Ihre Seite ein erfasstes Widget überleben, halten Sie es in einemQPointer.
Wie PluginApi/Qt/ISettingsPage.h ist dies ein Opt-in-Qt-Header: binden Sie ihn
nur aus Code ein, der ohnehin QWidgets baut (er benötigt Qt6::Widgets). Der
Qt-freie Teil von PluginApi bleibt unberührt.
Was nicht übersetzt wird¶
Zwei Dinge bleiben bewusst in der Sprache, in der ihr Autor sie geschrieben hat:
nameunddescriptionIhres Plugins ausplugin.json, angezeigt unter Einstellungen ▸ Erweiterungen. Das Manifest wird gelesen, bevor das Plugin geladen wird — genau das erlaubt der Seite, auch deaktivierte oder gegen eine andere API-Version gebaute Plugins aufzulisten — es gibt zu diesem Zeitpunkt also keinen Katalog, in dem man sie nachschlagen könnte.- Die Beschriftungen einer deklarativen (Python-)Einstellungsseite oder eines Dock-Panels. Sie sind Daten, die Ihr Worker an den Host sendet, und keine Strings, die der Host gegen einen Katalog auflösen könnte.
Alles, was ein Plugin zur Laufzeit registriert — Befehlstitel, Menüeinträge, Dock-Titel, Beschriftungen der Einstellungsseite — wird auf die oben beschriebene übliche Weise übersetzt.
Drei dieser Strings schlägt der Host nach, nicht Ihr Code, und zwar im
gemeinsamen Kontext PluginMenus: jedes Segment eines menuPath, jeder
Befehls-title und die category des Befehls. Liefern Sie alle drei als
<source>-Einträge im Kontext PluginMenus Ihrer eigenen Kataloge aus. Die
Kategorie ist, was der Nutzer in der Spalte Kategorie von Einstellungen ▸
Tastenkürzel liest; fehlt sie im Katalog, zeigt die Spalte das rohe englische
Wort neben den übersetzten Kernzeilen. Eine Kategorie, die auch ein Menütitel ist
(Search, Encoding), teilt sich einen Eintrag: behalten Sie darin den
&-Mnemonic für das Menü, der Host entfernt ihn für die Spalte.
Definition of Done¶
Die Lokalisierung eines Plugins ist erst fertig, wenn alle fünfzehn
.ts-Dateien existieren, eingebunden sind und lrelease 0 unfertige Strings
meldet.