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 /******************************************************************************/
120 void init_gettext(const char *path, const std::string &configured_language,
121 int argc, char *argv[])
124 // First, try to set user override environment
125 if (!configured_language.empty()) {
127 // Add user specified locale to environment
128 setenv("LANGUAGE", configured_language.c_str(), 1);
130 // Reload locale with changed environment
131 setlocale(LC_ALL, "");
132 #elif defined(_MSC_VER)
133 std::string current_language;
134 const char *env_lang = getenv("LANGUAGE");
136 current_language = env_lang;
138 _putenv(("LANGUAGE=" + configured_language).c_str());
139 SetEnvironmentVariableA("LANGUAGE", configured_language.c_str());
142 // Hack to force gettext to see the right environment
143 if (current_language != configured_language) {
144 errorstream << "MSVC localization workaround active. "
145 "Restarting " PROJECT_NAME_C " in a new environment!" << std::endl;
147 std::string parameters;
149 for (unsigned int i = 1; i < argc; i++) {
150 if (!parameters.empty())
153 parameters += argv[i];
156 const char *ptr_parameters = NULL;
158 if (!parameters.empty())
159 ptr_parameters = parameters.c_str();
161 // Allow calling without an extension
162 std::string app_name = argv[0];
163 if (app_name.compare(app_name.size() - 4, 4, ".exe") != 0)
166 STARTUPINFO startup_info = {0};
167 PROCESS_INFORMATION process_info = {0};
169 bool success = CreateProcess(app_name.c_str(), (char *)ptr_parameters,
170 NULL, NULL, false, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
171 NULL, NULL, &startup_info, &process_info);
179 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
180 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
181 sizeof(buffer) - 1, NULL);
183 errorstream << "*******************************************************" << std::endl;
184 errorstream << "CMD: " << app_name << std::endl;
185 errorstream << "Failed to restart with current locale: " << std::endl;
186 errorstream << buffer;
187 errorstream << "Expect language to be broken!" << std::endl;
188 errorstream << "*******************************************************" << std::endl;
192 errorstream << "*******************************************************" << std::endl;
193 errorstream << "Can't apply locale workaround for server!" << std::endl;
194 errorstream << "Expect language to be broken!" << std::endl;
195 errorstream << "*******************************************************" << std::endl;
198 setlocale(LC_ALL, configured_language.c_str());
200 _putenv(("LANGUAGE=" + configured_language).c_str());
201 setlocale(LC_ALL, "");
202 #endif // ifndef _WIN32
205 /* set current system default locale */
206 setlocale(LC_ALL, "");
210 if (getenv("LANGUAGE") != 0) {
211 setlocale(LC_ALL, getenv("LANGUAGE"));
214 else if (getenv("LANG") != 0) {
215 setlocale(LC_ALL, getenv("LANG"));
220 static std::string name = lowercase(PROJECT_NAME);
221 bindtextdomain(name.c_str(), path);
222 textdomain(name.c_str());
225 // Set character encoding for Win32
226 char *tdomain = textdomain( (char *) NULL );
227 if( tdomain == NULL )
229 errorstream << "Warning: domainname parameter is the null pointer" <<
230 ", default domain is not set" << std::endl;
231 tdomain = (char *) "messages";
233 /* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
234 //errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
235 #endif // defined(_WIN32)
238 /* set current system default locale */
239 setlocale(LC_ALL, "");
240 #endif // if USE_GETTEXT
242 /* no matter what locale is used we need number format to be "C" */
243 /* to ensure formspec parameters are evaluated correct! */
245 setlocale(LC_NUMERIC, "C");
246 infostream << "Message locale is now set to: "
247 << setlocale(LC_ALL, 0) << std::endl;