From 94b8928dcdb63b3a5af499216bb9bd1f461e44aa Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Mon, 2 Jan 2023 21:17:04 +0100 Subject: [PATCH 1/5] Change loaded languages to a vector --- .../localisation/LocalisationService.cpp | 58 +++++++++---------- .../localisation/LocalisationService.h | 3 +- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index cbb810202d..49baa93c46 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -40,10 +40,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 +52,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 @@ -99,48 +95,52 @@ void LocalisationService::OpenLanguage(int32_t id) } 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::FromFile(id, filename.c_str()); + if (preferredLanguage != nullptr) { _currentLanguage = id; + _loadedLanguages.emplace_back(std::move(preferredLanguage)); TryLoadFonts(*this); } else { throw std::runtime_error("Unable to open language " + std::to_string(id)); } + + if (id != LANGUAGE_ENGLISH_UK) + { + filename = GetLanguagePath(LANGUAGE_ENGLISH_UK); + _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(LANGUAGE_ENGLISH_UK, filename.c_str())); + } } void LocalisationService::CloseLanguages() { - _languageFallback = nullptr; - _languageCurrent = nullptr; + for (auto& language : _loadedLanguages) + { + language = nullptr; + } + _loadedLanguages.clear(); _currentLanguage = LANGUAGE_UNDEFINED; } std::tuple 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); + 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) diff --git a/src/openrct2/localisation/LocalisationService.h b/src/openrct2/localisation/LocalisationService.h index 30cf879d28..2e45964459 100644 --- a/src/openrct2/localisation/LocalisationService.h +++ b/src/openrct2/localisation/LocalisationService.h @@ -34,8 +34,7 @@ namespace OpenRCT2::Localisation const std::shared_ptr _env; int32_t _currentLanguage{}; bool _useTrueTypeFont{}; - std::unique_ptr _languageFallback; - std::unique_ptr _languageCurrent; + std::vector> _loadedLanguages; std::stack _availableObjectStringIds; std::vector _objectStrings; From 08270d7d31a498a2b9fa8e1f8608c85816ce80c7 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Mon, 2 Jan 2023 21:33:26 +0100 Subject: [PATCH 2/5] Close #18945: Allow languages to fall back to more than just en-GB --- distribution/changelog.txt | 1 + src/openrct2/localisation/Language.cpp | 52 +++++++-------- src/openrct2/localisation/Language.h | 1 + .../localisation/LocalisationService.cpp | 7 ++ src/openrct2/object/StringTable.cpp | 64 +++++++++++-------- 5 files changed, 73 insertions(+), 52 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 8a4091a47e..409b43a495 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -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. diff --git a/src/openrct2/localisation/Language.cpp b/src/openrct2/localisation/Language.cpp index 777ae28413..4c88d1b3ee 100644 --- a/src/openrct2/localisation/Language.cpp +++ b/src/openrct2/localisation/Language.cpp @@ -23,32 +23,32 @@ // 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 + { "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 diff --git a/src/openrct2/localisation/Language.h b/src/openrct2/localisation/Language.h index 75d4071141..3d5a395ca5 100644 --- a/src/openrct2/localisation/Language.h +++ b/src/openrct2/localisation/Language.h @@ -75,6 +75,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 diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index 49baa93c46..898137dd59 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -108,6 +108,13 @@ void LocalisationService::OpenLanguage(int32_t id) throw std::runtime_error("Unable to open language " + std::to_string(id)); } + const auto fallback = LanguagesDescriptors[id].fallback; + if (fallback != LANGUAGE_UNDEFINED) + { + filename = GetLanguagePath(fallback); + _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(fallback, filename.c_str())); + } + if (id != LANGUAGE_ENGLISH_UK) { filename = GetLanguagePath(LANGUAGE_ENGLISH_UK); diff --git a/src/openrct2/object/StringTable.cpp b/src/openrct2/object/StringTable.cpp index 09464e31ec..6e97a8dd33 100644 --- a/src/openrct2/object/StringTable.cpp +++ b/src/openrct2/object/StringTable.cpp @@ -155,34 +155,46 @@ 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 { - if (a.Id == b.Id) - { - if (a.LanguageId == b.LanguageId) + auto fallbackLanguage = LanguagesDescriptors[targetLanguage].fallback; + std::sort( + _strings.begin(), _strings.end(), + [targetLanguage, fallbackLanguage](const StringTableEntry& a, const StringTableEntry& b) -> bool { + if (a.Id == b.Id) { - return String::Compare(a.Text, b.Text, true) < 0; - } + if (a.LanguageId == b.LanguageId) + { + return String::Compare(a.Text, b.Text, true) < 0; + } - if (a.LanguageId == targetLanguage) - { - return true; - } - if (b.LanguageId == targetLanguage) - { - return false; - } + if (a.LanguageId == targetLanguage) + { + 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 (fallbackLanguage != LANGUAGE_UNDEFINED) + { + if (a.LanguageId == fallbackLanguage) + return true; - return a.LanguageId < b.LanguageId; - } - return a.Id < b.Id; - }); + if (b.LanguageId == fallbackLanguage) + return false; + } + + if (a.LanguageId == LANGUAGE_ENGLISH_UK) + { + return true; + } + if (b.LanguageId == LANGUAGE_ENGLISH_UK) + { + return false; + } + + return a.LanguageId < b.LanguageId; + } + return a.Id < b.Id; + }); } From 43988aa50f11e9d3cb3ad461428f9b5fb48954f4 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Tue, 3 Jan 2023 22:21:16 +0100 Subject: [PATCH 3/5] Allow cascaded fallback languages --- .../localisation/LocalisationService.cpp | 21 ++++-- .../localisation/LocalisationService.h | 2 + src/openrct2/object/StringTable.cpp | 65 +++++++------------ 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index 898137dd59..eee05c05e4 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -100,6 +100,7 @@ void LocalisationService::OpenLanguage(int32_t id) if (preferredLanguage != nullptr) { _currentLanguage = id; + _languageOrder.emplace_back(id); _loadedLanguages.emplace_back(std::move(preferredLanguage)); TryLoadFonts(*this); } @@ -108,15 +109,21 @@ void LocalisationService::OpenLanguage(int32_t id) throw std::runtime_error("Unable to open language " + std::to_string(id)); } - const auto fallback = LanguagesDescriptors[id].fallback; - if (fallback != LANGUAGE_UNDEFINED) + auto checkLanguage = LanguagesDescriptors[id].fallback; + while (true) { - filename = GetLanguagePath(fallback); - _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(fallback, filename.c_str())); + if (checkLanguage == LANGUAGE_UNDEFINED) + break; + + _languageOrder.emplace_back(checkLanguage); + filename = GetLanguagePath(checkLanguage); + _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(checkLanguage, filename.c_str())); + checkLanguage = LanguagesDescriptors[checkLanguage].fallback; } if (id != LANGUAGE_ENGLISH_UK) { + _languageOrder.emplace_back(LANGUAGE_ENGLISH_UK); filename = GetLanguagePath(LANGUAGE_ENGLISH_UK); _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(LANGUAGE_ENGLISH_UK, filename.c_str())); } @@ -128,6 +135,7 @@ void LocalisationService::CloseLanguages() { language = nullptr; } + _languageOrder.clear(); _loadedLanguages.clear(); _currentLanguage = LANGUAGE_UNDEFINED; } @@ -183,6 +191,11 @@ void LocalisationService::FreeObjectString(StringId stringId) } } +const std::vector& LocalisationService::GetLanguageOrder() const +{ + return _languageOrder; +} + int32_t LocalisationService_GetCurrentLanguage() { const auto& localisationService = GetContext()->GetLocalisationService(); diff --git a/src/openrct2/localisation/LocalisationService.h b/src/openrct2/localisation/LocalisationService.h index 2e45964459..d7b76b4c52 100644 --- a/src/openrct2/localisation/LocalisationService.h +++ b/src/openrct2/localisation/LocalisationService.h @@ -34,6 +34,7 @@ namespace OpenRCT2::Localisation const std::shared_ptr _env; int32_t _currentLanguage{}; bool _useTrueTypeFont{}; + std::vector _languageOrder; std::vector> _loadedLanguages; std::stack _availableObjectStringIds; std::vector _objectStrings; @@ -65,6 +66,7 @@ namespace OpenRCT2::Localisation void CloseLanguages(); StringId AllocateObjectString(const std::string& target); void FreeObjectString(StringId stringId); + const std::vector& GetLanguageOrder() const; }; } // namespace OpenRCT2::Localisation diff --git a/src/openrct2/object/StringTable.cpp b/src/openrct2/object/StringTable.cpp index 6e97a8dd33..ad0cda0682 100644 --- a/src/openrct2/object/StringTable.cpp +++ b/src/openrct2/object/StringTable.cpp @@ -9,6 +9,7 @@ #include "StringTable.h" +#include "../Context.h" #include "../core/IStream.hpp" #include "../core/Json.hpp" #include "../core/String.hpp" @@ -154,47 +155,29 @@ void StringTable::SetString(ObjectStringID id, uint8_t language, const std::stri void StringTable::Sort() { - auto targetLanguage = LocalisationService_GetCurrentLanguage(); - auto fallbackLanguage = LanguagesDescriptors[targetLanguage].fallback; - std::sort( - _strings.begin(), _strings.end(), - [targetLanguage, fallbackLanguage](const StringTableEntry& a, const StringTableEntry& b) -> bool { - if (a.Id == b.Id) + 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) { - if (a.LanguageId == b.LanguageId) - { - return String::Compare(a.Text, b.Text, true) < 0; - } - - if (a.LanguageId == targetLanguage) - { - return true; - } - if (b.LanguageId == targetLanguage) - { - return false; - } - - if (fallbackLanguage != LANGUAGE_UNDEFINED) - { - if (a.LanguageId == fallbackLanguage) - return true; - - if (b.LanguageId == fallbackLanguage) - return false; - } - - if (a.LanguageId == LANGUAGE_ENGLISH_UK) - { - return true; - } - if (b.LanguageId == LANGUAGE_ENGLISH_UK) - { - return false; - } - - return a.LanguageId < b.LanguageId; + return String::Compare(a.Text, b.Text, true) < 0; } - return a.Id < b.Id; - }); + + for (const auto& language : languageOrder) + { + if (a.LanguageId == language) + { + return true; + } + if (b.LanguageId == language) + { + return false; + } + } + + return a.LanguageId < b.LanguageId; + } + return a.Id < b.Id; + }); } From 784b7d9fccc1d5c5cb3389df4e79681b08281122 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Wed, 4 Jan 2023 19:39:14 +0100 Subject: [PATCH 4/5] Apply review requests from @tupaschoal --- src/openrct2/localisation/LanguagePack.cpp | 8 +++++ src/openrct2/localisation/LanguagePack.h | 1 + .../localisation/LocalisationService.cpp | 34 +++++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/openrct2/localisation/LanguagePack.cpp b/src/openrct2/localisation/LanguagePack.cpp index a82707245a..bda03db897 100644 --- a/src/openrct2/localisation/LanguagePack.cpp +++ b/src/openrct2/localisation/LanguagePack.cpp @@ -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 #include @@ -580,6 +582,12 @@ namespace LanguagePackFactory return languagePack; } + std::unique_ptr FromLanguageId(uint16_t id) + { + auto path = OpenRCT2::GetContext()->GetLocalisationService().GetLanguagePath(id); + return LanguagePack::FromFile(id, path.c_str()); + } + std::unique_ptr FromText(uint16_t id, const utf8* text) { auto languagePack = LanguagePack::FromText(id, text); diff --git a/src/openrct2/localisation/LanguagePack.h b/src/openrct2/localisation/LanguagePack.h index b6e63859ea..f5b8b9e8be 100644 --- a/src/openrct2/localisation/LanguagePack.h +++ b/src/openrct2/localisation/LanguagePack.h @@ -33,5 +33,6 @@ struct ILanguagePack namespace LanguagePackFactory { std::unique_ptr FromFile(uint16_t id, const utf8* path); + std::unique_ptr FromLanguageId(uint16_t id); std::unique_ptr FromText(uint16_t id, const utf8* text); } // namespace LanguagePackFactory diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index eee05c05e4..6716223312 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -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" @@ -94,9 +95,7 @@ void LocalisationService::OpenLanguage(int32_t id) throw std::invalid_argument("id was undefined"); } - std::string filename; - filename = GetLanguagePath(id); - auto preferredLanguage = LanguagePackFactory::FromFile(id, filename.c_str()); + auto preferredLanguage = LanguagePackFactory::FromLanguageId(id); if (preferredLanguage != nullptr) { _currentLanguage = id; @@ -110,31 +109,35 @@ void LocalisationService::OpenLanguage(int32_t id) } auto checkLanguage = LanguagesDescriptors[id].fallback; - while (true) + while (checkLanguage != LANGUAGE_UNDEFINED) { - if (checkLanguage == LANGUAGE_UNDEFINED) - break; - _languageOrder.emplace_back(checkLanguage); - filename = GetLanguagePath(checkLanguage); - _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(checkLanguage, filename.c_str())); + 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); - filename = GetLanguagePath(LANGUAGE_ENGLISH_UK); - _loadedLanguages.emplace_back(LanguagePackFactory::FromFile(LANGUAGE_ENGLISH_UK, filename.c_str())); + 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() { - for (auto& language : _loadedLanguages) - { - language = nullptr; - } _languageOrder.clear(); _loadedLanguages.clear(); _currentLanguage = LANGUAGE_UNDEFINED; @@ -143,6 +146,7 @@ void LocalisationService::CloseLanguages() std::tuple LocalisationService::GetLocalisedScenarioStrings( const std::string& scenarioFilename) const { + 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); From f4f6bfd5c5d6916ccf555eeec56a90cf4ede2d91 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Wed, 4 Jan 2023 19:42:38 +0100 Subject: [PATCH 5/5] Add Canadian French --- src/openrct2/localisation/Language.cpp | 1 + src/openrct2/localisation/Language.h | 1 + src/openrct2/platform/Platform.Win32.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/openrct2/localisation/Language.cpp b/src/openrct2/localisation/Language.cpp index 4c88d1b3ee..7f0eb9d86e 100644 --- a/src/openrct2/localisation/Language.cpp +++ b/src/openrct2/localisation/Language.cpp @@ -36,6 +36,7 @@ const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] = { "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 diff --git a/src/openrct2/localisation/Language.h b/src/openrct2/localisation/Language.h index 3d5a395ca5..20221ca5c6 100644 --- a/src/openrct2/localisation/Language.h +++ b/src/openrct2/localisation/Language.h @@ -30,6 +30,7 @@ enum LANGUAGE_ESPERANTO, LANGUAGE_SPANISH, LANGUAGE_FRENCH, + LANGUAGE_FRENCH_CA, LANGUAGE_ITALIAN, LANGUAGE_JAPANESE, LANGUAGE_KOREAN, diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index 9e735b4bc6..0c2d189710 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -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 },