gettext without gettext

master
darkrose 2015-04-10 04:09:36 +10:00
parent 74406aacdd
commit 88309b16df
32 changed files with 788 additions and 153 deletions

View File

@ -6,60 +6,13 @@ SET(CUSTOM_GETTEXT_PATH "${PROJECT_SOURCE_DIR}/../../gettext"
# by default
SET(GETTEXT_FOUND FALSE)
FIND_PATH(GETTEXT_INCLUDE_DIR
NAMES libintl.h
PATHS "${CUSTOM_GETTEXT_PATH}/include"
DOC "gettext include directory")
FIND_PROGRAM(GETTEXT_MSGFMT
NAMES msgfmt
PATHS "${CUSTOM_GETTEXT_PATH}/bin"
DOC "path to msgfmt")
# modern Linux, as well as Mac, seem to not need require special linking
# they do not because gettext is part of glibc
# TODO check the requirements on other BSDs and older Linux
IF (WIN32)
IF(MSVC)
SET(GETTEXT_LIB_NAMES
libintl.lib intl.lib libintl3.lib intl3.lib)
ELSE()
SET(GETTEXT_LIB_NAMES
libintl.dll.a intl.dll.a libintl3.dll.a intl3.dll.a)
ENDIF()
FIND_LIBRARY(GETTEXT_LIBRARY
NAMES ${GETTEXT_LIB_NAMES}
PATHS "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.lib")
FIND_FILE(GETTEXT_DLL
NAMES libintl.dll intl.dll libintl3.dll intl3.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.dll")
FIND_FILE(GETTEXT_ICONV_DLL
NAMES libiconv2.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *iconv*.lib")
ENDIF(WIN32)
IF(GETTEXT_INCLUDE_DIR AND GETTEXT_MSGFMT)
IF (WIN32)
# in the Win32 case check also for the extra linking requirements
IF(GETTEXT_LIBRARY AND GETTEXT_DLL AND GETTEXT_ICONV_DLL)
SET(GETTEXT_FOUND TRUE)
ENDIF()
ELSE(WIN32)
# *BSD variants require special linkage as they don't use glibc
IF(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
SET(GETTEXT_LIBRARY "intl")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(GETTEXT_LIBRARY "${CUSTOM_GETTEXT_PATH}/lib/libintl.dylib")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(GETTEXT_FOUND TRUE)
ENDIF(WIN32)
ENDIF()
IF(GETTEXT_FOUND)
IF(GETTEXT_MSGFMT)
SET(GETTEXT_FOUND TRUE)
SET(GETTEXT_PO_PATH ${CMAKE_SOURCE_DIR}/po)
SET(GETTEXT_MO_BUILD_PATH ${CMAKE_BINARY_DIR}/locale/<locale>/LC_MESSAGES)
SET(GETTEXT_MO_DEST_PATH ${SHAREDIR}/../locale/<locale>/LC_MESSAGES)

View File

@ -14,13 +14,7 @@ set(USE_GETTEXT 0)
find_package(GettextLib)
if(GETTEXT_FOUND AND ENABLE_GETTEXT)
message(STATUS "gettext include path: ${GETTEXT_INCLUDE_DIR}")
message(STATUS "gettext msgfmt path: ${GETTEXT_MSGFMT}")
if(WIN32)
message(STATUS "gettext library: ${GETTEXT_LIBRARY}")
message(STATUS "gettext dll: ${GETTEXT_DLL}")
message(STATUS "gettext iconv dll: ${GETTEXT_ICONV_DLL}")
endif()
set(USE_GETTEXT 1)
message(STATUS "GetText enabled; locales found: ${GETTEXT_AVAILABLE_LOCALES}")
elseif(GETTEXT_FOUND AND NOT ENABLE_GETTEXT)
@ -198,6 +192,7 @@ set(common_SRCS
content_mapnode_util.cpp
content_list.cpp
content_nodebox.cpp
intl.cpp
auth.cpp
collision.cpp
nodemetadata.cpp
@ -286,7 +281,6 @@ include_directories(
${CMAKE_BUILD_TYPE}
${PNG_INCLUDE_DIR}
${AUDIO_INCLUDE_DIRS}
${GETTEXT_INCLUDE_DIR}
${JTHREAD_INCLUDE_DIR}
${SQLITE3_INCLUDE_DIR}
)
@ -316,7 +310,6 @@ if(BUILD_CLIENT)
${PNG_LIBRARIES}
${X11_LIBRARIES}
${AUDIO_LIBRARIES}
${GETTEXT_LIBRARY}
${JTHREAD_LIBRARY}
${SQLITE3_LIBRARY}
${PLATFORM_LIBS}
@ -427,11 +420,9 @@ if(BUILD_CLIENT)
install(FILES ${images} DESTINATION ${SHAREDIR}/textures)
file(GLOB skins "${CMAKE_CURRENT_SOURCE_DIR}/../data/textures/skins/*.png")
install(FILES ${skins} DESTINATION ${SHAREDIR}/textures/skins)
file(GLOB models
"${CMAKE_CURRENT_SOURCE_DIR}/../data/models/*.b3d")
file(GLOB models "${CMAKE_CURRENT_SOURCE_DIR}/../data/models/*.b3d")
install(FILES ${models} DESTINATION ${SHAREDIR}/models)
file(GLOB modelsx
"${CMAKE_CURRENT_SOURCE_DIR}/../data/models/*.x")
file(GLOB modelsx "${CMAKE_CURRENT_SOURCE_DIR}/../data/models/*.x")
install(FILES ${modelsx} DESTINATION ${SHAREDIR}/models)
file(GLOB sounds "${CMAKE_CURRENT_SOURCE_DIR}/../data/sounds/*.ogg")
install(FILES ${sounds} DESTINATION ${SHAREDIR}/sounds)
@ -470,14 +461,6 @@ if(BUILD_CLIENT)
install(FILES ${OPENAL_DLL} DESTINATION ${BINDIR})
endif()
endif(USE_AUDIO)
if(USE_GETTEXT)
if(DEFINED GETTEXT_DLL)
install(FILES ${GETTEXT_DLL} DESTINATION ${BINDIR})
endif()
if(DEFINED GETTEXT_ICONV_DLL)
install(FILES ${GETTEXT_ICONV_DLL} DESTINATION ${BINDIR})
endif()
endif(USE_GETTEXT)
endif()
if(APPLE)
# TODO: install Irrlicht.framework into app bundle!

View File

@ -34,7 +34,7 @@
#include "utility.h"
#include "gui_colours.h"
#include "gettext.h"
#include "intl.h"
GUICharDefMenu::GUICharDefMenu(
IrrlichtDevice* device,

View File

@ -23,7 +23,7 @@
#include "content_list.h"
#include "content_mapnode.h"
#include <map>
#include "gettext.h"
#include "intl.h"
std::map<content_t,struct ClothesItemFeatures> g_content_clothesitem_features;

View File

@ -4,7 +4,7 @@
#include "content_mob.h"
#include "content_list.h"
#include <map>
#include "gettext.h"
#include "intl.h"
std::map<content_t,struct CraftItemFeatures> g_content_craftitem_features;

View File

@ -39,7 +39,7 @@
#ifndef SERVER
#include "tile.h"
#endif
#include "gettext.h"
#include "intl.h"
#define WATER_ALPHA 160

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_circuit(bool repeat)
{

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_door(bool repeat)
{

View File

@ -26,7 +26,7 @@
#include "content_craftitem.h"
#include "content_nodemeta.h"
#include "settings.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_farm(bool repeat)
{

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_furniture(bool repeat)
{

View File

@ -28,7 +28,7 @@
#include "content_craft.h"
#include "content_nodemeta.h"
#include "settings.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_plants(bool repeat)
{

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_slab(bool repeat)
{

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_special(bool repeat)
{

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "gettext.h"
#include "intl.h"
void content_mapnode_stair(bool repeat)
{

View File

@ -27,7 +27,7 @@
#define CONTENT_NODEMETA_HEADER
#include "nodemetadata.h"
#include "gettext.h"
#include "intl.h"
class ServerEnvironment;
class Inventory;

View File

@ -24,7 +24,7 @@
#include "content_list.h"
#include "content_mapnode.h"
#include <map>
#include "gettext.h"
#include "intl.h"
std::map<content_t,struct ToolItemFeatures> g_content_toolitem_features;

View File

@ -45,7 +45,7 @@
#include "settings.h"
#include "profiler.h"
#include "mainmenumanager.h"
#include "gettext.h"
#include "intl.h"
#include "log.h"
#include "filesys.h"
#include "path.h"

View File

@ -1,48 +0,0 @@
#ifndef GETTEXT_HEADER
#include "config.h" // for USE_GETTEXT
#include <iostream>
#if USE_GETTEXT
#include <libintl.h>
#else
#define gettext(String) String
#define ngettext(String1,String2,Int) String2
#endif
#define _(String) gettext(String)
#define gettext_noop(String) String
#define N_(String) gettext_noop (String)
inline void init_gettext(const char *path) {
#if USE_GETTEXT
// don't do this if MSVC compiler is used, it gives an assertion fail
#ifndef _MSC_VER
setlocale(LC_MESSAGES, "");
setlocale(LC_CTYPE, "");
#endif
bindtextdomain(PROJECT_NAME, path);
textdomain(PROJECT_NAME);
#endif
}
inline wchar_t* chartowchar_t(const char *str)
{
size_t l = strlen(str)+1;
wchar_t* nstr = new wchar_t[l];
mbstowcs(nstr, str, l);
return nstr;
}
inline wchar_t* wgettext(const char *str)
{
wchar_t *r = chartowchar_t(gettext(str));
return r;
}
inline wchar_t* wngettext(const char *str1, const char *str2, int n)
{
wchar_t *r = chartowchar_t(ngettext(str1,str2,n));
return r;
}
#define GETTEXT_HEADER
#endif

View File

@ -32,7 +32,7 @@
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "intl.h"
#include "client.h"
#include "gui_colours.h"

View File

@ -39,7 +39,7 @@
#include "tile.h" // ITextureSource
#include "path.h"
#include "gui_colours.h"
#include "gettext.h"
#include "intl.h"
#if USE_FREETYPE
#include "intlGUIEditBox.h"
#endif

View File

@ -32,7 +32,7 @@
#include "utility.h"
#include "modalMenu.h"
#include "client.h"
#include "gettext.h"
#include "intl.h"
#include "keycode.h"
#include <string>

View File

@ -45,7 +45,7 @@
#endif
#include "sound.h"
#include "gettext.h"
#include "intl.h"
GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,

View File

@ -33,7 +33,7 @@
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "intl.h"
#include "gui_colours.h"
GUIMessageMenu::GUIMessageMenu(gui::IGUIEnvironment* env,

View File

@ -33,7 +33,7 @@
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "intl.h"
#include "gui_colours.h"
#if USE_FREETYPE
#include "intlGUIEditBox.h"

View File

@ -35,7 +35,7 @@
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "intl.h"
#include "gui_colours.h"
GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env,

View File

@ -32,7 +32,7 @@
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "intl.h"
#include "gui_colours.h"
#if USE_FREETYPE
#include "intlGUIEditBox.h"

720
src/intl.cpp Normal file
View File

@ -0,0 +1,720 @@
/************************************************************************
* gettext.cpp
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2013-2015 <lisa@ltmnet.com>
*
* 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, see <http://www.gnu.org/licenses/>
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <ctype.h>
#ifdef _WIN32
#include <Windows.h>
#include <windows.h>
#endif
#include "intl.h"
#include "path.h"
typedef struct intl_s {
void *mo_data;
int inv_endian;
int str_count;
int tbl_offset[2];
int hash_count;
int hash_offset;
uint32_t plurals;
char* plural;
} intl_t;
#define INTL_MO_MAGIC 0x950412DE
#define INTL_MO_MAGIC_REV 0xDE120495
#define INTL_ORIG 0
#define INTL_TRANS 1
/* remove whitespace from beginning and end of a string */
static char* intl_trim(char* str)
{
int32_t l;
while (*str && isspace(*str)) {
str++;
}
l = strlen(str);
while (--l > -1 && (!str[l] || isspace(str[l]))) {
str[l] = 0;
}
return str;
}
static uint32_t intl_eval_preceed(char* str, char* p, char** b)
{
int mul = 1;
uint32_t r = 0;
while (isdigit(*p) || (mul == 1 && isspace(*p))) {
r += ((*p)-48)*mul;
mul *= 10;
if (p == str)
break;
p--;
}
if (p != str)
p++;
*b = p;
return r;
}
/* returns 1 if str contains only a number */
static uint32_t intl_eval_check(char* str)
{
char buff[50];
uint32_t v = strtoul(str,NULL,10);
if (!str || !str[0])
return 1;
sprintf(buff,"%u",v);
if (!strcmp(buff,str))
return 1;
return 0;
}
/* evaluate a plurals expression to an integer value */
static uint32_t intl_eval(char* str)
{
char buff[1024];
char* qc;
char* cc;
char* ac;
char* oc;
str = intl_trim(str);
if (intl_eval_check(str))
return strtoul(str,NULL,10);
if (str[0] == '(') {
int o = 1;
int c = 0;
uint32_t r;
int i;
for (i=1; str[i]; i++) {
switch (str[i]) {
case '(':
o++;
break;
case ')':
c++;
break;
default:;
}
if (o == c)
break;
}
c = str[i];
str[i] = 0;
r = intl_eval(str+1);
str[i] = c;
if (c) {
sprintf(buff,"%u%s",r,str+i+1);
}else{
sprintf(buff,"%u",r);
}
if (intl_eval_check(buff))
return strtoul(buff,NULL,10);
return intl_eval(buff);
}
qc = strchr(str,'?');
if (qc) {
int o = 1;
int c = 0;
uint32_t r;
int i;
for (i=1; qc[i]; i++) {
switch (qc[i]) {
case '?':
o++;
break;
case ':':
c++;
break;
default:;
}
if (o == c)
break;
}
if (o != c)
return 0;
cc = qc+i;
*qc = 0;
r = intl_eval(str);
*qc = '?';
if (r) {
*cc = 0;
strcpy(buff,qc+1);
*cc = ':';
}else{
strcpy(buff,cc+1);
}
if (intl_eval_check(buff))
return strtoul(buff,NULL,10);
return intl_eval(buff);
}
ac = strstr(str,"&&");
oc = strstr(str,"||");
if (ac && (!oc || ac < oc)) {
uint32_t r;
*ac = 0;
r = intl_eval(str);
*ac = '&';
if (!r)
return 0;
strcpy(buff,ac+2);
if (intl_eval_check(buff))
return strtoul(buff,NULL,10);
return intl_eval(buff);
}
if (oc) {
uint32_t r;
*oc = 0;
r = intl_eval(str);
*oc = '|';
if (r)
return 1;
strcpy(buff,oc+2);
if (intl_eval_check(buff))
return strtoul(buff,NULL,10);
return intl_eval(buff);
}
ac = strchr(str,'=');
if (ac) {
uint32_t r1;
uint32_t r2;
uint32_t r3 = 0;
char* e;
char* n;
char ec;
if (*(ac-1) == '!') {
e = ac-1;
n = ac+1;
}else if (*(ac-1) == '>') {
e = ac-1;
n = ac+1;
}else if (*(ac-1) == '<') {
e = ac-1;
n = ac+1;
}else if (*(ac+1) == '=') {
e = ac;
n = ac+2;
}else{
return 0;
}
ec = *e;
*e = 0;
r1 = intl_eval(str);
r2 = intl_eval(n);
*e = ec;
switch (ec) {
case '!':
r3 = (r1 != r2);
break;
case '>':
r3 = (r1 >= r2);
break;
case '<':
r3 = (r1 <= r2);
break;
case '=':
r3 = (r1 == r2);
break;
}
return r3;
}
ac = strchr(str,'<');
if (ac) {
uint32_t r1;
uint32_t r2;
*ac = 0;
r1 = intl_eval(str);
r2 = intl_eval(ac+1);
*ac = '<';
return (r1<r2);
}
ac = strchr(str,'>');
if (ac) {
uint32_t r1;
uint32_t r2;
*ac = 0;
r1 = intl_eval(str);
r2 = intl_eval(ac+1);
*ac = '>';
return (r1>r2);
}
ac = strchr(str,'*');
oc = strchr(str,'/');
if (!ac && !oc) {
ac = strchr(str,'%');
if (!ac) {
ac = strchr(str,'+');
oc = strchr(str,'-');
if (oc && (!ac || oc < ac))
ac = oc;
}
}else if (oc && (!ac || oc < ac)) {
ac = oc;
}
if (ac) {
uint32_t r1;
uint32_t r2;
uint32_t r3 = 0;
char* b;
char* e;
if (ac == str)
return 0;
r1 = intl_eval_preceed(str,ac-1,&b);
r2 = strtoul(ac+1,&e,10);
switch(*ac) {
case '*':
r3 = (r1*r2);
break;
case '/':
if (!r2) {
r3 = 0;
}else{
r3 = (r1/r2);
}
break;
case '%':
if (!r2) {
r3 = 0;
}else{
r3 = (r1%r2);
}
break;
case '+':
r3 = (r1+r2);
break;
case '-':
r3 = (r1-r2);
break;
}
if (b != str) {
char bc = *b;
*b = 0;
sprintf(buff,"%s%u%s",str,r3,e);
*b = bc;
}else if (*e) {
sprintf(buff,"%u%s",r3,e);
}else{
return r3;
}
if (intl_eval_check(buff))
return strtoul(buff,NULL,10);
return intl_eval(buff);
}
if (intl_eval_check(str))
return strtoul(str,NULL,10);
return 0;
}
/* get the plural index based on n */
static uint32_t intl_getplural(intl_t *intl, int n)
{
char buff[1024];
char nb[50];
int i;
int k;
int o;
uint32_t r;
if (!intl->plural)
return 0;
sprintf(nb,"%d",n);
for (o=0,i=7; intl->plural[i]; i++) {
if (o > 1022)
return 0;
if (intl->plural[i] == 'n') {
for (k=0; nb[k]; k++) {
buff[o++] = nb[k];
if (o > 1022)
return 0;
}
continue;
}
buff[o++] = intl->plural[i];
}
buff[o] = 0;
r = intl_eval(buff);
if (r >= intl->plurals)
return 0;
return r;
}
/* basic hashpjw used by lots of things, including mo files */
static uint32_t intl_hash(const char *str_param)
{
uint32_t hval = 0;
uint32_t g;
const char *s = str_param;
while (*s) {
hval <<= 4;
hval += (unsigned char) *s++;
g = hval & ((uint32_t) 0xf << 28);
if (g != 0) {
hval ^= g >> 24;
hval ^= g;
}
}
return hval;
}
/* read a 32 bit int with correct endianness */
static uint32_t intl_readint(intl_t *intl, int offset)
{
uint8_t *p;
uint32_t r = *((uint32_t*)(((char*)intl->mo_data) + offset));
if (!intl->inv_endian)
return r;
p = (uint8_t*)&r;
return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
}
/* get a string from either the original strings table INTL_ORIG
* or the translated strings tables INTL_TRANS */
static char* intl_getstr(intl_t *intl, int type, int index, int *length)
{
uint32_t offset = intl->tbl_offset[type] + (8 * index);
*length = intl_readint(intl,offset);
offset = intl_readint(intl,offset+4);
return ((char *)intl->mo_data) + offset;
}
/* get the language code (en_GB etc) */
static void intl_getlang(char* buff, int size)
{
#ifdef _WIN32
char l1[4];
char l2[4];
if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, (LPSTR)l1, 4))
strcpy(l1,"en");
if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME , (LPSTR)l2, 4))
l2[0] = 0;
if (l1[0] && l2[0]) {
snprintf(buff,size,"%s_%s",l1,l2);
}else if (l1[0]) {
strncpy(buff,l1,size);
}else{
strncpy(buff,"en",size);
}
#else
char* lang = getenv("LANG");
if (!lang || !lang[0])
lang = (char*)"en";
strncpy(buff,lang,size);
#endif
}
/* essentially gettext() but with a per-mo-file option */
char* intl_lookup(intl_t *intl, char *s, int *length)
{
uint32_t h;
int hp;
int hp_o;
int inc;
uint32_t i;
char* l;
int len;
if (!intl || !intl->mo_data)
return s;
h = intl_hash(s);
hp = h % intl->hash_count;
hp_o = hp;
inc = 1 + (h % (intl->hash_count - 2));
while (1) {
i = intl->hash_offset+(4*hp);
i = intl_readint(intl, i);
if (!i)
break;
/* entries in the table are stored +1 so that 0 means empty */
i--;
l = intl_getstr(intl,INTL_ORIG,i,&len);
if (!strcmp(l,s)) {
l = intl_getstr(intl,INTL_TRANS,i,&len);
if (length)
*length = len;
return l;
}
hp += inc;
hp %= intl->hash_count;
if (hp == hp_o)
break;
}
if (length)
*length = strlen(s);
return s;
}
/* as per intl_lookup, but for ngettext() */
char* intl_nlookup(intl_t *intl, char* s1, char* s2, int n)
{
char* s = s1;
int p;
int i;
int length;
int sl;
int cl;
int tl;
char* l;
char* c = NULL;
if (!s2)
return intl_lookup(intl,s1,NULL);
if (!intl || !intl->mo_data) {
if (n == 1)
return s1;
return s2;
}
l = intl_lookup(intl,s,&length);
if (intl->plurals < 2)
return l;
sl = strlen(l);
if (sl == length)
return l;
p = intl_getplural(intl,n);
if (!p)
return l;
tl = sl;
for (i=0; i<p; i++) {
if (tl >= length)
return l;
c = l+tl+1;
cl = strlen(c);
tl += cl+1;
}
return c;
}
/* initialise an intl_t by loading in an mo file */
int intl_init(intl_t *intl, const char* file)
{
char fbuff[2048];
char lbuff[128];
FILE *f;
int length;
uint32_t magic;
char* head;
char* p;
char* e;
std::string path;
intl_getlang(lbuff,128);
intl->mo_data = NULL;
intl->str_count = 0;
intl->tbl_offset[INTL_ORIG] = 0;
intl->tbl_offset[INTL_TRANS] = 0;
intl->hash_count = 0;
intl->hash_offset = 0;
intl->plurals = 1;
intl->plural = NULL;
path = std::string("translation-")+lbuff;
path = getPath(path.c_str(),file,true);
if (path == "") {
char* u = strchr(lbuff,'_');
if (!u)
return 1;
*u = 0;
path = std::string("translation-")+lbuff;
path = getPath(path.c_str(),file,true);
if (path == "")
return 1;
}
f = fopen(path.c_str(), "rb");
if (!f)
return 2;
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
if (length < 24) {
fclose(f);
return 3;
}
intl->mo_data = malloc(length);
if (!intl->mo_data) {
fclose(f);
return 4;
}
if (length != (int)fread(intl->mo_data, 1, length, f)) {
fclose(f);
free(intl->mo_data);
intl->mo_data = NULL;
return 5;
}
fclose(f);
magic = ((uint32_t*)intl->mo_data)[0];
if (magic == INTL_MO_MAGIC) {
intl->inv_endian = 0;
}else if (magic == INTL_MO_MAGIC_REV) {
intl->inv_endian = 1;
}else{
free(intl->mo_data);
intl->mo_data = NULL;
return 6;
}
intl->str_count = intl_readint(intl, 8);
intl->tbl_offset[INTL_ORIG] = intl_readint(intl, 12);
intl->tbl_offset[INTL_TRANS] = intl_readint(intl, 16);
intl->hash_count = intl_readint(intl, 20);
intl->hash_offset = intl_readint(intl, 24);
if (!intl->hash_count) {
free(intl->mo_data);
intl->mo_data = NULL;
return 7;
}
head = intl_lookup(intl,(char*)"",NULL);
if (!head)
return 0;
p = strstr(head,"Plural-Forms:");
if (!p)
return 0;
head = p;
e = strchr(head,'\n');
if (e)
*e = 0;
strncpy(fbuff,head+13,2048);
if (e)
*e = '\n';
head = fbuff;
p = strstr(head,"nplurals=");
if (!p)
return 0;
e = strchr(p,';');
if (e)
*e = 0;
intl->plurals = strtol(p+9,NULL,10);
if (e)
*e = ';';
p = strstr(head,"plural=");
if (!p)
return 0;
e = strchr(p,';');
if (e)
*e = 0;
intl->plural = strdup(p);
if (e)
*e = ';';
return 0;
}
/* the normal stuff */
static intl_t intl;
char* gettext(const char *s)
{
return intl_lookup(&intl,(char*)s,NULL);
}
char* ngettext(const char* s1, const char* s2, int n)
{
return intl_nlookup(&intl,(char*)s1,(char*)s2,n);
}
wchar_t *mb2wc(const char *src)
{
mbstate_t state;
int l = strlen(src)+1;
memset(&state, '\0', sizeof (state));
wchar_t *buff = new wchar_t[l];
size_t n = mbsrtowcs(buff, &src, l, &state);
printf("%ld\n",(int64_t)n);
buff[n] = L'\0';
return buff;
}
wchar_t* wgettext(const char *str)
{
char* s = intl_lookup(&intl,(char*)str,NULL);
printf("%s\n",s);
return mb2wc(s);
}
wchar_t* wngettext(const char *str1, const char *str2, int n)
{
char* s = intl_nlookup(&intl,(char*)str1,(char*)str2,n);
return mb2wc(s);
}
void init_gettext()
{
#ifndef _MSC_VER
setlocale(LC_MESSAGES, "");
setlocale(LC_CTYPE, "");
#endif
intl_init(&intl,"voxelands.mo");
}

20
src/intl.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef GETTEXT_HEADER
#define GETTEXT_HEADER
#include <iostream>
char* gettext(const char *s);
char* ngettext(const char* s1, const char* s2, int n);
void init_gettext();
inline wchar_t* chartowchar_t(const char *str)
{
size_t l = strlen(str)+1;
wchar_t* nstr = new wchar_t[l];
mbstowcs(nstr, str, l);
return nstr;
}
wchar_t* wgettext(const char *str);
wchar_t* wngettext(const char *str1, const char *str2, int n);
#endif

View File

@ -63,7 +63,7 @@
#include "keycode.h"
#include "tile.h"
#include "defaultsettings.h"
#include "gettext.h"
#include "intl.h"
#include "settings.h"
#include "profiler.h"
#include "log.h"
@ -825,7 +825,7 @@ int main(int argc, char *argv[])
// Create user data directory
fs::CreateDir(porting::path_userdata);
init_gettext((porting::path_data+DIR_DELIM+".."+DIR_DELIM+"locale").c_str());
init_gettext();
// Initialize debug streams
#ifdef RUN_IN_PLACE

View File

@ -206,7 +206,7 @@ ContentFeatures & content_features(MapNode &n)
#ifndef SERVER
#include "common_irrlicht.h"
#include "game.h"
#include "gettext.h"
#include "intl.h"
void init_mapnode(video::IVideoDriver* driver)
#else
void init_mapnode()

View File

@ -141,26 +141,32 @@ std::string getPath(const char* tp, const std::string &filename, bool must_exist
rel_path += std::string("sounds")+DIR_DELIM+filename;
}else if (type == "font") {
rel_path += std::string("fonts")+DIR_DELIM+filename;
}else if (type.substr(0,11) == "translation") {
std::string lang = type.substr(12);
type = "translation";
rel_path += std::string("locale")+DIR_DELIM+lang+DIR_DELIM+filename;
}else{
rel_path += filename;
}
/* check from data_path */
std::string data_path = g_settings->get("data_path");
if (data_path != "") {
std::string testpath = data_path + DIR_DELIM + rel_path;
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font") {
if (fs::PathExists(testpath))
fullpath = std::string(testpath);
}else{
fullpath = getImagePath(testpath);
if (g_settings->exists("data_path")) {
std::string data_path = g_settings->get("data_path");
if (data_path != "") {
std::string testpath = data_path + DIR_DELIM + rel_path;
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font" || type == "translation") {
if (fs::PathExists(testpath))
fullpath = std::string(testpath);
}else{
fullpath = getImagePath(testpath);
}
}
}
/* check from user data directory */
if (fullpath == "") {
std::string testpath = porting::path_userdata + DIR_DELIM + rel_path;
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font") {
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font" || type == "translation") {
if (fs::PathExists(testpath))
fullpath = std::string(testpath);
}else{
@ -171,7 +177,7 @@ std::string getPath(const char* tp, const std::string &filename, bool must_exist
/* check from default data directory */
if (fullpath == "") {
std::string testpath = porting::path_data + DIR_DELIM + rel_path;
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font") {
if (type == "model" || type == "html" || type == "sound" || type == "skin" || type == "font" || type == "translation") {
if (fs::PathExists(testpath))
fullpath = std::string(testpath);
}else{

View File

@ -412,6 +412,7 @@ public:
n = m_defaults.find(name);
if(n == NULL)
{
printf("Not Found: %s\n",name.c_str());
infostream<<"Settings: Setting not found: \""
<<name<<"\""<<std::endl;
throw SettingNotFoundException("Setting not found");