Commit 78d2525b authored by Gus Grubba's avatar Gus Grubba

Automated the ingestion of localization from Crowdin

Automated the generation of language resources into the application
Added all languages that come from Crowdin, even if empty.
Allow dynamic language changes
parent 9d255f45
......@@ -55,6 +55,7 @@ libs/thirdParty/libxbee/lib/
GeneratedFiles/
gstreamer-1.0-android*
src/Airmap/Airmap_api_key.h
localization/qgroundcontrol/
*.autosave
.settings/
......
......@@ -6,6 +6,10 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build
* Automated the ingestion of localization from Crowdin
* Automated the generation of language resources into the application
* Added all languages that come from Crowdin, even if empty.
* Allow dynamic language changes
* Check and respect camera storage status
* QGC now requires Qt 5.11 or greater. The idea is to standardize on Qt 5.12 (LTS). Just waiting for a solution for Windows as Qt dropped support for 32-bit.
* New, QtQuick MAVLink Inspector. The basics are already there but it still needs the ability to filter compID.
......
To generate (or update) a source translation file, use the "lupdate" command line tool. It can be found in the Qt distribution.
To generate (or update) a source translation file, use the `to-crowdin.sh` script in this directory. You will need to update the path to Qt within it.
(Easiest to just run the `gen_translation_source.sh` script, or get the commands from within the script and run them manually)
This will parse all the source files and generate a language translation file called qgc.ts, which should be uploaded to crowdin.
This will parse all the source files and generate a language translation file called qgc.ts. This file should be copied into whatever language it is to be translated to and sent to translation. The translation can either be done directly within the (XML) file, using Qt's "Linguist" tool, or uploaded to crowdin.
For instance, to localize to Germany German as an example you first copy the original source:
```
cp qgc.ts qgc_de-DE.ts
```
The German localization is then performed in qgc_de-DE.ts
Once localization is complete, you "compile" it using the "lrelease" command line tool.
```
lrelease qgc_de-DE.ts
```
This will generate the ("compiled") localization file `qgc_de-DE.qm`, which should be shipped with QGroundControl.
Further documentation can be found at:
http://doc.qt.io/qt-5/qtlinguist-index.html
Note about crowdin:
If you build the project and download the resulting ZIP file, the translated (.ts) files all come with the same name "qgc.ts". They each reside in a different directory named after the language for which it was translated into. Care must be taken to rename these files before moving them to the locale directory so you don't override the original, English source file.
Once translations have been done/updated, within Crowdin "Build and Download". Extract the resulting qgroundcontro.zip here and run `from-crowdin.py`.
#!/bin/bash
for f in *.ts
do
/Users/gus/Applications/Qt/5.11.2/clang_64/bin/lrelease $f
done
\ No newline at end of file
#!/usr/bin/env python
import os
from shutil import copyfile
# When you "Build and Download" from Crowdin, you endup with a qgroundcontro.zip file.
# It is assumed this zip file has been extracted into ./qgroundcontrol
for lang in os.listdir("./qgroundcontrol"):
srcFile = os.path.join("./qgroundcontrol", lang, "qgc.ts")
if(os.path.exists(srcFile)):
lang = lang.replace("-","_")
dstFile = "./qgc" + "_" + lang + ".ts"
print("qgc" + "_" + lang + ".ts")
copyfile(srcFile, dstFile)
<d!`
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -4796,7 +4796,7 @@ propellers on the green thrusters and counter-clockwise propellers on the blue t
<message>
<location filename="../src/VehicleSetup/FirmwareUpgradeController.cc" line="512"/>
<source>Firmware Files (*.px4 *.bin *.ihx)</source>
<translation>固件文件*.px4 *.bin *.ihx</translation>
<translation>固件文件 (*.px4 *.bin *.ihx)</translation>
</message>
<message>
<location filename="../src/VehicleSetup/FirmwareUpgradeController.cc" line="517"/>
......
#!/bin/bash
# This is set to find lupdate in my particular installation. You will need to set the path
# where you have Qt installed.
QT_PATH=~/Applications/Qt/5.11.0/clang_64/bin
QT_PATH=~/Applications/Qt/5.12.3/clang_64/bin
$QT_PATH/lupdate ../src -ts qgc.ts
<RCC>
<qresource prefix="/localization">
<file alias="qgc_bg.qm">localization/qgc_bg.qm</file>
<file alias="qgc_de_DE.qm">localization/qgc_de-DE.qm</file>
<file alias="qgc_fr_FR.qm">localization/qgc_fr_FR.qm</file>
<file alias="qgc_it.qm">localization/qgc_it.qm</file>
<file alias="qgc_ko.qm">localization/qgc_ko.qm</file>
<file alias="qgc_ru.qm">localization/qgc_ru.qm</file>
<file alias="qgc_tr.qm">localization/qgc_tr.qm</file>
<file alias="qgc_zh_CN.qm">localization/qgc_zh-CN.qm</file>
</qresource>
<qresource prefix="/fonts">
<file alias="opensans">resources/fonts/OpenSans-Regular.ttf</file>
<file alias="opensans-demibold">resources/fonts/OpenSans-Semibold.ttf</file>
......
......@@ -1216,6 +1216,14 @@ AndroidBuild {
}
}
#-------------------------------------------------------------------------------------
#
# Localization
#
TRANSLATIONS += $$files($$PWD/localization/qgc_*.ts)
CONFIG+=lrelease embed_translations
#-------------------------------------------------------------------------------------
#
# Post link configuration
......
......@@ -357,37 +357,86 @@ void QGCApplication::setLanguage()
if(langID) {
switch(langID) {
case 1:
locale = QLocale(QLocale::English);
locale = QLocale(QLocale::Bulgarian);
break;
case 2:
locale = QLocale(QLocale::Bulgarian);
locale = QLocale(QLocale::Chinese);
break;
case 3:
locale = QLocale(QLocale::German);
locale = QLocale(QLocale::Dutch);
break;
case 4:
locale = QLocale(QLocale::French);
locale = QLocale(QLocale::English);
break;
case 5:
locale = QLocale(QLocale::Italian);
locale = QLocale(QLocale::Finnish);
break;
case 6:
locale = QLocale(QLocale::Korean);
locale = QLocale(QLocale::French);
break;
case 7:
locale = QLocale(QLocale::Russian);
locale = QLocale(QLocale::German);
break;
case 8:
locale = QLocale(QLocale::Turkish);
locale = QLocale(QLocale::Greek);
break;
case 9:
locale = QLocale(QLocale::Chinese);
locale = QLocale(QLocale::Hebrew);
break;
case 10:
locale = QLocale(QLocale::Italian);
break;
case 11:
locale = QLocale(QLocale::Japanese);
break;
case 12:
locale = QLocale(QLocale::Korean);
if(QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Regular") < 0) {
qWarning() << "Could not load /fonts/NanumGothic-Regular font";
}
if(QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Bold") < 0) {
qWarning() << "Could not load /fonts/NanumGothic-Bold font";
}
break;
case 13:
locale = QLocale(QLocale::Norwegian);
break;
case 14:
locale = QLocale(QLocale::Polish);
break;
case 15:
locale = QLocale(QLocale::Portuguese);
break;
case 16:
locale = QLocale(QLocale::Russian);
break;
case 17:
locale = QLocale(QLocale::Spanish);
break;
case 18:
locale = QLocale(QLocale::Swedish);
break;
case 19:
locale = QLocale(QLocale::Turkish);
break;
}
}
//-- Our localization
if(_QGCTranslator.load(locale, "qgc_", "", ":/localization"))
qDebug() << "Loading localization for" << locale.name();
_app->removeTranslator(&_QGCTranslator);
_app->removeTranslator(&_QGCTranslatorQt);
if(_QGCTranslatorQt.load("qt_" + locale.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
_app->installTranslator(&_QGCTranslatorQt);
} else {
qDebug() << "Error loading Qt localization for" << locale.name();
}
if(_QGCTranslator.load(locale, QLatin1String("qgc_"), "", ":/i18n")) {
QLocale::setDefault(locale);
_app->installTranslator(&_QGCTranslator);
} else {
qDebug() << "Error loading application localization for" << locale.name();
}
if(_qmlAppEngine)
_qmlAppEngine->retranslate();
}
void QGCApplication::_shutdown()
......@@ -476,23 +525,11 @@ void QGCApplication::_initCommon()
bool QGCApplication::_initForNormalAppBoot()
{
//-- See App.SettinsGroup.json for index
int langID = toolbox()->settingsManager()->appSettings()->language()->rawValue().toInt();
//-- Load font appropriate for the language
if(langID == 6 /*Korean*/) {
if(QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Regular") < 0) {
qWarning() << "Could not load /fonts/NanumGothic-Regular font";
}
if(QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Bold") < 0) {
qWarning() << "Could not load /fonts/NanumGothic-Bold font";
}
} else {
if(QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) {
qWarning() << "Could not load /fonts/opensans font";
}
if(QFontDatabase::addApplicationFont(":/fonts/opensans-demibold") < 0) {
qWarning() << "Could not load /fonts/opensans-demibold font";
}
if(QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) {
qWarning() << "Could not load /fonts/opensans font";
}
if(QFontDatabase::addApplicationFont(":/fonts/opensans-demibold") < 0) {
qWarning() << "Could not load /fonts/opensans-demibold font";
}
QSettings settings;
......@@ -782,7 +819,7 @@ void QGCApplication::_onGPSDisconnect()
void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM, double latitude, double longitude, float altitude, bool valid, bool active)
{
_gpsRtkFactGroup->currentDuration()->setRawValue(duration);
_gpsRtkFactGroup->currentAccuracy()->setRawValue(accuracyMM/1000.0);
_gpsRtkFactGroup->currentAccuracy()->setRawValue(static_cast<double>(accuracyMM) / 1000.0);
_gpsRtkFactGroup->currentLatitude()->setRawValue(latitude);
_gpsRtkFactGroup->currentLongitude()->setRawValue(longitude);
_gpsRtkFactGroup->currentAltitude()->setRawValue(altitude);
......
......@@ -183,6 +183,7 @@ private:
QQuickItem* _mainRootWindow = nullptr;
bool _bluetoothAvailable = false;
QTranslator _QGCTranslator;
QTranslator _QGCTranslatorQt;
static const char* _settingsVersionKey; ///< Settings key which hold settings version
static const char* _deleteAllSettingsKey; ///< If this settings key is set on boot, all settings will be deleted
......
......@@ -239,8 +239,8 @@
"name": "language",
"shortDescription": "Language",
"type": "uint32",
"enumStrings": "System,English,български (Bulgarian),Deutsche (German),Français (French),Italiano (Italian),한국어 (Korean),Pусский (Russian),Türk (Turkish),中文 (Chinese)",
"enumValues": "0,1,2,3,4,5,6,7,8,9",
"enumStrings": "System,български (Bulgarian),中文 (Chinese),Nederlands (Dutch),English,Suomi (Finnish),Français (French),Deutsche (German),Ελληνικά (Greek), עברית (Hebrew),Italiano (Italian),日本人 (Japanese),한국어 (Korean),Norsk (Norwegian),Polskie (Polish),Português (Portuguese),Pусский (Russian),Español (Spanish),Svenska (Swedish),Türk (Turkish)",
"enumValues": "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
"defaultValue": 0
},
{
......
......@@ -27,7 +27,7 @@ DECLARE_SETTINGSFACT_NO_FUNC(UnitsSettings, distanceUnits)
enumValues << QVariant::fromValue(static_cast<uint32_t>(DistanceUnitsFeet)) << QVariant::fromValue(static_cast<uint32_t>(DistanceUnitsMeters));
FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, this);
metaData->setName(distanceUnitsName);
metaData->setShortDescription(tr("Distance units"));
metaData->setShortDescription("Distance units");
metaData->setEnumInfo(enumStrings, enumValues);
metaData->setRawDefaultValue(DistanceUnitsMeters);
metaData->setQGCRebootRequired(true);
......@@ -52,7 +52,7 @@ DECLARE_SETTINGSFACT_NO_FUNC(UnitsSettings, areaUnits)
QVariant::fromValue(static_cast<uint32_t>(AreaUnitsSquareMiles));
FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, this);
metaData->setName(areaUnitsName);
metaData->setShortDescription(tr("Area units"));
metaData->setShortDescription("Area units");
metaData->setEnumInfo(enumStrings, enumValues);
metaData->setRawDefaultValue(AreaUnitsSquareMeters);
metaData->setQGCRebootRequired(true);
......@@ -76,7 +76,7 @@ DECLARE_SETTINGSFACT_NO_FUNC(UnitsSettings, speedUnits)
QVariant::fromValue(static_cast<uint32_t>(SpeedUnitsKnots));
FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, this);
metaData->setName(speedUnitsName);
metaData->setShortDescription(tr("Speed units"));
metaData->setShortDescription("Speed units");
metaData->setEnumInfo(enumStrings, enumValues);
metaData->setRawDefaultValue(SpeedUnitsMetersPerSecond);
metaData->setQGCRebootRequired(true);
......@@ -95,7 +95,7 @@ DECLARE_SETTINGSFACT_NO_FUNC(UnitsSettings, temperatureUnits)
enumValues << QVariant::fromValue(static_cast<uint32_t>(TemperatureUnitsCelsius)) << QVariant::fromValue(static_cast<uint32_t>(TemperatureUnitsFarenheit));
FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, this);
metaData->setName(temperatureUnitsName);
metaData->setShortDescription(tr("Temperature units"));
metaData->setShortDescription("Temperature units");
metaData->setEnumInfo(enumStrings, enumValues);
metaData->setRawDefaultValue(TemperatureUnitsCelsius);
metaData->setQGCRebootRequired(true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment