mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-31 04:13:37 +00:00
236 lines
6.2 KiB
C++
236 lines
6.2 KiB
C++
#include "base_util.h"
|
|
#include "translations.h"
|
|
#include "translations_txt.h"
|
|
#include "str_util.h"
|
|
|
|
/*
|
|
This code relies on the following variables that must be defined in a
|
|
separate file (translations_txt.h and translations_txt.c).
|
|
The idea is that those files are automatically generated
|
|
by a script from translations file.
|
|
|
|
// number of languages we support
|
|
int g_transLangsCount;
|
|
|
|
// array of language names so that g_transLangs[i] is a name of
|
|
// language. i is 0..g_transLangsCount-1
|
|
const char **g_transLangs;
|
|
|
|
// total number of translated strings
|
|
int g_transTranslationsCount;
|
|
|
|
// array of translated strings.
|
|
// it has g_transLangsCount * g_translationsCount elements
|
|
// (for simplicity). Translation i for language n is at position
|
|
// (n * g_transTranslationsCount) + i
|
|
const char **g_transTranslations;
|
|
*/
|
|
|
|
// numeric index of the current language. 0 ... g_transLangsCount-1
|
|
static int currLangIdx = 0;
|
|
|
|
/* 'data'/'data_len' is a text describing all texts we translate.
|
|
It builds data structures need for quick lookup of translations
|
|
as well as a list of available languages.
|
|
It returns a list of available languages.
|
|
The list is not valid after a call to Translations_FreeData.
|
|
The function must be called before any other function in this module.
|
|
It can be called multiple times. This is to make debugging of translations
|
|
easier by allowing re-loading translation file at runtime.
|
|
*/
|
|
bool Translations_FromData(const char* langs, const char* data, size_t data_len)
|
|
{
|
|
assert(0); // TODO: implement me
|
|
return false;
|
|
}
|
|
|
|
bool Translations_SetCurrentLanguage(const char* lang)
|
|
{
|
|
for (int i=0; i < g_transLangsCount; i++) {
|
|
if (str_eq(lang, g_transLangs[i])) {
|
|
currLangIdx = i;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const char* Translatations_GetTranslation(const char* txt)
|
|
{
|
|
// perf shortcut: don't bother translating if we use default lanuage
|
|
if (0 == currLangIdx)
|
|
return txt;
|
|
for (int i=0; i < g_transTranslationsCount; i++) {
|
|
// TODO: translations are sorted so can use binary search
|
|
const char *tmp = g_transTranslations[i];
|
|
int cmp_res = strcmp(txt, tmp);
|
|
if (0 == cmp_res) {
|
|
tmp = g_transTranslations[(currLangIdx * g_transTranslationsCount) + i];
|
|
if (NULL == tmp)
|
|
return txt;
|
|
return tmp;
|
|
} else if (cmp_res < 0) {
|
|
assert(0); // bad - didn't find a translation
|
|
return txt;
|
|
}
|
|
}
|
|
assert(0); // bad - didn't find a translation
|
|
return txt;
|
|
}
|
|
|
|
static WCHAR* lastTxtCached = NULL;
|
|
|
|
#define UTF8_END -1
|
|
#define UTF8_ERROR -2
|
|
|
|
typedef struct json_utf8_decode
|
|
{
|
|
int the_index;
|
|
const char *the_input;
|
|
int the_length;
|
|
int the_char;
|
|
int the_byte;
|
|
} json_utf8_decode;
|
|
|
|
|
|
void
|
|
utf8_decode_init(json_utf8_decode *utf8, const char *p, int length)
|
|
{
|
|
utf8->the_index = 0;
|
|
utf8->the_input = p;
|
|
utf8->the_length = length;
|
|
utf8->the_char = 0;
|
|
utf8->the_byte = 0;
|
|
}
|
|
|
|
static int
|
|
get(json_utf8_decode *utf8)
|
|
{
|
|
int c;
|
|
if (utf8->the_index >= utf8->the_length) {
|
|
return UTF8_END;
|
|
}
|
|
c = utf8->the_input[utf8->the_index] & 0xFF;
|
|
utf8->the_index += 1;
|
|
return c;
|
|
}
|
|
|
|
static int
|
|
cont(json_utf8_decode *utf8)
|
|
{
|
|
int c = get(utf8);
|
|
return ((c & 0xC0) == 0x80) ? (c & 0x3F) : UTF8_ERROR;
|
|
}
|
|
|
|
int
|
|
utf8_decode_next(json_utf8_decode *utf8)
|
|
{
|
|
int c; /* the first byte of the character */
|
|
int r; /* the result */
|
|
|
|
if (utf8->the_index >= utf8->the_length) {
|
|
return utf8->the_index == utf8->the_length ? UTF8_END : UTF8_ERROR;
|
|
}
|
|
utf8->the_byte = utf8->the_index;
|
|
utf8->the_char += 1;
|
|
c = get(utf8);
|
|
/*
|
|
Zero continuation (0 to 127)
|
|
*/
|
|
if ((c & 0x80) == 0) {
|
|
return c;
|
|
}
|
|
/*
|
|
One contination (128 to 2047)
|
|
*/
|
|
if ((c & 0xE0) == 0xC0) {
|
|
int c1 = cont(utf8);
|
|
if (c1 < 0) {
|
|
return UTF8_ERROR;
|
|
}
|
|
r = ((c & 0x1F) << 6) | c1;
|
|
return r >= 128 ? r : UTF8_ERROR;
|
|
}
|
|
/*
|
|
Two continuation (2048 to 55295 and 57344 to 65535)
|
|
*/
|
|
if ((c & 0xF0) == 0xE0) {
|
|
int c1 = cont(utf8);
|
|
int c2 = cont(utf8);
|
|
if (c1 < 0 || c2 < 0) {
|
|
return UTF8_ERROR;
|
|
}
|
|
r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
|
|
return r >= 2048 && (r < 55296 || r > 57343) ? r : UTF8_ERROR;
|
|
}
|
|
/*
|
|
Three continuation (65536 to 1114111)
|
|
*/
|
|
if ((c & 0xF1) == 0xF0) {
|
|
int c1 = cont(utf8);
|
|
int c2 = cont(utf8);
|
|
int c3 = cont(utf8);
|
|
if (c1 < 0 || c2 < 0 || c3 < 0) {
|
|
return UTF8_ERROR;
|
|
}
|
|
r = ((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3;
|
|
return r >= 65536 && r <= 1114111 ? r : UTF8_ERROR;
|
|
}
|
|
return UTF8_ERROR;
|
|
}
|
|
|
|
static int json_utf8_to_utf16(unsigned short *w, const char *p, int length)
|
|
{
|
|
int c;
|
|
int the_index = 0;
|
|
json_utf8_decode utf8;
|
|
|
|
utf8_decode_init(&utf8, p, length);
|
|
for (;;) {
|
|
c = utf8_decode_next(&utf8);
|
|
if (c < 0) {
|
|
return UTF8_END ? the_index : UTF8_ERROR;
|
|
}
|
|
if (c < 0x10000) {
|
|
w[the_index] = (unsigned short)c;
|
|
the_index += 1;
|
|
} else {
|
|
c &= 0xFFFF;
|
|
w[the_index] = (unsigned short)(0xD800 | (c >> 10));
|
|
the_index += 1;
|
|
w[the_index] = (unsigned short)(0xDC00 | (c & 0x3FF));
|
|
the_index += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
WCHAR* utf8_to_utf16(const char *txt)
|
|
{
|
|
// TODO: this is not correct, need real conversion
|
|
size_t len = strlen(txt);
|
|
WCHAR* wstr = (WCHAR*)zmalloc((len+1) * sizeof(WCHAR));
|
|
if (!wstr) return NULL;
|
|
int res = json_utf8_to_utf16((unsigned short*)wstr, txt, len);
|
|
assert(UTF8_ERROR != res);
|
|
return wstr;
|
|
}
|
|
|
|
// TODO: this is not thread-safe. lastTxtCached should be per-thread
|
|
const WCHAR* Translatations_GetTranslationW(const char* txt)
|
|
{
|
|
txt = Translatations_GetTranslation(txt);
|
|
if (!txt) return NULL;
|
|
if (lastTxtCached)
|
|
free(lastTxtCached);
|
|
lastTxtCached = utf8_to_utf16(txt);
|
|
return (const WCHAR*)lastTxtCached;
|
|
}
|
|
|
|
void Translations_FreeData()
|
|
{
|
|
// TODO: will be more when we implement Translations_FromData
|
|
free(lastTxtCached);
|
|
lastTxtCached = NULL;
|
|
}
|
|
|