How to create a multi language application/ru: Difference between revisions
(Translated entire article in Russian) |
Yaroslavche (talk | contribs) m (typos) |
||
Line 1: | Line 1: | ||
{{LangSwitch}} | {{LangSwitch}} | ||
[[Category:HowTo]] | [[Category:HowTo]] | ||
== Создайте простое приложение, например с основным окном (QMainWindow) == | ==Создайте простое приложение, например с основным окном (QMainWindow)== | ||
[[File:LanguageApp.png]] | [[File:LanguageApp.png]] | ||
Line 9: | Line 9: | ||
[[File:LanguageAppMenu.png]] | [[File:LanguageAppMenu.png]] | ||
== Структура файловой системы приложения: == | ==Структура файловой системы приложения:== | ||
* Каталог приложения | *Каталог приложения | ||
** двоичные файлы | **двоичные файлы | ||
* Каталог приложения/languages | *Каталог приложения/languages | ||
** Для каждого установленного языка имеется опциональная картинка размером 16x16 пикселей с флагом (например de.png) | **Для каждого установленного языка имеется опциональная картинка размером 16x16 пикселей с флагом (например de.png) | ||
** Переведённые текстовые файлы приложения (TranslationExample_*.qm, где * может принимать значения de, en, и т.д.) | **Переведённые текстовые файлы приложения (TranslationExample_*.qm, где * может принимать значения de, en, и т.д.) | ||
** Файлы перевода Qt (qt_*.qm) | **Файлы перевода Qt (qt_*.qm) | ||
== Определение класса == | ==Определение класса== | ||
В классе MainWindow, виртуальный метод {{DocLink|QWidget|changeEvent|changeEvent(QEvent*)}} переписан. Для каждого необходимого | В классе MainWindow, виртуальный метод {{DocLink|QWidget|changeEvent|changeEvent(QEvent*)}} переписан. Для каждого необходимого файла перевода создаётся экземпляр {{DocLink|QTranslator}} .(в нашем примере 2, один для текстов приложения и один для Qt). Текущий язык сохраняется чтобы подавлять события на случай того, что пользователь попытается загрузить один и тот же язык дважды. | ||
<code> | <code> | ||
Line 45: | Line 45: | ||
QString m_currLang; // содержит текущий загруженный язык | QString m_currLang; // содержит текущий загруженный язык | ||
QString m_langPath; // Путь к языковым файлам. зафиксирован как /languages. | QString m_langPath; // Путь к языковым файлам. зафиксирован как /languages. | ||
}; | }; | ||
</code> | </code> | ||
== Создание языковых меню == | ==Создание языковых меню== | ||
Языковое меню создаётся динамически на старте приложения, в зависимости от наличия файлов перевода. Преимущество такого решения в том, что вы можете добавить позднее любой перевод, и он будет работоспособен после перезагрузки приложения. В этом примере все текстовые файлы расположены в подкаталоге "languages". Там возможно также разместить несколько иконок (language.png) которые будут применяться как иконки в меню (флаг, например). | Языковое меню создаётся динамически на старте приложения, в зависимости от наличия файлов перевода. Преимущество такого решения в том, что вы можете добавить позднее любой перевод, и он будет работоспособен после перезагрузки приложения. В этом примере все текстовые файлы расположены в подкаталоге "languages". Там возможно также разместить несколько иконок (language.png) которые будут применяться как иконки в меню (флаг, например). | ||
Line 101: | Line 102: | ||
} | } | ||
} | } | ||
} | } | ||
</code> | </code> | ||
== Переключение языка == | ==Переключение языка== | ||
Если язык должен быть переключен, необходимый целевой язык получаем из объекта {{DocLink|QAction}} и существующие переводчики удаляются. {{DocLink|QApplication|removeTranslator|QApplication::removeTranslator()}}. Затем, загружаются новые языковые файлы, и в случае успеха, переводчик устанавливается снова {{DocLink|QApplication|installTranslator|QApplication::installTranslator()}}. Делается это для того чтобы гарантировать факт того что сигнал {{DocLink|QEvent}}::LanguageChange будет выпущен объектом приложения. Если у приложения есть только одно окно верхнего уровня, созданное полностью в дизайнере, то также возможно просто прочитать новые файлы переводов и вызвать <tt>ui.retranslateUi(this)</tt> напрямую. | Если язык должен быть переключен, необходимый целевой язык получаем из объекта {{DocLink|QAction}} и существующие переводчики удаляются. {{DocLink|QApplication|removeTranslator|QApplication::removeTranslator()}}. Затем, загружаются новые языковые файлы, и в случае успеха, переводчик устанавливается снова {{DocLink|QApplication|installTranslator|QApplication::installTranslator()}}. Делается это для того чтобы гарантировать факт того что сигнал {{DocLink|QEvent}}::LanguageChange будет выпущен объектом приложения. Если у приложения есть только одно окно верхнего уровня, созданное полностью в дизайнере, то также возможно просто прочитать новые файлы переводов и вызвать <tt>ui.retranslateUi(this)</tt> напрямую. | ||
Line 142: | Line 144: | ||
ui.statusBar->showMessage(tr("Current Language changed to %1").arg(languageName)); | ui.statusBar->showMessage(tr("Current Language changed to %1").arg(languageName)); | ||
} | } | ||
} | } | ||
</code> | </code> | ||
* <tt>QEvent::LanguageChange</tt> всегда будет вызываться, если объект переводчика устанавливается в объект приложенияif a translator object is installed in the application object | *<tt>QEvent::LanguageChange</tt> всегда будет вызываться, если объект переводчика устанавливается в объект приложенияif a translator object is installed in the application object | ||
* <tt>QEvent::LocaleChange</tt> вызывается когда изменяется системный язык | *<tt>QEvent::LocaleChange</tt> вызывается когда изменяется системный язык | ||
<code> | <code> | ||
Line 169: | Line 172: | ||
} | } | ||
QMainWindow::changeEvent(event); | QMainWindow::changeEvent(event); | ||
} | } | ||
</code> | </code> | ||
== Добавление переводов в проект == | ==Добавление переводов в проект== | ||
В вашем проектном файле qmake такая переменная [http://doc.qt.io/qt-5/qmake-variable-reference.html#translations TRANSLATIONS] должна была быть добавлена и содержать все языковые файлы, которые Вы изначаально были намерены создавать. | В вашем проектном файле qmake такая переменная [http://doc.qt.io/qt-5/qmake-variable-reference.html#translations TRANSLATIONS] должна была быть добавлена и содержать все языковые файлы, которые Вы изначаально были намерены создавать. |
Latest revision as of 14:27, 4 April 2021
Создайте простое приложение, например с основным окном (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