changeset 13281:e241d1485669 draft

(svn r17790) -Feature: translatable base sound/graphics set descriptions
author rubidium <rubidium@openttd.org>
date Sat, 17 Oct 2009 20:34:09 +0000
parents 7b9b6a48f9a8
children a5ccb03e737b
files docs/obg_format.txt docs/obs_format.txt src/base_media_base.h src/base_media_func.h src/core/smallmap_type.hpp src/settings_gui.cpp src/strings.cpp src/strings_func.h
diffstat 8 files changed, 81 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/docs/obg_format.txt
+++ b/docs/obg_format.txt
@@ -31,7 +31,15 @@
 ; the version of this graphics set (read as single integer)
 version      = 0
 ; a fairly short description of the set
+; By adding '.<iso code>' 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 '.<iso code>').
+; 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
 
--- a/docs/obs_format.txt
+++ b/docs/obs_format.txt
@@ -31,7 +31,15 @@
 ; the version of this sound set (read as single integer)
 version      = 0
 ; a fairly short description of the set
+; By adding '.<iso code>' 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 '.<iso code>').
+; 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.
--- 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 @@
  */
 template <class T, size_t Tnum_files>
 struct BaseSet {
+	typedef SmallMap<const char *, const char *> 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 @@
 	 * @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;
+	}
 };
 
 /**
--- a/src/base_media_func.h
+++ b/src/base_media_func.h
@@ -40,7 +40,14 @@
 	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 @@
 {
 	p += seprintf(p, last, "List of " SET_TYPE " sets:\n");
 	for (const Tbase_set *s = BaseMedia<Tbase_set>::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();
--- a/src/core/smallmap_type.hpp
+++ b/src/core/smallmap_type.hpp
@@ -33,6 +33,7 @@
 struct SmallMap : SmallVector<SmallPair<T, U>, S> {
 	typedef ::SmallPair<T, U> Pair;
 	typedef Pair *iterator;
+	typedef const Pair *const_iterator;
 
 	/** Creates new SmallMap. Data are initialized in SmallVector constructor */
 	FORCEINLINE SmallMap() { }
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -218,12 +218,12 @@
 	{
 		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 @@
 			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 @@
 			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;
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -1487,6 +1487,15 @@
 }
 
 /**
+ * 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
  * does not support. If this is the case an error
--- a/src/strings_func.h
+++ b/src/strings_func.h
@@ -99,6 +99,7 @@
 
 bool ReadLanguagePack(int index);
 void InitializeLanguagePacks();
+const char *GetCurrentLanguageIsoCode();
 
 int CDECL StringIDSorter(const StringID *a, const StringID *b);