mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r14618) -Feature: when the chosen language isn't supported by the current font, try to find a font that does and use that instead. Thanks to glx/michi_cc for the Windows implementation.
This commit is contained in:
parent
6878b181c7
commit
fea78fbfbb
|
@ -154,8 +154,68 @@ registry_no_font_found:
|
|||
RegCloseKey(hKey);
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
# ifdef WITH_FONTCONFIG
|
||||
|
||||
|
||||
struct EFCParam {
|
||||
FreeTypeSettings *settings;
|
||||
LOCALESIGNATURE locale;
|
||||
};
|
||||
|
||||
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
|
||||
{
|
||||
EFCParam *info = (EFCParam *)lParam;
|
||||
|
||||
/* Only use TrueType fonts */
|
||||
if (!(type & TRUETYPE_FONTTYPE)) return 1;
|
||||
/* Don't use SYMBOL fonts */
|
||||
if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
|
||||
|
||||
/* The font has to have at least one of the supported locales to be usable. */
|
||||
if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
|
||||
/* On win9x metric->ntmFontSig seems to contain garbage. */
|
||||
FONTSIGNATURE fs;
|
||||
memset(&fs, 0, sizeof(fs));
|
||||
HFONT font = CreateFontIndirect(&logfont->elfLogFont);
|
||||
if (font != NULL) {
|
||||
HDC dc = GetDC(NULL);
|
||||
HGDIOBJ oldfont = SelectObject(dc, font);
|
||||
GetTextCharsetInfo(dc, &fs, 0);
|
||||
SelectObject(dc, oldfont);
|
||||
ReleaseDC(NULL, dc);
|
||||
DeleteObject(font);
|
||||
}
|
||||
if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
|
||||
}
|
||||
|
||||
strecpy(info->settings->small_font, font_name, lastof(info->settings->small_font));
|
||||
strecpy(info->settings->medium_font, font_name, lastof(info->settings->medium_font));
|
||||
strecpy(info->settings->large_font, font_name, lastof(info->settings->large_font));
|
||||
return 0; // stop enumerating
|
||||
}
|
||||
|
||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
|
||||
{
|
||||
EFCParam langInfo;
|
||||
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPWSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
|
||||
/* Invalid langid or some other mysterious error, can't determine fallback font. */
|
||||
DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
|
||||
return false;
|
||||
}
|
||||
langInfo.settings = settings;
|
||||
|
||||
LOGFONT font;
|
||||
/* Enumerate all fonts. */
|
||||
font.lfCharSet = DEFAULT_CHARSET;
|
||||
font.lfFaceName[0] = '\0';
|
||||
font.lfPitchAndFamily = 0;
|
||||
|
||||
HDC dc = GetDC(NULL);
|
||||
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
||||
ReleaseDC(NULL, dc);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
#elif defined(WITH_FONTCONFIG)
|
||||
static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
||||
{
|
||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
||||
|
@ -221,11 +281,75 @@ static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
|||
|
||||
return err;
|
||||
}
|
||||
# else
|
||||
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
|
||||
# endif /* WITH_FONTCONFIG */
|
||||
|
||||
#endif
|
||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
|
||||
{
|
||||
if (!FcInit()) return false;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
/* Fontconfig doesn't handle full language isocodes, only the part
|
||||
* before the _ of e.g. en_GB is used, so "remove" everything after
|
||||
* the _. */
|
||||
char lang[16];
|
||||
strecpy(lang, language_isocode, lastof(lang));
|
||||
char *split = strchr(lang, '_');
|
||||
if (split != NULL) *split = '\0';
|
||||
|
||||
FcPattern *pat;
|
||||
FcPattern *match;
|
||||
FcResult result;
|
||||
FcChar8 *file;
|
||||
FcFontSet *fs;
|
||||
FcValue val;
|
||||
val.type = FcTypeString;
|
||||
val.u.s = (FcChar8*)lang;
|
||||
|
||||
/* First create a pattern to match the wanted language */
|
||||
pat = FcPatternCreate();
|
||||
/* And fill it with the language and other defaults */
|
||||
if (pat == NULL ||
|
||||
!FcPatternAdd(pat, "lang", val, false) ||
|
||||
!FcConfigSubstitute(0, pat, FcMatchPattern)) {
|
||||
goto error_pattern;
|
||||
}
|
||||
|
||||
FcDefaultSubstitute(pat);
|
||||
|
||||
/* The create a font set and match that */
|
||||
match = FcFontMatch(0, pat, &result);
|
||||
|
||||
if (match == NULL) {
|
||||
goto error_pattern;
|
||||
}
|
||||
|
||||
/* Find all fonts that do match */
|
||||
fs = FcFontSetCreate();
|
||||
FcFontSetAdd(fs, match);
|
||||
|
||||
/* And take the first, if it exists */
|
||||
if (fs->nfont <= 0 || FcPatternGetString(fs->fonts[0], FC_FILE, 0, &file)) {
|
||||
goto error_fontset;
|
||||
}
|
||||
|
||||
strecpy(settings->small_font, (const char*)file, lastof(settings->small_font));
|
||||
strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font));
|
||||
strecpy(settings->large_font, (const char*)file, lastof(settings->large_font));
|
||||
|
||||
ret = true;
|
||||
|
||||
error_fontset:
|
||||
FcFontSetDestroy(fs);
|
||||
error_pattern:
|
||||
if (pat != NULL) FcPatternDestroy(pat);
|
||||
FcFini();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* without WITH_FONTCONFIG */
|
||||
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
|
||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode) { return false; }
|
||||
#endif /* WITH_FONTCONFIG */
|
||||
|
||||
/**
|
||||
* Loads the freetype font.
|
||||
|
@ -303,6 +427,35 @@ void InitFreeType()
|
|||
if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
|
||||
}
|
||||
|
||||
static void ResetGlyphCache();
|
||||
|
||||
/**
|
||||
* Unload a face and set it to NULL.
|
||||
* @param face the face to unload
|
||||
*/
|
||||
static void UnloadFace(FT_Face *face)
|
||||
{
|
||||
if (*face == NULL) return;
|
||||
|
||||
FT_Done_Face(*face);
|
||||
*face = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free everything allocated w.r.t. fonts.
|
||||
*/
|
||||
void UninitFreeType()
|
||||
{
|
||||
ResetGlyphCache();
|
||||
|
||||
UnloadFace(&_face_small);
|
||||
UnloadFace(&_face_medium);
|
||||
UnloadFace(&_face_large);
|
||||
|
||||
FT_Done_FreeType(_library);
|
||||
_library = NULL;
|
||||
}
|
||||
|
||||
|
||||
static FT_Face GetFontFace(FontSize size)
|
||||
{
|
||||
|
@ -335,6 +488,27 @@ struct GlyphEntry {
|
|||
*/
|
||||
static GlyphEntry **_glyph_ptr[FS_END];
|
||||
|
||||
/** Clear the complete cache */
|
||||
static void ResetGlyphCache()
|
||||
{
|
||||
for (int i = 0; i < FS_END; i++) {
|
||||
if (_glyph_ptr[i] == NULL) continue;
|
||||
|
||||
for (int j = 0; j < 256; j++) {
|
||||
if (_glyph_ptr[i][j] == NULL) continue;
|
||||
|
||||
for (int k = 0; k < 256; k++) {
|
||||
if (_glyph_ptr[i][j][k].sprite == NULL) continue;
|
||||
free(_glyph_ptr[i][j][k].sprite);
|
||||
}
|
||||
|
||||
free(_glyph_ptr[i][j]);
|
||||
}
|
||||
|
||||
free(_glyph_ptr[i]);
|
||||
_glyph_ptr[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
|
||||
{
|
||||
|
|
|
@ -19,9 +19,9 @@ void InitializeUnicodeGlyphMap();
|
|||
#ifdef WITH_FREETYPE
|
||||
|
||||
struct FreeTypeSettings {
|
||||
char small_font[260];
|
||||
char medium_font[260];
|
||||
char large_font[260];
|
||||
char small_font[MAX_PATH];
|
||||
char medium_font[MAX_PATH];
|
||||
char large_font[MAX_PATH];
|
||||
uint small_size;
|
||||
uint medium_size;
|
||||
uint large_size;
|
||||
|
@ -33,13 +33,26 @@ struct FreeTypeSettings {
|
|||
extern FreeTypeSettings _freetype;
|
||||
|
||||
void InitFreeType();
|
||||
void UninitFreeType();
|
||||
const struct Sprite *GetGlyph(FontSize size, uint32 key);
|
||||
uint GetGlyphWidth(FontSize size, uint32 key);
|
||||
|
||||
/**
|
||||
* We would like to have a fallback font as the current one
|
||||
* doesn't contain all characters we need.
|
||||
* This function must set all fonts of settings.
|
||||
* @param settings the settings to overwrite the fontname of.
|
||||
* @param language_isocode the language, e.g. en_GB.
|
||||
* @param winlangid the language ID windows style.
|
||||
* @return true if a font has been set, false otherwise.
|
||||
*/
|
||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid);
|
||||
|
||||
#else
|
||||
|
||||
/* Stub for initializiation */
|
||||
static inline void InitFreeType() {}
|
||||
static inline void UninitFreeType() {}
|
||||
|
||||
/** Get the Sprite for a glyph */
|
||||
static inline const Sprite *GetGlyph(FontSize size, uint32 key)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Afrikaans
|
||||
##ownname Jaybee
|
||||
##isocode af_ZA
|
||||
##winlangid 0x0436
|
||||
##plural 0
|
||||
##gender male
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Brazilian_Portuguese
|
||||
##ownname Português (BR)
|
||||
##isocode pt_BR
|
||||
##winlangid 0x0416
|
||||
##plural 2
|
||||
##gender m f
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Bulgarian
|
||||
##ownname Български
|
||||
##isocode bg_BG
|
||||
##winlangid 0x0402
|
||||
##plural 0
|
||||
##case m f n p
|
||||
##gender m f n p
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Catalan
|
||||
##ownname Català
|
||||
##isocode ca_ES
|
||||
##winlangid 0x0403
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Croatian
|
||||
##ownname Hrvatski
|
||||
##isocode hr_HR
|
||||
##winlangid 0x041a
|
||||
##plural 6
|
||||
##case nom gen dat aku vok lok ins
|
||||
##gender male female middle
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Czech
|
||||
##ownname Čeština
|
||||
##isocode cs_CZ
|
||||
##winlangid 0x0405
|
||||
##plural 6
|
||||
##case nom gen dat acc voc loc ins big small
|
||||
##gender m f n
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Danish
|
||||
##ownname Dansk
|
||||
##isocode da_DA
|
||||
##winlangid 0x0406
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Dutch
|
||||
##ownname Nederlands
|
||||
##isocode nl_NL
|
||||
##winlangid 0x0413
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name English (UK)
|
||||
##ownname English (UK)
|
||||
##isocode en_GB
|
||||
##winlangid 0x0809
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name English (US)
|
||||
##ownname English (US)
|
||||
##isocode en_US
|
||||
##winlangid 0x0409
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Esperanto
|
||||
##ownname Esperanto
|
||||
##isocode eo_EO
|
||||
##winlangid 0x0000
|
||||
##plural 0
|
||||
##case n
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Estonian
|
||||
##ownname Eesti keel
|
||||
##isocode et_ET
|
||||
##winlangid 0x0425
|
||||
##plural 0
|
||||
##case g in
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Finnish
|
||||
##ownname Suomi
|
||||
##isocode fi_FI
|
||||
##winlangid 0x040b
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name French
|
||||
##ownname Français
|
||||
##isocode fr_FR
|
||||
##winlangid 0x040c
|
||||
##plural 2
|
||||
##gender m m2 f
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Galician
|
||||
##ownname Galego
|
||||
##isocode gl_ES
|
||||
##winlangid 0x0456
|
||||
##plural 0
|
||||
##gender m f n
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name German
|
||||
##ownname Deutsch
|
||||
##isocode de_DE
|
||||
##winlangid 0x0407
|
||||
##plural 0
|
||||
##gender m w n p
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Hungarian
|
||||
##ownname Magyar
|
||||
##isocode hu_HU
|
||||
##winlangid 0x040e
|
||||
##plural 1
|
||||
##case t ba
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Icelandic
|
||||
##ownname Íslenska
|
||||
##isocode is_IS
|
||||
##winlangid 0x040f
|
||||
##plural 0
|
||||
##gender karlkyn kvenkyn hvorugkyn
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Italian
|
||||
##ownname Italiano
|
||||
##isocode it_IT
|
||||
##winlangid 0x0410
|
||||
##plural 0
|
||||
##case ms mp fs fp
|
||||
##gender m f
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Japanese
|
||||
##ownname 日本語
|
||||
##isocode ja_JP
|
||||
##winlangid 0x0411
|
||||
##plural 1
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Korean
|
||||
##ownname 한국어
|
||||
##isocode ko_KR
|
||||
##winlangid 0x0412
|
||||
##plural 1
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Lithuanian
|
||||
##ownname Lietuvių
|
||||
##isocode lt_LT
|
||||
##winlangid 0x0427
|
||||
##plural 5
|
||||
##case kas ko kam ka kuo kur kreip
|
||||
##gender vyr mot
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Norwegian
|
||||
##ownname Norsk (bokmål)
|
||||
##isocode nb_NO
|
||||
##winlangid 0x0414
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Norwegian new
|
||||
##ownname Norsk, Nynorsk
|
||||
##isocode nn_NO
|
||||
##winlangid 0x0814
|
||||
##plural 0
|
||||
##gender masculine feminine neuter
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Original vehicle names (ENG)
|
||||
##ownname Original vehicle names (ENG)
|
||||
##isocode xx
|
||||
##isocode xx_OV
|
||||
##winlangid 0x0000
|
||||
|
||||
##id 0x8000
|
||||
STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Pig latin
|
||||
##ownname Igpay atinlay
|
||||
##isocode xx_PL
|
||||
##winlangid 0x0000
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Polish
|
||||
##ownname Polski
|
||||
##isocode pl_PL
|
||||
##winlangid 0x0415
|
||||
##plural 7
|
||||
##case d c b n m w
|
||||
##gender m f n
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Portuguese
|
||||
##ownname Português
|
||||
##isocode pt_PT
|
||||
##winlangid 0x0816
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Romanian
|
||||
##ownname Românã
|
||||
##isocode ro_RO
|
||||
##winlangid 0x0418
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Russian
|
||||
##ownname Русский
|
||||
##isocode ru_RU
|
||||
##winlangid 0x0419
|
||||
##plural 6
|
||||
##case m f n p
|
||||
##gender m f n p
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Chinese (Simplified)
|
||||
##ownname 简体中文
|
||||
##isocode zh_CN
|
||||
##winlangid 0x0804
|
||||
##plural 1
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Slovak
|
||||
##ownname Slovensky
|
||||
##isocode sk_SK
|
||||
##winlangid 0x041b
|
||||
##plural 6
|
||||
##case g
|
||||
##gender m z s
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Slovenian
|
||||
##ownname Slovenščina
|
||||
##isocode sl_SL
|
||||
##winlangid 0x0424
|
||||
##plural 8
|
||||
##case r d t
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Spanish
|
||||
##ownname Español (ES)
|
||||
##isocode es_ES
|
||||
##winlangid 0x0c0a
|
||||
##plural 0
|
||||
##gender masculino femenino
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Swedish
|
||||
##ownname Svenska
|
||||
##isocode sv_SE
|
||||
##winlangid 0x081d
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Chinese (Traditional)
|
||||
##ownname 中文
|
||||
##isocode zh_TW
|
||||
##winlangid 0x0404
|
||||
##plural 1
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Turkish
|
||||
##ownname Türkçe
|
||||
##isocode tr_TR
|
||||
##winlangid 0x041f
|
||||
##plural 1
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Ukrainian
|
||||
##ownname Українська
|
||||
##isocode uk_UA
|
||||
##winlangid 0x0422
|
||||
##plural 6
|
||||
##gender m f s mn
|
||||
##case r d z
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Frisian
|
||||
##ownname Frysk
|
||||
##isocode fy_NL
|
||||
##winlangid 0x0462
|
||||
|
||||
##id 0x0000
|
||||
STR_NULL :
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Greek
|
||||
##ownname Ελληνικά
|
||||
##isocode el_GR
|
||||
##winlangid 0x0408
|
||||
##plural 0
|
||||
##gender m f n
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Ido
|
||||
##ownname Ido
|
||||
##isocode io_XX
|
||||
##winlangid 0x0000
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Indonesian
|
||||
##ownname Indonesian
|
||||
##isocode id_ID
|
||||
##winlangid 0x0421
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Latvian
|
||||
##ownname Latviešu
|
||||
##isocode lv_LV
|
||||
##winlangid 0x0426
|
||||
##plural 3
|
||||
##case kas
|
||||
##gender m f
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Macedonian
|
||||
##ownname Македонски
|
||||
##isocode mk_MK
|
||||
##winlangid 0x042f
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Persian
|
||||
##ownname Farsi
|
||||
##isocode fa_IR
|
||||
##winlangid 0x0429
|
||||
##plural 0
|
||||
##textdir rtl
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Serbian
|
||||
##ownname Srpski
|
||||
##isocode sr_YU
|
||||
##winlangid 0x7c1a
|
||||
##plural 0
|
||||
##case ih a ova ca ci ka ća va ao u om im e ke on ona to
|
||||
##gender muški ženski srednji
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
##name Welsh
|
||||
##ownname Cymraeg
|
||||
##isocode cy_GB
|
||||
##winlangid 0x0452
|
||||
##plural 0
|
||||
|
||||
#
|
||||
|
|
|
@ -87,6 +87,7 @@ static uint32 _hash;
|
|||
static char _lang_name[32], _lang_ownname[32], _lang_isocode[16];
|
||||
static byte _lang_pluralform;
|
||||
static byte _lang_textdir;
|
||||
static uint16 _lang_winlangid;
|
||||
#define MAX_NUM_GENDER 8
|
||||
static char _genders[MAX_NUM_GENDER][16];
|
||||
static int _numgenders;
|
||||
|
@ -649,6 +650,13 @@ static void HandlePragma(char *str)
|
|||
} else {
|
||||
error("Invalid textdir %s", str + 8);
|
||||
}
|
||||
} else if (!memcmp(str, "winlangid ", 10)) {
|
||||
char *buf = str + 10;
|
||||
long langid = strtol(buf, NULL, 16);
|
||||
if (langid > UINT16_MAX || langid < 0) {
|
||||
error("Invalid winlangid %s", buf);
|
||||
}
|
||||
_lang_winlangid = (uint16)langid;
|
||||
} else if (!memcmp(str, "gender ", 7)) {
|
||||
char* buf = str + 7;
|
||||
|
||||
|
@ -912,6 +920,7 @@ static void ParseFile(const char *file, bool english)
|
|||
_numgenders = 0;
|
||||
_lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0';
|
||||
_lang_textdir = TD_LTR;
|
||||
_lang_winlangid = 0x0000; // neutral language code
|
||||
// TODO:!! We can't reset the cases. In case the translated strings
|
||||
// derive some strings from english....
|
||||
|
||||
|
@ -1161,6 +1170,7 @@ static void WriteLangfile(const char *filename)
|
|||
hdr.version = TO_LE32(_hash);
|
||||
hdr.plural_form = _lang_pluralform;
|
||||
hdr.text_dir = _lang_textdir;
|
||||
hdr.winlangid = TO_LE16(_lang_winlangid);
|
||||
strcpy(hdr.name, _lang_name);
|
||||
strcpy(hdr.own_name, _lang_ownname);
|
||||
strcpy(hdr.isocode, _lang_isocode);
|
||||
|
|
|
@ -14,7 +14,16 @@ struct LanguagePackHeader {
|
|||
uint16 offsets[32]; // the offsets
|
||||
byte plural_form; // plural form index
|
||||
byte text_dir; // default direction of the text
|
||||
byte pad[2]; // pad header to be a multiple of 4
|
||||
/**
|
||||
* Windows language ID:
|
||||
* Windows cannot and will not convert isocodes to something it can use to
|
||||
* determine whether a font can be used for the language or not. As a result
|
||||
* of that we need to pass the language id via strgen to OpenTTD to tell
|
||||
* what language it is in "Windows". The ID is the 'locale identifier' on:
|
||||
* http://msdn.microsoft.com/en-us/library/ms776294.aspx
|
||||
*/
|
||||
uint16 winlangid; // windows language id
|
||||
/* byte pad[0]; // pad header to be a multiple of 4 */
|
||||
};
|
||||
|
||||
assert_compile(sizeof(LanguagePackHeader) % 4 == 0);
|
||||
|
|
114
src/strings.cpp
114
src/strings.cpp
|
@ -1358,9 +1358,13 @@ static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
|
|||
size_t read = fread(hdr, sizeof(*hdr), 1, f);
|
||||
fclose(f);
|
||||
|
||||
return read == 1 &&
|
||||
bool ret = read == 1 &&
|
||||
hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
|
||||
hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
|
||||
|
||||
/* Convert endianness for the windows language ID */
|
||||
if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1478,45 +1482,83 @@ void InitializeLanguagePacks()
|
|||
*/
|
||||
void CheckForMissingGlyphsInLoadedLanguagePack()
|
||||
{
|
||||
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
|
||||
#ifdef WITH_FREETYPE
|
||||
/* Reset to the original state; switching languages might cause us to
|
||||
* automatically choose another font. This resets that choice. */
|
||||
UninitFreeType();
|
||||
InitFreeType();
|
||||
#endif
|
||||
|
||||
for (uint i = 0; i != 32; i++) {
|
||||
for (uint j = 0; j < _langtab_num[i]; j++) {
|
||||
const char *string = _langpack_offs[_langtab_start[i] + j];
|
||||
WChar c;
|
||||
while ((c = Utf8Consume(&string)) != '\0') {
|
||||
if (c == SCC_SETX) {
|
||||
/*
|
||||
* SetX is, together with SetXY as special character that
|
||||
* uses the next (two) characters as data points. We have
|
||||
* to skip those, otherwise the UTF8 reading will go
|
||||
* haywire.
|
||||
*/
|
||||
string++;
|
||||
} else if (c == SCC_SETXY) {
|
||||
string += 2;
|
||||
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
|
||||
/*
|
||||
* The character is printable, but not in the normal font.
|
||||
* This is the case we were testing for. In this case we
|
||||
* have to show the error. As we do not want the string to
|
||||
* be translated by the translators, we 'force' it into the
|
||||
* binary and 'load' it via a BindCString. To do this
|
||||
* properly we have to set the color of the string,
|
||||
* otherwise we end up with a lot of artefacts. The color
|
||||
* 'character' might change in the future, so for safety
|
||||
* we just Utf8 Encode it into the string, which takes
|
||||
* exactly three characters, so it replaces the "XXX" with
|
||||
* the color marker.
|
||||
*/
|
||||
static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
|
||||
Utf8Encode(err_str, SCC_YELLOW);
|
||||
SetDParamStr(0, err_str);
|
||||
ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
|
||||
return;
|
||||
bool retry = false;
|
||||
for (;;) {
|
||||
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
|
||||
|
||||
for (uint i = 0; i != 32; i++) {
|
||||
for (uint j = 0; j < _langtab_num[i]; j++) {
|
||||
const char *string = _langpack_offs[_langtab_start[i] + j];
|
||||
WChar c;
|
||||
while ((c = Utf8Consume(&string)) != '\0') {
|
||||
if (c == SCC_SETX) {
|
||||
/*
|
||||
* SetX is, together with SetXY as special character that
|
||||
* uses the next (two) characters as data points. We have
|
||||
* to skip those, otherwise the UTF8 reading will go
|
||||
* haywire.
|
||||
*/
|
||||
string++;
|
||||
} else if (c == SCC_SETXY) {
|
||||
string += 2;
|
||||
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
|
||||
#ifdef WITH_FREETYPE
|
||||
if (!retry) {
|
||||
/* We found an unprintable character... lets try whether we can
|
||||
* find a fallback font that can print the characters in the
|
||||
* current language. */
|
||||
retry = true;
|
||||
|
||||
FreeTypeSettings backup;
|
||||
memcpy(&backup, &_freetype, sizeof(backup));
|
||||
|
||||
bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid);
|
||||
if (success) {
|
||||
UninitFreeType();
|
||||
InitFreeType();
|
||||
}
|
||||
|
||||
memcpy(&_freetype, &backup, sizeof(backup));
|
||||
|
||||
if (success) continue;
|
||||
} else {
|
||||
/* Our fallback font does miss characters too, so keep the
|
||||
* user chosen font as that is more likely to be any good than
|
||||
* the wild guess we made */
|
||||
UninitFreeType();
|
||||
InitFreeType();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* The character is printable, but not in the normal font.
|
||||
* This is the case we were testing for. In this case we
|
||||
* have to show the error. As we do not want the string to
|
||||
* be translated by the translators, we 'force' it into the
|
||||
* binary and 'load' it via a BindCString. To do this
|
||||
* properly we have to set the color of the string,
|
||||
* otherwise we end up with a lot of artefacts. The color
|
||||
* 'character' might change in the future, so for safety
|
||||
* we just Utf8 Encode it into the string, which takes
|
||||
* exactly three characters, so it replaces the "XXX" with
|
||||
* the color marker.
|
||||
*/
|
||||
static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
|
||||
Utf8Encode(err_str, SCC_YELLOW);
|
||||
SetDParamStr(0, err_str);
|
||||
ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if !defined(WITH_ICU)
|
||||
|
|
Loading…
Reference in New Issue