Fixed translations on windows (esp. when non-translated strings are used).

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4430 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2010-01-11 21:50:30 +00:00
parent 9f1d5893d4
commit 211c6cdb4e
2 changed files with 33 additions and 329 deletions

View File

@ -23,7 +23,6 @@
// warning message " 'swprintf' : macro redefinition"
// This happens if libintl.h is included before irrlicht.h (since
// both files redefine swprintf).
#include "irrlicht.h"
#include "utils/translation.hpp"
@ -32,281 +31,20 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
//#include <iconv.h>
#include <stdlib.h>
#include <iostream>
#include "irrlicht.h"
#include "io/file_manager.hpp"
enum CONVERT_TO
{
UTF_16 = 0,
UTF_32 = 1
};
const char* CODE_NAMES[] =
{
"UTF-16",
"UTF-32"
};
/*
The code below is based on Solaris' man pages code. No license was specified, but I assume that
they wrote man pages for people to use them...
*/
/*
* For state-dependent encodings, changes the state of the conversion
* descriptor to initial shift state. Also, outputs the byte sequence
* to change the state to initial state.
* This code is assuming the iconv call for initializing the state
* won't fail due to lack of space in the output buffer.
*/
/*
#if defined(__APPLE__) && _LIBICONV_VERSION < 0x010B
#define INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft) \
{ \
fptr = NULL; \
ileft = 0; \
tptr = to; \
oleft = BUFSIZ; \
iconv(cd, &fptr, &ileft, &tptr, &oleft); \
}
#else
#define INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft) \
{ \
fptr = NULL; \
ileft = 0; \
tptr = to; \
oleft = BUFSIZ; \
iconv(cd, const_cast<char**>(&fptr), &ileft, &tptr, &oleft); \
}
#endif
bool convertToEncoding(const char* from, char* to, const int BUF_SIZE, const char* from_code, CONVERT_TO to_code)
{
iconv_t cd;
char *tptr;
const char *fptr;
size_t ileft, oleft, ret;
cd = iconv_open(CODE_NAMES[to_code], from_code);
if (cd == (iconv_t)-1)
{
// failed
fprintf(stderr, "iconv_open(%s, %s) failed\n", CODE_NAMES[to_code], from_code);
return false;
}
ileft = strlen(from);
fptr = from;
for (;;)
{
tptr = to;
oleft = BUFSIZ;
#if defined(__APPLE__) && _LIBICONV_VERSION < 0x010B
ret = iconv(cd, &fptr, &ileft, &tptr, &oleft);
#else
ret = iconv(cd, const_cast<char**>(&fptr), &ileft, &tptr, &oleft);
#endif
if (ret != (size_t)-1)
{
// iconv succeeded
// Manually add ending '\0'
const int curr_offset = BUFSIZ - oleft;
to[curr_offset] = '\0';
if (curr_offset+1 >= BUFSIZ)
{
fprintf(stderr, "iconv failed : error while adding '\\0' character (Output buffer not big enough) \n");
return false;
}
to[curr_offset+1] = '\0';
// UTF-32 needs 2 more bytes at 0
if (to_code == UTF_32)
{
to[curr_offset+2] = '\0';
if (curr_offset+3 >= BUFSIZ)
{
fprintf(stderr, "iconv failed : error while adding '\\0' character (Output buffer not big enough) \n");
return false;
}
to[curr_offset+3] = '\0';
}
break;
}
// iconv failed
if (errno == EINVAL)
{
fprintf(stderr, "iconv failed : EINVAL error (Incomplete character or shift sequence) \n");
break;
}
else if (errno == E2BIG)
{
// Lack of space in output buffer
fprintf(stderr, "iconv failed : E2BIG error (Output buffer not big enough) \n");
std::cout << "So far, I have :\n";
for (int i=0; i<BUF_SIZE; i++)
{
std::cout << " " << to[i] << " (" << (unsigned int)to[i] << ")\n";
}
//Outputs converted characters
//fwrite(to, 1, BUFSIZ - oleft, stdout);
// Tries to convert remaining characters in
// input buffer with emptied output buffer
return false;
}
else if (errno == EILSEQ)
{
fprintf(stderr, "iconv failed : EILSEQ error (Illegal character or shift sequence) \n");
std::cout << "Original :\n";
for (int i=0; ; i++)
{
std::cout << " " << from[i] << " (" << std::hex << (unsigned int)from[i] << ")\n";
if (from[i] == 0) break;
}
// Outputs converted characters
//fwrite(to, 1, BUFSIZ - oleft, stdout);
// Initializes the conversion descriptor and
// outputs the sequence to change the state to
// initial state.
INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft);
iconv_close(cd);
return false;
}
else if (errno == EBADF)
{
fprintf(stderr, "iconv failed : EBADF error (invalid conversion description) \n");
return false;
}
else
{
fprintf(stderr, "iconv failed : other error\n");
return false;
}
}
// Initializes the conversion descriptor and outputs
// the sequence to change the state to initial state.
INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft);
iconv_close(cd);
return true;
}
*/
// TODO: use a type that works on all platforms
typedef unsigned int uint32;
/**
* \param input_text Some UTF-8 text
* \return The appropriate representation of this text in the platform's native wchar_t type, or
* NULL if conversion failed (in this case a message will be printed to the console)
*/
/*
wchar_t* utf8_to_wchar_t(const char* input_text)
{
const int buffer_size = 2048; // let's arbitrarly support 2048 chars
const int byte_size = buffer_size*sizeof(wchar_t); // we need more space if the system uses UTF-32
static char output_buffer[byte_size];
static wchar_t wide_form[buffer_size*2]; // Allow for some surrogate pairs
if (sizeof(wchar_t) == 2)
{
// UTF-16
if (!convertToEncoding(input_text, output_buffer, byte_size, "UTF-8", UTF_16)) return NULL;
return ((wchar_t*)output_buffer)+1; // Skip initial Unicode header
for (int n=0; true; n+=2)
{
wide_form[n/2] = (uint32(output_buffer[n ]) << 8) |
uint32(output_buffer[n+1] );
//std::cout << "char : <" << to[n] << ", " << to[n+1] << ">; wide char = " << std::hex << (uint32)wide_form[n/2] << "\n";
if (wide_form[n/2] == 0) break;
}
return &wide_form[1];
}
else if (sizeof(wchar_t) == 4)
{
// UTF-32
if (!convertToEncoding(input_text, output_buffer, byte_size, "UTF-8", UTF_32)) return NULL;
//return ((wchar_t*)output_buffer)+1; // Skip initial Unicode header
for (int n=0; true; n+=4)
{
wide_form[n/4] = (uint32(output_buffer[ n ]) << 24) |
(uint32(output_buffer[n+1]) << 16) |
(uint32(output_buffer[n+2]) << 8 ) |
uint32(output_buffer[n+3]) ;
//std::cout << "char : <" << to[n] << ", " << to[n+1] << ", " << to[n+2] << ", " << to[n+3]
// << ">; wide char = " << std::hex << (uint32)wide_form[n/4] << "\n";
if (wide_form[n/4] == 0) break;
}
return &wide_form[1];
}
else
{
std::cout << "ERROR : Unknown wchar_t size!\n";
return NULL;
}
}
*/
/*
int main()
{
const char* from = "Some text in plain ASCII. z";
wchar_t* out_ptr = utf8_to_wchar_t(from);
if (out_ptr == NULL)
{
std::cout << "ERROR!\n";
return 1;
}
else
{
std::wcout << L"Converted text : <" << out_ptr << L">\n";
}
return 0;
}
*/
Translations* translations=NULL;
// ----------------------------------------------------------------------------
Translations::Translations()
{
#ifdef HAVE_GETTEXT
#ifdef ENABLE_NLS
// LC_ALL does not work, sscanf will then not always be able
// to scan for example: s=-1.1,-2.3,-3.3 correctly, which is
// used in driveline files.
@ -318,19 +56,15 @@ Translations::Translations()
#endif
bindtextdomain (PACKAGE, file_manager->getTranslationDir().c_str());
if (sizeof(wchar_t) == 4) bind_textdomain_codeset(PACKAGE, "UTF-32");
else if (sizeof(wchar_t) == 2) bind_textdomain_codeset(PACKAGE, "UTF-16");
else if (sizeof(wchar_t) == 2) bind_textdomain_codeset(PACKAGE, "UTF-16LE");
else assert(false);
//bind_textdomain_codeset(PACKAGE, "iso-8859-1");
textdomain (PACKAGE);
#endif
} // Translations
//const int BUFFER_SIZE = 512;
//wchar_t out_buffer[BUFFER_SIZE];
wchar_t* w_gettext(const char* original)
// ----------------------------------------------------------------------------
const wchar_t* Translations::w_gettext(const char* original)
{
if (original[0] == '\0') return L"";
@ -339,49 +73,16 @@ wchar_t* w_gettext(const char* original)
#if ENABLE_NLS
const char* original_t = gettext(original);
#else
const char* original_t = original;
m_converted_string = core::stringw(original);
return m_converted_string.c_str();
#endif
/*
// print
for (int n=0;; n+=4)
if(original_t==original)
{
std::cout << original_t[n] << " (" << (unsigned int)(original_t[n]) << "), "
<< original_t[n+1] << " (" << (unsigned int)(original_t[n+1]) << "), "
<< original_t[n+2] << " (" << (unsigned int)(original_t[n+2]) << "), "
<< original_t[n+3] << " (" << (unsigned int)(original_t[n+3]) << ")\n";
if (original_t[n] | original_t[n+1] | original_t[n+2] | original_t[n+3] == 0) break;
m_converted_string = core::stringw(original);
return m_converted_string.c_str();
}
*/
//wchar_t* out_ptr = utf8_to_wchar_t(original_t);
wchar_t* out_ptr = (wchar_t*)original_t;
/*
if (out_ptr == NULL)
{
std::cerr << " ERROR in w_gettext! could not be converted to wchar_t.\n";
}
*/
std::wcout << L" translation : " << out_ptr << std::endl;
//std::wcout << L" translation : " << irr::core::stringc(out_ptr).c_str() << std::endl;
//fprintf(stdout, "translation is '%s'.\n", irr::core::stringc(out_ptr).c_str());
//std::wcout << L" translation : " << out_ptr << std::endl;
return out_ptr;
/*
int index = 0;
for (const char* c=original_t; *c != 0; c++)
{
out_buffer[index] = (wchar_t)(unsigned char)*c;
index++;
}
out_buffer[index] = 0;
//mbstowcs(out_buffer, original_t, BUFFER_SIZE);
return out_buffer;
*/
}

View File

@ -20,34 +20,37 @@
#ifndef TRANSLATION_HPP
#define TRANSLATION_HPP
#include "irrlicht.h"
#if ENABLE_NLS
# ifdef __APPLE__
# include <libintl/libintl.h>
# else
# include <libintl.h>
# endif
#ifdef __APPLE__
# include <libintl/libintl.h>
#else
# include <libintl.h>
#endif
# define _(String) w_gettext(String)
# define gettext_noop(String) String
# define N_(String) gettext_noop (String)
// libintl defines its own fprintf, which doesn't work for me :(
# define _(String) (translations->w_gettext(String))
# define gettext_noop(String) (String)
# define N_(String) (gettext_noop (String))
// libintl defines its own fprintf, which doesn't work properly
# if defined(WIN32) && !defined(__CYGWIN__)
# undef fprintf
# endif
#else
# define _(String) w_gettext(String)
# define gettext_noop(String) String
# define N_(String) String
#else // No NLS
# define _(String) (translations->w_gettext(String))
# define gettext_noop(String) (String)
# define N_(String) (String)
#endif
class Translations
{
private:
irr::core::stringw m_converted_string;
public:
Translations();
};
Translations();
const wchar_t *w_gettext(const char* original);
}; // Translations
wchar_t* w_gettext(const char* original);
extern Translations* translations;
#endif