summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2008-11-24 18:53:17 +0000
committerrubidium <rubidium@openttd.org>2008-11-24 18:53:17 +0000
commitfea78fbfbb2bfe5c6ddf90adb811eb60f4ecfc50 (patch)
treeead76c1aeb888d0a95a040f598f2614ff0ad201e /src
parent6878b181c7371ecc4af39eef6b01b710cc9f088b (diff)
downloadopenttd-fea78fbfbb2bfe5c6ddf90adb811eb60f4ecfc50.tar.xz
(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.
Diffstat (limited to 'src')
-rw-r--r--src/fontcache.cpp186
-rw-r--r--src/fontcache.h19
-rw-r--r--src/lang/afrikaans.txt1
-rw-r--r--src/lang/brazilian_portuguese.txt1
-rw-r--r--src/lang/bulgarian.txt1
-rw-r--r--src/lang/catalan.txt1
-rw-r--r--src/lang/croatian.txt1
-rw-r--r--src/lang/czech.txt1
-rw-r--r--src/lang/danish.txt1
-rw-r--r--src/lang/dutch.txt1
-rw-r--r--src/lang/english.txt1
-rw-r--r--src/lang/english_US.txt1
-rw-r--r--src/lang/esperanto.txt1
-rw-r--r--src/lang/estonian.txt1
-rw-r--r--src/lang/finnish.txt1
-rw-r--r--src/lang/french.txt1
-rw-r--r--src/lang/galician.txt1
-rw-r--r--src/lang/german.txt1
-rw-r--r--src/lang/hungarian.txt1
-rw-r--r--src/lang/icelandic.txt1
-rw-r--r--src/lang/italian.txt1
-rw-r--r--src/lang/japanese.txt1
-rw-r--r--src/lang/korean.txt1
-rw-r--r--src/lang/lithuanian.txt1
-rw-r--r--src/lang/norwegian_bokmal.txt1
-rw-r--r--src/lang/norwegian_nynorsk.txt1
-rw-r--r--src/lang/origveh.txt3
-rw-r--r--src/lang/piglatin.txt1
-rw-r--r--src/lang/polish.txt1
-rw-r--r--src/lang/portuguese.txt1
-rw-r--r--src/lang/romanian.txt1
-rw-r--r--src/lang/russian.txt1
-rw-r--r--src/lang/simplified_chinese.txt1
-rw-r--r--src/lang/slovak.txt1
-rw-r--r--src/lang/slovenian.txt1
-rw-r--r--src/lang/spanish.txt1
-rw-r--r--src/lang/swedish.txt1
-rw-r--r--src/lang/traditional_chinese.txt1
-rw-r--r--src/lang/turkish.txt1
-rw-r--r--src/lang/ukrainian.txt1
-rw-r--r--src/lang/unfinished/frisian.txt1
-rw-r--r--src/lang/unfinished/greek.txt1
-rw-r--r--src/lang/unfinished/ido.txt1
-rw-r--r--src/lang/unfinished/indonesian.txt1
-rw-r--r--src/lang/unfinished/latvian.txt1
-rw-r--r--src/lang/unfinished/macedonian.txt1
-rw-r--r--src/lang/unfinished/persian.txt1
-rw-r--r--src/lang/unfinished/serbian.txt1
-rw-r--r--src/lang/welsh.txt1
-rw-r--r--src/strgen/strgen.cpp10
-rw-r--r--src/strgen/strgen.h11
-rw-r--r--src/strings.cpp116
52 files changed, 343 insertions, 48 deletions
diff --git a/src/fontcache.cpp b/src/fontcache.cpp
index 28924885d..b35458046 100644
--- a/src/fontcache.cpp
+++ b/src/fontcache.cpp
@@ -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)
{
diff --git a/src/fontcache.h b/src/fontcache.h
index bf32c2927..e72fc8225 100644
--- a/src/fontcache.h
+++ b/src/fontcache.h
@@ -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)
diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt
index 1fe44e6c6..359c50c55 100644
--- a/src/lang/afrikaans.txt
+++ b/src/lang/afrikaans.txt
@@ -1,6 +1,7 @@
##name Afrikaans
##ownname Jaybee
##isocode af_ZA
+##winlangid 0x0436
##plural 0
##gender male
diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt
index a2bbd593b..bcd1d6bd0 100644
--- a/src/lang/brazilian_portuguese.txt
+++ b/src/lang/brazilian_portuguese.txt
@@ -1,6 +1,7 @@
##name Brazilian_Portuguese
##ownname Português (BR)
##isocode pt_BR
+##winlangid 0x0416
##plural 2
##gender m f
diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt
index a1704fd14..66acc6044 100644
--- a/src/lang/bulgarian.txt
+++ b/src/lang/bulgarian.txt
@@ -1,6 +1,7 @@
##name Bulgarian
##ownname Български
##isocode bg_BG
+##winlangid 0x0402
##plural 0
##case m f n p
##gender m f n p
diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt
index 4d5ffd392..ea0d0bf06 100644
--- a/src/lang/catalan.txt
+++ b/src/lang/catalan.txt
@@ -1,6 +1,7 @@
##name Catalan
##ownname Català
##isocode ca_ES
+##winlangid 0x0403
##plural 0
#
diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt
index 9a70432e8..9a27ca102 100644
--- a/src/lang/croatian.txt
+++ b/src/lang/croatian.txt
@@ -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
diff --git a/src/lang/czech.txt b/src/lang/czech.txt
index 73f807b52..f2da56ab1 100644
--- a/src/lang/czech.txt
+++ b/src/lang/czech.txt
@@ -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
diff --git a/src/lang/danish.txt b/src/lang/danish.txt
index 931de2a82..d048c261a 100644
--- a/src/lang/danish.txt
+++ b/src/lang/danish.txt
@@ -1,6 +1,7 @@
##name Danish
##ownname Dansk
##isocode da_DA
+##winlangid 0x0406
##plural 0
#
diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt
index 73908f23c..113ea0cb0 100644
--- a/src/lang/dutch.txt
+++ b/src/lang/dutch.txt
@@ -1,6 +1,7 @@
##name Dutch
##ownname Nederlands
##isocode nl_NL
+##winlangid 0x0413
##plural 0
#
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 4a8f8f243..d77741b02 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1,6 +1,7 @@
##name English (UK)
##ownname English (UK)
##isocode en_GB
+##winlangid 0x0809
##plural 0
#
diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt
index 68efdf1ea..60404b192 100644
--- a/src/lang/english_US.txt
+++ b/src/lang/english_US.txt
@@ -1,6 +1,7 @@
##name English (US)
##ownname English (US)
##isocode en_US
+##winlangid 0x0409
##plural 0
#
diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt
index 1ed900995..8d55e779c 100644
--- a/src/lang/esperanto.txt
+++ b/src/lang/esperanto.txt
@@ -1,6 +1,7 @@
##name Esperanto
##ownname Esperanto
##isocode eo_EO
+##winlangid 0x0000
##plural 0
##case n
diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt
index 425e6f71d..e592c57f0 100644
--- a/src/lang/estonian.txt
+++ b/src/lang/estonian.txt
@@ -1,6 +1,7 @@
##name Estonian
##ownname Eesti keel
##isocode et_ET
+##winlangid 0x0425
##plural 0
##case g in
diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt
index 0bee74f9c..120f247c0 100644
--- a/src/lang/finnish.txt
+++ b/src/lang/finnish.txt
@@ -1,6 +1,7 @@
##name Finnish
##ownname Suomi
##isocode fi_FI
+##winlangid 0x040b
##plural 0
#
diff --git a/src/lang/french.txt b/src/lang/french.txt
index 6371c432d..8770cf9f2 100644
--- a/src/lang/french.txt
+++ b/src/lang/french.txt
@@ -1,6 +1,7 @@
##name French
##ownname Français
##isocode fr_FR
+##winlangid 0x040c
##plural 2
##gender m m2 f
diff --git a/src/lang/galician.txt b/src/lang/galician.txt
index 6c2db27c8..b1c4b8ea5 100644
--- a/src/lang/galician.txt
+++ b/src/lang/galician.txt
@@ -1,6 +1,7 @@
##name Galician
##ownname Galego
##isocode gl_ES
+##winlangid 0x0456
##plural 0
##gender m f n
diff --git a/src/lang/german.txt b/src/lang/german.txt
index e823b5ebb..108377fe5 100644
--- a/src/lang/german.txt
+++ b/src/lang/german.txt
@@ -1,6 +1,7 @@
##name German
##ownname Deutsch
##isocode de_DE
+##winlangid 0x0407
##plural 0
##gender m w n p
diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt
index 683ac78d1..bef7d66dc 100644
--- a/src/lang/hungarian.txt
+++ b/src/lang/hungarian.txt
@@ -1,6 +1,7 @@
##name Hungarian
##ownname Magyar
##isocode hu_HU
+##winlangid 0x040e
##plural 1
##case t ba
diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt
index 9791b24d8..cba7f8cc0 100644
--- a/src/lang/icelandic.txt
+++ b/src/lang/icelandic.txt
@@ -1,6 +1,7 @@
##name Icelandic
##ownname Íslenska
##isocode is_IS
+##winlangid 0x040f
##plural 0
##gender karlkyn kvenkyn hvorugkyn
diff --git a/src/lang/italian.txt b/src/lang/italian.txt
index d09ef4f1b..c7ed03c97 100644
--- a/src/lang/italian.txt
+++ b/src/lang/italian.txt
@@ -1,6 +1,7 @@
##name Italian
##ownname Italiano
##isocode it_IT
+##winlangid 0x0410
##plural 0
##case ms mp fs fp
##gender m f
diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt
index 0c5752468..413ec8209 100644
--- a/src/lang/japanese.txt
+++ b/src/lang/japanese.txt
@@ -1,6 +1,7 @@
##name Japanese
##ownname 日本語
##isocode ja_JP
+##winlangid 0x0411
##plural 1
#
diff --git a/src/lang/korean.txt b/src/lang/korean.txt
index d3f3c0a41..9f337a889 100644
--- a/src/lang/korean.txt
+++ b/src/lang/korean.txt
@@ -1,6 +1,7 @@
##name Korean
##ownname 한국어
##isocode ko_KR
+##winlangid 0x0412
##plural 1
#
diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt
index 24f154b27..d212b535c 100644
--- a/src/lang/lithuanian.txt
+++ b/src/lang/lithuanian.txt
@@ -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
diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt
index e8665f076..703e7a327 100644
--- a/src/lang/norwegian_bokmal.txt
+++ b/src/lang/norwegian_bokmal.txt
@@ -1,6 +1,7 @@
##name Norwegian
##ownname Norsk (bokmål)
##isocode nb_NO
+##winlangid 0x0414
##plural 0
#
diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt
index c68a1c237..87e829ceb 100644
--- a/src/lang/norwegian_nynorsk.txt
+++ b/src/lang/norwegian_nynorsk.txt
@@ -1,6 +1,7 @@
##name Norwegian new
##ownname Norsk, Nynorsk
##isocode nn_NO
+##winlangid 0x0814
##plural 0
##gender masculine feminine neuter
diff --git a/src/lang/origveh.txt b/src/lang/origveh.txt
index 17b9a665b..d1cc58ee3 100644
--- a/src/lang/origveh.txt
+++ b/src/lang/origveh.txt
@@ -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)
diff --git a/src/lang/piglatin.txt b/src/lang/piglatin.txt
index 5acac3cbd..9ce6bbbd6 100644
--- a/src/lang/piglatin.txt
+++ b/src/lang/piglatin.txt
@@ -1,6 +1,7 @@
##name Pig latin
##ownname Igpay atinlay
##isocode xx_PL
+##winlangid 0x0000
##plural 0
#
diff --git a/src/lang/polish.txt b/src/lang/polish.txt
index 1db3d8d0b..0b3eb2825 100644
--- a/src/lang/polish.txt
+++ b/src/lang/polish.txt
@@ -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
diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt
index c0a8f5f71..6258acae8 100644
--- a/src/lang/portuguese.txt
+++ b/src/lang/portuguese.txt
@@ -1,6 +1,7 @@
##name Portuguese
##ownname Português
##isocode pt_PT
+##winlangid 0x0816
##plural 0
#
diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt
index d8078ae71..def0a12d6 100644
--- a/src/lang/romanian.txt
+++ b/src/lang/romanian.txt
@@ -1,6 +1,7 @@
##name Romanian
##ownname Românã
##isocode ro_RO
+##winlangid 0x0418
##plural 0
#
diff --git a/src/lang/russian.txt b/src/lang/russian.txt
index a1d7fc5e3..2812e4372 100644
--- a/src/lang/russian.txt
+++ b/src/lang/russian.txt
@@ -1,6 +1,7 @@
##name Russian
##ownname Русский
##isocode ru_RU
+##winlangid 0x0419
##plural 6
##case m f n p
##gender m f n p
diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt
index b04c67abe..1922d964c 100644
--- a/src/lang/simplified_chinese.txt
+++ b/src/lang/simplified_chinese.txt
@@ -1,6 +1,7 @@
##name Chinese (Simplified)
##ownname 简体中文
##isocode zh_CN
+##winlangid 0x0804
##plural 1
#
diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt
index ce19cafe7..a7cb3f2b3 100644
--- a/src/lang/slovak.txt
+++ b/src/lang/slovak.txt
@@ -1,6 +1,7 @@
##name Slovak
##ownname Slovensky
##isocode sk_SK
+##winlangid 0x041b
##plural 6
##case g
##gender m z s
diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt
index e15a6c0a7..cf145a995 100644
--- a/src/lang/slovenian.txt
+++ b/src/lang/slovenian.txt
@@ -1,6 +1,7 @@
##name Slovenian
##ownname Slovenščina
##isocode sl_SL
+##winlangid 0x0424
##plural 8
##case r d t
diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt
index eff25caa9..6070bce7f 100644
--- a/src/lang/spanish.txt
+++ b/src/lang/spanish.txt
@@ -1,6 +1,7 @@
##name Spanish
##ownname Español (ES)
##isocode es_ES
+##winlangid 0x0c0a
##plural 0
##gender masculino femenino
diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt
index 4cc81c4d8..0d5b6bf02 100644
--- a/src/lang/swedish.txt
+++ b/src/lang/swedish.txt
@@ -1,6 +1,7 @@
##name Swedish
##ownname Svenska
##isocode sv_SE
+##winlangid 0x081d
##plural 0
#
diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt
index ee85486f6..5c8dbd13f 100644
--- a/src/lang/traditional_chinese.txt
+++ b/src/lang/traditional_chinese.txt
@@ -1,6 +1,7 @@
##name Chinese (Traditional)
##ownname 中文
##isocode zh_TW
+##winlangid 0x0404
##plural 1
#
diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt
index 92d5fe48f..c57979c0a 100644
--- a/src/lang/turkish.txt
+++ b/src/lang/turkish.txt
@@ -1,6 +1,7 @@
##name Turkish
##ownname Türkçe
##isocode tr_TR
+##winlangid 0x041f
##plural 1
#
diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt
index db7b53bbc..393bfbef1 100644
--- a/src/lang/ukrainian.txt
+++ b/src/lang/ukrainian.txt
@@ -1,6 +1,7 @@
##name Ukrainian
##ownname Українська
##isocode uk_UA
+##winlangid 0x0422
##plural 6
##gender m f s mn
##case r d z
diff --git a/src/lang/unfinished/frisian.txt b/src/lang/unfinished/frisian.txt
index ff09635c6..39d316f35 100644
--- a/src/lang/unfinished/frisian.txt
+++ b/src/lang/unfinished/frisian.txt
@@ -1,6 +1,7 @@
##name Frisian
##ownname Frysk
##isocode fy_NL
+##winlangid 0x0462
##id 0x0000
STR_NULL :
diff --git a/src/lang/unfinished/greek.txt b/src/lang/unfinished/greek.txt
index 81eb57011..0f7a1220d 100644
--- a/src/lang/unfinished/greek.txt
+++ b/src/lang/unfinished/greek.txt
@@ -1,6 +1,7 @@
##name Greek
##ownname Ελληνικά
##isocode el_GR
+##winlangid 0x0408
##plural 0
##gender m f n
diff --git a/src/lang/unfinished/ido.txt b/src/lang/unfinished/ido.txt
index 67c22b2b2..8d6b7ddc9 100644
--- a/src/lang/unfinished/ido.txt
+++ b/src/lang/unfinished/ido.txt
@@ -1,6 +1,7 @@
##name Ido
##ownname Ido
##isocode io_XX
+##winlangid 0x0000
##plural 0
#
diff --git a/src/lang/unfinished/indonesian.txt b/src/lang/unfinished/indonesian.txt
index 143172e10..9f6f1ab55 100644
--- a/src/lang/unfinished/indonesian.txt
+++ b/src/lang/unfinished/indonesian.txt
@@ -1,6 +1,7 @@
##name Indonesian
##ownname Indonesian
##isocode id_ID
+##winlangid 0x0421
##plural 0
#
diff --git a/src/lang/unfinished/latvian.txt b/src/lang/unfinished/latvian.txt
index 6dbc62d9f..da260bfae 100644
--- a/src/lang/unfinished/latvian.txt
+++ b/src/lang/unfinished/latvian.txt
@@ -1,6 +1,7 @@
##name Latvian
##ownname Latviešu
##isocode lv_LV
+##winlangid 0x0426
##plural 3
##case kas
##gender m f
diff --git a/src/lang/unfinished/macedonian.txt b/src/lang/unfinished/macedonian.txt
index 3b03e516a..a5b022467 100644
--- a/src/lang/unfinished/macedonian.txt
+++ b/src/lang/unfinished/macedonian.txt
@@ -1,6 +1,7 @@
##name Macedonian
##ownname Македонски
##isocode mk_MK
+##winlangid 0x042f
##plural 0
#
diff --git a/src/lang/unfinished/persian.txt b/src/lang/unfinished/persian.txt
index 82ed1c99b..4f797ffbe 100644
--- a/src/lang/unfinished/persian.txt
+++ b/src/lang/unfinished/persian.txt
@@ -1,6 +1,7 @@
##name Persian
##ownname Farsi
##isocode fa_IR
+##winlangid 0x0429
##plural 0
##textdir rtl
diff --git a/src/lang/unfinished/serbian.txt b/src/lang/unfinished/serbian.txt
index 389e3b96e..94c43d4a8 100644
--- a/src/lang/unfinished/serbian.txt
+++ b/src/lang/unfinished/serbian.txt
@@ -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
diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt
index daef80993..4b65b5223 100644
--- a/src/lang/welsh.txt
+++ b/src/lang/welsh.txt
@@ -1,6 +1,7 @@
##name Welsh
##ownname Cymraeg
##isocode cy_GB
+##winlangid 0x0452
##plural 0
#
diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp
index 298597311..ba6a9bb40 100644
--- a/src/strgen/strgen.cpp
+++ b/src/strgen/strgen.cpp
@@ -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);
diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h
index a38b1760d..93253259f 100644
--- a/src/strgen/strgen.h
+++ b/src/strgen/strgen.h
@@ -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);
diff --git a/src/strings.cpp b/src/strings.cpp
index 2fb3a7854..a93645341 100644
--- a/src/strings.cpp
+++ b/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, '?');
-
- 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;
+#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
+
+ 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)