Move locale code to separate module.
Introduce convenience methods to handle localized string resources and obtain strings.
This commit is contained in:
parent
056b85bc1f
commit
470552fab1
11 changed files with 464 additions and 168 deletions
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include <Main/main.hxx>
|
#include <Main/main.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
#include <Main/locale.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/WindowSystemAdapter.hxx>
|
#include <Main/WindowSystemAdapter.hxx>
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/new_gui.hxx>
|
||||||
|
@ -78,8 +79,7 @@ public:
|
||||||
FGFontCache *fc = globals->get_fontcache();
|
FGFontCache *fc = globals->get_fontcache();
|
||||||
fc->initializeFonts();
|
fc->initializeFonts();
|
||||||
puFont *GuiFont
|
puFont *GuiFont
|
||||||
= fc->get(globals->get_locale()->getStringValue("font",
|
= fc->get(globals->get_locale()->getDefaultFont("typewriter.txf"),
|
||||||
"typewriter.txf"),
|
|
||||||
15);
|
15);
|
||||||
puSetDefaultFonts(*GuiFont, *GuiFont);
|
puSetDefaultFonts(*GuiFont, *GuiFont);
|
||||||
guiFnt = puGetDefaultLabelFont();
|
guiFnt = puGetDefaultLabelFont();
|
||||||
|
|
|
@ -4,9 +4,30 @@
|
||||||
|
|
||||||
|
|
||||||
#include "menubar.hxx"
|
#include "menubar.hxx"
|
||||||
|
#include <Main/locale.hxx>
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
|
||||||
|
FGMenuBar::FGMenuBar()
|
||||||
|
{
|
||||||
|
// load locale's menu resources (default and current language)
|
||||||
|
globals->get_locale()->loadResource("menu");
|
||||||
|
}
|
||||||
|
|
||||||
FGMenuBar::~FGMenuBar ()
|
FGMenuBar::~FGMenuBar ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
FGMenuBar::getLocalizedLabel(SGPropertyNode* node)
|
||||||
|
{
|
||||||
|
const char* name = node->getStringValue("name", 0);
|
||||||
|
|
||||||
|
const char* translated = globals->get_locale()->getLocalizedString(name, "menu");
|
||||||
|
if (translated)
|
||||||
|
return translated;
|
||||||
|
|
||||||
|
// return default
|
||||||
|
return node->getStringValue("label");
|
||||||
|
}
|
||||||
|
|
||||||
// end of menubar.cxx
|
// end of menubar.cxx
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#ifndef __MENUBAR_HXX
|
#ifndef __MENUBAR_HXX
|
||||||
#define __MENUBAR_HXX 1
|
#define __MENUBAR_HXX 1
|
||||||
|
|
||||||
|
class SGPropertyNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML-configured menu bar interface
|
* XML-configured menu bar interface
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
class FGMenuBar
|
class FGMenuBar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
FGMenuBar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
|
@ -45,6 +46,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool isVisible () const = 0;
|
virtual bool isVisible () const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a menu label from the menu's property tree.
|
||||||
|
* Take care of mapping it to the appropriate translation, if available.
|
||||||
|
* Returns an UTF-8 encoded string.
|
||||||
|
*/
|
||||||
|
const char* getLocalizedLabel(SGPropertyNode* node);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __MENUBAR_HXX
|
#endif // __MENUBAR_HXX
|
||||||
|
|
|
@ -21,6 +21,7 @@ set(SOURCES
|
||||||
fg_props.cxx
|
fg_props.cxx
|
||||||
fgviewer.cxx
|
fgviewer.cxx
|
||||||
globals.cxx
|
globals.cxx
|
||||||
|
locale.cxx
|
||||||
logger.cxx
|
logger.cxx
|
||||||
main.cxx
|
main.cxx
|
||||||
options.cxx
|
options.cxx
|
||||||
|
@ -43,6 +44,7 @@ set(HEADERS
|
||||||
fg_props.hxx
|
fg_props.hxx
|
||||||
fgviewer.hxx
|
fgviewer.hxx
|
||||||
globals.hxx
|
globals.hxx
|
||||||
|
locale.hxx
|
||||||
logger.hxx
|
logger.hxx
|
||||||
main.hxx
|
main.hxx
|
||||||
options.hxx
|
options.hxx
|
||||||
|
|
|
@ -149,136 +149,6 @@ string fgBasePackageVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Select the proper language based on the given locale/language name.
|
|
||||||
//
|
|
||||||
static SGPropertyNode* findLocale(SGPropertyNode *intl, const char* language)
|
|
||||||
{
|
|
||||||
vector<SGPropertyNode_ptr> localeList = intl->getChildren("locale");
|
|
||||||
for (unsigned int i = 0; i < localeList.size(); i++) {
|
|
||||||
|
|
||||||
vector<SGPropertyNode_ptr> lang = localeList[i]->getChildren("lang");
|
|
||||||
for (unsigned int j = 0; j < lang.size(); j++) {
|
|
||||||
|
|
||||||
if (!strcmp(lang[j]->getStringValue(), language)) {
|
|
||||||
return localeList[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the localization
|
|
||||||
SGPropertyNode *fgInitLocale(const char *language) {
|
|
||||||
SGPropertyNode *c_node = NULL, *d_node = NULL;
|
|
||||||
SGPropertyNode *intl = fgGetNode("/sim/intl");
|
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Selecting language: " << language );
|
|
||||||
|
|
||||||
// localization not defined
|
|
||||||
if (!intl)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
c_node = findLocale(intl, language);
|
|
||||||
if (!c_node)
|
|
||||||
{
|
|
||||||
/* be tolerant about locale names, i.e. instead of "de_DE.utf8" also
|
|
||||||
* consider "de_DE" ... */
|
|
||||||
string l = language;
|
|
||||||
size_t pos = l.find(".");
|
|
||||||
if ((pos != string::npos)&&(pos>0))
|
|
||||||
c_node = findLocale(intl, l.substr(0, pos).c_str());
|
|
||||||
|
|
||||||
/* finally consider country alone, i.e. "de" */
|
|
||||||
pos = l.find("_");
|
|
||||||
if ((!c_node)&&(pos != string::npos)&&(pos>0))
|
|
||||||
c_node = findLocale(intl, l.substr(0, pos).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get the defaults
|
|
||||||
d_node = intl->getChild("locale");
|
|
||||||
if (!c_node)
|
|
||||||
c_node = d_node;
|
|
||||||
|
|
||||||
// Check for localized font
|
|
||||||
SGPropertyNode *font_n = c_node->getNode("font", true);
|
|
||||||
if ( !strcmp(font_n->getStringValue(), "") )
|
|
||||||
font_n->setStringValue(d_node->getStringValue("font", "typewriter.txf"));
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Load the default strings
|
|
||||||
//
|
|
||||||
SGPath d_path( globals->get_fg_root() );
|
|
||||||
|
|
||||||
const char *d_path_str = d_node->getStringValue("strings");
|
|
||||||
if (!d_path_str) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << d_node->getPath() << "/strings.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
d_path.append(d_path_str);
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << d_path.str());
|
|
||||||
|
|
||||||
SGPropertyNode *strings = c_node->getNode("strings");
|
|
||||||
try {
|
|
||||||
readProperties(d_path.str(), strings);
|
|
||||||
} catch (const sg_exception &) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Load the language specific strings
|
|
||||||
//
|
|
||||||
if (c_node != d_node) {
|
|
||||||
SGPath c_path( globals->get_fg_root() );
|
|
||||||
|
|
||||||
const char *c_path_str = c_node->getStringValue("strings");
|
|
||||||
if (!c_path_str) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << c_node->getPath() << "/strings");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
c_path.append(c_path_str);
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << c_path.str());
|
|
||||||
|
|
||||||
try {
|
|
||||||
readProperties(c_path.str(), strings);
|
|
||||||
} catch (const sg_exception &) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
||||||
"Unable to read the localized strings from " << c_path.str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return c_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize the localization routines
|
|
||||||
bool fgDetectLanguage() {
|
|
||||||
const char *language = ::getenv("LANG");
|
|
||||||
|
|
||||||
if (language == NULL) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
|
|
||||||
language = "C";
|
|
||||||
}
|
|
||||||
|
|
||||||
SGPropertyNode *locale = fgInitLocale(language);
|
|
||||||
if (!locale) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
||||||
"No internationalization settings specified in preferences.xml" );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
globals->set_locale( locale );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
|
bool fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
|
||||||
|
@ -561,11 +431,6 @@ bool fgInitConfig ( int argc, char **argv )
|
||||||
fgLoadProps("preferences.xml", globals->get_props());
|
fgLoadProps("preferences.xml", globals->get_props());
|
||||||
SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
|
SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
|
||||||
|
|
||||||
// Detect the required language as early as possible
|
|
||||||
if ( !fgDetectLanguage() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
globals->loadUserSettings(dataPath);
|
globals->loadUserSettings(dataPath);
|
||||||
|
|
||||||
// Scan user config files and command line for a specified aircraft.
|
// Scan user config files and command line for a specified aircraft.
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "globals.hxx"
|
#include "globals.hxx"
|
||||||
#include "renderer.hxx"
|
#include "renderer.hxx"
|
||||||
#include "viewmgr.hxx"
|
#include "viewmgr.hxx"
|
||||||
|
#include "locale.hxx"
|
||||||
|
|
||||||
#include "fg_props.hxx"
|
#include "fg_props.hxx"
|
||||||
#include "fg_io.hxx"
|
#include "fg_io.hxx"
|
||||||
|
@ -122,7 +123,7 @@ FGGlobals *globals;
|
||||||
FGGlobals::FGGlobals() :
|
FGGlobals::FGGlobals() :
|
||||||
props( new SGPropertyNode ),
|
props( new SGPropertyNode ),
|
||||||
initial_state( NULL ),
|
initial_state( NULL ),
|
||||||
locale( NULL ),
|
locale( new FGLocale(props) ),
|
||||||
renderer( new FGRenderer ),
|
renderer( new FGRenderer ),
|
||||||
subsystem_mgr( new SGSubsystemMgr ),
|
subsystem_mgr( new SGSubsystemMgr ),
|
||||||
event_mgr( new SGEventMgr ),
|
event_mgr( new SGEventMgr ),
|
||||||
|
@ -211,6 +212,9 @@ FGGlobals::~FGGlobals()
|
||||||
delete carrierlist;
|
delete carrierlist;
|
||||||
delete channellist;
|
delete channellist;
|
||||||
delete sound;
|
delete sound;
|
||||||
|
|
||||||
|
delete locale;
|
||||||
|
locale = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ class FGControls;
|
||||||
class FGFlightPlanDispatcher;
|
class FGFlightPlanDispatcher;
|
||||||
class FGNavList;
|
class FGNavList;
|
||||||
class FGTACANList;
|
class FGTACANList;
|
||||||
|
class FGLocale;
|
||||||
class FGModelMgr;
|
class FGModelMgr;
|
||||||
class FGRouteMgr;
|
class FGRouteMgr;
|
||||||
class FGScenery;
|
class FGScenery;
|
||||||
|
@ -86,7 +87,7 @@ private:
|
||||||
SGPropertyNode_ptr initial_state;
|
SGPropertyNode_ptr initial_state;
|
||||||
|
|
||||||
// localization
|
// localization
|
||||||
SGPropertyNode_ptr locale;
|
FGLocale* locale;
|
||||||
|
|
||||||
FGRenderer *renderer;
|
FGRenderer *renderer;
|
||||||
SGSubsystemMgr *subsystem_mgr;
|
SGSubsystemMgr *subsystem_mgr;
|
||||||
|
@ -255,8 +256,7 @@ public:
|
||||||
inline SGPropertyNode *get_props () { return props; }
|
inline SGPropertyNode *get_props () { return props; }
|
||||||
inline void set_props( SGPropertyNode *n ) { props = n; }
|
inline void set_props( SGPropertyNode *n ) { props = n; }
|
||||||
|
|
||||||
inline SGPropertyNode *get_locale () { return locale; }
|
inline FGLocale* get_locale () { return locale; }
|
||||||
inline void set_locale( SGPropertyNode *n ) { locale = n; }
|
|
||||||
|
|
||||||
inline SGCommandMgr *get_commands () { return commands; }
|
inline SGCommandMgr *get_commands () { return commands; }
|
||||||
|
|
||||||
|
|
294
src/Main/locale.cxx
Normal file
294
src/Main/locale.cxx
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
// locale.cxx -- FlightGear Localization Support
|
||||||
|
//
|
||||||
|
// Written by Thorsten Brehm, started April 2012.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012 Thorsten Brehm - brehmt (at) gmail com
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
#include <simgear/props/props_io.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
|
#include "fg_props.hxx"
|
||||||
|
#include "locale.hxx"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
FGLocale::FGLocale(SGPropertyNode* root) :
|
||||||
|
_intl(root->getNode("/sim/intl",0, true)),
|
||||||
|
_defaultLocale(_intl->getChild("locale",0, true))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FGLocale::~FGLocale()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search property tree for matching locale description
|
||||||
|
SGPropertyNode*
|
||||||
|
FGLocale::findLocaleNode(const string& language)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Searching language resource for locale: " << language);
|
||||||
|
|
||||||
|
SGPropertyNode* node = NULL;
|
||||||
|
|
||||||
|
// remove character encoding from the locale spec, i.e. "de_DE.utf8" => "de_DE"
|
||||||
|
size_t pos = language.find(".");
|
||||||
|
if ((pos != string::npos)&&(pos>0))
|
||||||
|
{
|
||||||
|
node = findLocaleNode(language.substr(0, pos));
|
||||||
|
if (node)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try country's default resource, i.e. "de_DE" => "de"
|
||||||
|
pos = language.find("_");
|
||||||
|
if ((pos != string::npos)&&(pos>0))
|
||||||
|
{
|
||||||
|
node = findLocaleNode(language.substr(0, pos));
|
||||||
|
if (node)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search locale using full string
|
||||||
|
vector<SGPropertyNode_ptr> localeList = _intl->getChildren("locale");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < localeList.size(); i++)
|
||||||
|
{
|
||||||
|
vector<SGPropertyNode_ptr> langList = localeList[i]->getChildren("lang");
|
||||||
|
|
||||||
|
for (size_t j = 0; j < langList.size(); j++)
|
||||||
|
{
|
||||||
|
if (!language.compare(langList[j]->getStringValue()))
|
||||||
|
return localeList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the language. When no language is given (NULL),
|
||||||
|
// a default is determined matching the system locale.
|
||||||
|
bool
|
||||||
|
FGLocale::selectLanguage(const char *language)
|
||||||
|
{
|
||||||
|
// Use environment setting when no language is given.
|
||||||
|
if ((language == NULL)||(language[0]==0))
|
||||||
|
language = ::getenv("LANG");
|
||||||
|
|
||||||
|
// Use plain C locale if nothing is available.
|
||||||
|
if (language == NULL)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
|
||||||
|
language = "C";
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPropertyNode *locale = findLocaleNode(language);
|
||||||
|
if (!locale)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"No internationalization settings specified in preferences.xml" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentLocale = locale;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load strings for requested resource and locale.
|
||||||
|
// Result is stored below "strings" in the property tree of the given locale.
|
||||||
|
bool
|
||||||
|
FGLocale::loadResource(SGPropertyNode* localeNode, const char* resource)
|
||||||
|
{
|
||||||
|
SGPath path( globals->get_fg_root() );
|
||||||
|
|
||||||
|
SGPropertyNode* stringNode = localeNode->getNode("strings", 0, true);
|
||||||
|
|
||||||
|
const char *path_str = stringNode->getStringValue(resource, NULL);
|
||||||
|
if (!path_str)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << stringNode->getPath() << "/" << resource << ".");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.append(path_str);
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings for '" <<
|
||||||
|
localeNode->getStringValue("lang", "<none>")
|
||||||
|
<<"' from " << path.str());
|
||||||
|
|
||||||
|
// load the actual file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
readProperties(path.str(), stringNode->getNode(resource, 0, true));
|
||||||
|
} catch (const sg_exception &e)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings from " << path.str() <<
|
||||||
|
". Error: " << e.getFormattedMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load strings for requested resource (for current and default locale).
|
||||||
|
// Result is stored below "strings" in the property tree of the locales.
|
||||||
|
bool
|
||||||
|
FGLocale::loadResource(const char* resource)
|
||||||
|
{
|
||||||
|
// load defaults first
|
||||||
|
bool Ok = loadResource(_defaultLocale, resource);
|
||||||
|
|
||||||
|
// also load language specific resource, unless identical
|
||||||
|
if ((_currentLocale!=0)&&
|
||||||
|
(_defaultLocale != _currentLocale))
|
||||||
|
{
|
||||||
|
Ok &= loadResource(_currentLocale, resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
FGLocale::getLocalizedString(SGPropertyNode *localeNode, const char* id, const char* context)
|
||||||
|
{
|
||||||
|
SGPropertyNode *n = localeNode->getNode("strings",0, true)->getNode(context);
|
||||||
|
if (n)
|
||||||
|
return n->getStringValue(id, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
FGLocale::getLocalizedString(const char* id, const char* resource, const char* Default)
|
||||||
|
{
|
||||||
|
if (id && resource)
|
||||||
|
{
|
||||||
|
const char* s = NULL;
|
||||||
|
if (_currentLocale)
|
||||||
|
s = getLocalizedString(_currentLocale, id, resource);
|
||||||
|
if (s && s[0]!=0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
if (_defaultLocale)
|
||||||
|
s = getLocalizedString(_defaultLocale, id, resource);
|
||||||
|
if (s && s[0]!=0)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgear::PropertyList
|
||||||
|
FGLocale::getLocalizedStrings(SGPropertyNode *localeNode, const char* id, const char* context)
|
||||||
|
{
|
||||||
|
SGPropertyNode *n = localeNode->getNode("strings",0, true)->getNode(context);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
return n->getChildren(id);
|
||||||
|
}
|
||||||
|
return simgear::PropertyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
simgear::PropertyList
|
||||||
|
FGLocale::getLocalizedStrings(const char* id, const char* resource)
|
||||||
|
{
|
||||||
|
if (id && resource)
|
||||||
|
{
|
||||||
|
if (_currentLocale)
|
||||||
|
{
|
||||||
|
simgear::PropertyList s = getLocalizedStrings(_currentLocale, id, resource);
|
||||||
|
if (s.size())
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_defaultLocale)
|
||||||
|
{
|
||||||
|
simgear::PropertyList s = getLocalizedStrings(_defaultLocale, id, resource);
|
||||||
|
if (s.size())
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return simgear::PropertyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for localized font
|
||||||
|
const char*
|
||||||
|
FGLocale::getDefaultFont(const char* fallbackFont)
|
||||||
|
{
|
||||||
|
const char* font = NULL;
|
||||||
|
if (_currentLocale)
|
||||||
|
{
|
||||||
|
font = _currentLocale->getStringValue("font", "");
|
||||||
|
if (font[0] != 0)
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
if (_defaultLocale)
|
||||||
|
{
|
||||||
|
font = _defaultLocale->getStringValue("font", "");
|
||||||
|
if (font[0] != 0)
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple UTF8 to Latin1 encoder.
|
||||||
|
void FGLocale::utf8toLatin1(string& s)
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
// map '0xc3..' utf8 characters to Latin1
|
||||||
|
while ((string::npos != (pos = s.find('\xc3',pos)))&&
|
||||||
|
(pos+1 < s.size()))
|
||||||
|
{
|
||||||
|
char c='*';
|
||||||
|
unsigned char p = s[pos+1];
|
||||||
|
if ((p>=0x80)&&(p<0xc0))
|
||||||
|
c = 0x40 + p;
|
||||||
|
char v[2];
|
||||||
|
v[0]=c;
|
||||||
|
v[1]=0;
|
||||||
|
s.replace(pos, 2, v);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENCODING
|
||||||
|
printf("'%s': ", s.c_str());
|
||||||
|
for (pos = 0;pos<s.size();pos++)
|
||||||
|
printf("%02x ", (unsigned char) s[pos]);
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// hack: also map some Latin2 characters to plain-text ASCII
|
||||||
|
pos = 0;
|
||||||
|
while ((string::npos != (pos = s.find('\xc5',pos)))&&
|
||||||
|
(pos+1 < s.size()))
|
||||||
|
{
|
||||||
|
char c='*';
|
||||||
|
unsigned char p = s[pos+1];
|
||||||
|
switch(p)
|
||||||
|
{
|
||||||
|
case 0x82:c='l';break;
|
||||||
|
case 0x9a:c='S';break;
|
||||||
|
case 0x9b:c='s';break;
|
||||||
|
case 0xba:c='z';break;
|
||||||
|
case 0xbc:c='z';break;
|
||||||
|
}
|
||||||
|
char v[2];
|
||||||
|
v[0]=c;
|
||||||
|
v[1]=0;
|
||||||
|
s.replace(pos, 2, v);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
101
src/Main/locale.hxx
Normal file
101
src/Main/locale.hxx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// locale.hxx -- FlightGear Localization Support
|
||||||
|
//
|
||||||
|
// Written by Thorsten Brehm, started April 2012.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012 Thorsten Brehm - brehmt (at) gmail com
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
#ifndef __FGLOCALE_HXX
|
||||||
|
#define __FGLOCALE_HXX
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FGLocale //////////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class FGLocale
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FGLocale(SGPropertyNode* root);
|
||||||
|
virtual ~FGLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the locale's primary language. When no language is given (NULL),
|
||||||
|
* a default is determined matching the system locale.
|
||||||
|
*/
|
||||||
|
bool selectLanguage (const char* language = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load strings for requested resource, i.e. "menu", "options", "dialogs".
|
||||||
|
* Loads data for current and default locale (the latter is the fallback).
|
||||||
|
* Result is stored below the "strings" node in the property tree of the
|
||||||
|
* respective locale.
|
||||||
|
*/
|
||||||
|
bool loadResource (const char* resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a single string from the localized resource matching the given identifier.
|
||||||
|
* Selected context refers to "menu", "options", "dialog" etc.
|
||||||
|
*/
|
||||||
|
const char* getLocalizedString (const char* id, const char* resource, const char* Default=NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a list of strings from the localized resource matching the given identifier.
|
||||||
|
* Selected context refers to "menu", "options", "dialog" etc.
|
||||||
|
* Returns a list of (string) properties.
|
||||||
|
*/
|
||||||
|
simgear::PropertyList getLocalizedStrings(const char* id, const char* resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain default font for current locale.
|
||||||
|
*/
|
||||||
|
const char* getDefaultFont (const char* fallbackFont);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple UTF8 to Latin1 encoder.
|
||||||
|
*/
|
||||||
|
static void utf8toLatin1 (std::string& s);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Find property node matching given language.
|
||||||
|
*/
|
||||||
|
SGPropertyNode* findLocaleNode (const std::string& language);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load resource data for given locale node.
|
||||||
|
*/
|
||||||
|
bool loadResource (SGPropertyNode* localeNode, const char* resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a single string from locale node matching the given identifier and context.
|
||||||
|
*/
|
||||||
|
const char* getLocalizedString (SGPropertyNode *localeNode, const char* id, const char* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a list of strings from locale node matching the given identifier and context.
|
||||||
|
*/
|
||||||
|
simgear::PropertyList getLocalizedStrings(SGPropertyNode *localeNode, const char* id, const char* context);
|
||||||
|
|
||||||
|
SGPropertyNode_ptr _intl;
|
||||||
|
SGPropertyNode_ptr _currentLocale;
|
||||||
|
SGPropertyNode_ptr _defaultLocale;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __FGLOCALE_HXX
|
|
@ -499,7 +499,7 @@ int fgMainInit( int argc, char **argv ) {
|
||||||
#endif
|
#endif
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "FlightGear: Version "
|
SG_LOG( SG_GENERAL, SG_INFO, "FlightGear: Version "
|
||||||
<< version );
|
<< version );
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "Built with " << SG_COMPILER_STR << std::endl );
|
SG_LOG( SG_GENERAL, SG_INFO, "Built with " << SG_COMPILER_STR << std::endl );
|
||||||
|
|
||||||
// Allocate global data structures. This needs to happen before
|
// Allocate global data structures. This needs to happen before
|
||||||
// we parse command line options
|
// we parse command line options
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
#include "viewmgr.hxx"
|
#include "viewmgr.hxx"
|
||||||
#include "main.hxx"
|
#include "main.hxx"
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
|
#include <Main/locale.hxx>
|
||||||
#include <Environment/presets.hxx>
|
#include <Environment/presets.hxx>
|
||||||
|
|
||||||
#include <osg/Version>
|
#include <osg/Version>
|
||||||
|
@ -1971,11 +1972,10 @@ string_list Options::valuesForOption(const std::string& key) const
|
||||||
|
|
||||||
void Options::processOptions()
|
void Options::processOptions()
|
||||||
{
|
{
|
||||||
// establish locale before showing help
|
// establish locale before showing help (this selects the default locale,
|
||||||
if (isOptionSet("language")) {
|
// when no explicit option was set)
|
||||||
globals->set_locale( fgInitLocale( valueForOption("language").c_str() ) );
|
globals->get_locale()->selectLanguage(valueForOption("language").c_str());
|
||||||
}
|
|
||||||
|
|
||||||
// now FG_ROOT is setup, process various command line options that bail us
|
// now FG_ROOT is setup, process various command line options that bail us
|
||||||
// out quickly, but rely on aircraft / root settings
|
// out quickly, but rely on aircraft / root settings
|
||||||
if (p->showHelp) {
|
if (p->showHelp) {
|
||||||
|
@ -2064,12 +2064,12 @@ void Options::showUsage() const
|
||||||
{
|
{
|
||||||
fgOptLogLevel( "alert" );
|
fgOptLogLevel( "alert" );
|
||||||
|
|
||||||
SGPropertyNode *locale = globals->get_locale();
|
FGLocale *locale = globals->get_locale();
|
||||||
SGPropertyNode options_root;
|
SGPropertyNode options_root;
|
||||||
|
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
|
SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fgLoadProps("options.xml", &options_root);
|
fgLoadProps("options.xml", &options_root);
|
||||||
} catch (const sg_exception &) {
|
} catch (const sg_exception &) {
|
||||||
|
@ -2080,17 +2080,23 @@ void Options::showUsage() const
|
||||||
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode *options = options_root.getNode("options");
|
SGPropertyNode *options = options_root.getNode("options");
|
||||||
if (!options) {
|
if (!options) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||||
"Error reading options.xml: <options> directive not found." );
|
"Error reading options.xml: <options> directive not found." );
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode *usage = locale->getNode(options->getStringValue("usage"));
|
if (!locale->loadResource("options"))
|
||||||
|
{
|
||||||
|
cout << "Unable to read the language resource." << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* usage = locale->getLocalizedString(options->getStringValue("usage"), "options");
|
||||||
if (usage) {
|
if (usage) {
|
||||||
cout << usage->getStringValue() << endl;
|
cout << usage << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<SGPropertyNode_ptr>section = options->getChildren("section");
|
vector<SGPropertyNode_ptr>section = options->getChildren("section");
|
||||||
|
@ -2131,21 +2137,17 @@ void Options::showUsage() const
|
||||||
msg += tmp + '\n';
|
msg += tmp + '\n';
|
||||||
msg.append(32, ' ');
|
msg.append(32, ' ');
|
||||||
}
|
}
|
||||||
// There may be more than one <description> tag assosiated
|
// There may be more than one <description> tag associated
|
||||||
// with one option
|
// with one option
|
||||||
|
|
||||||
vector<SGPropertyNode_ptr> desc;
|
vector<SGPropertyNode_ptr> desc;
|
||||||
desc = option[k]->getChildren("description");
|
desc = option[k]->getChildren("description");
|
||||||
if (desc.size() > 0) {
|
if (desc.size() > 0) {
|
||||||
for ( unsigned int l = 0; l < desc.size(); l++) {
|
for ( unsigned int l = 0; l < desc.size(); l++) {
|
||||||
|
|
||||||
// There may be more than one translation line.
|
|
||||||
|
|
||||||
string t = desc[l]->getStringValue();
|
string t = desc[l]->getStringValue();
|
||||||
SGPropertyNode *n = locale->getNode("strings");
|
|
||||||
vector<SGPropertyNode_ptr>trans_desc =
|
// There may be more than one translation line.
|
||||||
n->getChildren(t.substr(8).c_str());
|
vector<SGPropertyNode_ptr>trans_desc = locale->getLocalizedStrings(t.c_str(),"options");
|
||||||
|
|
||||||
for ( unsigned int m = 0; m < trans_desc.size(); m++ ) {
|
for ( unsigned int m = 0; m < trans_desc.size(); m++ ) {
|
||||||
string t_str = trans_desc[m]->getStringValue();
|
string t_str = trans_desc[m]->getStringValue();
|
||||||
|
|
||||||
|
@ -2171,19 +2173,18 @@ void Options::showUsage() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode *name;
|
const char* name = locale->getLocalizedString(section[j]->getStringValue("name"),"options");
|
||||||
name = locale->getNode(section[j]->getStringValue("name"));
|
|
||||||
|
|
||||||
if (!msg.empty() && name) {
|
if (!msg.empty() && name) {
|
||||||
cout << endl << name->getStringValue() << ":" << endl;
|
cout << endl << name << ":" << endl;
|
||||||
cout << msg;
|
cout << msg;
|
||||||
msg.erase();
|
msg.erase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !p->verbose ) {
|
if ( !p->verbose ) {
|
||||||
cout << endl;
|
const char* verbose_help = locale->getLocalizedString(options->getStringValue("verbose-help"),"options");
|
||||||
cout << "For a complete list of options use --help --verbose" << endl;
|
if (verbose_help)
|
||||||
|
cout << endl << verbose_help << endl;
|
||||||
}
|
}
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
std::cout << "Hit a key to continue..." << std::endl;
|
std::cout << "Hit a key to continue..." << std::endl;
|
||||||
|
|
Loading…
Add table
Reference in a new issue