3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "util/string.h"
28 #if USE_GETTEXT && defined(_MSC_VER)
34 #define setlocale(category, localename) \
35 setlocale(category, MSVC_LocaleLookup(localename))
37 static std::map<std::wstring, std::wstring> glb_supported_locales;
39 /******************************************************************************/
40 BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
43 int LOCALEID = strtol(pStr, &endptr,16);
45 wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
46 memset(buffer, 0, sizeof(buffer));
49 LOCALE_SISO639LANGNAME,
51 LOCALE_NAME_MAX_LENGTH)) {
53 std::wstring name = buffer;
55 memset(buffer, 0, sizeof(buffer));
58 LOCALE_SISO3166CTRYNAME,
60 LOCALE_NAME_MAX_LENGTH);
62 std::wstring country = buffer;
64 memset(buffer, 0, sizeof(buffer));
67 LOCALE_SENGLISHLANGUAGENAME,
69 LOCALE_NAME_MAX_LENGTH);
71 std::wstring languagename = buffer;
73 /* set both short and long variant */
74 glb_supported_locales[name] = languagename;
75 glb_supported_locales[name + L"_" + country] = languagename;
80 /******************************************************************************/
81 const char* MSVC_LocaleLookup(const char* raw_shortname) {
83 /* NULL is used to read locale only so we need to return it too */
84 if (raw_shortname == NULL) return NULL;
86 std::string shortname(raw_shortname);
87 if (shortname == "C") return "C";
88 if (shortname == "") return "";
90 static std::string last_raw_value = "";
91 static std::string last_full_name = "";
92 static bool first_use = true;
94 if (last_raw_value == shortname) {
95 return last_full_name.c_str();
99 EnumSystemLocalesA(UpdateLocaleCallback, LCID_SUPPORTED | LCID_ALTERNATE_SORTS);
103 last_raw_value = shortname;
105 if (glb_supported_locales.find(utf8_to_wide(shortname)) != glb_supported_locales.end()) {
106 last_full_name = wide_to_utf8(
107 glb_supported_locales[utf8_to_wide(shortname)]);
108 return last_full_name.c_str();
111 /* empty string is system default */
112 errorstream << "MSVC_LocaleLookup: unsupported locale: \"" << shortname
113 << "\" switching to system default!" << std::endl;
119 /******************************************************************************/
121 void init_gettext(const char *path, const std::string &configured_language,
122 int argc, const char *argv[])
124 void init_gettext(const char *path, const std::string &configured_language)
128 // First, try to set user override environment
129 if (!configured_language.empty()) {
131 // Add user specified locale to environment
132 setenv("LANGUAGE", configured_language.c_str(), 1);
134 // Reload locale with changed environment
135 setlocale(LC_ALL, "");
136 #elif defined(_MSC_VER)
137 std::string current_language;
138 const char *env_lang = getenv("LANGUAGE");
140 current_language = env_lang;
142 _putenv(("LANGUAGE=" + configured_language).c_str());
143 SetEnvironmentVariableA("LANGUAGE", configured_language.c_str());
146 // Hack to force gettext to see the right environment
147 if (current_language != configured_language) {
148 errorstream << "MSVC localization workaround active. "
149 "Restarting " PROJECT_NAME_C " in a new environment!" << std::endl;
151 std::string parameters;
153 for (unsigned int i = 1; i < argc; i++) {
154 if (!parameters.empty())
157 parameters += argv[i];
160 const char *ptr_parameters = NULL;
162 if (!parameters.empty())
163 ptr_parameters = parameters.c_str();
165 // Allow calling without an extension
166 std::string app_name = argv[0];
167 if (app_name.compare(appname.size() - 4, 4, ".exe") != 0)
170 STARTUPINFO startup_info = {0};
171 PROCESS_INFORMATION process_info = {0};
173 bool success = CreateProcess(app_name.c_str(), (char *)ptr_parameters,
174 NULL, NULL, false, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
175 NULL, NULL, &startup_info, &process_info);
183 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
184 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
185 sizeof(buffer) - 1, NULL);
187 errorstream << "*******************************************************" << std::endl;
188 errorstream << "CMD: " << app_name << std::endl;
189 errorstream << "Failed to restart with current locale: " << std::endl;
190 errorstream << buffer;
191 errorstream << "Expect language to be broken!" << std::endl;
192 errorstream << "*******************************************************" << std::endl;
196 errorstream << "*******************************************************" << std::endl;
197 errorstream << "Can't apply locale workaround for server!" << std::endl;
198 errorstream << "Expect language to be broken!" << std::endl;
199 errorstream << "*******************************************************" << std::endl;
202 setlocale(LC_ALL, configured_language.c_str());
204 _putenv(("LANGUAGE=" + configured_language).c_str());
205 setlocale(LC_ALL, "");
206 #endif // ifndef _WIN32
209 /* set current system default locale */
210 setlocale(LC_ALL, "");
214 if (getenv("LANGUAGE") != 0) {
215 setlocale(LC_ALL, getenv("LANGUAGE"));
218 else if (getenv("LANG") != 0) {
219 setlocale(LC_ALL, getenv("LANG"));
224 static std::string name = lowercase(PROJECT_NAME);
225 bindtextdomain(name.c_str(), path);
226 textdomain(name.c_str());
229 // Set character encoding for Win32
230 char *tdomain = textdomain( (char *) NULL );
231 if( tdomain == NULL )
233 errorstream << "Warning: domainname parameter is the null pointer" <<
234 ", default domain is not set" << std::endl;
235 tdomain = (char *) "messages";
237 /* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
238 //errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
239 #endif // defined(_WIN32)
242 /* set current system default locale */
243 setlocale(LC_ALL, "");
244 #endif // if USE_GETTEXT
246 /* no matter what locale is used we need number format to be "C" */
247 /* to ensure formspec parameters are evaluated correct! */
249 setlocale(LC_NUMERIC, "C");
250 infostream << "Message locale is now set to: "
251 << setlocale(LC_ALL, 0) << std::endl;