Translated using Weblate (Russian)
[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 <cstring>
22 #include <iostream>
23 #include <cstdlib>
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(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();
109         }
110
111         /* empty string is system default */
112         errorstream << "MSVC_LocaleLookup: unsupported locale: \"" << shortname
113                                 << "\" switching to system default!" << std::endl;
114         return "";
115 }
116
117 #endif
118
119 /******************************************************************************/
120 void init_gettext(const char *path, const std::string &configured_language,
121         int argc, char *argv[])
122 {
123 #if USE_GETTEXT
124         // First, try to set user override environment
125         if (!configured_language.empty()) {
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;
134                 const char *env_lang = getenv("LANGUAGE");
135                 if (env_lang)
136                         current_language = env_lang;
137
138                 _putenv(("LANGUAGE=" + configured_language).c_str());
139                 SetEnvironmentVariableA("LANGUAGE", configured_language.c_str());
140
141 #ifndef SERVER
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;
146
147                         std::string parameters;
148
149                         for (unsigned int i = 1; i < argc; i++) {
150                                 if (!parameters.empty())
151                                         parameters += ' ';
152
153                                 parameters += argv[i];
154                         }
155
156                         const char *ptr_parameters = NULL;
157
158                         if (!parameters.empty())
159                                 ptr_parameters = parameters.c_str();
160
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)
164                                 app_name += ".exe";
165
166                         STARTUPINFO startup_info = {0};
167                         PROCESS_INFORMATION process_info = {0};
168
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);
172
173                         if (success) {
174                                 exit(0);
175                                 // NOTREACHED
176                         } else {
177                                 char buffer[1024];
178
179                                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
180                                         MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
181                                         sizeof(buffer) - 1, NULL);
182
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;
189                         }
190                 }
191 #else
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;
196 #endif
197
198                 setlocale(LC_ALL, configured_language.c_str());
199 #else // Mingw
200                 _putenv(("LANGUAGE=" + configured_language).c_str());
201                 setlocale(LC_ALL, "");
202 #endif // ifndef _WIN32
203         }
204         else {
205                  /* set current system default locale */
206                 setlocale(LC_ALL, "");
207         }
208
209 #if defined(_WIN32)
210         if (getenv("LANGUAGE") != 0) {
211                 setlocale(LC_ALL, getenv("LANGUAGE"));
212         }
213 #ifdef _MSC_VER
214         else if (getenv("LANG") != 0) {
215                 setlocale(LC_ALL, getenv("LANG"));
216         }
217 #endif
218 #endif
219
220         std::string name = lowercase(PROJECT_NAME);
221         infostream << "Gettext: domainname=\"" << name
222                 << "\" path=\"" << path << "\"" << std::endl;
223
224         bindtextdomain(name.c_str(), path);
225         textdomain(name.c_str());
226
227 #if defined(_WIN32)
228         // Set character encoding for Win32
229         char *tdomain = textdomain( (char *) NULL );
230         if( tdomain == NULL )
231         {
232                 errorstream << "Warning: domainname parameter is the null pointer" <<
233                                 ", default domain is not set" << std::endl;
234                 tdomain = (char *) "messages";
235         }
236         /* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
237         //errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
238 #endif // defined(_WIN32)
239
240 #else
241         /* set current system default locale */
242         setlocale(LC_ALL, "");
243 #endif // if USE_GETTEXT
244
245         /* no matter what locale is used we need number format to be "C" */
246         /* to ensure formspec parameters are evaluated correct!          */
247
248         setlocale(LC_NUMERIC, "C");
249         infostream << "Message locale is now set to: "
250                         << setlocale(LC_ALL, 0) << std::endl;
251 }