Traducciones¶
Toda cadena visible para el usuario que muestre un plugin debe ser traducible,
con catálogos para los quince idiomas admitidos —en, pl, de, fr, es,
pt_PT, pt_BR, nl, sv, nb, da, fi, it, cs, sk— antes de dar el
plugin por terminado. El listón es el mismo que el de las pruebas.
Catálogos¶
Cada plugin que tenga alguna cadena lleva un catálogo .ts por idioma en su
carpeta Translations/:
Conéctalos a la compilación mediante 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 compilación ejecuta lrelease para preparar los archivos .qm;
TranslationManager los carga por nombre de catálogo en tiempo de ejecución (los
catálogos de plugin, bajo Plugins/Translations/<Plugin>/).
Marcar cadenas para su traducción¶
- Prefiere
QObject::tr(...)(contexto = la clase) para las cadenas de interfaz normales. - El ayudante
tr_()envuelveQCoreApplication::translate("<Context>", s)para las cadenas que están fuera de unQObject.
tr_() es invisible para lupdate
lupdate no puede resolver el contexto dentro de tr_(), así que esos
catálogos se mantienen a mano. Mantén el texto de <source> idéntico byte
a byte a la cadena en tiempo de ejecución, o la traducción no se aplicará y no
lo dirá.
Seguir un cambio de idioma con una página abierta¶
El usuario puede cambiar el idioma de la interfaz en Preferencias ▸ General
sin reiniciar. Qt envía entonces QEvent::LanguageChange a todos los widgets;
pero un árbol de widgets cuyas cadenas se fijaron una sola vez, en el código que
lo construyó, conserva el idioma antiguo hasta que el diálogo se cierra y se
vuelve a abrir.
PluginApi/Qt/Retranslator.h se encarga de eso sin escribir cada cadena dos
veces. Registra cómo se produjo cada cadena y reproduce la grabación cuando
cambia el idioma:
#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()ejecuta su lambda de inmediato, así que el punto de llamada se lee exactamente igual que la línea de «pon el texto» a la que sustituye, y cada cadena sigue apareciendo una vez en tu código fuente.row()hace lo mismo con el rótulo de unQFormLayout, que de otro modo es inalcanzable una vez queaddRow()lo ha consumido.installOn()es idempotente por widget; el grabador es hijo de ese widget y muere con él. Si tu página puede sobrevivir a un widget que capturaste, guárdalo en unQPointer.
Igual que PluginApi/Qt/ISettingsPage.h, esta es una cabecera de Qt opcional:
inclúyela solo desde código que ya construye QWidget (necesita Qt6::Widgets).
La parte de PluginApi libre de Qt no se ve afectada.
Qué no se traduce¶
Dos cosas se quedan, por diseño, en el idioma en que su autor las escribió:
- El
namey ladescriptionde tu plugin enplugin.json, tal como aparecen en Preferencias ▸ Complementos. El manifiesto se lee antes de cargar el plugin —eso es lo que permite que la página liste plugins desactivados o compilados contra otra versión de la API—, así que en ese momento no hay ningún catálogo en el que buscarlos. - Las etiquetas de una página de ajustes o de un panel acoplable declarativos (de Python). Son datos que tu trabajador envía al anfitrión, no cadenas que el anfitrión pueda resolver contra un catálogo.
Todo lo que un plugin registra en tiempo de ejecución —títulos de comandos, entradas de menú, títulos de paneles, rótulos de páginas de ajustes— se traduce de la forma habitual descrita arriba.
Tres de esas cadenas las busca el anfitrión, no tu código, en el contexto
compartido PluginMenus: cada segmento de un menuPath, cada title de comando
y la category del comando. Entrega las tres como entradas <source> en el
contexto PluginMenus de tus propios catálogos. La categoría es lo que el usuario
lee en la columna Categoría de Preferencias ▸ Atajos de teclado; cuando falta en el
catálogo, la columna muestra la palabra inglesa en crudo junto a las filas
traducidas del núcleo. Una categoría que además es un título de menú (Search,
Encoding) comparte una sola entrada: conserva en ella el mnemónico & para el
menú, el anfitrión lo quita para la columna.
Definición de «terminado»¶
La localización de un plugin está terminada solo cuando existen los quince
archivos .ts, están conectados y lrelease informa de 0 cadenas sin
terminar.