1
0
Fork 0

I18N: support localised local aircraft strings

Allows us to localize aircraft names/descriptions, especially for the
UFO and C172
This commit is contained in:
James Turner 2020-06-19 10:45:47 +01:00
parent 585c821bde
commit 5a11e57d0a
5 changed files with 129 additions and 26 deletions

View file

@ -277,11 +277,11 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
if (role >= AircraftVariantDescriptionRole) {
int variantIndex = role - AircraftVariantDescriptionRole;
if (variantIndex == 0) {
return item->description;
return item->name();
}
Q_ASSERT(variantIndex < item->variants.size());
return item->variants.at(variantIndex)->description;
return item->variants.at(variantIndex)->name();
}
if (state.variant) {
@ -292,11 +292,11 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
}
if (role == Qt::DisplayRole) {
if (item->description.isEmpty()) {
if (item->name().isEmpty()) {
return tr("Missing description for: %1").arg(item->baseName());
}
return item->description;
return item->name();
} else if (role == AircraftPathRole) {
return item->path;
} else if (role == AircraftAuthorsRole) {
@ -318,7 +318,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
}
return have;
} else if (role == AircraftLongDescriptionRole) {
return item->longDescription;
return item->description();
} else if (role == AircraftIsHelicopterRole) {
return item->usesHeliports;
} else if (role == AircraftIsSeaplaneRole) {
@ -564,14 +564,14 @@ QString AircraftItemModel::nameForAircraftURI(QUrl uri) const
const QString path = uri.toLocalFile();
if (item->path == path) {
return item->description;
return item->name();
}
// check variants too
for (int vr=0; vr < item->variants.size(); ++vr) {
auto variant = item->variants.at(vr);
if (variant->path == path) {
return variant->description;
return variant->name();
}
}
} else if (uri.scheme() == "package") {

View file

@ -31,17 +31,28 @@
#include <QSettings>
#include <QDebug>
#include <Main/globals.hxx>
#include <Include/version.h>
#include <Main/globals.hxx>
#include <Main/locale.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
static quint32 CACHE_VERSION = 12;
static quint32 CACHE_VERSION = 13;
AircraftItem::AircraftItem()
const std::vector<QByteArray> static_localizedStringTags = {"name", "desc"};
QDataStream& operator<<(QDataStream& ds, const AircraftItem::LocalizedStrings& ls)
{
ds << ls.locale << ls.strings;
return ds;
}
QDataStream& operator>>(QDataStream& ds, AircraftItem::LocalizedStrings& ls)
{
ds >> ls.locale >> ls.strings;
return ds;
}
AircraftItem::AircraftItem(QDir dir, QString filePath)
@ -62,10 +73,9 @@ AircraftItem::AircraftItem(QDir dir, QString filePath)
return;
}
description = sim->getStringValue("description");
// trim the description to ensure the alphabetical sort
// doesn't get thrown off by leading whitespace
description = description.trimmed();
LocalizedStrings ls;
ls.locale = "en";
ls.strings["name"] = QString::fromStdString(sim->getStringValue("description")).trimmed();
authors = sim->getStringValue("author");
if (sim->hasChild("rating")) {
@ -77,7 +87,7 @@ AircraftItem::AircraftItem(QDir dir, QString filePath)
if (sim->hasChild("long-description")) {
// clean up any XML whitspace in the text.
longDescription = QString(sim->getStringValue("long-description")).simplified();
ls.strings["desc"] = QString(sim->getStringValue("long-description")).simplified();
}
if (sim->hasChild("variant-of")) {
@ -132,6 +142,65 @@ AircraftItem::AircraftItem(QDir dir, QString filePath)
homepageUrl = QUrl(QString::fromStdString(sim->getStringValue("urls/home-page")));
supportUrl = QUrl(QString::fromStdString(sim->getStringValue("urls/support")));
wikipediaUrl = QUrl(QString::fromStdString(sim->getStringValue("urls/wikipedia")));
_localized.push_front(ls);
readLocalizedStrings(sim);
doLocalizeStrings();
}
void AircraftItem::readLocalizedStrings(SGPropertyNode_ptr simNode)
{
if (!simNode->hasChild("localized"))
return;
auto localeNode = simNode->getChild("localized");
const auto num = localeNode->nChildren();
for (int i = 0; i < num; i++) {
const SGPropertyNode* c = localeNode->getChild(i);
LocalizedStrings ls;
ls.locale = QString::fromStdString(c->getNameString());
if (c->hasChild("description")) {
ls.strings["name"] = QString::fromStdString(c->getStringValue("description"));
}
if (c->hasChild("long-description")) {
ls.strings["desc"] = QString::fromStdString(c->getStringValue("long-description")).simplified();
}
_localized.push_back(ls);
}
}
void AircraftItem::doLocalizeStrings()
{
// default strings are always at the front
_currentStrings = _localized.front().strings;
const auto lang = QString::fromStdString(globals->get_locale()->getPreferredLanguage());
// find the matching locale
auto it = std::find_if(_localized.begin(), _localized.end(), [lang](const LocalizedStrings& ls) {
return ls.locale == lang;
});
if (it == _localized.end())
return; // nothing else to do
for (auto t : static_localizedStringTags) {
if (it->strings.contains(t)) {
// copy the value we found
_currentStrings[t] = it->strings.value(t);
}
} // of strings iteration
}
QString AircraftItem::name() const
{
return _currentStrings.value("name");
}
QString AircraftItem::description() const
{
return _currentStrings.value("desc");
}
QString AircraftItem::baseName() const
@ -148,7 +217,7 @@ void AircraftItem::fromDataStream(QDataStream& ds)
return;
}
ds >> description >> longDescription >> authors >> variantOf >> isPrimary;
ds >> authors >> variantOf >> isPrimary;
for (int i=0; i<4; ++i) ds >> ratings[i];
ds >> previews;
ds >> thumbnailPath;
@ -156,6 +225,9 @@ void AircraftItem::fromDataStream(QDataStream& ds)
ds >> needsMaintenance >> usesHeliports >> usesSeaports;
ds >> homepageUrl >> supportUrl >> wikipediaUrl;
ds >> tags;
ds >> _localized;
doLocalizeStrings();
}
void AircraftItem::toDataStream(QDataStream& ds) const
@ -165,7 +237,7 @@ void AircraftItem::toDataStream(QDataStream& ds) const
return;
}
ds << description << longDescription << authors << variantOf << isPrimary;
ds << authors << variantOf << isPrimary;
for (int i=0; i<4; ++i) ds << ratings[i];
ds << previews;
ds << thumbnailPath;
@ -173,6 +245,7 @@ void AircraftItem::toDataStream(QDataStream& ds) const
ds << needsMaintenance << usesHeliports << usesSeaports;
ds << homepageUrl << supportUrl << wikipediaUrl;
ds << tags;
ds << _localized;
}
int AircraftItem::indexOfVariant(QUrl uri) const
@ -216,6 +289,7 @@ public:
SGPath resolve(const std::string& aResource, SGPath& aContext) const override
{
Q_UNUSED(aContext)
string_list pieces(sgPathBranchSplit(aResource));
if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) {
return SGPath{}; // not an Aircraft path

View file

@ -29,6 +29,8 @@
#include <QDir>
#include <QVariant>
#include <simgear/props/props.hxx>
class QDataStream;
struct AircraftItem;
class AircraftScanThread;
@ -38,13 +40,17 @@ typedef QSharedPointer<AircraftItem> AircraftItemPtr;
struct AircraftItem
{
AircraftItem();
AircraftItem() = default;
AircraftItem(QDir dir, QString filePath);
// the file-name without -set.xml suffix
QString baseName() const;
QString name() const;
QString description() const;
void fromDataStream(QDataStream& ds);
void toDataStream(QDataStream& ds) const;
@ -53,8 +59,7 @@ struct AircraftItem
bool excluded = false;
QString path;
QString description;
QString longDescription;
QString authors; // legacy authors data only
int ratings[4] = {0, 0, 0, 0};
QString variantOf;
@ -72,7 +77,31 @@ struct AircraftItem
QUrl wikipediaUrl;
QUrl supportUrl;
QVariant status(int variant);
private:
struct LocalizedStrings {
QString locale;
QMap<QByteArray, QString> strings;
};
friend QDataStream& operator<<(QDataStream&, const LocalizedStrings&);
friend QDataStream& operator>>(QDataStream&, LocalizedStrings&);
using LocalizedStringsVec = QVector<LocalizedStrings>;
// store all localized strings. We need this to avoid rebuilding
// the cache when switching languages.
LocalizedStringsVec _localized;
// the resolved values for our strings, based on QLocale
// if we support dynamic switching of language, this would need to
// be flushed and re-computed
QMap<QByteArray, QString> _currentStrings;
void doLocalizeStrings();
void readLocalizedStrings(SGPropertyNode_ptr simNode);
};
class LocalAircraftCache : public QObject

View file

@ -342,7 +342,7 @@ quint32 QmlAircraftInfo::numVariants() const
QString QmlAircraftInfo::name() const
{
if (_item) {
return resolveItem()->description;
return resolveItem()->name();
} else if (_package) {
return QString::fromStdString(_package->nameForVariant(_variant));
}
@ -353,7 +353,7 @@ QString QmlAircraftInfo::name() const
QString QmlAircraftInfo::description() const
{
if (_item) {
return resolveItem()->longDescription;
return resolveItem()->description();
} else if (_package) {
std::string longDesc = _package->getLocalisedProp("description", _variant);
return QString::fromStdString(longDesc).simplified();
@ -773,12 +773,12 @@ QStringList QmlAircraftInfo::variantNames() const
{
QStringList result;
if (_item) {
result.append(_item->description);
result.append(_item->name());
Q_FOREACH(auto v, _item->variants) {
if (v->description.isEmpty()) {
if (v->name().isEmpty()) {
qWarning() << Q_FUNC_INFO << "missing description for " << v->path;
}
result.append(v->description);
result.append(v->name());
}
} else if (_package) {
for (quint32 vindex = 0; vindex < _package->variants().size(); ++vindex) {

View file

@ -462,7 +462,7 @@ bool runLauncherDialog()
// we will re-do this later, but we want to access translated strings
// from within the launcher
globals->get_locale()->selectLanguage(lang);
globals->packageRoot()->setLocale(lang);
globals->packageRoot()->setLocale(globals->get_locale()->getPreferredLanguage());
// startup the HTTP system now since packages needs it
FGHTTPClient* http = globals->add_new_subsystem<FGHTTPClient>();