2012-04-21 18:17:42 +00:00
|
|
|
// 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
|
2012-05-04 23:42:41 +00:00
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2012-04-21 18:17:42 +00:00
|
|
|
|
2013-02-08 07:46:34 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2012-05-06 21:15:27 +00:00
|
|
|
#ifdef HAVE_WINDOWS_H
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2013-11-14 23:32:02 +00:00
|
|
|
#include <cstdio>
|
Load --help output and translated strings from $FG_INSTALL_PREFIX/share/flightgear
$FG_INSTALL_PREFIX represents the FlightGear installation prefix, such
as /usr, /usr/local or /opt/FlightGear on Unix systems. Copying the
--help output and translated strings there avoids having to write to
$FG_ROOT when 'make install' (or some OS-dependent equivalent) is run
from the FlightGear build directory---that would be ugly when $FG_ROOT
points to the FGData Git repository.
In FGLocale::FGLocale(), Translations/locale.xml is loaded using
readProperties() and fatalMessageBox() (in case an error is
encountered). Note that it couldn't be loaded via fgLoadProps() in the
current state, because this function relies on guiErrorMessage() when an
error is encountered, which calls mkDialog(), which itself does
globals->get_subsystem("gui"). This last call can't be done from
FGGlobals' constructor---where the 'globals' pointer is still
NULL---hence the need for a different mechanism not relying on
FGGlobals.
For consistency, and also because it provides a better user experience[1],
load options.xml using the same method instead of with fgLoadProps().
[1] I.e., in case of an error, the user gets to see a graphical popup
window with an explanatory message before FG exits, assuming he is
either on Windows, or on Mac, or has Qt support built in FG, as
opposed to only an SG_LOG() call [because when options.xml is
loaded, guiErrorMessage() used by fgLoadProps() can't use the 'gui'
subsystem].
2016-12-26 15:56:04 +00:00
|
|
|
#include <cstdlib>
|
2013-03-27 22:48:16 +00:00
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
|
2012-04-21 18:17:42 +00:00
|
|
|
#include <simgear/props/props_io.hxx>
|
|
|
|
#include <simgear/structure/exception.hxx>
|
|
|
|
|
|
|
|
#include "fg_props.hxx"
|
|
|
|
#include "locale.hxx"
|
Load --help output and translated strings from $FG_INSTALL_PREFIX/share/flightgear
$FG_INSTALL_PREFIX represents the FlightGear installation prefix, such
as /usr, /usr/local or /opt/FlightGear on Unix systems. Copying the
--help output and translated strings there avoids having to write to
$FG_ROOT when 'make install' (or some OS-dependent equivalent) is run
from the FlightGear build directory---that would be ugly when $FG_ROOT
points to the FGData Git repository.
In FGLocale::FGLocale(), Translations/locale.xml is loaded using
readProperties() and fatalMessageBox() (in case an error is
encountered). Note that it couldn't be loaded via fgLoadProps() in the
current state, because this function relies on guiErrorMessage() when an
error is encountered, which calls mkDialog(), which itself does
globals->get_subsystem("gui"). This last call can't be done from
FGGlobals' constructor---where the 'globals' pointer is still
NULL---hence the need for a different mechanism not relying on
FGGlobals.
For consistency, and also because it provides a better user experience[1],
load options.xml using the same method instead of with fgLoadProps().
[1] I.e., in case of an error, the user gets to see a graphical popup
window with an explanatory message before FG exits, assuming he is
either on Windows, or on Mac, or has Qt support built in FG, as
opposed to only an SG_LOG() call [because when options.xml is
loaded, guiErrorMessage() used by fgLoadProps() can't use the 'gui'
subsystem].
2016-12-26 15:56:04 +00:00
|
|
|
#include <GUI/MessageBox.hxx>
|
2012-04-21 18:17:42 +00:00
|
|
|
|
|
|
|
using std::vector;
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
FGLocale::FGLocale(SGPropertyNode* root) :
|
|
|
|
_intl(root->getNode("/sim/intl",0, true)),
|
|
|
|
_defaultLocale(_intl->getChild("locale",0, true))
|
|
|
|
{
|
Load --help output and translated strings from $FG_INSTALL_PREFIX/share/flightgear
$FG_INSTALL_PREFIX represents the FlightGear installation prefix, such
as /usr, /usr/local or /opt/FlightGear on Unix systems. Copying the
--help output and translated strings there avoids having to write to
$FG_ROOT when 'make install' (or some OS-dependent equivalent) is run
from the FlightGear build directory---that would be ugly when $FG_ROOT
points to the FGData Git repository.
In FGLocale::FGLocale(), Translations/locale.xml is loaded using
readProperties() and fatalMessageBox() (in case an error is
encountered). Note that it couldn't be loaded via fgLoadProps() in the
current state, because this function relies on guiErrorMessage() when an
error is encountered, which calls mkDialog(), which itself does
globals->get_subsystem("gui"). This last call can't be done from
FGGlobals' constructor---where the 'globals' pointer is still
NULL---hence the need for a different mechanism not relying on
FGGlobals.
For consistency, and also because it provides a better user experience[1],
load options.xml using the same method instead of with fgLoadProps().
[1] I.e., in case of an error, the user gets to see a graphical popup
window with an explanatory message before FG exits, assuming he is
either on Windows, or on Mac, or has Qt support built in FG, as
opposed to only an SG_LOG() call [because when options.xml is
loaded, guiErrorMessage() used by fgLoadProps() can't use the 'gui'
subsystem].
2016-12-26 15:56:04 +00:00
|
|
|
// Load locale.xml under _intl (which corresponds to /sim/intl). I don't
|
|
|
|
// pretend it is very useful to have this in the Global Property Tree; I
|
|
|
|
// am just making it visible under /sim/intl to preserve the previous
|
|
|
|
// behavior (when locale.xml was in FGData and automatically loaded under
|
|
|
|
// /sim/intl via an <intl include=... /> in $FG_ROOT/preferences.xml).
|
|
|
|
SGPath localeXML =
|
|
|
|
SGPath(FG_INSTALL_PREFIX) / "share/flightgear/Translations/locale.xml";
|
|
|
|
|
|
|
|
try {
|
|
|
|
readProperties(localeXML, _intl);
|
|
|
|
} catch (const sg_exception &e) {
|
|
|
|
string msg = "Unable to load '" + localeXML.utf8Str() + "'. "
|
|
|
|
"Please check that this file exists and is readable.\n\n" +
|
|
|
|
"Exception information: " + e.getFormattedMessage();
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, msg );
|
|
|
|
flightgear::fatalMessageBox(
|
|
|
|
"FlightGear", "Unable to load translation data.", msg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-21 18:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGLocale::~FGLocale()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:04:53 +00:00
|
|
|
#ifdef _WIN32
|
2012-05-06 21:15:27 +00:00
|
|
|
/**
|
|
|
|
* Determine locale/language settings on Windows.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1997, 2002, 2003 Martin von Loewis
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
|
|
* documentation for any purpose and without fee is hereby granted,
|
|
|
|
* provided that the above copyright notice appear in all copies.
|
|
|
|
*
|
|
|
|
* This software comes with no warranty. Use at your own risk.
|
|
|
|
*/
|
2013-03-27 22:48:16 +00:00
|
|
|
string_list
|
2012-05-06 21:15:27 +00:00
|
|
|
FGLocale::getUserLanguage()
|
|
|
|
{
|
2013-03-27 22:48:16 +00:00
|
|
|
string_list result;
|
2012-05-06 21:15:27 +00:00
|
|
|
static char locale[100] = {0};
|
|
|
|
|
|
|
|
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
|
|
LOCALE_SISO639LANGNAME,
|
|
|
|
locale, sizeof(locale)))
|
|
|
|
{
|
2012-05-09 21:47:34 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Detected locale's language setting: " << locale);
|
2012-05-06 21:15:27 +00:00
|
|
|
size_t i = strlen(locale);
|
|
|
|
locale[i++] = '_';
|
|
|
|
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
|
|
LOCALE_SISO3166CTRYNAME,
|
|
|
|
locale+i, (int)(sizeof(locale)-i)))
|
2013-03-27 22:48:16 +00:00
|
|
|
{
|
|
|
|
result.push_back(locale);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:04:53 +00:00
|
|
|
locale[--i] = 0;
|
2012-05-09 21:47:34 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Failed to detected locale's country setting.");
|
2013-03-27 22:48:16 +00:00
|
|
|
result.push_back(locale);
|
|
|
|
return result;
|
2012-05-06 21:15:27 +00:00
|
|
|
}
|
|
|
|
|
2013-03-27 22:48:16 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#elif __APPLE__
|
2013-11-19 22:01:11 +00:00
|
|
|
// implemented in CocoaHelpers.mm
|
2012-05-06 21:15:27 +00:00
|
|
|
#else
|
|
|
|
/**
|
2013-03-27 22:48:16 +00:00
|
|
|
* Determine locale/language settings on Linux/Unix.
|
2012-05-06 21:15:27 +00:00
|
|
|
*/
|
2013-03-27 22:48:16 +00:00
|
|
|
string_list
|
2012-05-06 21:15:27 +00:00
|
|
|
FGLocale::getUserLanguage()
|
|
|
|
{
|
2013-03-27 22:48:16 +00:00
|
|
|
string_list result;
|
|
|
|
const char* langEnv = ::getenv("LANG");
|
|
|
|
if (langEnv) {
|
|
|
|
result.push_back(langEnv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2012-05-06 21:15:27 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-04-21 18:17:42 +00:00
|
|
|
// Search property tree for matching locale description
|
|
|
|
SGPropertyNode*
|
|
|
|
FGLocale::findLocaleNode(const string& 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;
|
|
|
|
}
|
|
|
|
|
2012-05-09 21:47:34 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Searching language resource for locale: " << language);
|
2012-04-21 18:17:42 +00:00
|
|
|
// 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++)
|
|
|
|
{
|
2012-05-08 21:04:53 +00:00
|
|
|
if (!language.compare(langList[j]->getStringValue()))
|
|
|
|
{
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Found language resource for: " << language);
|
|
|
|
return localeList[i];
|
|
|
|
}
|
2012-04-21 18:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:04:53 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-04-21 18:17:42 +00:00
|
|
|
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)
|
|
|
|
{
|
2013-03-27 22:48:16 +00:00
|
|
|
string_list languages = getUserLanguage();
|
|
|
|
if (languages.empty()) {
|
|
|
|
// Use plain C locale if nothing is available.
|
2012-05-09 21:47:34 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Unable to detect system language" );
|
2013-03-27 22:48:16 +00:00
|
|
|
languages.push_back("C");
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we were passed a language option, try it first
|
|
|
|
if ((language != NULL) && (strlen(language) > 0)) {
|
|
|
|
languages.insert(languages.begin(), string(language));
|
2012-04-21 18:17:42 +00:00
|
|
|
}
|
|
|
|
|
2013-03-27 22:48:16 +00:00
|
|
|
|
2014-12-04 08:18:41 +00:00
|
|
|
_currentLocale = NULL;
|
2013-03-27 22:48:16 +00:00
|
|
|
BOOST_FOREACH(string lang, languages) {
|
2014-12-04 08:18:41 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "trying to find locale for " << lang );
|
|
|
|
_currentLocale = findLocaleNode(lang);
|
|
|
|
if (_currentLocale) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "found locale for " << lang << " at " << _currentLocale->getPath() );
|
2013-03-27 22:48:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-21 17:36:25 +00:00
|
|
|
// load resource for system messages (translations for fgfs internal messages)
|
|
|
|
loadResource("sys");
|
|
|
|
|
2014-02-19 13:24:34 +00:00
|
|
|
// load resource for atc messages
|
|
|
|
loadResource("atc");
|
|
|
|
|
2014-12-04 08:18:41 +00:00
|
|
|
if (!_currentLocale)
|
|
|
|
{
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
"System locale not found or no internationalization settings specified in preferences.xml. Using default (en)." );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-04-21 18:17:42 +00:00
|
|
|
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)
|
|
|
|
{
|
Load --help output and translated strings from $FG_INSTALL_PREFIX/share/flightgear
$FG_INSTALL_PREFIX represents the FlightGear installation prefix, such
as /usr, /usr/local or /opt/FlightGear on Unix systems. Copying the
--help output and translated strings there avoids having to write to
$FG_ROOT when 'make install' (or some OS-dependent equivalent) is run
from the FlightGear build directory---that would be ugly when $FG_ROOT
points to the FGData Git repository.
In FGLocale::FGLocale(), Translations/locale.xml is loaded using
readProperties() and fatalMessageBox() (in case an error is
encountered). Note that it couldn't be loaded via fgLoadProps() in the
current state, because this function relies on guiErrorMessage() when an
error is encountered, which calls mkDialog(), which itself does
globals->get_subsystem("gui"). This last call can't be done from
FGGlobals' constructor---where the 'globals' pointer is still
NULL---hence the need for a different mechanism not relying on
FGGlobals.
For consistency, and also because it provides a better user experience[1],
load options.xml using the same method instead of with fgLoadProps().
[1] I.e., in case of an error, the user gets to see a graphical popup
window with an explanatory message before FG exits, assuming he is
either on Windows, or on Mac, or has Qt support built in FG, as
opposed to only an SG_LOG() call [because when options.xml is
loaded, guiErrorMessage() used by fgLoadProps() can't use the 'gui'
subsystem].
2016-12-26 15:56:04 +00:00
|
|
|
SGPath path = SGPath(FG_INSTALL_PREFIX) / "share/flightgear";
|
2012-04-21 18:17:42 +00:00
|
|
|
|
|
|
|
SGPropertyNode* stringNode = localeNode->getNode("strings", 0, true);
|
|
|
|
|
|
|
|
const char *path_str = stringNode->getStringValue(resource, NULL);
|
|
|
|
if (!path_str)
|
|
|
|
{
|
2012-05-06 21:15:27 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "No path in " << stringNode->getPath() << "/" << resource << ".");
|
2014-05-05 20:24:47 +00:00
|
|
|
return false;
|
2012-04-21 18:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
path.append(path_str);
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings for '" <<
|
|
|
|
localeNode->getStringValue("lang", "<none>")
|
2016-06-23 13:26:34 +00:00
|
|
|
<<"' from " << path);
|
2012-04-21 18:17:42 +00:00
|
|
|
|
|
|
|
// load the actual file
|
|
|
|
try
|
|
|
|
{
|
2016-06-23 13:26:34 +00:00
|
|
|
readProperties(path, stringNode->getNode(resource, 0, true));
|
2012-04-21 18:17:42 +00:00
|
|
|
} catch (const sg_exception &e)
|
|
|
|
{
|
2016-06-23 13:26:34 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings from " << path <<
|
2012-04-21 18:17:42 +00:00
|
|
|
". 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);
|
2013-03-22 02:42:22 +00:00
|
|
|
if (! s.empty())
|
2012-04-21 18:17:42 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_defaultLocale)
|
|
|
|
{
|
|
|
|
simgear::PropertyList s = getLocalizedStrings(_defaultLocale, id, resource);
|
2013-03-22 02:42:22 +00:00
|
|
|
if (! s.empty())
|
2012-04-21 18:17:42 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-11-14 16:22:13 +00:00
|
|
|
std::string FGLocale::localizedPrintf(const char* id, const char* resource, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, resource);
|
|
|
|
string r = vlocalizedPrintf(id, resource, args);
|
|
|
|
va_end(args);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FGLocale::vlocalizedPrintf(const char* id, const char* resource, va_list args)
|
|
|
|
{
|
|
|
|
const char* format = getLocalizedString(id, resource);
|
|
|
|
int len = ::vsprintf(NULL, format, args);
|
|
|
|
char* buf = (char*) alloca(len);
|
|
|
|
::vsprintf(buf, format, args);
|
|
|
|
return std::string(buf);
|
|
|
|
}
|
|
|
|
|
2012-04-21 18:17:42 +00:00
|
|
|
// 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++;
|
|
|
|
}
|
|
|
|
}
|
2013-11-14 16:22:13 +00:00
|
|
|
|
|
|
|
const char* fgTrMsg(const char* key)
|
|
|
|
{
|
|
|
|
return globals->get_locale()->getLocalizedString(key, "message");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string fgTrPrintfMsg(const char* key, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, key);
|
|
|
|
string r = globals->get_locale()->vlocalizedPrintf(key, "message", args);
|
|
|
|
va_end(args);
|
|
|
|
return r;
|
|
|
|
|
|
|
|
}
|