2009-02-28 19:46:47 -05:00
// $Id: transation.cpp 839 2006-10-24 00:01:56Z hiker $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2006, 2007, 2008 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2010-12-08 10:08:28 -05:00
// Note: the irrlicht include is only here (and esp. before including
// translation.hpp, which contradicts our style rule) to avoid the
2009-05-25 00:29:09 -04:00
// warning message " 'swprintf' : macro redefinition"
// This happens if libintl.h is included before irrlicht.h (since
// both files redefine swprintf).
2009-03-11 23:49:31 -04:00
# include "utils/translation.hpp"
2010-01-10 22:34:36 -05:00
# include <assert.h>
2009-12-13 20:40:54 -05:00
# include <locale.h>
2010-01-07 19:23:31 -05:00
# include <stdio.h>
# include <errno.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
2010-01-11 16:50:30 -05:00
# include "irrlicht.h"
2010-01-07 19:23:31 -05:00
2010-01-11 16:50:30 -05:00
# include "io/file_manager.hpp"
2010-01-12 19:57:17 -05:00
# include "utils/constants.hpp"
2009-12-13 20:40:54 -05:00
2010-05-30 15:11:39 -04:00
# if ENABLE_BIDI
2010-06-12 13:18:28 -04:00
# include <fribidi/fribidi.h>
2010-05-30 15:11:39 -04:00
# endif
2010-01-11 18:22:44 -05:00
// set to 1 to debug i18n
# define TRANSLATE_VERBOSE 0
2009-02-28 19:46:47 -05:00
Translations * translations = NULL ;
2010-01-11 18:22:44 -05:00
bool remove_bom = false ;
2009-02-28 19:46:47 -05:00
2010-12-08 10:08:28 -05:00
# ifdef LINUX // m_debug
# define PACKAGE "supertuxkart"
# endif
2010-01-11 16:50:30 -05:00
// ----------------------------------------------------------------------------
2010-01-07 19:23:31 -05:00
Translations : : Translations ( )
2010-12-08 10:08:28 -05:00
{
2010-01-11 16:50:30 -05:00
# ifdef ENABLE_NLS
2010-12-08 10:08:28 -05:00
2009-02-28 19:46:47 -05:00
// 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.
# if defined(WIN32) && !defined(__CYGWIN__)
// Windows does not have LC_MESSAGES
setlocale ( LC_CTYPE , " " ) ;
# else
setlocale ( LC_MESSAGES , " " ) ;
# endif
2010-12-08 10:08:28 -05:00
2009-02-28 19:46:47 -05:00
bindtextdomain ( PACKAGE , file_manager - > getTranslationDir ( ) . c_str ( ) ) ;
2010-12-08 10:08:28 -05:00
2010-01-11 18:22:44 -05:00
if ( sizeof ( wchar_t ) = = 4 )
{
2010-01-12 19:57:17 -05:00
if ( IS_LITTLE_ENDIAN ) bind_textdomain_codeset ( PACKAGE , " UTF-32LE " ) ;
else bind_textdomain_codeset ( PACKAGE , " UTF-32BE " ) ;
2010-01-11 18:22:44 -05:00
}
else if ( sizeof ( wchar_t ) = = 2 )
{
bind_textdomain_codeset ( PACKAGE , " UTF-16LE " ) ;
}
else
{
fprintf ( stderr , " Your wchar_t is neither 2 byte-long nor 4. What now?? \n " ) ;
exit ( 1 ) ;
}
2010-12-08 10:08:28 -05:00
2009-02-28 19:46:47 -05:00
textdomain ( PACKAGE ) ;
2010-12-08 10:08:28 -05:00
2010-09-03 14:57:44 -04:00
// This is a silly but working hack I added to determine whether the current language is RTL or
// not, since gettext doesn't seem to provide this information
2010-12-08 10:08:28 -05:00
2010-09-03 14:57:44 -04:00
// This one is just for the xgettext parser to pick up
# define ignore(X)
2010-12-08 10:08:28 -05:00
2010-09-03 14:57:44 -04:00
ignore ( _ ( " Is this a RTL language? " ) ) ;
2010-12-08 10:08:28 -05:00
2010-09-03 14:57:44 -04:00
//I18N: Do NOT literally translate this string!! Please enter Y as the translation if your language is a RTL (right-to-left) language, N (or nothing) otherwise
const char * isRtl = gettext ( " Is this a RTL language? " ) ;
2011-01-09 18:59:12 -05:00
const wchar_t * isRtlW = reinterpret_cast < const wchar_t * > ( isRtl ) ;
m_rtl = false ;
for ( int n = 0 ; isRtlW [ n ] ! = 0 ; n + + )
{
if ( isRtlW [ n ] = = ' Y ' )
{
m_rtl = true ;
break ;
}
}
2010-12-08 10:08:28 -05:00
2009-02-28 19:46:47 -05:00
# endif
2010-12-08 10:08:28 -05:00
2009-02-28 19:46:47 -05:00
} // Translations
2010-01-11 16:50:30 -05:00
// ----------------------------------------------------------------------------
const wchar_t * Translations : : w_gettext ( const char * original )
2009-08-30 15:18:05 -04:00
{
2010-01-07 19:23:31 -05:00
if ( original [ 0 ] = = ' \0 ' ) return L " " ;
2010-12-08 10:08:28 -05:00
2010-01-11 18:22:44 -05:00
# if TRANSLATE_VERBOSE
2010-01-15 14:11:34 -05:00
# if ENABLE_NLS
2010-01-07 19:23:31 -05:00
std : : cout < < " Translating " < < original < < " \n " ;
2010-01-15 14:11:34 -05:00
# else
std : : cout < < " NOT Translating " < < original < < " \n " ;
# endif
2010-01-11 18:22:44 -05:00
# endif
2010-12-08 10:08:28 -05:00
2009-08-30 15:57:51 -04:00
# if ENABLE_NLS
2009-08-30 15:18:05 -04:00
const char * original_t = gettext ( original ) ;
2009-08-30 15:57:51 -04:00
# else
2010-01-11 16:50:30 -05:00
m_converted_string = core : : stringw ( original ) ;
return m_converted_string . c_str ( ) ;
2009-08-30 15:57:51 -04:00
# endif
2010-01-11 18:22:44 -05:00
/*
std : : cout < < " --> original_t==original ? " < < ( original_t = = original ) < < std : : endl ;
int zeros = 0 ;
for ( int n = 0 ; ; n + = 1 )
{
std : : cout < < original_t [ n ] < < " ( " < < ( unsigned ) ( original_t [ n ] ) < < " ) \n " ;
if ( original_t [ n ] = = 0 )
{
zeros + + ;
if ( zeros > = 4 ) break ;
}
else
{
zeros = 0 ;
}
} */
2010-12-08 10:08:28 -05:00
2010-01-11 16:50:30 -05:00
if ( original_t = = original )
2010-01-10 22:12:35 -05:00
{
2010-01-11 16:50:30 -05:00
m_converted_string = core : : stringw ( original ) ;
2010-12-08 10:08:28 -05:00
2010-01-11 18:22:44 -05:00
# if TRANSLATE_VERBOSE
std : : wcout < < L " translation : " < < m_converted_string . c_str ( ) < < std : : endl ;
# endif
2010-01-11 16:50:30 -05:00
return m_converted_string . c_str ( ) ;
2010-01-10 22:12:35 -05:00
}
2010-12-08 10:08:28 -05:00
2010-01-11 18:22:44 -05:00
// print
//for (int n=0;; n+=4)
2010-12-08 10:08:28 -05:00
2010-01-10 22:12:35 -05:00
wchar_t * out_ptr = ( wchar_t * ) original_t ;
2010-01-11 18:22:44 -05:00
if ( remove_bom ) out_ptr + + ;
2010-12-08 10:08:28 -05:00
2010-01-11 18:22:44 -05:00
# if TRANSLATE_VERBOSE
std : : wcout < < L " translation : " < < out_ptr < < std : : endl ;
# endif
2010-12-08 10:08:28 -05:00
2010-05-30 15:11:39 -04:00
# if ENABLE_BIDI
2010-06-27 06:26:47 -04:00
if ( this - > isRTLLanguage ( ) )
2010-05-30 15:11:39 -04:00
{
2010-06-27 06:26:47 -04:00
const int FRIBIDI_BUFFER_SIZE = 512 ;
FriBidiChar fribidiInput [ FRIBIDI_BUFFER_SIZE ] ;
int len = 0 ;
int n = 0 ;
//std::cout << "fribidi input : ";
2010-12-08 10:08:28 -05:00
for ( n = 0 ; ; n + + )
2010-05-30 15:11:39 -04:00
{
2010-06-27 06:26:47 -04:00
fribidiInput [ n ] = out_ptr [ n ] ;
//std::cout << (int)fribidiInput[n] << " ";
len + + ;
2010-12-08 10:08:28 -05:00
2010-06-27 06:26:47 -04:00
if ( n = = FRIBIDI_BUFFER_SIZE - 1 ) // prevent buffeoverflows
{
std : : cerr < < " WARNING : translated string too long, truncating! \n " ;
fribidiInput [ n ] = 0 ;
break ;
}
if ( fribidiInput [ n ] = = 0 ) break ; // stop on '\0'
2010-05-30 15:11:39 -04:00
}
2010-06-27 06:26:47 -04:00
//std::cout << " (len=" << len << ")\n";
2010-05-30 15:11:39 -04:00
2011-01-10 22:40:27 -05:00
// Assume right to left as start direction.
2011-01-11 18:11:02 -05:00
# if FRIBIDI_MINOR_VERSION==10
// While the doc for older fribidi versions is somewhat sparse,
// using the RIGHT-TO-LEFT EMBEDDING character here appears to
// work correct.
FriBidiCharType pbase_dir = L ' \ u202B ' ;
# else
2011-01-10 22:40:27 -05:00
FriBidiCharType pbase_dir = FRIBIDI_PAR_ON ;
2011-01-11 18:11:02 -05:00
# endif
2010-12-08 10:08:28 -05:00
2010-06-27 06:26:47 -04:00
static FriBidiChar fribidiOutput [ FRIBIDI_BUFFER_SIZE ] ;
2010-06-27 13:19:28 -04:00
for ( n = 0 ; n < 512 ; n + + ) { fribidiOutput [ n ] = 0 ; }
2010-06-27 06:26:47 -04:00
fribidi_boolean result = fribidi_log2vis ( fribidiInput ,
len - 1 ,
& pbase_dir ,
fribidiOutput ,
/* gint *position_L_to_V_list */ NULL ,
/* gint *position_V_to_L_list */ NULL ,
/* gint8 *embedding_level_list */ NULL
) ;
2010-12-08 10:08:28 -05:00
2010-06-27 06:26:47 -04:00
if ( ! result )
{
std : : cerr < < " Fribidi failed in 'fribidi_log2vis' =( \n " ;
2010-06-27 12:46:30 -04:00
m_converted_string = core : : stringw ( original ) ;
return m_converted_string . c_str ( ) ;
2010-06-27 06:26:47 -04:00
}
2010-12-08 10:08:28 -05:00
2010-06-27 06:26:47 -04:00
//std::cout << "fribidi output : ";
//for (FriBidiChar* c=fribidiOutput; *c != 0; c++)
//{
// std::cout << (int)fribidiOutput[n] << " ";
//}
//std::cout << "\n";
2011-01-10 22:40:27 -05:00
# ifdef WIN32
// On windows FriBidiChar is 4 bytes, but wchar_t is 2 bytes.
// So we simply copy the characters over here (note that this
// is technically incorrect, all characters we use/support fit
// in 16 bits, which is what irrlicht supports atm).
static wchar_t out [ FRIBIDI_BUFFER_SIZE ] ;
for ( int i = 0 ; i < len ; i + + )
out [ i ] = fribidiOutput [ i ] ;
out [ len ] = 0 ;
return out ;
# else
2010-06-27 06:26:47 -04:00
return ( const wchar_t * ) fribidiOutput ;
2011-01-10 22:40:27 -05:00
# endif
2010-06-27 06:26:47 -04:00
}
2010-12-08 10:08:28 -05:00
2010-06-30 20:13:31 -04:00
# endif
2010-01-07 19:23:31 -05:00
return out_ptr ;
2010-12-08 10:08:28 -05:00
2010-05-30 15:11:39 -04:00
}
2010-01-07 19:23:31 -05:00
2010-05-30 15:11:39 -04:00
bool Translations : : isRTLLanguage ( ) const
{
return m_rtl ;
2009-08-30 15:18:05 -04:00
}
2010-05-30 15:11:39 -04:00