mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Add [locale] inline tag for per-locale fonts
New `[locale='xx']...[/locale]` markup lets GUI text sections render with a locale-specific font (e.g. CJK) while the rest of the caption keeps the current game font. guiObject.caption = "Hello [locale='ja']世界[/locale], how do you [locale='zh']感覺[/locale]" This is ideal for language pickers and similar UI where you want the language name shown in its own script. This commit unlocks richer, self-explanatory international UI while keeping the legacy text behaviour unchanged.
This commit is contained in:
parent
47454a592e
commit
690838e3dc
15 changed files with 56 additions and 20 deletions
|
|
@ -110,11 +110,22 @@ CFontManager::CFontManager()
|
|||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<CFont> CFontManager::LoadFont(CStrIntern fontName)
|
||||
std::shared_ptr<CFont> CFontManager::LoadFont(CStrIntern fontName, CStrIntern locale)
|
||||
{
|
||||
const std::string locale{g_L10n.GetCurrentLocale() != icu::Locale::getUS() ? g_L10n.GetCurrentLocaleString() : ""};
|
||||
const std::string localeToUse{[&]
|
||||
{
|
||||
if (!locale.empty())
|
||||
return locale.string();
|
||||
|
||||
if (g_L10n.GetCurrentLocale() == icu::Locale::getUS())
|
||||
return std::string{};
|
||||
|
||||
// Use the current locale, but not US English.
|
||||
return g_L10n.GetCurrentLocaleString();
|
||||
} ()
|
||||
};
|
||||
const float guiScale{g_ConfigDB.Get("gui.scale", 1.0f)};
|
||||
CStrIntern localeFontName{fmt::format("{}{}-{}", locale ,fontName.string(), guiScale)};
|
||||
CStrIntern localeFontName{fmt::format("{}{}-{}", localeToUse ,fontName.string(), guiScale)};
|
||||
|
||||
FontsMap::iterator it{m_Fonts.find(localeFontName)};
|
||||
if (it != m_Fonts.end())
|
||||
|
|
@ -148,13 +159,13 @@ std::shared_ptr<CFont> CFontManager::LoadFont(CStrIntern fontName)
|
|||
|
||||
// TODO: explicit Locale like RTL or Arabic fonts.
|
||||
// 1. Locale-specific fonts first
|
||||
if (!locale.empty())
|
||||
if (!localeToUse.empty())
|
||||
{
|
||||
if (fontSpec.bold)
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.bold", locale, fontSpec.type));
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.bold", localeToUse, fontSpec.type));
|
||||
if (fontSpec.italic)
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.italic", locale, fontSpec.type));
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.regular", locale, fontSpec.type));
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.italic", localeToUse, fontSpec.type));
|
||||
candidateFonts.push_back(fmt::format("fonts.{}.{}.regular", localeToUse, fontSpec.type));
|
||||
}
|
||||
|
||||
// 2. Then global fonts
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public:
|
|||
~CFontManager() = default;
|
||||
NONCOPYABLE(CFontManager);
|
||||
|
||||
std::shared_ptr<CFont> LoadFont(CStrIntern fontName);
|
||||
std::shared_ptr<CFont> LoadFont(CStrIntern fontName, CStrIntern locale);
|
||||
void UploadTexturesAtlasToGPU();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -25,8 +25,13 @@
|
|||
#include "renderer/Renderer.h"
|
||||
|
||||
CFontMetrics::CFontMetrics(CStrIntern font)
|
||||
: CFontMetrics(font, CStrIntern())
|
||||
{
|
||||
m_Font = g_Renderer.GetFontManager().LoadFont(font);
|
||||
}
|
||||
|
||||
CFontMetrics::CFontMetrics(CStrIntern font, CStrIntern locale)
|
||||
{
|
||||
m_Font = g_Renderer.GetFontManager().LoadFont(font, locale);
|
||||
}
|
||||
|
||||
float CFontMetrics::GetHeight() const
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class CFontMetrics
|
|||
{
|
||||
public:
|
||||
CFontMetrics(CStrIntern font);
|
||||
CFontMetrics(CStrIntern font, CStrIntern locale);
|
||||
|
||||
float GetHeight() const;
|
||||
float GetCapHeight();
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ CTextRenderer::CTextRenderer()
|
|||
{
|
||||
ResetTranslate();
|
||||
SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
SetCurrentFont(str_sans_10);
|
||||
SetCurrentFont(str_sans_10, CStrIntern{});
|
||||
}
|
||||
|
||||
void CTextRenderer::ResetTranslate(const CVector2D& translate)
|
||||
|
|
@ -84,12 +84,12 @@ void CTextRenderer::SetCurrentColor(const CColor& color)
|
|||
}
|
||||
}
|
||||
|
||||
void CTextRenderer::SetCurrentFont(CStrIntern font)
|
||||
void CTextRenderer::SetCurrentFont(CStrIntern font, CStrIntern locale)
|
||||
{
|
||||
if (font != m_FontName)
|
||||
{
|
||||
m_FontName = font;
|
||||
m_Font = g_Renderer.GetFontManager().LoadFont(font);
|
||||
m_Font = g_Renderer.GetFontManager().LoadFont(font, locale);
|
||||
m_Dirty = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
/**
|
||||
* Set the font for subsequent print calls.
|
||||
*/
|
||||
void SetCurrentFont(CStrIntern font);
|
||||
void SetCurrentFont(CStrIntern font, CStrIntern locale);
|
||||
|
||||
/**
|
||||
* Print formatted text at (0,0) under the current transform,
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ void CGUIText::Draw(CGUI& pGUI, CCanvas2D& canvas, const CGUIColor& DefaultColor
|
|||
continue;
|
||||
|
||||
textRenderer.SetCurrentColor(tc.m_UseCustomColor ? tc.m_Color : DefaultColor);
|
||||
textRenderer.SetCurrentFont(tc.m_Font);
|
||||
textRenderer.SetCurrentFont(tc.m_Font, tc.m_FontLocale);
|
||||
textRenderer.Put(pos.X + tc.m_Pos.X, pos.Y + tc.m_Pos.Y, &tc.m_String);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,19 @@ public:
|
|||
*/
|
||||
CStrIntern m_Font;
|
||||
|
||||
/**
|
||||
* BCP-47 locale tag (e.g. `"en"`, `"ja"`, `"zh-hans"`) that tells the
|
||||
* FontManager which per-locale font to use for this portion of text.
|
||||
*
|
||||
* If the string is non-empty, the renderer tries to substitute a font
|
||||
* registered for that locale; otherwise it falls back to the game-wide
|
||||
* UI font so legacy captions behave exactly as before.
|
||||
*
|
||||
* The value is filled in by the `[locale='xx']…[/locale]` inline-markup
|
||||
* parser and read during glyph layout.
|
||||
*/
|
||||
CStrIntern m_FontLocale;
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1255,7 +1255,7 @@ void CInput::DrawContent(CCanvas2D& canvas)
|
|||
const float ls{font.GetHeight()};
|
||||
|
||||
CTextRenderer textRenderer;
|
||||
textRenderer.SetCurrentFont(font_name);
|
||||
textRenderer.SetCurrentFont(font_name, CStrIntern{});
|
||||
|
||||
textRenderer.Translate(
|
||||
(float)(int)(m_CachedActualSize.left) + m_BufferZone,
|
||||
|
|
|
|||
|
|
@ -207,6 +207,9 @@ void CGUIString::GenerateTextCall(const CGUI& pGUI, SFeedback& Feedback, CStrInt
|
|||
// TODO Gee: (2004-08-15) Check if Font exists?
|
||||
TextCall.m_Font = CStrIntern(utf8_from_wstring(tag.m_TagValue));
|
||||
break;
|
||||
case TextChunk::Tag::TAG_LOCALE:
|
||||
TextCall.m_FontLocale = CStrIntern(utf8_from_wstring(tag.m_TagValue));
|
||||
break;
|
||||
case TextChunk::Tag::TAG_TOOLTIP:
|
||||
TextCall.m_Tooltip = tag.m_TagValue;
|
||||
break;
|
||||
|
|
@ -219,7 +222,7 @@ void CGUIString::GenerateTextCall(const CGUI& pGUI, SFeedback& Feedback, CStrInt
|
|||
// Calculate the size of the font.
|
||||
CSize2D size;
|
||||
float cx, cy;
|
||||
CFontMetrics font (TextCall.m_Font);
|
||||
CFontMetrics font{TextCall.m_Font, TextCall.m_FontLocale};
|
||||
font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy);
|
||||
|
||||
size.Width = cx;
|
||||
|
|
@ -273,6 +276,8 @@ CGUIString::TextChunk::Tag::TagType CGUIString::TextChunk::Tag::GetTagType(const
|
|||
return TAG_COLOR;
|
||||
if (tagtype == L"font")
|
||||
return TAG_FONT;
|
||||
if (tagtype == L"locale")
|
||||
return TAG_LOCALE;
|
||||
if (tagtype == L"icon")
|
||||
return TAG_ICON;
|
||||
if (tagtype == L"imgleft")
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public:
|
|||
TAG_B,
|
||||
TAG_I,
|
||||
TAG_FONT,
|
||||
TAG_LOCALE,
|
||||
TAG_SIZE,
|
||||
TAG_COLOR,
|
||||
TAG_IMGLEFT,
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ void CConsole::Render(CCanvas2D& canvas)
|
|||
DrawWindow(canvas);
|
||||
|
||||
CTextRenderer textRenderer;
|
||||
textRenderer.SetCurrentFont(CStrIntern(m_consoleFont));
|
||||
textRenderer.SetCurrentFont(CStrIntern{m_consoleFont}, CStrIntern{});
|
||||
// Animation: slide in from top of screen.
|
||||
const float deltaY = (1.0f - m_VisibleFrac) * m_Height;
|
||||
textRenderer.Translate(m_X, m_Y - deltaY);
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ void CLogger::Render(CCanvas2D& canvas)
|
|||
float height{font.GetHeight()};
|
||||
|
||||
CTextRenderer textRenderer;
|
||||
textRenderer.SetCurrentFont(font_name);
|
||||
textRenderer.SetCurrentFont(font_name, CStrIntern{});
|
||||
textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Offset by an extra 35px vertically to avoid the top bar.
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ void CProfileViewer::RenderProfile(CCanvas2D& canvas)
|
|||
|
||||
// Print table and column titles.
|
||||
CTextRenderer textRenderer;
|
||||
textRenderer.SetCurrentFont(font_name);
|
||||
textRenderer.SetCurrentFont(font_name, CStrIntern{});
|
||||
textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
textRenderer.PrintfAt(2.0f, height, L"%hs", table->GetTitle().c_str());
|
||||
textRenderer.Translate(22.0f, height*2.0f);
|
||||
|
|
|
|||
|
|
@ -793,7 +793,7 @@ void TerrainRenderer::RenderPriorities(CCanvas2D& canvas, int cullGroup)
|
|||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
CTextRenderer textRenderer;
|
||||
textRenderer.SetCurrentFont(CStrIntern("mono-stroke-10"));
|
||||
textRenderer.SetCurrentFont(CStrIntern{"mono-stroke-10"}, CStrIntern{});
|
||||
textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
|
||||
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
||||
|
|
|
|||
Loading…
Reference in a new issue