2013-11-03 17:28:16 +01:00
|
|
|
/*
|
|
|
|
Minetest
|
|
|
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
2017-08-18 07:44:42 +02:00
|
|
|
#include <cstring>
|
2013-11-03 17:28:16 +01:00
|
|
|
#include <iostream>
|
2017-08-18 07:44:42 +02:00
|
|
|
#include <cstdlib>
|
2013-11-03 17:28:16 +01:00
|
|
|
#include "gettext.h"
|
|
|
|
#include "util/string.h"
|
2015-02-01 23:59:23 +01:00
|
|
|
#include "log.h"
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2014-02-02 13:22:33 +01:00
|
|
|
#if USE_GETTEXT && defined(_MSC_VER)
|
2015-02-12 02:55:50 +01:00
|
|
|
#include <windows.h>
|
2013-11-03 17:28:16 +01:00
|
|
|
#include <map>
|
|
|
|
#include <direct.h>
|
|
|
|
#include "filesys.h"
|
|
|
|
|
2015-02-12 02:55:50 +01:00
|
|
|
#define setlocale(category, localename) \
|
|
|
|
setlocale(category, MSVC_LocaleLookup(localename))
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2015-02-12 02:55:50 +01:00
|
|
|
static std::map<std::wstring, std::wstring> glb_supported_locales;
|
2013-11-03 17:28:16 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
|
|
|
|
{
|
|
|
|
char* endptr = 0;
|
2015-02-12 02:55:50 +01:00
|
|
|
int LOCALEID = strtol(pStr, &endptr,16);
|
2013-11-03 17:28:16 +01:00
|
|
|
|
|
|
|
wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
|
2015-02-12 02:55:50 +01:00
|
|
|
memset(buffer, 0, sizeof(buffer));
|
2013-11-03 17:28:16 +01:00
|
|
|
if (GetLocaleInfoW(
|
|
|
|
LOCALEID,
|
|
|
|
LOCALE_SISO639LANGNAME,
|
|
|
|
buffer,
|
|
|
|
LOCALE_NAME_MAX_LENGTH)) {
|
|
|
|
|
|
|
|
std::wstring name = buffer;
|
|
|
|
|
2015-02-12 02:55:50 +01:00
|
|
|
memset(buffer, 0, sizeof(buffer));
|
2013-11-03 17:28:16 +01:00
|
|
|
GetLocaleInfoW(
|
|
|
|
LOCALEID,
|
|
|
|
LOCALE_SISO3166CTRYNAME,
|
|
|
|
buffer,
|
|
|
|
LOCALE_NAME_MAX_LENGTH);
|
|
|
|
|
|
|
|
std::wstring country = buffer;
|
|
|
|
|
2015-02-12 02:55:50 +01:00
|
|
|
memset(buffer, 0, sizeof(buffer));
|
2013-11-03 17:28:16 +01:00
|
|
|
GetLocaleInfoW(
|
|
|
|
LOCALEID,
|
|
|
|
LOCALE_SENGLISHLANGUAGENAME,
|
|
|
|
buffer,
|
|
|
|
LOCALE_NAME_MAX_LENGTH);
|
|
|
|
|
|
|
|
std::wstring languagename = buffer;
|
|
|
|
|
|
|
|
/* set both short and long variant */
|
|
|
|
glb_supported_locales[name] = languagename;
|
|
|
|
glb_supported_locales[name + L"_" + country] = languagename;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
const char* MSVC_LocaleLookup(const char* raw_shortname) {
|
|
|
|
|
|
|
|
/* NULL is used to read locale only so we need to return it too */
|
|
|
|
if (raw_shortname == NULL) return NULL;
|
|
|
|
|
|
|
|
std::string shortname(raw_shortname);
|
|
|
|
if (shortname == "C") return "C";
|
|
|
|
if (shortname == "") return "";
|
|
|
|
|
|
|
|
static std::string last_raw_value = "";
|
|
|
|
static std::string last_full_name = "";
|
|
|
|
static bool first_use = true;
|
|
|
|
|
|
|
|
if (last_raw_value == shortname) {
|
|
|
|
return last_full_name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first_use) {
|
2015-02-12 02:55:50 +01:00
|
|
|
EnumSystemLocalesA(UpdateLocaleCallback, LCID_SUPPORTED | LCID_ALTERNATE_SORTS);
|
2013-11-03 17:28:16 +01:00
|
|
|
first_use = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_raw_value = shortname;
|
|
|
|
|
2015-07-07 05:55:07 +02:00
|
|
|
if (glb_supported_locales.find(utf8_to_wide(shortname)) != glb_supported_locales.end()) {
|
|
|
|
last_full_name = wide_to_utf8(
|
|
|
|
glb_supported_locales[utf8_to_wide(shortname)]);
|
2013-11-03 17:28:16 +01:00
|
|
|
return last_full_name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* empty string is system default */
|
|
|
|
errorstream << "MSVC_LocaleLookup: unsupported locale: \"" << shortname
|
|
|
|
<< "\" switching to system default!" << std::endl;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2015-10-15 06:45:56 +02:00
|
|
|
void init_gettext(const char *path, const std::string &configured_language,
|
2015-10-24 19:31:42 +02:00
|
|
|
int argc, char *argv[])
|
2015-10-15 06:45:56 +02:00
|
|
|
{
|
2013-11-03 17:28:16 +01:00
|
|
|
#if USE_GETTEXT
|
2015-10-15 06:45:56 +02:00
|
|
|
// First, try to set user override environment
|
|
|
|
if (!configured_language.empty()) {
|
2013-11-03 17:28:16 +01:00
|
|
|
#ifndef _WIN32
|
2015-10-15 06:45:56 +02:00
|
|
|
// Add user specified locale to environment
|
2013-11-03 17:28:16 +01:00
|
|
|
setenv("LANGUAGE", configured_language.c_str(), 1);
|
|
|
|
|
2021-08-08 18:59:07 +02:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
setenv("LANG", configured_language.c_str(), 1);
|
|
|
|
#endif
|
|
|
|
|
2015-10-15 06:45:56 +02:00
|
|
|
// Reload locale with changed environment
|
2013-11-03 17:28:16 +01:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
#elif defined(_MSC_VER)
|
2015-10-15 06:45:56 +02:00
|
|
|
std::string current_language;
|
|
|
|
const char *env_lang = getenv("LANGUAGE");
|
|
|
|
if (env_lang)
|
|
|
|
current_language = env_lang;
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2015-10-15 06:45:56 +02:00
|
|
|
_putenv(("LANGUAGE=" + configured_language).c_str());
|
|
|
|
SetEnvironmentVariableA("LANGUAGE", configured_language.c_str());
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2013-11-09 10:57:41 +01:00
|
|
|
#ifndef SERVER
|
2015-10-15 06:45:56 +02:00
|
|
|
// Hack to force gettext to see the right environment
|
|
|
|
if (current_language != configured_language) {
|
|
|
|
errorstream << "MSVC localization workaround active. "
|
|
|
|
"Restarting " PROJECT_NAME_C " in a new environment!" << std::endl;
|
|
|
|
|
|
|
|
std::string parameters;
|
2023-01-23 00:19:30 +01:00
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
if (i > 1)
|
2015-10-15 06:45:56 +02:00
|
|
|
parameters += ' ';
|
2023-01-23 00:19:30 +01:00
|
|
|
parameters += porting::QuoteArgv(argv[i]);
|
2013-11-03 17:28:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-23 00:19:30 +01:00
|
|
|
char *ptr_parameters = nullptr;
|
2015-10-15 06:45:56 +02:00
|
|
|
if (!parameters.empty())
|
2023-01-23 00:19:30 +01:00
|
|
|
ptr_parameters = ¶meters[0];
|
2015-08-31 20:36:02 +02:00
|
|
|
|
2015-10-15 06:45:56 +02:00
|
|
|
// Allow calling without an extension
|
|
|
|
std::string app_name = argv[0];
|
2015-10-26 15:14:22 +01:00
|
|
|
if (app_name.compare(app_name.size() - 4, 4, ".exe") != 0)
|
2015-10-15 06:45:56 +02:00
|
|
|
app_name += ".exe";
|
|
|
|
|
2023-01-23 00:19:30 +01:00
|
|
|
STARTUPINFO startup_info = {};
|
|
|
|
PROCESS_INFORMATION process_info = {};
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2023-01-23 00:19:30 +01:00
|
|
|
bool success = CreateProcess(app_name.c_str(), ptr_parameters,
|
2015-10-15 06:45:56 +02:00
|
|
|
NULL, NULL, false, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
|
|
|
|
NULL, NULL, &startup_info, &process_info);
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
exit(0);
|
|
|
|
// NOTREACHED
|
|
|
|
} else {
|
2015-08-31 20:36:02 +02:00
|
|
|
char buffer[1024];
|
2015-10-15 06:45:56 +02:00
|
|
|
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
|
|
|
|
sizeof(buffer) - 1, NULL);
|
|
|
|
|
2013-11-03 17:28:16 +01:00
|
|
|
errorstream << "*******************************************************" << std::endl;
|
2015-10-15 06:45:56 +02:00
|
|
|
errorstream << "CMD: " << app_name << std::endl;
|
2013-11-03 17:28:16 +01:00
|
|
|
errorstream << "Failed to restart with current locale: " << std::endl;
|
|
|
|
errorstream << buffer;
|
|
|
|
errorstream << "Expect language to be broken!" << std::endl;
|
|
|
|
errorstream << "*******************************************************" << std::endl;
|
|
|
|
}
|
2015-08-31 20:36:02 +02:00
|
|
|
}
|
2013-11-09 10:57:41 +01:00
|
|
|
#else
|
2015-08-31 20:36:02 +02:00
|
|
|
errorstream << "*******************************************************" << std::endl;
|
|
|
|
errorstream << "Can't apply locale workaround for server!" << std::endl;
|
|
|
|
errorstream << "Expect language to be broken!" << std::endl;
|
|
|
|
errorstream << "*******************************************************" << std::endl;
|
2013-11-09 10:57:41 +01:00
|
|
|
#endif
|
2013-11-03 17:28:16 +01:00
|
|
|
|
2015-10-15 06:45:56 +02:00
|
|
|
setlocale(LC_ALL, configured_language.c_str());
|
2013-11-03 17:28:16 +01:00
|
|
|
#else // Mingw
|
2015-10-15 06:45:56 +02:00
|
|
|
_putenv(("LANGUAGE=" + configured_language).c_str());
|
2013-11-03 17:28:16 +01:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
#endif // ifndef _WIN32
|
|
|
|
}
|
|
|
|
else {
|
2023-06-05 12:02:10 +02:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
setenv("LANG", porting::getLanguageAndroid().c_str(), 1);
|
|
|
|
#endif
|
|
|
|
/* set current system default locale */
|
2013-11-03 17:28:16 +01:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (getenv("LANGUAGE") != 0) {
|
|
|
|
setlocale(LC_ALL, getenv("LANGUAGE"));
|
|
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
else if (getenv("LANG") != 0) {
|
|
|
|
setlocale(LC_ALL, getenv("LANG"));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2020-04-25 15:44:32 +02:00
|
|
|
std::string name = lowercase(PROJECT_NAME);
|
|
|
|
infostream << "Gettext: domainname=\"" << name
|
|
|
|
<< "\" path=\"" << path << "\"" << std::endl;
|
|
|
|
|
2015-04-26 22:24:48 +02:00
|
|
|
bindtextdomain(name.c_str(), path);
|
|
|
|
textdomain(name.c_str());
|
2013-11-03 17:28:16 +01:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
// Set character encoding for Win32
|
|
|
|
char *tdomain = textdomain( (char *) NULL );
|
|
|
|
if( tdomain == NULL )
|
|
|
|
{
|
|
|
|
errorstream << "Warning: domainname parameter is the null pointer" <<
|
|
|
|
", default domain is not set" << std::endl;
|
|
|
|
tdomain = (char *) "messages";
|
|
|
|
}
|
|
|
|
/* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
|
|
|
|
//errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
|
|
|
|
#endif // defined(_WIN32)
|
|
|
|
|
2013-01-09 13:37:00 +01:00
|
|
|
#else
|
|
|
|
/* set current system default locale */
|
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
#endif // if USE_GETTEXT
|
|
|
|
|
2013-11-03 17:28:16 +01:00
|
|
|
/* no matter what locale is used we need number format to be "C" */
|
|
|
|
/* to ensure formspec parameters are evaluated correct! */
|
|
|
|
|
2015-02-12 02:55:50 +01:00
|
|
|
setlocale(LC_NUMERIC, "C");
|
2013-11-03 17:28:16 +01:00
|
|
|
infostream << "Message locale is now set to: "
|
2015-02-01 23:59:23 +01:00
|
|
|
<< setlocale(LC_ALL, 0) << std::endl;
|
2013-11-03 17:28:16 +01:00
|
|
|
}
|