mirror of https://github.com/OpenTTD/OpenTTD
(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.
parent
6878b181c7
commit
fea78fbfbb
|
@ -154,8 +154,68 @@ registry_no_font_found:
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
return err;
|
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)
|
static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
||||||
{
|
{
|
||||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
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;
|
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.
|
* Loads the freetype font.
|
||||||
|
@ -303,6 +427,35 @@ void InitFreeType()
|
||||||
if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
|
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)
|
static FT_Face GetFontFace(FontSize size)
|
||||||
{
|
{
|
||||||
|
@ -335,6 +488,27 @@ struct GlyphEntry {
|
||||||
*/
|
*/
|
||||||
static GlyphEntry **_glyph_ptr[FS_END];
|
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)
|
static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,9 +19,9 @@ void InitializeUnicodeGlyphMap();
|
||||||
#ifdef WITH_FREETYPE
|
#ifdef WITH_FREETYPE
|
||||||
|
|
||||||
struct FreeTypeSettings {
|
struct FreeTypeSettings {
|
||||||
char small_font[260];
|
char small_font[MAX_PATH];
|
||||||
char medium_font[260];
|
char medium_font[MAX_PATH];
|
||||||
char large_font[260];
|
char large_font[MAX_PATH];
|
||||||
uint small_size;
|
uint small_size;
|
||||||
uint medium_size;
|
uint medium_size;
|
||||||
uint large_size;
|
uint large_size;
|
||||||
|
@ -33,13 +33,26 @@ struct FreeTypeSettings {
|
||||||
extern FreeTypeSettings _freetype;
|
extern FreeTypeSettings _freetype;
|
||||||
|
|
||||||
void InitFreeType();
|
void InitFreeType();
|
||||||
|
void UninitFreeType();
|
||||||
const struct Sprite *GetGlyph(FontSize size, uint32 key);
|
const struct Sprite *GetGlyph(FontSize size, uint32 key);
|
||||||
uint GetGlyphWidth(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
|
#else
|
||||||
|
|
||||||
/* Stub for initializiation */
|
/* Stub for initializiation */
|
||||||
static inline void InitFreeType() {}
|
static inline void InitFreeType() {}
|
||||||
|
static inline void UninitFreeType() {}
|
||||||
|
|
||||||
/** Get the Sprite for a glyph */
|
/** Get the Sprite for a glyph */
|
||||||
static inline const Sprite *GetGlyph(FontSize size, uint32 key)
|
static inline const Sprite *GetGlyph(FontSize size, uint32 key)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Afrikaans
|
##name Afrikaans
|
||||||
##ownname Jaybee
|
##ownname Jaybee
|
||||||
##isocode af_ZA
|
##isocode af_ZA
|
||||||
|
##winlangid 0x0436
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender male
|
##gender male
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Brazilian_Portuguese
|
##name Brazilian_Portuguese
|
||||||
##ownname Português (BR)
|
##ownname Português (BR)
|
||||||
##isocode pt_BR
|
##isocode pt_BR
|
||||||
|
##winlangid 0x0416
|
||||||
##plural 2
|
##plural 2
|
||||||
##gender m f
|
##gender m f
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Bulgarian
|
##name Bulgarian
|
||||||
##ownname Български
|
##ownname Български
|
||||||
##isocode bg_BG
|
##isocode bg_BG
|
||||||
|
##winlangid 0x0402
|
||||||
##plural 0
|
##plural 0
|
||||||
##case m f n p
|
##case m f n p
|
||||||
##gender m f n p
|
##gender m f n p
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Catalan
|
##name Catalan
|
||||||
##ownname Català
|
##ownname Català
|
||||||
##isocode ca_ES
|
##isocode ca_ES
|
||||||
|
##winlangid 0x0403
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Croatian
|
##name Croatian
|
||||||
##ownname Hrvatski
|
##ownname Hrvatski
|
||||||
##isocode hr_HR
|
##isocode hr_HR
|
||||||
|
##winlangid 0x041a
|
||||||
##plural 6
|
##plural 6
|
||||||
##case nom gen dat aku vok lok ins
|
##case nom gen dat aku vok lok ins
|
||||||
##gender male female middle
|
##gender male female middle
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Czech
|
##name Czech
|
||||||
##ownname Čeština
|
##ownname Čeština
|
||||||
##isocode cs_CZ
|
##isocode cs_CZ
|
||||||
|
##winlangid 0x0405
|
||||||
##plural 6
|
##plural 6
|
||||||
##case nom gen dat acc voc loc ins big small
|
##case nom gen dat acc voc loc ins big small
|
||||||
##gender m f n
|
##gender m f n
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Danish
|
##name Danish
|
||||||
##ownname Dansk
|
##ownname Dansk
|
||||||
##isocode da_DA
|
##isocode da_DA
|
||||||
|
##winlangid 0x0406
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Dutch
|
##name Dutch
|
||||||
##ownname Nederlands
|
##ownname Nederlands
|
||||||
##isocode nl_NL
|
##isocode nl_NL
|
||||||
|
##winlangid 0x0413
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name English (UK)
|
##name English (UK)
|
||||||
##ownname English (UK)
|
##ownname English (UK)
|
||||||
##isocode en_GB
|
##isocode en_GB
|
||||||
|
##winlangid 0x0809
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name English (US)
|
##name English (US)
|
||||||
##ownname English (US)
|
##ownname English (US)
|
||||||
##isocode en_US
|
##isocode en_US
|
||||||
|
##winlangid 0x0409
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Esperanto
|
##name Esperanto
|
||||||
##ownname Esperanto
|
##ownname Esperanto
|
||||||
##isocode eo_EO
|
##isocode eo_EO
|
||||||
|
##winlangid 0x0000
|
||||||
##plural 0
|
##plural 0
|
||||||
##case n
|
##case n
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Estonian
|
##name Estonian
|
||||||
##ownname Eesti keel
|
##ownname Eesti keel
|
||||||
##isocode et_ET
|
##isocode et_ET
|
||||||
|
##winlangid 0x0425
|
||||||
##plural 0
|
##plural 0
|
||||||
##case g in
|
##case g in
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Finnish
|
##name Finnish
|
||||||
##ownname Suomi
|
##ownname Suomi
|
||||||
##isocode fi_FI
|
##isocode fi_FI
|
||||||
|
##winlangid 0x040b
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name French
|
##name French
|
||||||
##ownname Français
|
##ownname Français
|
||||||
##isocode fr_FR
|
##isocode fr_FR
|
||||||
|
##winlangid 0x040c
|
||||||
##plural 2
|
##plural 2
|
||||||
##gender m m2 f
|
##gender m m2 f
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Galician
|
##name Galician
|
||||||
##ownname Galego
|
##ownname Galego
|
||||||
##isocode gl_ES
|
##isocode gl_ES
|
||||||
|
##winlangid 0x0456
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender m f n
|
##gender m f n
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name German
|
##name German
|
||||||
##ownname Deutsch
|
##ownname Deutsch
|
||||||
##isocode de_DE
|
##isocode de_DE
|
||||||
|
##winlangid 0x0407
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender m w n p
|
##gender m w n p
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Hungarian
|
##name Hungarian
|
||||||
##ownname Magyar
|
##ownname Magyar
|
||||||
##isocode hu_HU
|
##isocode hu_HU
|
||||||
|
##winlangid 0x040e
|
||||||
##plural 1
|
##plural 1
|
||||||
##case t ba
|
##case t ba
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Icelandic
|
##name Icelandic
|
||||||
##ownname Íslenska
|
##ownname Íslenska
|
||||||
##isocode is_IS
|
##isocode is_IS
|
||||||
|
##winlangid 0x040f
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender karlkyn kvenkyn hvorugkyn
|
##gender karlkyn kvenkyn hvorugkyn
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Italian
|
##name Italian
|
||||||
##ownname Italiano
|
##ownname Italiano
|
||||||
##isocode it_IT
|
##isocode it_IT
|
||||||
|
##winlangid 0x0410
|
||||||
##plural 0
|
##plural 0
|
||||||
##case ms mp fs fp
|
##case ms mp fs fp
|
||||||
##gender m f
|
##gender m f
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Japanese
|
##name Japanese
|
||||||
##ownname 日本語
|
##ownname 日本語
|
||||||
##isocode ja_JP
|
##isocode ja_JP
|
||||||
|
##winlangid 0x0411
|
||||||
##plural 1
|
##plural 1
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Korean
|
##name Korean
|
||||||
##ownname 한국어
|
##ownname 한국어
|
||||||
##isocode ko_KR
|
##isocode ko_KR
|
||||||
|
##winlangid 0x0412
|
||||||
##plural 1
|
##plural 1
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Lithuanian
|
##name Lithuanian
|
||||||
##ownname Lietuvių
|
##ownname Lietuvių
|
||||||
##isocode lt_LT
|
##isocode lt_LT
|
||||||
|
##winlangid 0x0427
|
||||||
##plural 5
|
##plural 5
|
||||||
##case kas ko kam ka kuo kur kreip
|
##case kas ko kam ka kuo kur kreip
|
||||||
##gender vyr mot
|
##gender vyr mot
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Norwegian
|
##name Norwegian
|
||||||
##ownname Norsk (bokmål)
|
##ownname Norsk (bokmål)
|
||||||
##isocode nb_NO
|
##isocode nb_NO
|
||||||
|
##winlangid 0x0414
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Norwegian new
|
##name Norwegian new
|
||||||
##ownname Norsk, Nynorsk
|
##ownname Norsk, Nynorsk
|
||||||
##isocode nn_NO
|
##isocode nn_NO
|
||||||
|
##winlangid 0x0814
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender masculine feminine neuter
|
##gender masculine feminine neuter
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Original vehicle names (ENG)
|
##name Original vehicle names (ENG)
|
||||||
##ownname Original vehicle names (ENG)
|
##ownname Original vehicle names (ENG)
|
||||||
##isocode xx
|
##isocode xx_OV
|
||||||
|
##winlangid 0x0000
|
||||||
|
|
||||||
##id 0x8000
|
##id 0x8000
|
||||||
STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam)
|
STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Pig latin
|
##name Pig latin
|
||||||
##ownname Igpay atinlay
|
##ownname Igpay atinlay
|
||||||
##isocode xx_PL
|
##isocode xx_PL
|
||||||
|
##winlangid 0x0000
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Polish
|
##name Polish
|
||||||
##ownname Polski
|
##ownname Polski
|
||||||
##isocode pl_PL
|
##isocode pl_PL
|
||||||
|
##winlangid 0x0415
|
||||||
##plural 7
|
##plural 7
|
||||||
##case d c b n m w
|
##case d c b n m w
|
||||||
##gender m f n
|
##gender m f n
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Portuguese
|
##name Portuguese
|
||||||
##ownname Português
|
##ownname Português
|
||||||
##isocode pt_PT
|
##isocode pt_PT
|
||||||
|
##winlangid 0x0816
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Romanian
|
##name Romanian
|
||||||
##ownname Românã
|
##ownname Românã
|
||||||
##isocode ro_RO
|
##isocode ro_RO
|
||||||
|
##winlangid 0x0418
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Russian
|
##name Russian
|
||||||
##ownname Русский
|
##ownname Русский
|
||||||
##isocode ru_RU
|
##isocode ru_RU
|
||||||
|
##winlangid 0x0419
|
||||||
##plural 6
|
##plural 6
|
||||||
##case m f n p
|
##case m f n p
|
||||||
##gender m f n p
|
##gender m f n p
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Chinese (Simplified)
|
##name Chinese (Simplified)
|
||||||
##ownname 简体中文
|
##ownname 简体中文
|
||||||
##isocode zh_CN
|
##isocode zh_CN
|
||||||
|
##winlangid 0x0804
|
||||||
##plural 1
|
##plural 1
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Slovak
|
##name Slovak
|
||||||
##ownname Slovensky
|
##ownname Slovensky
|
||||||
##isocode sk_SK
|
##isocode sk_SK
|
||||||
|
##winlangid 0x041b
|
||||||
##plural 6
|
##plural 6
|
||||||
##case g
|
##case g
|
||||||
##gender m z s
|
##gender m z s
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Slovenian
|
##name Slovenian
|
||||||
##ownname Slovenščina
|
##ownname Slovenščina
|
||||||
##isocode sl_SL
|
##isocode sl_SL
|
||||||
|
##winlangid 0x0424
|
||||||
##plural 8
|
##plural 8
|
||||||
##case r d t
|
##case r d t
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Spanish
|
##name Spanish
|
||||||
##ownname Español (ES)
|
##ownname Español (ES)
|
||||||
##isocode es_ES
|
##isocode es_ES
|
||||||
|
##winlangid 0x0c0a
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender masculino femenino
|
##gender masculino femenino
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Swedish
|
##name Swedish
|
||||||
##ownname Svenska
|
##ownname Svenska
|
||||||
##isocode sv_SE
|
##isocode sv_SE
|
||||||
|
##winlangid 0x081d
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Chinese (Traditional)
|
##name Chinese (Traditional)
|
||||||
##ownname 中文
|
##ownname 中文
|
||||||
##isocode zh_TW
|
##isocode zh_TW
|
||||||
|
##winlangid 0x0404
|
||||||
##plural 1
|
##plural 1
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Turkish
|
##name Turkish
|
||||||
##ownname Türkçe
|
##ownname Türkçe
|
||||||
##isocode tr_TR
|
##isocode tr_TR
|
||||||
|
##winlangid 0x041f
|
||||||
##plural 1
|
##plural 1
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Ukrainian
|
##name Ukrainian
|
||||||
##ownname Українська
|
##ownname Українська
|
||||||
##isocode uk_UA
|
##isocode uk_UA
|
||||||
|
##winlangid 0x0422
|
||||||
##plural 6
|
##plural 6
|
||||||
##gender m f s mn
|
##gender m f s mn
|
||||||
##case r d z
|
##case r d z
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Frisian
|
##name Frisian
|
||||||
##ownname Frysk
|
##ownname Frysk
|
||||||
##isocode fy_NL
|
##isocode fy_NL
|
||||||
|
##winlangid 0x0462
|
||||||
|
|
||||||
##id 0x0000
|
##id 0x0000
|
||||||
STR_NULL :
|
STR_NULL :
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Greek
|
##name Greek
|
||||||
##ownname Ελληνικά
|
##ownname Ελληνικά
|
||||||
##isocode el_GR
|
##isocode el_GR
|
||||||
|
##winlangid 0x0408
|
||||||
##plural 0
|
##plural 0
|
||||||
##gender m f n
|
##gender m f n
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Ido
|
##name Ido
|
||||||
##ownname Ido
|
##ownname Ido
|
||||||
##isocode io_XX
|
##isocode io_XX
|
||||||
|
##winlangid 0x0000
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Indonesian
|
##name Indonesian
|
||||||
##ownname Indonesian
|
##ownname Indonesian
|
||||||
##isocode id_ID
|
##isocode id_ID
|
||||||
|
##winlangid 0x0421
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Latvian
|
##name Latvian
|
||||||
##ownname Latviešu
|
##ownname Latviešu
|
||||||
##isocode lv_LV
|
##isocode lv_LV
|
||||||
|
##winlangid 0x0426
|
||||||
##plural 3
|
##plural 3
|
||||||
##case kas
|
##case kas
|
||||||
##gender m f
|
##gender m f
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Macedonian
|
##name Macedonian
|
||||||
##ownname Македонски
|
##ownname Македонски
|
||||||
##isocode mk_MK
|
##isocode mk_MK
|
||||||
|
##winlangid 0x042f
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Persian
|
##name Persian
|
||||||
##ownname Farsi
|
##ownname Farsi
|
||||||
##isocode fa_IR
|
##isocode fa_IR
|
||||||
|
##winlangid 0x0429
|
||||||
##plural 0
|
##plural 0
|
||||||
##textdir rtl
|
##textdir rtl
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Serbian
|
##name Serbian
|
||||||
##ownname Srpski
|
##ownname Srpski
|
||||||
##isocode sr_YU
|
##isocode sr_YU
|
||||||
|
##winlangid 0x7c1a
|
||||||
##plural 0
|
##plural 0
|
||||||
##case ih a ova ca ci ka ća va ao u om im e ke on ona to
|
##case ih a ova ca ci ka ća va ao u om im e ke on ona to
|
||||||
##gender muški ženski srednji
|
##gender muški ženski srednji
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##name Welsh
|
##name Welsh
|
||||||
##ownname Cymraeg
|
##ownname Cymraeg
|
||||||
##isocode cy_GB
|
##isocode cy_GB
|
||||||
|
##winlangid 0x0452
|
||||||
##plural 0
|
##plural 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -87,6 +87,7 @@ static uint32 _hash;
|
||||||
static char _lang_name[32], _lang_ownname[32], _lang_isocode[16];
|
static char _lang_name[32], _lang_ownname[32], _lang_isocode[16];
|
||||||
static byte _lang_pluralform;
|
static byte _lang_pluralform;
|
||||||
static byte _lang_textdir;
|
static byte _lang_textdir;
|
||||||
|
static uint16 _lang_winlangid;
|
||||||
#define MAX_NUM_GENDER 8
|
#define MAX_NUM_GENDER 8
|
||||||
static char _genders[MAX_NUM_GENDER][16];
|
static char _genders[MAX_NUM_GENDER][16];
|
||||||
static int _numgenders;
|
static int _numgenders;
|
||||||
|
@ -649,6 +650,13 @@ static void HandlePragma(char *str)
|
||||||
} else {
|
} else {
|
||||||
error("Invalid textdir %s", str + 8);
|
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)) {
|
} else if (!memcmp(str, "gender ", 7)) {
|
||||||
char* buf = str + 7;
|
char* buf = str + 7;
|
||||||
|
|
||||||
|
@ -912,6 +920,7 @@ static void ParseFile(const char *file, bool english)
|
||||||
_numgenders = 0;
|
_numgenders = 0;
|
||||||
_lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0';
|
_lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0';
|
||||||
_lang_textdir = TD_LTR;
|
_lang_textdir = TD_LTR;
|
||||||
|
_lang_winlangid = 0x0000; // neutral language code
|
||||||
// TODO:!! We can't reset the cases. In case the translated strings
|
// TODO:!! We can't reset the cases. In case the translated strings
|
||||||
// derive some strings from english....
|
// derive some strings from english....
|
||||||
|
|
||||||
|
@ -1161,6 +1170,7 @@ static void WriteLangfile(const char *filename)
|
||||||
hdr.version = TO_LE32(_hash);
|
hdr.version = TO_LE32(_hash);
|
||||||
hdr.plural_form = _lang_pluralform;
|
hdr.plural_form = _lang_pluralform;
|
||||||
hdr.text_dir = _lang_textdir;
|
hdr.text_dir = _lang_textdir;
|
||||||
|
hdr.winlangid = TO_LE16(_lang_winlangid);
|
||||||
strcpy(hdr.name, _lang_name);
|
strcpy(hdr.name, _lang_name);
|
||||||
strcpy(hdr.own_name, _lang_ownname);
|
strcpy(hdr.own_name, _lang_ownname);
|
||||||
strcpy(hdr.isocode, _lang_isocode);
|
strcpy(hdr.isocode, _lang_isocode);
|
||||||
|
|
|
@ -14,7 +14,16 @@ struct LanguagePackHeader {
|
||||||
uint16 offsets[32]; // the offsets
|
uint16 offsets[32]; // the offsets
|
||||||
byte plural_form; // plural form index
|
byte plural_form; // plural form index
|
||||||
byte text_dir; // default direction of the text
|
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);
|
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);
|
size_t read = fread(hdr, sizeof(*hdr), 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
return read == 1 &&
|
bool ret = read == 1 &&
|
||||||
hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
|
hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
|
||||||
hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
|
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()
|
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++) {
|
bool retry = false;
|
||||||
for (uint j = 0; j < _langtab_num[i]; j++) {
|
for (;;) {
|
||||||
const char *string = _langpack_offs[_langtab_start[i] + j];
|
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
|
||||||
WChar c;
|
|
||||||
while ((c = Utf8Consume(&string)) != '\0') {
|
for (uint i = 0; i != 32; i++) {
|
||||||
if (c == SCC_SETX) {
|
for (uint j = 0; j < _langtab_num[i]; j++) {
|
||||||
/*
|
const char *string = _langpack_offs[_langtab_start[i] + j];
|
||||||
* SetX is, together with SetXY as special character that
|
WChar c;
|
||||||
* uses the next (two) characters as data points. We have
|
while ((c = Utf8Consume(&string)) != '\0') {
|
||||||
* to skip those, otherwise the UTF8 reading will go
|
if (c == SCC_SETX) {
|
||||||
* haywire.
|
/*
|
||||||
*/
|
* SetX is, together with SetXY as special character that
|
||||||
string++;
|
* uses the next (two) characters as data points. We have
|
||||||
} else if (c == SCC_SETXY) {
|
* to skip those, otherwise the UTF8 reading will go
|
||||||
string += 2;
|
* haywire.
|
||||||
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
|
*/
|
||||||
/*
|
string++;
|
||||||
* The character is printable, but not in the normal font.
|
} else if (c == SCC_SETXY) {
|
||||||
* This is the case we were testing for. In this case we
|
string += 2;
|
||||||
* have to show the error. As we do not want the string to
|
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
|
||||||
* be translated by the translators, we 'force' it into the
|
#ifdef WITH_FREETYPE
|
||||||
* binary and 'load' it via a BindCString. To do this
|
if (!retry) {
|
||||||
* properly we have to set the color of the string,
|
/* We found an unprintable character... lets try whether we can
|
||||||
* otherwise we end up with a lot of artefacts. The color
|
* find a fallback font that can print the characters in the
|
||||||
* 'character' might change in the future, so for safety
|
* current language. */
|
||||||
* we just Utf8 Encode it into the string, which takes
|
retry = true;
|
||||||
* exactly three characters, so it replaces the "XXX" with
|
|
||||||
* the color marker.
|
FreeTypeSettings backup;
|
||||||
*/
|
memcpy(&backup, &_freetype, sizeof(backup));
|
||||||
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);
|
bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid);
|
||||||
SetDParamStr(0, err_str);
|
if (success) {
|
||||||
ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
|
UninitFreeType();
|
||||||
return;
|
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)
|
#if !defined(WITH_ICU)
|
||||||
|
|
Loading…
Reference in New Issue