Skip to content
Permalink
Browse files

Fix win32/msvc i18n (quite UGLY version, blame Microsoft)

  • Loading branch information
sapier authored and sapier committed Nov 11, 2013
1 parent 0f9440f commit 22a59b3912ff5e7bb1516faa06f1841545a8117c
@@ -306,6 +306,7 @@ set(common_SRCS
serverlist.cpp
pathfinder.cpp
convert_json.cpp
gettext.cpp
${JTHREAD_SRCS}
${common_SCRIPT_SRCS}
${UTIL_SRCS}
@@ -205,6 +205,10 @@ inline core::array<u8> getUnicodeBOM(EUTF_ENCODE mode)
case EUTFE_UTF32_LE:
COPY_ARRAY(BOM_ENCODE_UTF32_LE, BOM_ENCODE_UTF32_LEN);
break;
case EUTFE_NONE:
// TODO sapier: fixed warning only,
// don't know if something needs to be done here
break;
}
return ret;

@@ -257,7 +261,7 @@ class ustring16
_set(c);
return *this;
}

//! Increments the value by 1.
//! \return Myself.
_ustring16_iterator_access& operator++()
@@ -392,7 +396,7 @@ class ustring16
return unicode::toUTF32(a[pos], a[pos + 1]);
}
}

//! Sets a uchar32_t at our current position.
void _set(uchar32_t c)
{
@@ -707,7 +711,6 @@ class ustring16
//! Moves the iterator to the end of the string.
void toEnd()
{
const uchar16_t* a = ref->c_str();
pos = ref->size_raw();
}

@@ -732,12 +735,13 @@ class ustring16
typedef typename _Base::const_pointer const_pointer;
typedef typename _Base::const_reference const_reference;


typedef typename _Base::value_type value_type;
typedef typename _Base::difference_type difference_type;
typedef typename _Base::distance_type distance_type;
typedef access pointer;
typedef access reference;

using _Base::pos;
using _Base::ref;

@@ -2096,7 +2100,7 @@ class ustring16
}
#endif


//! Appends a number to this ustring16.
//! \param c Number to append.
//! \return A reference to our current string.
@@ -2958,7 +2962,7 @@ class ustring16
if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian)
{
for (u32 i = 0; i <= used; ++i)
*ptr++ = unicode::swapEndian16(*ptr);
ptr[i] = unicode::swapEndian16(ptr[i]);
}
ret.set_used(used + (addBOM ? unicode::BOM_UTF16_LEN : 0));
ret.push_back(0);
@@ -0,0 +1,259 @@
/*
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>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include "gettext.h"
#include "util/string.h"

#if USE_GETTEXT and defined(_MSC_VER)
#include <WinNls.h>
#include <map>
#include <direct.h>
#include "filesys.h"

#define setlocale(category,localename) \
setlocale(category,MSVC_LocaleLookup(localename))

static std::map<std::wstring,std::wstring> glb_supported_locales;

/******************************************************************************/
BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
{
char* endptr = 0;
int LOCALEID = strtol(pStr,&endptr,16);

wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
memset(buffer,0,sizeof(buffer));
if (GetLocaleInfoW(
LOCALEID,
LOCALE_SISO639LANGNAME,
buffer,
LOCALE_NAME_MAX_LENGTH)) {

std::wstring name = buffer;

memset(buffer,0,sizeof(buffer));
GetLocaleInfoW(
LOCALEID,
LOCALE_SISO3166CTRYNAME,
buffer,
LOCALE_NAME_MAX_LENGTH);

std::wstring country = buffer;

memset(buffer,0,sizeof(buffer));
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) {
EnumSystemLocalesA(UpdateLocaleCallback,LCID_SUPPORTED | LCID_ALTERNATE_SORTS);
first_use = false;
}

last_raw_value = shortname;

if (glb_supported_locales.find(narrow_to_wide(shortname)) != glb_supported_locales.end()) {
last_full_name = wide_to_narrow(glb_supported_locales[narrow_to_wide(shortname)]);
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

/******************************************************************************/
#ifdef _MSC_VER
void init_gettext(const char *path,std::string configured_language,int argc, char** argv) {
#else
void init_gettext(const char *path,std::string configured_language) {
#endif
#if USE_GETTEXT
/** first try to set user override environment **/
if (configured_language.length() != 0) {
#ifndef _WIN32
/* add user specified locale to environment */
setenv("LANGUAGE", configured_language.c_str(), 1);

/* reload locale with changed environment */
setlocale(LC_ALL, "");
#elif defined(_MSC_VER)
std::string current_language_var("");
if (getenv("LANGUAGE") != 0) {
current_language_var = std::string(getenv("LANGUAGE"));
}

char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char));
strcat(lang_str, "LANGUAGE=");
strcat(lang_str, configured_language.c_str());
putenv(lang_str);

SetEnvironmentVariableA("LANGUAGE",configured_language.c_str());

//very very dirty workaround to force gettext to see the right environment
if (current_language_var != configured_language) {
STARTUPINFO startupinfo;
PROCESS_INFORMATION processinfo;
memset(&startupinfo,0,sizeof(startupinfo));
memset(&processinfo,0,sizeof(processinfo));
errorstream << "MSVC localization workaround aktive restating minetest in new environment!" << std::endl;

std::string parameters = "";

for (unsigned int i=1;i < argc; i++) {
if (parameters != "") {
parameters += " ";
}
parameters += argv[i];
}

const char* ptr_parameters = 0;

if (parameters != "") {
ptr_parameters = parameters.c_str();
}

/** users may start by short name in commandline without extention **/
std::string appname = argv[0];
if (appname.substr(appname.length() -4) != ".exe") {
appname += ".exe";
}

if (!CreateProcess(appname.c_str(),
(char*) ptr_parameters,
NULL,
NULL,
false,
DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
NULL,
NULL,
&startupinfo,
&processinfo)) {
char buffer[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
buffer,
sizeof(buffer)-1,
NULL);
errorstream << "*******************************************************" << std::endl;
errorstream << "CMD: " << appname << std::endl;
errorstream << "Failed to restart with current locale: " << std::endl;
errorstream << buffer;
errorstream << "Expect language to be broken!" << std::endl;
errorstream << "*******************************************************" << std::endl;
}
else {
exit(0);
}
}

setlocale(LC_ALL,configured_language.c_str());
#else // Mingw
char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char));
strcat(lang_str, "LANGUAGE=");
strcat(lang_str, configured_language.c_str());
putenv(lang_str);

setlocale(LC_ALL, "");
#endif // ifndef _WIN32
}
else {
/* set current system default locale */
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

bindtextdomain(PROJECT_NAME, path);
textdomain(PROJECT_NAME);

#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)

/* no matter what locale is used we need number format to be "C" */
/* to ensure formspec parameters are evaluated correct! */


setlocale(LC_NUMERIC,"C");
infostream << "Message locale is now set to: "
<< setlocale(LC_ALL,0) << std::endl;

#endif // if USE_GETTEXT
}




0 comments on commit 22a59b3

Please sign in to comment.