How to create a multi language application/ru

From Qt Wiki
Jump to navigation Jump to search

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)

LanguageApp.png

В этом примере мы создадим основное окно с языковым меню и несколькими виджетами. Если пользователь открыл языковое меню, там предусмотрен выбор языка, созданный на этапе старта приложения, зависимый от имеющихся языковых файлов.

LanguageAppMenu.png

Структура файловой системы приложения:

  • Каталог приложения
    • двоичные файлы
  • Каталог приложения/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