Jump to content

How to create a multi language application/ru

From Qt Wiki
Revision as of 14:27, 4 April 2021 by Yaroslavche (talk | contribs) (typos)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

Создайте простое приложение, например с основным окном (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