add basic support for arabic.

This commit is contained in:
aliaspider 2018-02-05 20:54:55 +01:00
parent 5549b136c2
commit 45580cb9a8
25 changed files with 5810 additions and 3 deletions

View File

@ -284,7 +284,8 @@ OBJ += intl/msg_hash_de.o \
intl/msg_hash_ru.o \
intl/msg_hash_vn.o \
intl/msg_hash_chs.o \
intl/msg_hash_cht.o
intl/msg_hash_cht.o \
intl/msg_hash_ar.o
endif

View File

@ -470,14 +470,255 @@ static bool font_init_first(
return false;
}
#ifdef HAVE_LANGEXTRA
/* ACII: 0xxxxxxx (c & 0x80) == 0x00
* other start: 11xxxxxx (c & 0xC0) == 0xC0
* other cont: 10xxxxxx (c & 0xC0) == 0x80
* Neutral :
* 0020 - 002F : 001xxxxx (c & 0xE0) == 0x20
* Arabic:
* 0600 - 07FF : 11011xxx (c & 0xF8) == 0xD8 (2 bytes)
* 0800 - 08FF : 11100000 101000xx c == 0xE0 && (c1 & 0xAC) == 0xA0 (3 bytes) */
/* clang-format off */
#define IS_ASCII(p) ((*(p)&0x80) == 0x00)
#define IS_MBSTART(p) ((*(p)&0xC0) == 0xC0)
#define IS_MBCONT(p) ((*(p)&0xC0) == 0x80)
#define IS_DIR_NEUTRAL(p) ((*(p)&0xE0) == 0x20)
#define IS_ARABIC0(p) ((*(p)&0xF8) == 0xD8)
#define IS_ARABIC1(p) ((*(p) == 0xE0) && ((*((p) + 1) & 0xAC) == 0xA0))
#define IS_ARABIC(p) (IS_ARABIC0(p) || IS_ARABIC1(p))
#define IS_RTL(p) IS_ARABIC(p)
/* 0x0620 to 0x064F */
static const unsigned arabic_shape_map[0x50 - 0x20][0x4] = {
{ 0 }, /* 0x0620 */
{ 0xFE80 },
{ 0xFE81, 0xFE82 },
{ 0xFE83, 0xFE84 },
{ 0xFE85, 0xFE86 },
{ 0xFE87, 0xFE88 },
{ 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C },
{ 0xFE8D, 0xFE8E },
{ 0xFE8F, 0xFE90, 0xFE91, 0xFE92 },
{ 0xFE93, 0xFE94 },
{ 0xFE95, 0xFE96, 0xFE97, 0xFE98 },
{ 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C },
{ 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0 },
{ 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4 },
{ 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8 },
{ 0xFEA9, 0xFEAA },
{ 0xFEAB, 0xFEAC }, /* 0x0630 */
{ 0xFEAD, 0xFEAE },
{ 0xFEAF, 0xFEB0 },
{ 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4 },
{ 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8 },
{ 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC },
{ 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 },
{ 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 },
{ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },
{ 0xFEC9, 0xFECA, 0xFECB, 0xFECC },
{ 0xFECD, 0xFECE, 0xFECF, 0xFED0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0xFED1, 0xFED2, 0xFED3, 0xFED4 }, /* 0x0640 */
{ 0xFED5, 0xFED6, 0xFED7, 0xFED8 },
{ 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC },
{ 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 },
{ 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 },
{ 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 },
{ 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC },
{ 0xFEED, 0xFEEE },
{ 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 },
{ 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 },
};
/* clang-format on */
static INLINE unsigned font_get_replacement(const char* src, const char* start)
{
if ((*src & 0xFC) == 0xD8) /* 0x0600 to 0x06FF */
{
int lookup;
unsigned result;
bool prev_connected = false;
bool next_connected = false;
unsigned char id = (src[0] << 6) | (src[1] & 0x3F);
const char* prev1 = src - 2;
const char* prev2 = src - 4;
if (id < 0x21 || id > 0x4A)
return 0;
if(prev2 < start)
{
prev2 = NULL;
if(prev1 < start)
prev1 = NULL;
}
if (prev1 && (*prev1 & 0xFC) == 0xD8)
{
unsigned char prev1_id = 0;
if (prev1)
prev1_id = (prev1[0] << 6) | (prev1[1] & 0x3F);
if (prev1_id == 0x44)
{
unsigned char prev2_id = 0;
if (prev2)
prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F);
if (prev2_id > 0x20 || prev2_id < 0x50)
prev_connected = !!arabic_shape_map[prev2_id - 0x20][2];
switch (id)
{
case 0x22:
return 0xFEF5 + prev_connected;
case 0x23:
return 0xFEF7 + prev_connected;
case 0x25:
return 0xFEF9 + prev_connected;
case 0x27:
return 0xFEFB + prev_connected;
}
}
if (prev1_id > 0x20 || prev1_id < 0x50)
prev_connected = !!arabic_shape_map[prev1_id - 0x20][2];
}
if ((src[2] & 0xFC) == 0xD8)
{
unsigned char next_id = (src[2] << 6) | (src[3] & 0x3F);
if (next_id > 0x20 || next_id < 0x50)
next_connected = true;
}
result = arabic_shape_map[id - 0x20][prev_connected | (next_connected << 1)];
if (result)
return result;
return arabic_shape_map[id - 0x20][prev_connected];
}
return 0;
}
static char* font_driver_reshape_msg(const char* msg)
{
/* worst case transformations are 2 bytes to 4 bytes */
char* buffer = (char*)malloc((strlen(msg) * 2) + 1);
const char* src = msg;
char* dst = buffer;
bool reverse = false;
while (*src || reverse)
{
if (reverse)
{
src--;
while (IS_MBCONT(src))
src--;
if (IS_RTL(src) || IS_DIR_NEUTRAL(src))
{
unsigned replacement = font_get_replacement(src, msg);
if (replacement)
{
if (replacement < 0x80)
*dst++ = replacement;
else if (replacement < 0x8000)
{
*dst++ = 0xC0 | (replacement >> 6);
*dst++ = 0x80 | (replacement & 0x3F);
}
else if (replacement < 0x10000)
{
/* merged glyphs */
if ((replacement >= 0xFEF5) && (replacement <= 0xFEFC))
src -= 2;
*dst++ = 0xE0 | (replacement >> 12);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | (replacement & 0x3F);
}
else
{
*dst++ = 0xF0 | (replacement >> 18);
*dst++ = 0x80 | ((replacement >> 12) & 0x3F);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | (replacement & 0x3F);
}
continue;
}
*dst++ = *src++;
while (IS_MBCONT(src))
*dst++ = *src++;
src--;
while (IS_MBCONT(src))
src--;
}
else
{
reverse = false;
src++;
while (IS_MBCONT(src) || IS_RTL(src) || IS_DIR_NEUTRAL(src))
src++;
}
}
else
{
if (IS_RTL(src))
{
reverse = true;
while (IS_MBCONT(src) || IS_RTL(src) || IS_DIR_NEUTRAL(src))
src++;
}
else
*dst++ = *src++;
}
}
*dst = '\0';
return buffer;
}
#endif
void font_driver_render_msg(
video_frame_info_t *video_info,
void *font_data,
const char *msg, const void *params)
{
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
if (font && font->renderer && font->renderer->render_msg)
{
#ifdef HAVE_LANGEXTRA
char* new_msg = font_driver_reshape_msg(msg);
font->renderer->render_msg(video_info, font->renderer_data, new_msg, params);
free(new_msg);
#else
font->renderer->render_msg(video_info, font->renderer_data, msg, params);
#endif
}
}
void font_driver_bind_block(void *font_data, void *block)

View File

@ -995,6 +995,7 @@ RETROARCH
#include "../intl/msg_hash_vn.c"
#include "../intl/msg_hash_chs.c"
#include "../intl/msg_hash_cht.c"
#include "../intl/msg_hash_ar.c"
#endif
#include "../intl/msg_hash_us.c"

2089
intl/msg_hash_ar.c Normal file

File diff suppressed because it is too large Load Diff

3417
intl/msg_hash_ar.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -922,6 +922,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"西班牙语")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"越南语")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"左侧摇杆")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -922,6 +922,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"西班牙語")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"越南語")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"左側搖桿")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -931,6 +931,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Spanisch")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamesisch")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabisch")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Linker Analogstick")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -836,6 +836,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Spanish")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamese")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Left Analog")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -1390,6 +1390,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamita"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Analogico izquierdo"
@ -5701,4 +5705,4 @@ MSG_HASH(
MSG_HASH(
MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY,
"Valores mas bajos favorecen el rendimiento y bajan la latencia a costa de la calidad, incrementar el valor aumentará la calidad a costa del rendimiento y latencia"
)
)

View File

@ -921,6 +921,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Espagnol")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamien")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabe")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Analogique gauche")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -931,6 +931,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Spagnolo")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamese")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Analogico sinistro")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -961,6 +961,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"スペイン語")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"ベトナム語")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"アラビア語")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"左のアナログ")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -907,6 +907,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"스페인어")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"베트남어")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"좌 아날로그")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -836,6 +836,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Spaans")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamees")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Linkse Analoog Stick")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -943,6 +943,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Spanish")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"wietnamski")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Lewy analogowy")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -1013,6 +1013,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamita"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic"
)
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Analógico Esquerdo"
)

View File

@ -907,6 +907,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Espanhol")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Vietnamita")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Analógico Esquerdo")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -930,6 +930,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Испанский")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Вьетнамский")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Левый аналоговый стик")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -919,6 +919,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH,
"Tiếng Tây Ban Nha")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
"Tiếng Việt")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
"Arabic")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG,
"Left Analog")
MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH,

View File

@ -270,6 +270,7 @@ enum retro_language
RETRO_LANGUAGE_ESPERANTO = 13,
RETRO_LANGUAGE_POLISH = 14,
RETRO_LANGUAGE_VIETNAMESE = 15,
RETRO_LANGUAGE_ARABIC = 16,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */

View File

@ -2936,7 +2936,19 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
strlcpy(title_truncated, xmb->title_name, sizeof(title_truncated));
if (selection > 1)
title_truncated[25] = '\0';
{
/* skip 25 utf8 multi-byte chars */
char* end = title_truncated;
for(i = 0; i < 25 && *end; i++)
{
end++;
while((*end & 0xC0) == 0x80)
end++;
}
*end = '\0';
}
/* Title text */
xmb_draw_text(menu_disp_info, xmb,

View File

@ -605,6 +605,7 @@ static void setting_get_string_representation_uint_user_language(void *data,
modes[RETRO_LANGUAGE_ESPERANTO] = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO);
modes[RETRO_LANGUAGE_POLISH] = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LANG_POLISH);
modes[RETRO_LANGUAGE_VIETNAMESE] = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE);
modes[RETRO_LANGUAGE_ARABIC] = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LANG_ARABIC);
strlcpy(s, modes[*msg_hash_get_uint(MSG_HASH_USER_LANGUAGE)], len);
}

View File

@ -78,6 +78,9 @@ int menu_hash_get_help_enum(enum msg_hash_enums msg, char *s, size_t len)
case RETRO_LANGUAGE_CHINESE_TRADITIONAL:
ret = menu_hash_get_help_cht_enum(msg, s, len);
break;
case RETRO_LANGUAGE_ARABIC:
ret = menu_hash_get_help_ar_enum(msg, s, len);
break;
default:
break;
}
@ -141,6 +144,9 @@ const char *msg_hash_to_str(enum msg_hash_enums msg)
case RETRO_LANGUAGE_CHINESE_TRADITIONAL:
ret = msg_hash_to_str_cht(msg);
break;
case RETRO_LANGUAGE_ARABIC:
ret = msg_hash_to_str_ar(msg);
break;
default:
break;
}

View File

@ -1658,6 +1658,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO,
MENU_ENUM_LABEL_VALUE_LANG_POLISH,
MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE,
MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
MENU_ENUM_LABEL_VALUE_NONE,
MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE,
@ -2014,6 +2015,9 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len);
const char *msg_hash_to_str_us(enum msg_hash_enums msg);
int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len);
const char *msg_hash_to_str_ar(enum msg_hash_enums msg);
int menu_hash_get_help_ar_enum(enum msg_hash_enums msg, char *s, size_t len);
int menu_hash_get_help_enum(enum msg_hash_enums msg, char *s, size_t len);
enum msg_file_type msg_hash_to_file_type(uint32_t hash);