1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-16 19:43:06 +01:00

Merge pull request #19023 from Gymnasiast/refactor/18945

Close #18945: Allow languages to fall back to more than just en-GB
This commit is contained in:
Michael Steenbeek
2023-01-04 20:32:28 +01:00
committed by GitHub
9 changed files with 110 additions and 76 deletions

View File

@@ -5,6 +5,7 @@
- Feature: [#18744] Cheat to allow using a regular path as a queue path.
- Improved: [#18749] Ability to have 4 active awards for more than one month in a row.
- Improved: [#18826] [Plugin] Added all actions and their documentation to plugin API.
- Improved: [#18945] Languages can now fall back to other languages than English.
- Fix: [#18467] “Selected only” Object Selection filter is active in Track Designs Manager, and cannot be toggled.
- Fix: [#18905] Ride Construction window theme is not applied correctly.
- Fix: [#18911] Mini Golf station does not draw correctly from all angles.

View File

@@ -23,32 +23,33 @@
// clang-format off
const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] =
{
{ "", "", "", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_UNDEFINED
{ "ar-EG", "Arabic (experimental)", "Arabic (experimental)", FAMILY(&TTFFamilySansSerif), true }, // LANGUAGE_ARABIC
{ "ca-ES", "Catalan", u8"Català", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_CATALAN
{ "zh-CN", "Chinese (Simplified)", "Chinese (Simplified)", FAMILY(&TTFFamilyChineseSimplified), false }, // LANGUAGE_CHINESE_SIMPLIFIED
{ "zh-TW", "Chinese (Traditional)", "Chinese (Traditional)", FAMILY(&TTFFamilyChineseTraditional), false }, // LANGUAGE_CHINESE_TRADITIONAL
{ "cs-CZ", "Czech", u8"Čeština", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_CZECH
{ "da-DK", "Danish", "Dansk", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_DANISH
{ "de-DE", "German", "Deutsch", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_GERMAN
{ "en-GB", "English (UK)", "English (UK)", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ENGLISH_UK
{ "en-US", "English (US)", "English (US)", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ENGLISH_US
{ "eo-ZZ", "Esperanto", "Esperanto", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ESPERANTO
{ "es-ES", "Spanish", u8"Español", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_SPANISH
{ "fr-FR", "French", u8"Français", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_FRENCH
{ "it-IT", "Italian", "Italiano", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ITALIAN
{ "ja-JP", "Japanese", "Japanese", FAMILY(&TTFFamilyJapanese), false }, // LANGUAGE_JAPANESE
{ "ko-KR", "Korean", "Korean", FAMILY(&TTFFamilyKorean), false }, // LANGUAGE_KOREAN
{ "hu-HU", "Hungarian", "Magyar", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_HUNGARIAN
{ "nl-NL", "Dutch", "Nederlands", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_DUTCH
{ "nb-NO", "Norwegian", "Norsk", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_NORWEGIAN
{ "pl-PL", "Polish", "Polski", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_POLISH
{ "pt-BR", "Portuguese (BR)", u8"Português (BR)", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_PORTUGUESE_BR
{ "ru-RU", "Russian", u8"Русский", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_RUSSIAN
{ "fi-FI", "Finnish", "Suomi", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_FINNISH
{ "sv-SE", "Swedish", "Svenska", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_SWEDISH
{ "tr-TR", "Turkish", "Türkçe", FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_TURKISH
{ "vi-VN", "Vietnamese", "Vietnamese", FAMILY(&TTFFamilySansSerif), false }, // LANGUAGE_VIETNAMESE
{ "", "", "", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_UNDEFINED
{ "ar-EG", "Arabic (experimental)", "Arabic (experimental)", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilySansSerif), true }, // LANGUAGE_ARABIC
{ "ca-ES", "Catalan", u8"Català", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_CATALAN
{ "zh-CN", "Chinese (Simplified)", "Chinese (Simplified)", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilyChineseSimplified), false }, // LANGUAGE_CHINESE_SIMPLIFIED
{ "zh-TW", "Chinese (Traditional)", "Chinese (Traditional)", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilyChineseTraditional), false }, // LANGUAGE_CHINESE_TRADITIONAL
{ "cs-CZ", "Czech", u8"Čeština", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_CZECH
{ "da-DK", "Danish", "Dansk", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_DANISH
{ "de-DE", "German", "Deutsch", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_GERMAN
{ "en-GB", "English (UK)", "English (UK)", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ENGLISH_UK
{ "en-US", "English (US)", "English (US)", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ENGLISH_US
{ "eo-ZZ", "Esperanto", "Esperanto", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ESPERANTO
{ "es-ES", "Spanish", u8"Español", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_SPANISH
{ "fr-FR", "French", u8"Français", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_FRENCH
{ "fr-CA", "French (CA)", u8"Français (CA)", LANGUAGE_FRENCH, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_FRENCH_CA
{ "it-IT", "Italian", "Italiano", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_ITALIAN
{ "ja-JP", "Japanese", "Japanese", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilyJapanese), false }, // LANGUAGE_JAPANESE
{ "ko-KR", "Korean", "Korean", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilyKorean), false }, // LANGUAGE_KOREAN
{ "hu-HU", "Hungarian", "Magyar", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_HUNGARIAN
{ "nl-NL", "Dutch", "Nederlands", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_DUTCH
{ "nb-NO", "Norwegian", "Norsk", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_NORWEGIAN
{ "pl-PL", "Polish", "Polski", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_POLISH
{ "pt-BR", "Portuguese (BR)", u8"Português (BR)", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_PORTUGUESE_BR
{ "ru-RU", "Russian", u8"Русский", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_RUSSIAN
{ "fi-FI", "Finnish", "Suomi", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_FINNISH
{ "sv-SE", "Swedish", "Svenska", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_SWEDISH
{ "tr-TR", "Turkish", "Türkçe", LANGUAGE_UNDEFINED, FAMILY_OPENRCT2_SPRITE, false }, // LANGUAGE_TURKISH
{ "vi-VN", "Vietnamese", "Vietnamese", LANGUAGE_UNDEFINED, FAMILY(&TTFFamilySansSerif), false }, // LANGUAGE_VIETNAMESE
};
// clang-format on

View File

@@ -30,6 +30,7 @@ enum
LANGUAGE_ESPERANTO,
LANGUAGE_SPANISH,
LANGUAGE_FRENCH,
LANGUAGE_FRENCH_CA,
LANGUAGE_ITALIAN,
LANGUAGE_JAPANESE,
LANGUAGE_KOREAN,
@@ -75,6 +76,7 @@ struct language_descriptor
const char* locale;
const utf8* english_name;
const utf8* native_name;
uint8_t fallback;
#if !defined(NO_TTF)
TTFontFamily const* font_family;
#else

View File

@@ -9,6 +9,7 @@
#include "LanguagePack.h"
#include "../Context.h"
#include "../common.h"
#include "../core/FileStream.h"
#include "../core/Memory.hpp"
@@ -18,6 +19,7 @@
#include "../core/StringReader.h"
#include "Language.h"
#include "Localisation.h"
#include "LocalisationService.h"
#include <algorithm>
#include <memory>
@@ -580,6 +582,12 @@ namespace LanguagePackFactory
return languagePack;
}
std::unique_ptr<ILanguagePack> FromLanguageId(uint16_t id)
{
auto path = OpenRCT2::GetContext()->GetLocalisationService().GetLanguagePath(id);
return LanguagePack::FromFile(id, path.c_str());
}
std::unique_ptr<ILanguagePack> FromText(uint16_t id, const utf8* text)
{
auto languagePack = LanguagePack::FromText(id, text);

View File

@@ -33,5 +33,6 @@ struct ILanguagePack
namespace LanguagePackFactory
{
std::unique_ptr<ILanguagePack> FromFile(uint16_t id, const utf8* path);
std::unique_ptr<ILanguagePack> FromLanguageId(uint16_t id);
std::unique_ptr<ILanguagePack> FromText(uint16_t id, const utf8* text);
} // namespace LanguagePackFactory

View File

@@ -11,6 +11,7 @@
#include "../Context.h"
#include "../PlatformEnvironment.h"
#include "../core/Guard.hpp"
#include "../core/Path.hpp"
#include "../interface/Fonts.h"
#include "../object/ObjectManager.h"
@@ -40,10 +41,9 @@ LocalisationService::~LocalisationService() = default;
const char* LocalisationService::GetString(StringId id) const
{
const char* result = nullptr;
if (id == STR_EMPTY)
{
result = "";
return "";
}
else if (id >= BASE_OBJECT_STRING_ID && id < BASE_OBJECT_STRING_ID + MAX_OBJECT_CACHED_STRINGS)
{
@@ -53,24 +53,21 @@ const char* LocalisationService::GetString(StringId id) const
return _objectStrings[index].c_str();
}
result = "(unallocated string)";
return "(unallocated string)";
}
else if (id != STR_NONE)
{
if (_languageCurrent != nullptr)
for (const auto& language : _loadedLanguages)
{
result = _languageCurrent->GetString(id);
}
if (result == nullptr && _languageFallback != nullptr)
{
result = _languageFallback->GetString(id);
}
if (result == nullptr)
{
result = "(undefined string)";
const auto result = language->GetString(id);
if (result != nullptr)
return result;
}
return "(undefined string)";
}
return result;
return nullptr;
}
std::string LocalisationService::GetLanguagePath(uint32_t languageId) const
@@ -98,49 +95,71 @@ void LocalisationService::OpenLanguage(int32_t id)
throw std::invalid_argument("id was undefined");
}
std::string filename;
if (id != LANGUAGE_ENGLISH_UK)
{
filename = GetLanguagePath(LANGUAGE_ENGLISH_UK);
_languageFallback = LanguagePackFactory::FromFile(LANGUAGE_ENGLISH_UK, filename.c_str());
}
filename = GetLanguagePath(id);
_languageCurrent = LanguagePackFactory::FromFile(id, filename.c_str());
if (_languageCurrent != nullptr)
auto preferredLanguage = LanguagePackFactory::FromLanguageId(id);
if (preferredLanguage != nullptr)
{
_currentLanguage = id;
_languageOrder.emplace_back(id);
_loadedLanguages.emplace_back(std::move(preferredLanguage));
TryLoadFonts(*this);
}
else
{
throw std::runtime_error("Unable to open language " + std::to_string(id));
}
auto checkLanguage = LanguagesDescriptors[id].fallback;
while (checkLanguage != LANGUAGE_UNDEFINED)
{
_languageOrder.emplace_back(checkLanguage);
auto fallbackLanguagePack = LanguagePackFactory::FromLanguageId(checkLanguage);
if (fallbackLanguagePack != nullptr)
{
_loadedLanguages.emplace_back(std::move(fallbackLanguagePack));
}
checkLanguage = LanguagesDescriptors[checkLanguage].fallback;
}
if (id != LANGUAGE_ENGLISH_UK)
{
_languageOrder.emplace_back(LANGUAGE_ENGLISH_UK);
auto englishLanguagePack = LanguagePackFactory::FromLanguageId(LANGUAGE_ENGLISH_UK);
if (englishLanguagePack != nullptr)
{
_loadedLanguages.emplace_back(std::move(englishLanguagePack));
}
else
{
throw std::runtime_error("Unable to open the English language file!");
}
}
}
void LocalisationService::CloseLanguages()
{
_languageFallback = nullptr;
_languageCurrent = nullptr;
_languageOrder.clear();
_loadedLanguages.clear();
_currentLanguage = LANGUAGE_UNDEFINED;
}
std::tuple<StringId, StringId, StringId> LocalisationService::GetLocalisedScenarioStrings(
const std::string& scenarioFilename) const
{
auto result0 = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename.c_str(), 0);
auto result1 = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename.c_str(), 1);
auto result2 = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename.c_str(), 2);
Guard::Assert(!_loadedLanguages.empty());
auto result0 = _loadedLanguages[0]->GetScenarioOverrideStringId(scenarioFilename.c_str(), 0);
auto result1 = _loadedLanguages[0]->GetScenarioOverrideStringId(scenarioFilename.c_str(), 1);
auto result2 = _loadedLanguages[0]->GetScenarioOverrideStringId(scenarioFilename.c_str(), 2);
return std::make_tuple(result0, result1, result2);
}
StringId LocalisationService::GetObjectOverrideStringId(std::string_view legacyIdentifier, uint8_t index) const
{
if (_languageCurrent == nullptr)
if (_loadedLanguages.empty())
{
return STR_NONE;
}
return _languageCurrent->GetObjectOverrideStringId(legacyIdentifier, index);
return _loadedLanguages[0]->GetObjectOverrideStringId(legacyIdentifier, index);
}
StringId LocalisationService::AllocateObjectString(const std::string& target)
@@ -176,6 +195,11 @@ void LocalisationService::FreeObjectString(StringId stringId)
}
}
const std::vector<int32_t>& LocalisationService::GetLanguageOrder() const
{
return _languageOrder;
}
int32_t LocalisationService_GetCurrentLanguage()
{
const auto& localisationService = GetContext()->GetLocalisationService();

View File

@@ -34,8 +34,8 @@ namespace OpenRCT2::Localisation
const std::shared_ptr<IPlatformEnvironment> _env;
int32_t _currentLanguage{};
bool _useTrueTypeFont{};
std::unique_ptr<ILanguagePack> _languageFallback;
std::unique_ptr<ILanguagePack> _languageCurrent;
std::vector<int32_t> _languageOrder;
std::vector<std::unique_ptr<ILanguagePack>> _loadedLanguages;
std::stack<StringId> _availableObjectStringIds;
std::vector<std::string> _objectStrings;
@@ -66,6 +66,7 @@ namespace OpenRCT2::Localisation
void CloseLanguages();
StringId AllocateObjectString(const std::string& target);
void FreeObjectString(StringId stringId);
const std::vector<int32_t>& GetLanguageOrder() const;
};
} // namespace OpenRCT2::Localisation

View File

@@ -9,6 +9,7 @@
#include "StringTable.h"
#include "../Context.h"
#include "../core/IStream.hpp"
#include "../core/Json.hpp"
#include "../core/String.hpp"
@@ -154,8 +155,8 @@ void StringTable::SetString(ObjectStringID id, uint8_t language, const std::stri
void StringTable::Sort()
{
auto targetLanguage = LocalisationService_GetCurrentLanguage();
std::sort(_strings.begin(), _strings.end(), [targetLanguage](const StringTableEntry& a, const StringTableEntry& b) -> bool {
const auto& languageOrder = OpenRCT2::GetContext()->GetLocalisationService().GetLanguageOrder();
std::sort(_strings.begin(), _strings.end(), [languageOrder](const StringTableEntry& a, const StringTableEntry& b) -> bool {
if (a.Id == b.Id)
{
if (a.LanguageId == b.LanguageId)
@@ -163,22 +164,16 @@ void StringTable::Sort()
return String::Compare(a.Text, b.Text, true) < 0;
}
if (a.LanguageId == targetLanguage)
for (const auto& language : languageOrder)
{
return true;
}
if (b.LanguageId == targetLanguage)
{
return false;
}
if (a.LanguageId == LANGUAGE_ENGLISH_UK)
{
return true;
}
if (b.LanguageId == LANGUAGE_ENGLISH_UK)
{
return false;
if (a.LanguageId == language)
{
return true;
}
if (b.LanguageId == language)
{
return false;
}
}
return a.LanguageId < b.LanguageId;

View File

@@ -609,6 +609,7 @@ namespace Platform
{ L"eo", LANGUAGE_ESPERANTO },
{ L"es", LANGUAGE_SPANISH },
{ L"fr", LANGUAGE_FRENCH },
{ L"fr-CA", LANGUAGE_FRENCH_CA },
{ L"it", LANGUAGE_ITALIAN },
{ L"ja", LANGUAGE_JAPANESE },
{ L"ko", LANGUAGE_KOREAN },