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