mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #7806 from Gymnasiast/feature/rtl-rendering
Fix RTL text rendering for Linux / macOS
This commit is contained in:
commit
211bd84cc3
|
@ -23,30 +23,30 @@
|
|||
// clang-format off
|
||||
const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] =
|
||||
{
|
||||
{ "", "", "", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_UNDEFINED
|
||||
{ "ar-EG", "Arabic (experimental)", "Arabic (experimental)", FAMILY(&TTFFamilySansSerif), RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_ARABIC
|
||||
{ "ca-ES", "Catalan", u8"Català", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SPANISH }, // LANGUAGE_CATALAN
|
||||
{ "zh-CN", "Chinese (Simplified)", "Chinese (Simplified)", FAMILY(&TTFFamilyChineseSimplified), RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED }, // LANGUAGE_CHINESE_SIMPLIFIED
|
||||
{ "zh-TW", "Chinese (Traditional)", "Chinese (Traditional)", FAMILY(&TTFFamilyChineseTraditional), RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL }, // LANGUAGE_CHINESE_TRADITIONAL
|
||||
{ "cs-CZ", "Czech", "Czech", FAMILY(&TTFFamilySansSerif), RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_CZECH
|
||||
{ "da-DK", "Danish", "Dansk", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_DANISH
|
||||
{ "de-DE", "German", "Deutsch", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_GERMAN }, // LANGUAGE_GERMAN
|
||||
{ "en-GB", "English (UK)", "English (UK)", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_ENGLISH_UK
|
||||
{ "en-US", "English (US)", "English (US)", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_US }, // LANGUAGE_ENGLISH_US
|
||||
{ "es-ES", "Spanish", u8"Español", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SPANISH }, // LANGUAGE_SPANISH
|
||||
{ "fr-FR", "French", u8"Français", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_FRENCH }, // LANGUAGE_FRENCH
|
||||
{ "it-IT", "Italian", "Italiano", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ITALIAN }, // LANGUAGE_ITALIAN
|
||||
{ "ja-JP", "Japanese", "Japanese", FAMILY(&TTFFamilyJapanese), RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_JAPANESE
|
||||
{ "ko-KR", "Korean", "Korean", FAMILY(&TTFFamilyKorean), RCT2_LANGUAGE_ID_KOREAN }, // LANGUAGE_KOREAN
|
||||
{ "hu-HU", "Hungarian", "Magyar", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_HUNGARIAN
|
||||
{ "nl-NL", "Dutch", "Nederlands", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_DUTCH }, // LANGUAGE_DUTCH
|
||||
{ "nb-NO", "Norwegian", "Norsk", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_NORWEGIAN
|
||||
{ "pl-PL", "Polish", "Polski", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_POLISH
|
||||
{ "pt-BR", "Portuguese (BR)", u8"Português (BR)", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_PORTUGUESE }, // LANGUAGE_PORTUGUESE_BR
|
||||
{ "ru-RU", "Russian", u8"Русский", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_RUSSIAN
|
||||
{ "fi-FI", "Finnish", "Suomi", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_FINNISH
|
||||
{ "sv-SE", "Swedish", "Svenska", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SWEDISH }, // LANGUAGE_SWEDISH
|
||||
{ "tr-TR", "Turkish", "Türkçe", FAMILY_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_TURKISH
|
||||
{ "", "", "", 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", "Czech", FAMILY(&TTFFamilySansSerif), 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
|
||||
{ "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
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ struct language_descriptor
|
|||
#else
|
||||
void* font_family;
|
||||
#endif
|
||||
RCT2LanguageId rct2_original_id;
|
||||
bool isRtl;
|
||||
};
|
||||
|
||||
extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT];
|
||||
|
|
|
@ -15,11 +15,20 @@
|
|||
#include "../core/String.hpp"
|
||||
#include "../core/StringBuilder.hpp"
|
||||
#include "../core/StringReader.hpp"
|
||||
#include "Language.h"
|
||||
#include "Localisation.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#ifndef _WIN32
|
||||
# include <unicode/ubidi.h>
|
||||
# include <unicode/unistr.h>
|
||||
# include <unicode/ushape.h>
|
||||
# include <unicode/ustring.h>
|
||||
# include <unicode/utf.h>
|
||||
# include <unicode/utypes.h>
|
||||
#endif
|
||||
|
||||
// Don't try to load more than language files that exceed 64 MiB
|
||||
constexpr uint64_t MAX_LANGUAGE_SIZE = 64 * 1024 * 1024;
|
||||
|
@ -564,7 +573,17 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
auto s = std::string(sb.GetBuffer(), sb.GetLength());
|
||||
std::string s;
|
||||
if (LanguagesDescriptors[_id].isRtl)
|
||||
{
|
||||
auto ts = std::string(sb.GetBuffer(), sb.GetLength());
|
||||
s = FixRTL(ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = std::string(sb.GetBuffer(), sb.GetLength());
|
||||
}
|
||||
|
||||
if (_currentGroup.empty())
|
||||
{
|
||||
// Make sure the list is big enough to contain this string id
|
||||
|
@ -627,6 +646,37 @@ private:
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string FixRTL(std::string& input)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return input;
|
||||
#else
|
||||
UErrorCode err = (UErrorCode)0;
|
||||
// Force a hard left-to-right at the beginning (will mess up mixed strings' word order otherwise)
|
||||
std::string text2 = std::string(u8"\xE2\x80\xAA") + input;
|
||||
|
||||
icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(icu::StringPiece(text2));
|
||||
|
||||
int32_t length = ustr.length();
|
||||
icu::UnicodeString reordered;
|
||||
icu::UnicodeString shaped;
|
||||
UBiDi* bidi = ubidi_openSized(length, 0, &err);
|
||||
// UBIDI_DEFAULT_LTR preserves formatting codes.
|
||||
ubidi_setPara(bidi, ustr.getBuffer(), length, UBIDI_DEFAULT_LTR, nullptr, &err);
|
||||
ubidi_writeReordered(bidi, reordered.getBuffer(length), length, UBIDI_DO_MIRRORING | UBIDI_REMOVE_BIDI_CONTROLS, &err);
|
||||
ubidi_close(bidi);
|
||||
reordered.releaseBuffer(length);
|
||||
u_shapeArabic(
|
||||
reordered.getBuffer(), length, shaped.getBuffer(length), length,
|
||||
U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &err);
|
||||
shaped.releaseBuffer(length);
|
||||
|
||||
std::string cppstring;
|
||||
shaped.toUTF8String(cppstring);
|
||||
return cppstring;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
namespace LanguagePackFactory
|
||||
|
|
|
@ -9,10 +9,15 @@
|
|||
|
||||
#include "openrct2/localisation/LanguagePack.h"
|
||||
|
||||
#include "openrct2/localisation/Language.h"
|
||||
#include "openrct2/localisation/StringIds.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
const language_descriptor LanguagesDescriptors[] = {};
|
||||
#endif
|
||||
|
||||
class LanguagePackTest : public testing::Test
|
||||
{
|
||||
protected:
|
||||
|
|
Loading…
Reference in New Issue