1
0
Fork 0

Improve locale handling

- fgfs --language=fr-FR now works as expected for the launcher (also with
  --language=fr_FR as before): the value added by option --language to
  the _languages member of FGLocale is normalized in "underscore" style
  (e.g., fr_FR).

- Add-on translations must now use a hyphen in their property node names
  in addon-metadata.xml (talking about children of <localized>): i.e.,
  use for instance <fr-FR> there, not <fr_FR>. An exception
  (addons::errors::error_loading_metadata_file) is thrown if one of
  these nodes has a name containing an underscore.
This commit is contained in:
Florent Rougon 2020-07-14 12:38:09 +02:00 committed by James Turner
parent 54264e6591
commit f105e8dfb2
3 changed files with 38 additions and 4 deletions

View file

@ -73,6 +73,29 @@ static string getMaybeLocalized(const string& tag, SGPropertyNode* base, SGPrope
return {}; return {};
} }
static SGPropertyNode* getAndCheckLocalizedNode(SGPropertyNode* addonNode,
const SGPath& metadataFile)
{
const auto localizedNode = addonNode->getChild("localized");
if (!localizedNode) {
return nullptr;
}
for (int i = 0; i < localizedNode->nChildren(); ++i) {
const auto node = localizedNode->getChild(i);
const string& name = node->getNameString();
if (name.find('_') != string::npos) {
throw errors::error_loading_metadata_file(
"underscores not allowed in names of children of <localized> "
"(in add-on metadata file '" + metadataFile.utf8Str() + "'); "
"hyphens should be used, as in 'fr-FR' or 'en-GB'");
}
}
return localizedNode;
}
// Static method // Static method
Addon::Metadata Addon::Metadata
Addon::MetadataParser::parseMetadataFile(const SGPath& addonPath) Addon::MetadataParser::parseMetadataFile(const SGPath& addonPath)
@ -141,7 +164,7 @@ Addon::MetadataParser::parseMetadataFile(const SGPath& addonPath)
metadataFile.utf8Str() + "'"); metadataFile.utf8Str() + "'");
} }
SGPropertyNode* localizedNode = addonNode->getChild("localized"); const auto localizedNode = getAndCheckLocalizedNode(addonNode, metadataFile);
SGPropertyNode* langStringsNode = globals->get_locale()->selectLanguageNode(localizedNode); SGPropertyNode* langStringsNode = globals->get_locale()->selectLanguageNode(localizedNode);
SGPropertyNode *idNode = addonNode->getChild("identifier"); SGPropertyNode *idNode = addonNode->getChild("identifier");

View file

@ -46,6 +46,7 @@
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/package/Root.hxx> #include <simgear/package/Root.hxx>
#include <simgear/package/Catalog.hxx> #include <simgear/package/Catalog.hxx>
#include <simgear/package/Package.hxx> #include <simgear/package/Package.hxx>
@ -292,7 +293,10 @@ void initApp(int& argc, char** argv, bool doInitQSettings)
QTranslator* translator = new QTranslator(static_qApp.get()); QTranslator* translator = new QTranslator(static_qApp.get());
// check for --langauge=xx option and prefer that over QLocale // check for --langauge=xx option and prefer that over QLocale
// detection of the locale if it exists // detection of the locale if it exists
auto lang = Options::getArgValue(argc, argv, "--language"); auto lang = simgear::strutils::replace(
Options::getArgValue(argc, argv, "--language"),
"-",
"_");
if (!lang.empty()) { if (!lang.empty()) {
QString localeFile = "FlightGear_" + QString::fromStdString(lang); QString localeFile = "FlightGear_" + QString::fromStdString(lang);
if (translator->load(localeFile, QLatin1String(":/"))) { if (translator->load(localeFile, QLatin1String(":/"))) {

View file

@ -29,6 +29,7 @@
#include <cstddef> // std::size_t #include <cstddef> // std::size_t
#include <cassert> #include <cassert>
#include <simgear/misc/strutils.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx> #include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
@ -41,6 +42,7 @@
using std::vector; using std::vector;
using std::string; using std::string;
namespace strutils = simgear::strutils;
FGLocale::FGLocale(SGPropertyNode* root) : FGLocale::FGLocale(SGPropertyNode* root) :
_intl(root->getNode("/sim/intl", 0, true)), _intl(root->getNode("/sim/intl", 0, true)),
@ -178,6 +180,7 @@ FGLocale::findLocaleNode(const string& localeSpec)
} }
} }
// try country's default resource, i.e. "de_DE" => "de"
const auto justTheLanguage = removeLocalePart(language); const auto justTheLanguage = removeLocalePart(language);
if (!justTheLanguage.empty()) { if (!justTheLanguage.empty()) {
node = findLocaleNode(justTheLanguage); node = findLocaleNode(justTheLanguage);
@ -201,7 +204,8 @@ bool FGLocale::selectLanguage(const std::string& language)
// if we were passed a language option, try it first // if we were passed a language option, try it first
if (!language.empty()) { if (!language.empty()) {
_languages.insert(_languages.begin(), language); const auto normalizedLang = strutils::replace(language, "-", "_");
_languages.insert(_languages.begin(), normalizedLang);
} }
_currentLocaleString = removeEncodingPart(_languages.front()); _currentLocaleString = removeEncodingPart(_languages.front());
@ -600,7 +604,10 @@ SGPropertyNode_ptr FGLocale::selectLanguageNode(SGPropertyNode* langs) const
return {}; return {};
for (auto l : _languages) { for (auto l : _languages) {
const auto langNoEncoding = removeEncodingPart(l); // Only accept the hyphen separator in PropertyList node names between
// language and territory
const auto langNoEncoding = strutils::replace(removeEncodingPart(l),
"_", "-");
if (langs->hasChild(langNoEncoding)) { if (langs->hasChild(langNoEncoding)) {
return langs->getChild(langNoEncoding); return langs->getChild(langNoEncoding);
} }