Skip to content

Commit b101e01

Browse files
DeaTh-Gbrianuuu
andauthored
Japanese localization (#415)
* translate most option names and setting names * add most header/button guide japanese localizations * include furigana usage guidance for japanese localization * remove os message window furigana note * fix incorrect kana usage for 'lock' * add more option localization * translate achievement notification option * remove english battle theme description from japanese * fix compilation errors * Japanese localization 1st pass * Revert JP localization taken from in-game * Use "Window Size" * add support for zero width line break hints * add dirty hack for kana being clipped at the right edge of the info panel * Changed line to original meaning * Added zero width spaces to option descriptions * Japanese localization 2nd pass * Remove furigana from Video_BackendError * add more japanese specific hacks for installer_wizard description * locale small fixes * Update config_locale.cpp * options menu scroll fixes, minor localization touchups * adjust installer wizard text spacing * fix installer wizard text positioning when a line starts with a normal kana in japanese * Installer adjustment * option fixes * Added missing line break on introduction * do touchups to message window annotation drop shadow * adjust spacing in TitleMissingDLC text to fit furigana properly * add brianuuuSonic to credits * change capitalization of xbox in xbox color correction * remove usage of temporaries * tweak cutscene aspect ratio description * add missing credit for german translation * update resources submodule --------- Co-authored-by: brianuuu <38166666+brianuuu@users.noreply.github.com>
1 parent de71487 commit b101e01

10 files changed

Lines changed: 376 additions & 128 deletions

File tree

UnleashedRecomp/gpu/imgui/imgui_font_builder.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,19 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
247247
u1 / packer.width,
248248
v0 / packer.height,
249249
advance);
250+
251+
config.DstFont->AddGlyph(
252+
&config,
253+
0x200B,
254+
0.0f,
255+
0.0f,
256+
0.0f,
257+
0.0f,
258+
0.0f,
259+
0.0f,
260+
0.0f,
261+
0.0f,
262+
0.0f);
250263
}
251264

252265
config.DstFont->BuildLookupTable();

UnleashedRecomp/locale/config_locale.cpp

Lines changed: 105 additions & 58 deletions
Large diffs are not rendered by default.

UnleashedRecomp/locale/locale.cpp

Lines changed: 98 additions & 60 deletions
Large diffs are not rendered by default.

UnleashedRecomp/res/credits.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
22

3-
inline std::array<const char*, 15> g_credits =
3+
inline std::array<const char*, 17> g_credits =
44
{
55
"Skyth",
66
"Hyper",
@@ -17,4 +17,6 @@ inline std::array<const char*, 15> g_credits =
1717
"Goalringmod27",
1818
"M&M",
1919
"DaGuAr",
20+
"brianuuuSonic",
21+
"Kitzuku"
2022
};

UnleashedRecomp/ui/imgui_utils.cpp

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,17 +464,39 @@ std::vector<std::string> Split(const char* strStart, const ImFont* font, float f
464464
const bool wordWrapEnabled = (maxWidth > 0.0f);
465465
const char *wordWrapEOL = nullptr;
466466

467+
auto IsKanji = [](const char* str, const char* strEnd)
468+
{
469+
const char* tempStr = str;
470+
unsigned int c = (unsigned int)*tempStr;
471+
if (c < 0x80)
472+
tempStr += 1;
473+
else
474+
tempStr += ImTextCharFromUtf8(&c, tempStr, strEnd);
475+
476+
// Basic CJK and CJK Extension A
477+
return (c >= 0x4E00 && c <= 0x9FBF) || (c >= 0x3400 && c <= 0x4DBF);
478+
};
479+
467480
while (*str != 0)
468481
{
469482
if (wordWrapEnabled)
470483
{
471484
if (wordWrapEOL == nullptr)
472485
{
473-
wordWrapEOL = font->CalcWordWrapPositionA(scale, str, strEnd, maxWidth - lineWidth);
486+
wordWrapEOL = CalcWordWrapPositionA(font, scale, str, strEnd, maxWidth - lineWidth);
474487
}
475488

476489
if (str >= wordWrapEOL)
477490
{
491+
if (IsKanji(str, strEnd))
492+
{
493+
// If the current character is Kanji, move back to prevent splitting Kanji
494+
while (str > lineStart && IsKanji(str - 3, strEnd))
495+
{
496+
str -= 3;
497+
}
498+
}
499+
478500
if (textWidth < lineWidth)
479501
textWidth = lineWidth;
480502

@@ -648,16 +670,22 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt
648670
return MeasureCentredParagraph(font, fontSize, lineMargin, lines);
649671
}
650672

651-
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred)
673+
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred, bool leadingSpace)
652674
{
653675
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
654676

655677
const auto input = RemoveRubyAnnotations(text);
656678
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
657679

658680
for (auto& line : lines)
681+
{
659682
line = ReAddRubyAnnotations(line, input.second);
660-
683+
if (!line.empty() && line.substr(0, 3) != "" && leadingSpace)
684+
{
685+
line.insert(0, " ");
686+
}
687+
}
688+
661689
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
662690
auto offsetY = 0.0f;
663691

@@ -826,3 +854,105 @@ void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
826854
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
827855
}
828856
}
857+
858+
// Taken from ImGui because we need to modify to break for '\u200B\ too
859+
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
860+
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
861+
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
862+
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width)
863+
{
864+
// For references, possible wrap point marked with ^
865+
// "aaa bbb, ccc,ddd. eee fff. ggg!"
866+
// ^ ^ ^ ^ ^__ ^ ^
867+
868+
// List of hardcoded separators: .,;!?'"
869+
870+
// Skip extra blanks after a line returns (that includes not counting them in width computation)
871+
// e.g. "Hello world" --> "Hello" "World"
872+
873+
// Cut words that cannot possibly fit within one line.
874+
// e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
875+
float line_width = 0.0f;
876+
float word_width = 0.0f;
877+
float blank_width = 0.0f;
878+
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
879+
880+
const char* word_end = text;
881+
const char* prev_word_end = NULL;
882+
bool inside_word = true;
883+
884+
const char* s = text;
885+
IM_ASSERT(text_end != NULL);
886+
while (s < text_end)
887+
{
888+
unsigned int c = (unsigned int)*s;
889+
const char* next_s;
890+
if (c < 0x80)
891+
next_s = s + 1;
892+
else
893+
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
894+
895+
if (c < 32)
896+
{
897+
if (c == '\n')
898+
{
899+
line_width = word_width = blank_width = 0.0f;
900+
inside_word = true;
901+
s = next_s;
902+
continue;
903+
}
904+
if (c == '\r')
905+
{
906+
s = next_s;
907+
continue;
908+
}
909+
}
910+
911+
const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX);
912+
if (ImCharIsBlankW(c) || c == 0x200B)
913+
{
914+
if (inside_word)
915+
{
916+
line_width += blank_width;
917+
blank_width = 0.0f;
918+
word_end = s;
919+
}
920+
blank_width += char_width;
921+
inside_word = false;
922+
}
923+
else
924+
{
925+
word_width += char_width;
926+
if (inside_word)
927+
{
928+
word_end = next_s;
929+
}
930+
else
931+
{
932+
prev_word_end = word_end;
933+
line_width += word_width + blank_width;
934+
word_width = blank_width = 0.0f;
935+
}
936+
937+
// Allow wrapping after punctuation.
938+
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
939+
}
940+
941+
// We ignore blank width at the end of the line (they can be skipped)
942+
if (line_width + word_width > wrap_width)
943+
{
944+
// Words that cannot possibly fit within an entire line will be cut anywhere.
945+
if (word_width < wrap_width)
946+
s = prev_word_end ? prev_word_end : word_end;
947+
break;
948+
}
949+
950+
s = next_s;
951+
}
952+
953+
// Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
954+
// +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
955+
if (s == text && text < text_end)
956+
return s + 1;
957+
return s;
958+
}

UnleashedRecomp/ui/imgui_utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
7272
std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& annotatedLine);
7373
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector<std::string>& lines);
7474
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text);
75-
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred = false);
75+
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred = false, bool leadingSpace = false);
7676
float Lerp(float a, float b, float t);
7777
float Cubic(float a, float b, float t);
7878
float Hermite(float a, float b, float t);
@@ -81,3 +81,4 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t);
8181
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
8282
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
8383
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
84+
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width);

UnleashedRecomp/ui/installer_wizard.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,14 @@ static void DrawDescriptionContainer()
736736
}
737737
else if (g_currentPage == WizardPage::InstallFailed)
738738
{
739+
// Japanese needs text to be brought in by a normal width space
740+
// as it allows for text to begin further than others for
741+
// special characters.
742+
if (Config::Language == ELanguage::Japanese)
743+
{
744+
strncat(descriptionText, " ", 1);
745+
}
746+
739747
strncat(descriptionText, g_installerErrorMessage.c_str(), sizeof(descriptionText) - 1);
740748
}
741749

@@ -769,6 +777,8 @@ static void DrawDescriptionContainer()
769777

770778
textX += annotationFontSize;
771779
textY += annotationFontSize;
780+
781+
lineWidth += annotationFontSize;
772782
}
773783

774784
drawList->PushClipRect(clipRectMin, clipRectMax, false);
@@ -788,7 +798,9 @@ static void DrawDescriptionContainer()
788798
[=](const char* str, float size, ImVec2 pos)
789799
{
790800
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str);
791-
}
801+
},
802+
false,
803+
Config::Language == ELanguage::Japanese
792804
);
793805

794806
drawList->PopClipRect();

UnleashedRecomp/ui/message_window.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ void MessageWindow::Draw()
370370
},
371371
[=](const char* str, float size, ImVec2 pos)
372372
{
373-
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.0f);
373+
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.5f, 1.5f);
374374
},
375375

376376
true

UnleashedRecomp/ui/options_menu.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
14971497

14981498
auto textX = clipRectMin.x - Scale(0.5f);
14991499
auto textY = thumbnailMax.y + offsetY;
1500+
float lineWidth = clipRectMax.x - clipRectMin.x;
15001501

15011502
if (Config::Language == ELanguage::Japanese)
15021503
{
@@ -1511,9 +1512,13 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
15111512
clipRectMax.x += annotationFontSize;
15121513

15131514
textY += annotationFontSize;
1515+
1516+
// Dirty hack to disallow clipping on Japanese text
1517+
// whilst allowing annotations to go over the border
1518+
lineWidth -= annotationFontSize;
15141519
}
15151520

1516-
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
1521+
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, lineWidth, 5.0f, desc.c_str());
15171522

15181523
drawList->PushClipRect(clipRectMin, clipRectMax, false);
15191524

@@ -1589,7 +1594,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
15891594
(
15901595
g_seuratFont,
15911596
fontSize,
1592-
clipRectMax.x - clipRectMin.x,
1597+
lineWidth,
15931598
{ textX, textY - scrollOffset },
15941599
5.0f,
15951600
desc.c_str(),

UnleashedRecompResources

0 commit comments

Comments
 (0)