1 // locale.cxx -- FlightGear Localization Support
3 // Written by Thorsten Brehm, started April 2012.
5 // Copyright (C) 2012 Thorsten Brehm - brehmt (at) gmail com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <simgear/props/props_io.hxx>
22 #include <simgear/structure/exception.hxx>
24 #include "fg_props.hxx"
30 FGLocale::FGLocale(SGPropertyNode* root) :
31 _intl(root->getNode("/sim/intl",0, true)),
32 _defaultLocale(_intl->getChild("locale",0, true))
40 // Search property tree for matching locale description
42 FGLocale::findLocaleNode(const string& language)
44 SG_LOG(SG_GENERAL, SG_INFO, "Searching language resource for locale: " << language);
46 SGPropertyNode* node = NULL;
48 // remove character encoding from the locale spec, i.e. "de_DE.utf8" => "de_DE"
49 size_t pos = language.find(".");
50 if ((pos != string::npos)&&(pos>0))
52 node = findLocaleNode(language.substr(0, pos));
57 // try country's default resource, i.e. "de_DE" => "de"
58 pos = language.find("_");
59 if ((pos != string::npos)&&(pos>0))
61 node = findLocaleNode(language.substr(0, pos));
66 // search locale using full string
67 vector<SGPropertyNode_ptr> localeList = _intl->getChildren("locale");
69 for (size_t i = 0; i < localeList.size(); i++)
71 vector<SGPropertyNode_ptr> langList = localeList[i]->getChildren("lang");
73 for (size_t j = 0; j < langList.size(); j++)
75 if (!language.compare(langList[j]->getStringValue()))
83 // Select the language. When no language is given (NULL),
84 // a default is determined matching the system locale.
86 FGLocale::selectLanguage(const char *language)
88 // Use environment setting when no language is given.
89 if ((language == NULL)||(language[0]==0))
90 language = ::getenv("LANG");
92 // Use plain C locale if nothing is available.
95 SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
99 SGPropertyNode *locale = findLocaleNode(language);
102 SG_LOG(SG_GENERAL, SG_ALERT,
103 "No internationalization settings specified in preferences.xml" );
107 _currentLocale = locale;
111 // Load strings for requested resource and locale.
112 // Result is stored below "strings" in the property tree of the given locale.
114 FGLocale::loadResource(SGPropertyNode* localeNode, const char* resource)
116 SGPath path( globals->get_fg_root() );
118 SGPropertyNode* stringNode = localeNode->getNode("strings", 0, true);
120 const char *path_str = stringNode->getStringValue(resource, NULL);
123 SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << stringNode->getPath() << "/" << resource << ".");
127 path.append(path_str);
128 SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings for '" <<
129 localeNode->getStringValue("lang", "<none>")
130 <<"' from " << path.str());
132 // load the actual file
135 readProperties(path.str(), stringNode->getNode(resource, 0, true));
136 } catch (const sg_exception &e)
138 SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings from " << path.str() <<
139 ". Error: " << e.getFormattedMessage());
146 // Load strings for requested resource (for current and default locale).
147 // Result is stored below "strings" in the property tree of the locales.
149 FGLocale::loadResource(const char* resource)
151 // load defaults first
152 bool Ok = loadResource(_defaultLocale, resource);
154 // also load language specific resource, unless identical
155 if ((_currentLocale!=0)&&
156 (_defaultLocale != _currentLocale))
158 Ok &= loadResource(_currentLocale, resource);
165 FGLocale::getLocalizedString(SGPropertyNode *localeNode, const char* id, const char* context)
167 SGPropertyNode *n = localeNode->getNode("strings",0, true)->getNode(context);
169 return n->getStringValue(id, NULL);
174 FGLocale::getLocalizedString(const char* id, const char* resource, const char* Default)
178 const char* s = NULL;
180 s = getLocalizedString(_currentLocale, id, resource);
185 s = getLocalizedString(_defaultLocale, id, resource);
192 simgear::PropertyList
193 FGLocale::getLocalizedStrings(SGPropertyNode *localeNode, const char* id, const char* context)
195 SGPropertyNode *n = localeNode->getNode("strings",0, true)->getNode(context);
198 return n->getChildren(id);
200 return simgear::PropertyList();
203 simgear::PropertyList
204 FGLocale::getLocalizedStrings(const char* id, const char* resource)
210 simgear::PropertyList s = getLocalizedStrings(_currentLocale, id, resource);
217 simgear::PropertyList s = getLocalizedStrings(_defaultLocale, id, resource);
222 return simgear::PropertyList();
225 // Check for localized font
227 FGLocale::getDefaultFont(const char* fallbackFont)
229 const char* font = NULL;
232 font = _currentLocale->getStringValue("font", "");
238 font = _defaultLocale->getStringValue("font", "");
246 // Simple UTF8 to Latin1 encoder.
247 void FGLocale::utf8toLatin1(string& s)
251 // map '0xc3..' utf8 characters to Latin1
252 while ((string::npos != (pos = s.find('\xc3',pos)))&&
256 unsigned char p = s[pos+1];
257 if ((p>=0x80)&&(p<0xc0))
262 s.replace(pos, 2, v);
266 #ifdef DEBUG_ENCODING
267 printf("'%s': ", s.c_str());
268 for (pos = 0;pos<s.size();pos++)
269 printf("%02x ", (unsigned char) s[pos]);
273 // hack: also map some Latin2 characters to plain-text ASCII
275 while ((string::npos != (pos = s.find('\xc5',pos)))&&
279 unsigned char p = s[pos+1];
282 case 0x82:c='l';break;
283 case 0x9a:c='S';break;
284 case 0x9b:c='s';break;
285 case 0xba:c='z';break;
286 case 0xbc:c='z';break;
291 s.replace(pos, 2, v);