00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "global.hpp"
00017
00018 #include "config.hpp"
00019 #include "filesystem.hpp"
00020 #include "foreach.hpp"
00021 #include "game_config.hpp"
00022 #include "gettext.hpp"
00023 #include "language.hpp"
00024 #include "log.hpp"
00025 #include "preferences.hpp"
00026 #include "util.hpp"
00027 #include "serialization/parser.hpp"
00028 #include "serialization/preprocessor.hpp"
00029 #include "wesconfig.h"
00030
00031 #include <algorithm>
00032 #include <cassert>
00033 #include <cctype>
00034 #include <cerrno>
00035 #include <clocale>
00036 #include <cstdlib>
00037 #include <cstring>
00038 #include <iostream>
00039 #include <stdexcept>
00040
00041
00042 static bool has_locale(const char* s) {
00043 try {
00044
00045
00046 std::locale dummy(s);
00047 return true;
00048 } catch (std::runtime_error&) {
00049 return false;
00050 }
00051 }
00052
00053
00054 static bool has_language(const std::string& language)
00055 {
00056 if(has_locale(language.c_str())) {
00057 return true;
00058 }
00059
00060 std::string utf = language + ".utf-8";
00061 if(has_locale(utf.c_str())) {
00062 return true;
00063 }
00064
00065 utf = language + ".UTF-8";
00066 if(has_locale(utf.c_str())) {
00067 return true;
00068 }
00069
00070 return false;
00071 }
00072
00073 namespace {
00074 language_def current_language;
00075 string_map strings_;
00076 }
00077
00078 static std::vector<language_def> known_languages;
00079
00080 std::string languagedef_name (const language_def& def)
00081 {
00082 return def.language;
00083 }
00084
00085 bool current_language_rtl()
00086 {
00087 return get_language().rtl;
00088 }
00089
00090 bool language_def::operator== (const language_def& a) const
00091 {
00092 return ((language == a.language) );
00093 }
00094
00095 bool language_def::available() const
00096 {
00097 #ifdef USE_DUMMYLOCALES
00098
00099 return true;
00100 #else
00101 if(has_language(localename)) {
00102 return true;
00103 } else {
00104 foreach(const std::string& lang, alternates) {
00105 if(has_language(lang)) {
00106 return true;
00107 }
00108 }
00109 }
00110 return false;
00111 #endif
00112 }
00113
00114 symbol_table string_table;
00115
00116 const t_string& symbol_table::operator[](const std::string& key) const
00117 {
00118 const string_map::const_iterator i = strings_.find(key);
00119 if(i != strings_.end()) {
00120 return i->second;
00121 } else {
00122 static t_string empty_string;
00123
00124
00125
00126
00127 empty_string = "UNTLB " + key;
00128 return empty_string;
00129 }
00130 }
00131
00132 const t_string& symbol_table::operator[](const char* key) const
00133 {
00134 return (*this)[std::string(key)];
00135 }
00136
00137 bool load_language_list()
00138 {
00139 config cfg;
00140 try {
00141 scoped_istream stream = preprocess_file("data/hardwired/language.cfg");
00142 read(cfg, *stream);
00143 } catch(config::error &) {
00144 return false;
00145 }
00146
00147 known_languages.clear();
00148 known_languages.push_back(
00149 language_def("", t_string(N_("System default language"), "wesnoth"), "ltr"));
00150
00151 config::const_child_itors langs = cfg.child_range("locale");
00152 for(;langs.first != langs.second; ++langs.first) {
00153 known_languages.push_back(
00154 language_def((**langs.first)["locale"], (**langs.first)["name"], (**langs.first)["dir"],
00155 (**langs.first)["alternates"]));
00156 }
00157
00158 return true;
00159 }
00160
00161 std::vector<language_def> get_languages()
00162 {
00163 return known_languages;
00164 }
00165
00166 static void wesnoth_setlocale(int category, std::string const &slocale,
00167 std::vector<std::string> const *alternates)
00168 {
00169 char const *locale = slocale.c_str();
00170
00171
00172
00173
00174
00175 #ifndef _WIN32
00176 #ifndef __AMIGAOS4__
00177 unsetenv ("LANGUAGE");
00178 #endif
00179 #endif
00180
00181 #ifdef __BEOS__
00182 if(setenv ("LANG", locale, 1) == -1)
00183 std::cerr << "setenv LANG failed: " << strerror(errno);
00184 if(setenv ("LC_ALL", locale, 1) == -1)
00185 std::cerr << "setenv LC_ALL failed: " << strerror(errno);
00186 #endif
00187 #ifdef __APPLE__
00188 if(setenv ("LANGUAGE", locale, 1) == -1)
00189 std::cerr << "setenv LANGUAGE failed: " << strerror(errno);
00190 if(setenv ("LC_ALL", locale, 1) == -1)
00191 std::cerr << "setenv LC_ALL failed: " << strerror(errno);
00192 #endif
00193
00194 #ifdef _WIN32
00195 const std::string env = "LANG=" + slocale;
00196 putenv(env.c_str());
00197 #endif
00198
00199 #ifdef USE_DUMMYLOCALES
00200 static enum { UNINIT, NONE, PRESENT } status = UNINIT;
00201 static std::string locpath;
00202 if (status == UNINIT)
00203 if (char const *p = getenv("LOCPATH")) {
00204 locpath = p;
00205 status = PRESENT;
00206 } else status = NONE;
00207 if (slocale.empty())
00208 if (status == NONE)
00209 unsetenv("LOCPATH");
00210 else
00211 setenv("LOCPATH", locpath.c_str(), 1);
00212 else setenv("LOCPATH", (game_config::path + "/locales").c_str(), 1);
00213 std::string xlocale;
00214 if (!slocale.empty()) {
00215
00216 xlocale = slocale + "@wesnoth";
00217 locale = xlocale.c_str();
00218 }
00219 #endif
00220
00221 char *res = NULL;
00222 char const *try_loc = locale;
00223 std::vector<std::string>::const_iterator i;
00224 if (alternates) i = alternates->begin();
00225 while (true) {
00226 res = std::setlocale(category, try_loc);
00227 if (res) break;
00228
00229 std::string utf8 = std::string(try_loc) + std::string(".utf-8");
00230 res = std::setlocale(category, utf8.c_str());
00231 if (res) break;
00232
00233 utf8 = std::string(try_loc) + std::string(".UTF-8");
00234 res = std::setlocale(category, utf8.c_str());
00235 if (res) break;
00236
00237 if (!alternates) break;
00238 if (i == alternates->end()) break;
00239 try_loc = i->c_str();
00240 i++;
00241 }
00242
00243 if (res == NULL)
00244 std::cerr << "WARNING: setlocale() failed for '"
00245 << locale << "'.\n";
00246 else
00247 std::cerr << "set locale to '" << try_loc << "'\n";
00248 }
00249
00250 bool set_language(const language_def& locale)
00251 {
00252 strings_.clear();
00253
00254 std::string locale_lc;
00255 locale_lc.resize(locale.localename.size());
00256 std::transform(locale.localename.begin(),locale.localename.end(),locale_lc.begin(),tolower);
00257
00258 config cfg;
00259
00260 current_language = locale;
00261 wesnoth_setlocale(LC_MESSAGES, locale.localename, &locale.alternates);
00262 wesnoth_setlocale(LC_COLLATE, locale.localename, &locale.alternates);
00263
00264
00265 try {
00266 scoped_istream stream = preprocess_file("data/hardwired/english.cfg");
00267 read(cfg, *stream);
00268 } catch(config::error& e) {
00269 std::cerr << "Could not read english.cfg\n";
00270 throw e;
00271 }
00272
00273 config* langp = cfg.child("language");
00274 if (langp == NULL) {
00275 std::cerr << "No [language] block found in english.cfg\n";
00276 return false;
00277 }
00278
00279 for(string_map::const_iterator j = langp->values.begin(); j != langp->values.end(); ++j) {
00280 strings_[j->first] = j->second;
00281 }
00282
00283
00284
00285 for (std::vector<language_def>::iterator itor = known_languages.begin();
00286 itor != known_languages.end(); ++itor) {
00287
00288 itor->language.reset_translation();
00289 }
00290
00291 return true;
00292 }
00293
00294 const language_def& get_language() { return current_language; }
00295
00296 const language_def& get_locale()
00297 {
00298
00299
00300 assert(known_languages.size() != 0);
00301
00302 const std::string& prefs_locale = preferences::language();
00303 if(prefs_locale.empty() == false) {
00304 wesnoth_setlocale(LC_MESSAGES, prefs_locale, NULL);
00305 for(std::vector<language_def>::const_iterator i = known_languages.begin();
00306 i != known_languages.end(); ++i) {
00307 if (prefs_locale == i->localename)
00308 return *i;
00309 }
00310 LOG_STREAM(info, general) << "'" << prefs_locale << "' locale not found in known array; defaulting to system locale\n";
00311 return known_languages[0];
00312 }
00313
00314 #if 0
00315 const char* const locale = getenv("LANG");
00316 if(locale != NULL && strlen(locale) >= 2) {
00317
00318
00319
00320 std::string res(2,'z');
00321 res[0] = tolower(locale[0]);
00322 res[1] = tolower(locale[1]);
00323 return res;
00324 }
00325 #endif
00326
00327 LOG_STREAM(info, general) << "locale could not be determined; defaulting to system locale\n";
00328 return known_languages[0];
00329 }
00330
00331 void init_textdomains(const config& cfg)
00332 {
00333 config::const_child_itors t = cfg.child_range("textdomain");
00334
00335 for(;t.first != t.second; ++t.first) {
00336 const std::string name = (**t.first)["name"];
00337 const std::string path = (**t.first)["path"];
00338
00339 if(path.empty()) {
00340 t_string::add_textdomain(name, get_intl_dir());
00341 } else {
00342 const std::string& location = get_binary_file_location(path, "");
00343
00344
00345
00346 if(location.empty()) {
00347 std::cerr << "no location found for '" << path << "', not adding textdomain\n";
00348 } else {
00349 t_string::add_textdomain(name, location);
00350 }
00351 }
00352 }
00353 }
00354