Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
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.
9 :
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.
14 :
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.
18 : */
19 :
20 : #include <string>
21 : #include <string.h>
22 : #include <iostream>
23 : #include <stdlib.h>
24 : #include "gettext.h"
25 : #include "util/string.h"
26 : #include "log.h"
27 :
28 : #if USE_GETTEXT && defined(_MSC_VER)
29 : #include <windows.h>
30 : #include <map>
31 : #include <direct.h>
32 : #include "filesys.h"
33 :
34 : #define setlocale(category, localename) \
35 : setlocale(category, MSVC_LocaleLookup(localename))
36 :
37 : static std::map<std::wstring, std::wstring> glb_supported_locales;
38 :
39 : /******************************************************************************/
40 : BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
41 : {
42 : char* endptr = 0;
43 : int LOCALEID = strtol(pStr, &endptr,16);
44 :
45 : wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
46 : memset(buffer, 0, sizeof(buffer));
47 : if (GetLocaleInfoW(
48 : LOCALEID,
49 : LOCALE_SISO639LANGNAME,
50 : buffer,
51 : LOCALE_NAME_MAX_LENGTH)) {
52 :
53 : std::wstring name = buffer;
54 :
55 : memset(buffer, 0, sizeof(buffer));
56 : GetLocaleInfoW(
57 : LOCALEID,
58 : LOCALE_SISO3166CTRYNAME,
59 : buffer,
60 : LOCALE_NAME_MAX_LENGTH);
61 :
62 : std::wstring country = buffer;
63 :
64 : memset(buffer, 0, sizeof(buffer));
65 : GetLocaleInfoW(
66 : LOCALEID,
67 : LOCALE_SENGLISHLANGUAGENAME,
68 : buffer,
69 : LOCALE_NAME_MAX_LENGTH);
70 :
71 : std::wstring languagename = buffer;
72 :
73 : /* set both short and long variant */
74 : glb_supported_locales[name] = languagename;
75 : glb_supported_locales[name + L"_" + country] = languagename;
76 : }
77 : return true;
78 : }
79 :
80 : /******************************************************************************/
81 : const char* MSVC_LocaleLookup(const char* raw_shortname) {
82 :
83 : /* NULL is used to read locale only so we need to return it too */
84 : if (raw_shortname == NULL) return NULL;
85 :
86 : std::string shortname(raw_shortname);
87 : if (shortname == "C") return "C";
88 : if (shortname == "") return "";
89 :
90 : static std::string last_raw_value = "";
91 : static std::string last_full_name = "";
92 : static bool first_use = true;
93 :
94 : if (last_raw_value == shortname) {
95 : return last_full_name.c_str();
96 : }
97 :
98 : if (first_use) {
99 : EnumSystemLocalesA(UpdateLocaleCallback, LCID_SUPPORTED | LCID_ALTERNATE_SORTS);
100 : first_use = false;
101 : }
102 :
103 : last_raw_value = shortname;
104 :
105 : if (glb_supported_locales.find(narrow_to_wide(shortname)) != glb_supported_locales.end()) {
106 : last_full_name = wide_to_narrow(glb_supported_locales[narrow_to_wide(shortname)]);
107 : return last_full_name.c_str();
108 : }
109 :
110 : /* empty string is system default */
111 : errorstream << "MSVC_LocaleLookup: unsupported locale: \"" << shortname
112 : << "\" switching to system default!" << std::endl;
113 : return "";
114 : }
115 :
116 : #endif
117 :
118 : /******************************************************************************/
119 : #ifdef _MSC_VER
120 : void init_gettext(const char *path, const std::string &configured_language, int argc, char** argv) {
121 : #else
122 1 : void init_gettext(const char *path, const std::string &configured_language) {
123 : #endif
124 : #if USE_GETTEXT
125 : /** first try to set user override environment **/
126 : if (configured_language.length() != 0) {
127 : #ifndef _WIN32
128 : /* add user specified locale to environment */
129 : setenv("LANGUAGE", configured_language.c_str(), 1);
130 :
131 : /* reload locale with changed environment */
132 : setlocale(LC_ALL, "");
133 : #elif defined(_MSC_VER)
134 : std::string current_language_var("");
135 : if (getenv("LANGUAGE") != 0) {
136 : current_language_var = std::string(getenv("LANGUAGE"));
137 : }
138 :
139 : char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char));
140 : strcat(lang_str, "LANGUAGE=");
141 : strcat(lang_str, configured_language.c_str());
142 : putenv(lang_str);
143 :
144 : SetEnvironmentVariableA("LANGUAGE",configured_language.c_str());
145 :
146 : #ifndef SERVER
147 : //very very dirty workaround to force gettext to see the right environment
148 : if (current_language_var != configured_language) {
149 : STARTUPINFO startupinfo;
150 : PROCESS_INFORMATION processinfo;
151 : memset(&startupinfo, 0, sizeof(startupinfo));
152 : memset(&processinfo, 0, sizeof(processinfo));
153 : errorstream << "MSVC localization workaround active restating minetest in new environment!" << std::endl;
154 :
155 : std::string parameters = "";
156 :
157 : for (unsigned int i=1;i < argc; i++) {
158 : if (parameters != "") {
159 : parameters += " ";
160 : }
161 : parameters += argv[i];
162 : }
163 :
164 : const char* ptr_parameters = 0;
165 :
166 : if (parameters != "") {
167 : ptr_parameters = parameters.c_str();
168 : }
169 :
170 : /** users may start by short name in commandline without extention **/
171 : std::string appname = argv[0];
172 : if (appname.substr(appname.length() - 4) != ".exe") {
173 : appname += ".exe";
174 : }
175 :
176 : if (!CreateProcess(appname.c_str(),
177 : (char*) ptr_parameters,
178 : NULL,
179 : NULL,
180 : false,
181 : DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
182 : NULL,
183 : NULL,
184 : &startupinfo,
185 : &processinfo)) {
186 : char buffer[1024];
187 : FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
188 : NULL,
189 : GetLastError(),
190 : MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
191 : buffer,
192 : sizeof(buffer)-1,
193 : NULL);
194 : errorstream << "*******************************************************" << std::endl;
195 : errorstream << "CMD: " << appname << std::endl;
196 : errorstream << "Failed to restart with current locale: " << std::endl;
197 : errorstream << buffer;
198 : errorstream << "Expect language to be broken!" << std::endl;
199 : errorstream << "*******************************************************" << std::endl;
200 : }
201 : else {
202 : exit(0);
203 : }
204 : #else
205 : errorstream << "*******************************************************" << std::endl;
206 : errorstream << "Can't apply locale workaround for server!" << std::endl;
207 : errorstream << "Expect language to be broken!" << std::endl;
208 : errorstream << "*******************************************************" << std::endl;
209 :
210 : #endif
211 : }
212 :
213 : setlocale(LC_ALL,configured_language.c_str());
214 : #else // Mingw
215 : char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char));
216 : strcat(lang_str, "LANGUAGE=");
217 : strcat(lang_str, configured_language.c_str());
218 : putenv(lang_str);
219 :
220 : setlocale(LC_ALL, "");
221 : #endif // ifndef _WIN32
222 : }
223 : else {
224 : /* set current system default locale */
225 : setlocale(LC_ALL, "");
226 : }
227 :
228 : #if defined(_WIN32)
229 : if (getenv("LANGUAGE") != 0) {
230 : setlocale(LC_ALL, getenv("LANGUAGE"));
231 : }
232 : #ifdef _MSC_VER
233 : else if (getenv("LANG") != 0) {
234 : setlocale(LC_ALL, getenv("LANG"));
235 : }
236 : #endif
237 : #endif
238 :
239 : static std::string name = lowercase(PROJECT_NAME);
240 : bindtextdomain(name.c_str(), path);
241 : textdomain(name.c_str());
242 :
243 : #if defined(_WIN32)
244 : // Set character encoding for Win32
245 : char *tdomain = textdomain( (char *) NULL );
246 : if( tdomain == NULL )
247 : {
248 : errorstream << "Warning: domainname parameter is the null pointer" <<
249 : ", default domain is not set" << std::endl;
250 : tdomain = (char *) "messages";
251 : }
252 : /* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
253 : //errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
254 : #endif // defined(_WIN32)
255 :
256 : #else
257 : /* set current system default locale */
258 1 : setlocale(LC_ALL, "");
259 : #endif // if USE_GETTEXT
260 :
261 : /* no matter what locale is used we need number format to be "C" */
262 : /* to ensure formspec parameters are evaluated correct! */
263 :
264 1 : setlocale(LC_NUMERIC, "C");
265 1 : infostream << "Message locale is now set to: "
266 2 : << setlocale(LC_ALL, 0) << std::endl;
267 4 : }
268 :
|