mirror of https://github.com/OpenTTD/OpenTTD
(svn r17790) -Feature: translatable base sound/graphics set descriptions
parent
f7944f5554
commit
d5d2354296
|
@ -31,7 +31,15 @@ shortname = XMPL
|
||||||
; the version of this graphics set (read as single integer)
|
; the version of this graphics set (read as single integer)
|
||||||
version = 0
|
version = 0
|
||||||
; a fairly short description of the set
|
; 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 = foo
|
||||||
|
description.en_US = howdie
|
||||||
; palette used by the set; either DOS or Windows
|
; palette used by the set; either DOS or Windows
|
||||||
palette = DOS
|
palette = DOS
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,15 @@ shortname = XMPL
|
||||||
; the version of this sound set (read as single integer)
|
; the version of this sound set (read as single integer)
|
||||||
version = 0
|
version = 0
|
||||||
; a fairly short description of the set
|
; 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 = foo
|
||||||
|
description.en_US = howdie
|
||||||
|
|
||||||
; The files section lists the files that replace sprites.
|
; The files section lists the files that replace sprites.
|
||||||
; The file names are case sensitive.
|
; The file names are case sensitive.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define BASE_MEDIA_BASE_H
|
#define BASE_MEDIA_BASE_H
|
||||||
|
|
||||||
#include "fileio_func.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 */
|
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
|
||||||
struct IniFile;
|
struct IniFile;
|
||||||
|
@ -41,6 +42,8 @@ struct MD5File {
|
||||||
*/
|
*/
|
||||||
template <class T, size_t Tnum_files>
|
template <class T, size_t Tnum_files>
|
||||||
struct BaseSet {
|
struct BaseSet {
|
||||||
|
typedef SmallMap<const char *, const char *> TranslatedStrings;
|
||||||
|
|
||||||
/** Number of files in this set */
|
/** Number of files in this set */
|
||||||
static const size_t NUM_FILES = Tnum_files;
|
static const size_t NUM_FILES = Tnum_files;
|
||||||
|
|
||||||
|
@ -48,7 +51,7 @@ struct BaseSet {
|
||||||
static const char * const *file_names;
|
static const char * const *file_names;
|
||||||
|
|
||||||
const char *name; ///< The name of the base set
|
const char *name; ///< The name of the base set
|
||||||
const char *description; ///< Description of the base set
|
TranslatedStrings description; ///< Description of the base set
|
||||||
uint32 shortname; ///< Four letter short variant of the name
|
uint32 shortname; ///< Four letter short variant of the name
|
||||||
uint32 version; ///< The version of this base set
|
uint32 version; ///< The version of this base set
|
||||||
|
|
||||||
|
@ -62,7 +65,12 @@ struct BaseSet {
|
||||||
~BaseSet()
|
~BaseSet()
|
||||||
{
|
{
|
||||||
free((void*)this->name);
|
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++) {
|
for (uint i = 0; i < NUM_FILES; i++) {
|
||||||
free((void*)this->files[i].filename);
|
free((void*)this->files[i].filename);
|
||||||
free((void*)this->files[i].missing_warning);
|
free((void*)this->files[i].missing_warning);
|
||||||
|
@ -97,6 +105,30 @@ struct BaseSet {
|
||||||
* @return true if loading was successful.
|
* @return true if loading was successful.
|
||||||
*/
|
*/
|
||||||
bool FillSetDetails(IniFile *ini, const char *path);
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -40,7 +40,14 @@ bool BaseSet<T, Tnum_files>::FillSetDetails(IniFile *ini, const char *path)
|
||||||
this->name = strdup(item->value);
|
this->name = strdup(item->value);
|
||||||
|
|
||||||
fetch_metadata("description");
|
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");
|
fetch_metadata("shortname");
|
||||||
for (uint i = 0; item->value[i] != '\0' && i < 4; i++) {
|
for (uint i = 0; item->value[i] != '\0' && i < 4; i++) {
|
||||||
|
@ -213,7 +220,7 @@ template <class Tbase_set>
|
||||||
{
|
{
|
||||||
p += seprintf(p, last, "List of " SET_TYPE " sets:\n");
|
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) {
|
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();
|
int invalid = s->GetNumInvalid();
|
||||||
if (invalid != 0) {
|
if (invalid != 0) {
|
||||||
int missing = s->GetNumMissing();
|
int missing = s->GetNumMissing();
|
||||||
|
|
|
@ -33,6 +33,7 @@ template <typename T, typename U, uint S = 16>
|
||||||
struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||||
typedef ::SmallPair<T, U> Pair;
|
typedef ::SmallPair<T, U> Pair;
|
||||||
typedef Pair *iterator;
|
typedef Pair *iterator;
|
||||||
|
typedef const Pair *const_iterator;
|
||||||
|
|
||||||
/** Creates new SmallMap. Data are initialized in SmallVector constructor */
|
/** Creates new SmallMap. Data are initialized in SmallVector constructor */
|
||||||
FORCEINLINE SmallMap() { }
|
FORCEINLINE SmallMap() { }
|
||||||
|
|
|
@ -218,12 +218,12 @@ struct GameOptionsWindow : Window {
|
||||||
{
|
{
|
||||||
switch (widget) {
|
switch (widget) {
|
||||||
case GOW_BASE_GRF_DESCRIPTION:
|
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);
|
DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GOW_BASE_SFX_DESCRIPTION:
|
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);
|
DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ struct GameOptionsWindow : Window {
|
||||||
case GOW_BASE_GRF_DESCRIPTION:
|
case GOW_BASE_GRF_DESCRIPTION:
|
||||||
/* Find the biggest description for the default size. */
|
/* Find the biggest description for the default size. */
|
||||||
for (int i = 0; i < BaseGraphics::GetNumSets(); i++) {
|
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));
|
size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -254,7 +254,7 @@ struct GameOptionsWindow : Window {
|
||||||
case GOW_BASE_SFX_DESCRIPTION:
|
case GOW_BASE_SFX_DESCRIPTION:
|
||||||
/* Find the biggest description for the default size. */
|
/* Find the biggest description for the default size. */
|
||||||
for (int i = 0; i < BaseSounds::GetNumSets(); i++) {
|
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));
|
size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1486,6 +1486,15 @@ void InitializeLanguagePacks()
|
||||||
if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", dl->ent[chosen_language].file);
|
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
|
* Check whether the currently loaded language pack
|
||||||
* uses characters that the currently loaded font
|
* uses characters that the currently loaded font
|
||||||
|
|
|
@ -99,6 +99,7 @@ extern DynamicLanguages _dynlang; // defined in strings.cpp
|
||||||
|
|
||||||
bool ReadLanguagePack(int index);
|
bool ReadLanguagePack(int index);
|
||||||
void InitializeLanguagePacks();
|
void InitializeLanguagePacks();
|
||||||
|
const char *GetCurrentLanguageIsoCode();
|
||||||
|
|
||||||
int CDECL StringIDSorter(const StringID *a, const StringID *b);
|
int CDECL StringIDSorter(const StringID *a, const StringID *b);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue