How to create a multi language application/ru
Создайте простое приложение, например с основным окном (QMainWindow)
В этом примере мы создадим основное окно с языковым меню и несколькими виджетами. Если пользователь открыл языковое меню, там предусмотрен выбор языка, созданный на этапе старта приложения, зависимый от имеющихся языковых файлов.
Структура файловой системы приложения:
- Каталог приложения
- двоичные файлы
- Каталог приложения/languages
- Для каждого установленного языка имеется опциональная картинка размером 16x16 пикселей с флагом (например de.png)
- Переведённые текстовые файлы приложения (TranslationExample_*.qm, где * может принимать значения de, en, и т.д.)
- Файлы перевода Qt (qt_*.qm)
Определение класса
В классе MainWindow, виртуальный метод changeEvent(QEvent*) переписан. Для каждого необходимого файла перевода создаётся экземпляр QTranslator .(в нашем примере 2, один для текстов приложения и один для Qt). Текущий язык сохраняется чтобы подавлять события на случай того, что пользователь попытается загрузить один и тот же язык дважды.
class MainWindow : public QMainWindow
{
protected:
// Это событие вызывается когда новый переводчик загружен или был изменён язык системы
void changeEvent(QEvent*);
protected slots:
// Этот слот вызывается действиями (QAction) меню
void slotLanguageChanged(QAction* action);
private:
// загружает язык по данному префиксу (например: de, en)
void loadLanguage(const QString& rLanguage);
// Создаёт меню языка динамически из содержимого m_langPath
void createLanguageMenu(void);
Ui::MainWindow ui; // ui определение из дизайнера
QTranslator m_translator; // содержит переводчик этого приложения
QTranslator m_translatorQt; // содержит переводчик qt
QString m_currLang; // содержит текущий загруженный язык
QString m_langPath; // Путь к языковым файлам. зафиксирован как /languages.
};
Создание языковых меню
Языковое меню создаётся динамически на старте приложения, в зависимости от наличия файлов перевода. Преимущество такого решения в том, что вы можете добавить позднее любой перевод, и он будет работоспособен после перезагрузки приложения. В этом примере все текстовые файлы расположены в подкаталоге "languages". Там возможно также разместить несколько иконок (language.png) которые будут применяться как иконки в меню (флаг, например).
Каждый язык представлен QAction объектом, который добавлен в QActionGroup. Это сделано чтобы был необходин только один слот для всех языков:
connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));
Языковое меню создаётся так:
// создаём пункты динамически, в зависимости от существующих переводов.
void MainWindow::createLanguageMenu(void)
{
QActionGroup* langGroup = new QActionGroup(ui.menuLanguage);
langGroup->setExclusive(true);
connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));
// формат языка системы
QString defaultLocale = QLocale::system().name(); // e.g. "de_DE"
defaultLocale.truncate(defaultLocale.lastIndexOf('_')); // e.g. "de"
m_langPath = QApplication::applicationDirPath();
m_langPath.append("/languages");
QDir dir(m_langPath);
QStringList fileNames = dir.entryList(QStringList("TranslationExample_*.qm"));
for (int i = 0; i < fileNames.size(); ++i) {
// получение локали из имени файлаget locale extracted by filename
QString locale;
locale = fileNames[i]; // "TranslationExample_de.qm"
locale.truncate(locale.lastIndexOf('.')); // "TranslationExample_de"
locale.remove(0, locale.lastIndexOf('_') + 1); // "de"
QString lang = QLocale::languageToString(QLocale(locale).language());
QIcon ico(QString("%1/%2.png").arg(m_langPath).arg(locale));
QAction *action = new QAction(ico, lang, this);
action->setCheckable(true);
action->setData(locale);
ui.menuLanguage->addAction(action);
langGroup->addAction(action);
// Установить переводчики и язык по умолчанию в состояние помеченых галочкой.
if (defaultLocale == locale)
{
action->setChecked(true);
}
}
}
Переключение языка
Если язык должен быть переключен, необходимый целевой язык получаем из объекта QAction и существующие переводчики удаляются. QApplication::removeTranslator(). Затем, загружаются новые языковые файлы, и в случае успеха, переводчик устанавливается снова QApplication::installTranslator(). Делается это для того чтобы гарантировать факт того что сигнал QEvent::LanguageChange будет выпущен объектом приложения. Если у приложения есть только одно окно верхнего уровня, созданное полностью в дизайнере, то также возможно просто прочитать новые файлы переводов и вызвать ui.retranslateUi(this) напрямую.
// Вызывается каждый раз, когда вызывается пункт языкового меню
void MainWindow::slotLanguageChanged(QAction* action)
{
if(0 != action) {
// load the language dependant on the action content
loadLanguage(action->data().toString());
setWindowIcon(action->icon());
}
}
void switchTranslator(QTranslator& translator, const QString& filename)
{
// убрать старый переводчик
qApp->removeTranslator(&translator);
// загрузить новый переводчик
QString path = QApplication::applicationDirPath();
path.append("/languages/");
if(translator.load(path + filename)) // Здесь необходимо указывать путь и имя файла, потому что система иначе не найдёт файлы QM Files else
qApp->installTranslator(&translator);
}
void MainWindow::loadLanguage(const QString& rLanguage)
{
if(m_currLang != rLanguage) {
m_currLang = rLanguage;
QLocale locale = QLocale(m_currLang);
QLocale::setDefault(locale);
QString languageName = QLocale::languageToString(locale.language());
switchTranslator(m_translator, QString("TranslationExample_%1.qm").arg(rLanguage));
switchTranslator(m_translatorQt, QString("qt_%1.qm").arg(rLanguage));
ui.statusBar->showMessage(tr("Current Language changed to %1").arg(languageName));
}
}
- QEvent::LanguageChange всегда будет вызываться, если объект переводчика устанавливается в объект приложенияif a translator object is installed in the application object
- QEvent::LocaleChange вызывается когда изменяется системный язык
void MainWindow::changeEvent(QEvent* event)
{
if(0 != event) {
switch(event->type()) {
// это событие посылается если переводчик загружен
case QEvent::LanguageChange:
ui.retranslateUi(this);
break;
// это событие вызывается если системный язык меняется
case QEvent::LocaleChange:
{
QString locale = QLocale::system().name();
locale.truncate(locale.lastIndexOf('_'));
loadLanguage(locale);
}
break;
}
}
QMainWindow::changeEvent(event);
}
Добавление переводов в проект
В вашем проектном файле qmake такая переменная TRANSLATIONS должна была быть добавлена и содержать все языковые файлы, которые Вы изначаально были намерены создавать.
TRANSLATIONS = languages/TranslationExample_en.ts languages/TranslationExample_de.ts
Запуская lupdate
lupdate -verbose TranslationExample.pro
Вы тем самым создаёте языковой файл (.ts), который вы переводите инструментом Qt Linguist.
linguist languages/TranslationExample_en.ts languages/TranslationExample_de.ts
После того как Вы это сделали, вы запустите lrelease для создания двоичных файлов перевода (.qm):
lrelease TranslationExample.pro