From d5d23542960c5c090c4b7593d156a008b3d84914 Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 17 Oct 2009 20:34:09 +0000 Subject: [PATCH] (svn r17790) -Feature: translatable base sound/graphics set descriptions --- docs/obg_format.txt | 8 ++++++ docs/obs_format.txt | 8 ++++++ src/base_media_base.h | 50 +++++++++++++++++++++++++++++++------- src/base_media_func.h | 11 +++++++-- src/core/smallmap_type.hpp | 1 + src/settings_gui.cpp | 8 +++--- src/strings.cpp | 9 +++++++ src/strings_func.h | 1 + 8 files changed, 81 insertions(+), 15 deletions(-) diff --git a/docs/obg_format.txt b/docs/obg_format.txt index 87fe11a71b..9be2883c40 100644 --- a/docs/obg_format.txt +++ b/docs/obg_format.txt @@ -31,7 +31,15 @@ shortname = XMPL ; the version of this graphics set (read as single integer) version = 0 ; a fairly short description of the set +; By adding '.' you can translate the description. +; Note that OpenTTD first tries the full ISO code, then the first +; two characters and then uses the fallback (no '.'). +; The ISO code matching is case sensitive! +; So en_US will be used for en_UK if no en_UK translation is added. +; As a result the below example has 'howdie' for en_US and en_UK but +; 'foo' for all other languages. description = foo +description.en_US = howdie ; palette used by the set; either DOS or Windows palette = DOS diff --git a/docs/obs_format.txt b/docs/obs_format.txt index 7519f1bfe6..f18676891d 100644 --- a/docs/obs_format.txt +++ b/docs/obs_format.txt @@ -31,7 +31,15 @@ shortname = XMPL ; the version of this sound set (read as single integer) version = 0 ; a fairly short description of the set +; By adding '.' you can translate the description. +; Note that OpenTTD first tries the full ISO code, then the first +; two characters and then uses the fallback (no '.'). +; The ISO code matching is case sensitive! +; So en_US will be used for en_UK if no en_UK translation is added. +; As a result the below example has 'howdie' for en_US and en_UK but +; 'foo' for all other languages. description = foo +description.en_US = howdie ; The files section lists the files that replace sprites. ; The file names are case sensitive. diff --git a/src/base_media_base.h b/src/base_media_base.h index 070a332918..1d52145b90 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -13,6 +13,7 @@ #define BASE_MEDIA_BASE_H #include "fileio_func.h" +#include "core/smallmap_type.hpp" /* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */ struct IniFile; @@ -41,28 +42,35 @@ struct MD5File { */ template struct BaseSet { + typedef SmallMap TranslatedStrings; + /** Number of files in this set */ static const size_t NUM_FILES = Tnum_files; /** Internal names of the files in this set. */ static const char * const *file_names; - const char *name; ///< The name of the base set - const char *description; ///< Description of the base set - uint32 shortname; ///< Four letter short variant of the name - uint32 version; ///< The version of this base set + const char *name; ///< The name of the base set + TranslatedStrings description; ///< Description of the base set + uint32 shortname; ///< Four letter short variant of the name + uint32 version; ///< The version of this base set - MD5File files[NUM_FILES]; ///< All files part of this set - uint found_files; ///< Number of the files that could be found - uint valid_files; ///< Number of the files that could be found and are valid + MD5File files[NUM_FILES]; ///< All files part of this set + uint found_files; ///< Number of the files that could be found + uint valid_files; ///< Number of the files that could be found and are valid - T *next; ///< The next base set in this list + T *next; ///< The next base set in this list /** Free everything we allocated */ ~BaseSet() { free((void*)this->name); - free((void*)this->description); + + for (TranslatedStrings::iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + free((void*)iter->first); + free((void*)iter->second); + } + for (uint i = 0; i < NUM_FILES; i++) { free((void*)this->files[i].filename); free((void*)this->files[i].missing_warning); @@ -97,6 +105,30 @@ struct BaseSet { * @return true if loading was successful. */ bool FillSetDetails(IniFile *ini, const char *path); + + /** + * Get the description for the given ISO code. + * It falls back to the first two characters of the ISO code in case + * no match could be made with the full ISO code. If even then the + * matching fails the default is returned. + * @param isocode the isocode to search for + * @return the description + */ + const char *GetDescription(const char *isocode = NULL) const + { + if (isocode != NULL) { + /* First the full ISO code */ + for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + if (strcmp(iter->first, isocode) == 0) return iter->second; + } + /* Then the first two characters */ + for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + if (strncmp(iter->first, isocode, 2) == 0) return iter->second; + } + } + /* Then fall back */ + return this->description.Begin()->second; + } }; /** diff --git a/src/base_media_func.h b/src/base_media_func.h index 40d154d65a..df49f0b1b1 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -40,7 +40,14 @@ bool BaseSet::FillSetDetails(IniFile *ini, const char *path) this->name = strdup(item->value); fetch_metadata("description"); - this->description = strdup(item->value); + this->description[strdup("")] = strdup(item->value); + + /* Add the translations of the descriptions too. */ + for (const IniItem *item = metadata->item; item != NULL; item = item->next) { + if (strncmp("description.", item->name, 12) != 0) continue; + + this->description[strdup(item->name + 12)] = strdup(item->value); + } fetch_metadata("shortname"); for (uint i = 0; item->value[i] != '\0' && i < 4; i++) { @@ -213,7 +220,7 @@ template { p += seprintf(p, last, "List of " SET_TYPE " sets:\n"); for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { - p += seprintf(p, last, "%18s: %s", s->name, s->description); + p += seprintf(p, last, "%18s: %s", s->name, s->GetDescription()); int invalid = s->GetNumInvalid(); if (invalid != 0) { int missing = s->GetNumMissing(); diff --git a/src/core/smallmap_type.hpp b/src/core/smallmap_type.hpp index 68ee4aff5b..2699505445 100644 --- a/src/core/smallmap_type.hpp +++ b/src/core/smallmap_type.hpp @@ -33,6 +33,7 @@ template struct SmallMap : SmallVector, S> { typedef ::SmallPair Pair; typedef Pair *iterator; + typedef const Pair *const_iterator; /** Creates new SmallMap. Data are initialized in SmallVector constructor */ FORCEINLINE SmallMap() { } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 3315b6428b..fd352c3e3e 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -218,12 +218,12 @@ struct GameOptionsWindow : Window { { switch (widget) { case GOW_BASE_GRF_DESCRIPTION: - SetDParamStr(0, BaseGraphics::GetUsedSet()->description); + SetDParamStr(0, BaseGraphics::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; case GOW_BASE_SFX_DESCRIPTION: - SetDParamStr(0, BaseSounds::GetUsedSet()->description); + SetDParamStr(0, BaseSounds::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; } @@ -235,7 +235,7 @@ struct GameOptionsWindow : Window { case GOW_BASE_GRF_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { - SetDParamStr(0, BaseGraphics::GetSet(i)->description); + SetDParamStr(0, BaseGraphics::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; @@ -254,7 +254,7 @@ struct GameOptionsWindow : Window { case GOW_BASE_SFX_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseSounds::GetNumSets(); i++) { - SetDParamStr(0, BaseSounds::GetSet(i)->description); + SetDParamStr(0, BaseSounds::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; diff --git a/src/strings.cpp b/src/strings.cpp index bfe583148d..bb9bacd930 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1486,6 +1486,15 @@ void InitializeLanguagePacks() if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", dl->ent[chosen_language].file); } +/** + * Get the ISO language code of the currently loaded language. + * @return the ISO code. + */ +const char *GetCurrentLanguageIsoCode() +{ + return _langpack->isocode; +} + /** * Check whether the currently loaded language pack * uses characters that the currently loaded font diff --git a/src/strings_func.h b/src/strings_func.h index e4b1cd3bdd..e9a22288de 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -99,6 +99,7 @@ extern DynamicLanguages _dynlang; // defined in strings.cpp bool ReadLanguagePack(int index); void InitializeLanguagePacks(); +const char *GetCurrentLanguageIsoCode(); int CDECL StringIDSorter(const StringID *a, const StringID *b);