Two decisions, both yours. Where Square Enix ships a client in a language, that client's word wins. German says Flüstern, French message privé, Japanese テル, Korean 귓속말, Simplified Chinese 密语. Everywhere else there is no official client and the loanword is what players actually say, so it stays. That meant rewriting the whole corpus in those languages rather than just the new keys, which is the reason the split existed in the first place: forty German values and thirty-seven French ones carried the old word. /tell is untouched, because that is a command and not a noun. The mechanical pass left French with three agreement errors -- "des message privé", "ce onglet", "messages de message privé" -- which is what happens when you substring-replace a language with gender and number. Fixed by hand. Traditional Chinese keeps 悄悄話, which the file already used nineteen times; it has no official client of its own. The appearance tab is translated as well. Thirty keys: the colour editor's groups and buttons, the theme categories, fork and import and export, the font labels and the preview's input placeholder. Theme token names stay English -- WindowBg and TextPrimary are JSON keys, not prose -- and so do the brand strings. 465 keys, 25 files, no gaps, no orphans, no placeholder drift. Still English and not in this commit: the database viewer behind /hellionView, which is a documented user command rather than a developer tool, and the symbol picker. Both are their own block.
224 lines
7.3 KiB
C#
224 lines
7.3 KiB
C#
using Dalamud;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface.FontIdentifier;
|
|
using HellionChat.Resources;
|
|
using HellionChat.Util;
|
|
|
|
namespace HellionChat.Ui.Components.Settings;
|
|
|
|
// Restores the 1.5.6 font-selection UI (1d3b429:Appearance.cs:249-405): pick the
|
|
// bundled Hellion font vs a custom global/Japanese/italic font, sizes, and extra
|
|
// glyph ranges. v1.6.0 saves live, so any change persists and rebuilds the atlas
|
|
// at once (RebuildDelegateFonts, unconditional — a face change keeps the size, so
|
|
// the size-gated IfChanged path would miss it).
|
|
internal sealed class FontsSection
|
|
{
|
|
private readonly Plugin _plugin;
|
|
private readonly FontManager _fontManager;
|
|
private readonly SectionRenderer _sections;
|
|
|
|
public FontsSection(Plugin plugin, FontManager fontManager, SectionRenderer sections)
|
|
{
|
|
_sections = sections;
|
|
_plugin = plugin;
|
|
_fontManager = fontManager;
|
|
}
|
|
|
|
private void Apply()
|
|
{
|
|
_plugin.SaveConfig();
|
|
_fontManager.RebuildDelegateFonts();
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
if (
|
|
!_sections.Draw(
|
|
ImGui.GetID("appearance.fonts"u8),
|
|
HellionStrings.Settings_Section_Fonts,
|
|
open: false
|
|
)
|
|
)
|
|
return;
|
|
|
|
// Readout so the user can see which font is actually active.
|
|
var active =
|
|
Plugin.Config.UseHellionFont ? HellionStrings.Settings_Fonts_Bundled
|
|
: Plugin.Config.FontsEnabled
|
|
? string.Format(
|
|
HellionStrings.Settings_Fonts_Global,
|
|
Plugin.Config.GlobalFontV2.FontId.Family.EnglishName
|
|
)
|
|
: HellionStrings.Settings_Fonts_GameFont;
|
|
ImGui.TextDisabled(string.Format(HellionStrings.Settings_Fonts_Active, active));
|
|
ImGui.Spacing();
|
|
|
|
if (
|
|
ImGui.Checkbox(
|
|
HellionStrings.Theme_UseHellionFont_Name,
|
|
ref Plugin.Config.UseHellionFont
|
|
)
|
|
)
|
|
{
|
|
if (Plugin.Config.UseHellionFont)
|
|
Plugin.Config.FontsEnabled = false;
|
|
Apply();
|
|
}
|
|
ImGuiUtil.HelpMarker(HellionStrings.Theme_UseHellionFont_Description);
|
|
ImGui.Spacing();
|
|
|
|
if (Plugin.Config.UseHellionFont)
|
|
{
|
|
DrawSizeCombo(Language.Options_FontSize_Name, ref Plugin.Config.FontSizeV2);
|
|
ImGui.Spacing();
|
|
}
|
|
else if (ImGui.Checkbox(Language.Options_FontsEnabled, ref Plugin.Config.FontsEnabled))
|
|
{
|
|
Apply();
|
|
}
|
|
|
|
var unused = false;
|
|
if (!Plugin.Config.UseHellionFont && !Plugin.Config.FontsEnabled)
|
|
{
|
|
DrawSizeCombo(Language.Options_FontSize_Name, ref Plugin.Config.FontSizeV2);
|
|
}
|
|
else if (!Plugin.Config.UseHellionFont)
|
|
{
|
|
DrawFontChooser(
|
|
Language.Options_Font_Name,
|
|
Plugin.Config.GlobalFontV2,
|
|
false,
|
|
ref unused,
|
|
spec => Plugin.Config.GlobalFontV2 = spec,
|
|
() => Plugin.Config.GlobalFontV2 = DefaultFont(DalamudAsset.NotoSansCjkRegular),
|
|
"global"
|
|
);
|
|
ImGuiUtil.HelpMarker(
|
|
string.Format(Language.Options_Font_Description, Plugin.PluginName)
|
|
);
|
|
ImGuiUtil.WarningText(Language.Options_Font_Warning);
|
|
ImGui.Spacing();
|
|
|
|
DrawFontChooser(
|
|
Language.Options_JapaneseFont_Name,
|
|
Plugin.Config.JapaneseFontV2,
|
|
false,
|
|
ref unused,
|
|
spec => Plugin.Config.JapaneseFontV2 = spec,
|
|
() => Plugin.Config.JapaneseFontV2 = DefaultFont(DalamudAsset.NotoSansCjkMedium),
|
|
"japanese",
|
|
id => !id.LocaleNames?.ContainsKey("ja-jp") ?? false,
|
|
"いろはにほへと ちりぬるを"
|
|
);
|
|
ImGuiUtil.HelpMarker(
|
|
string.Format(Language.Options_JapaneseFont_Description, Plugin.PluginName)
|
|
);
|
|
ImGui.Spacing();
|
|
|
|
DrawFontChooser(
|
|
Language.Options_ItalicFont_Name,
|
|
Plugin.Config.ItalicFontV2,
|
|
true,
|
|
ref Plugin.Config.ItalicEnabled,
|
|
spec => Plugin.Config.ItalicFontV2 = spec,
|
|
() =>
|
|
{
|
|
Plugin.Config.ItalicEnabled = false;
|
|
Plugin.Config.ItalicFontV2 = DefaultFont(DalamudAsset.NotoSansCjkRegular);
|
|
},
|
|
"italic"
|
|
);
|
|
ImGuiUtil.HelpMarker(
|
|
string.Format(Language.Options_Italic_Description, Plugin.PluginName)
|
|
);
|
|
ImGui.Spacing();
|
|
}
|
|
|
|
// ExtraGlyphRanges stays reachable regardless of the font source so the
|
|
// user can verify/override the per-language auto-activation (v1.5.3 note).
|
|
ImGui.Spacing();
|
|
if (
|
|
_sections.Draw(
|
|
ImGui.GetID("appearance.fonts.glyphs"u8),
|
|
Language.Options_ExtraGlyphs_Name,
|
|
open: false
|
|
)
|
|
)
|
|
{
|
|
ImGuiUtil.HelpMarker(
|
|
string.Format(Language.Options_ExtraGlyphs_Description, Plugin.PluginName)
|
|
);
|
|
|
|
var range = (int)Plugin.Config.ExtraGlyphRanges;
|
|
var changed = false;
|
|
foreach (var extra in Enum.GetValues<ExtraGlyphRanges>())
|
|
changed |= ImGui.CheckboxFlags(extra.Name(), ref range, (int)extra);
|
|
|
|
if (changed)
|
|
{
|
|
Plugin.Config.ExtraGlyphRanges = (ExtraGlyphRanges)range;
|
|
Apply();
|
|
}
|
|
}
|
|
|
|
DrawSizeCombo(Language.Options_SymbolsFontSize_Name, ref Plugin.Config.SymbolsFontSizeV2);
|
|
ImGuiUtil.HelpMarker(Language.Options_SymbolsFontSize_Description);
|
|
ImGui.Spacing();
|
|
}
|
|
|
|
private void DrawSizeCombo(string label, ref float size)
|
|
{
|
|
var before = size;
|
|
ImGuiUtil.FontSizeCombo(label, ref size);
|
|
if (!size.Equals(before))
|
|
Apply();
|
|
}
|
|
|
|
private void DrawFontChooser(
|
|
string label,
|
|
SingleFontSpec font,
|
|
bool checkbox,
|
|
ref bool checkboxValue,
|
|
Action<SingleFontSpec> set,
|
|
Action reset,
|
|
string resetId,
|
|
Predicate<IFontFamilyId>? exclusion = null,
|
|
string? preview = null
|
|
)
|
|
{
|
|
var prevCheckbox = checkboxValue;
|
|
var chooser = ImGuiUtil.FontChooser(
|
|
label,
|
|
font,
|
|
checkbox,
|
|
ref checkboxValue,
|
|
exclusion,
|
|
preview
|
|
);
|
|
if (checkbox && checkboxValue != prevCheckbox)
|
|
Apply();
|
|
|
|
// The chooser dialog resolves on a worker thread; marshal the result back
|
|
// onto the framework thread before touching config + the font atlas.
|
|
chooser?.ResultTask.ContinueWith(r =>
|
|
{
|
|
if (r.IsCompletedSuccessfully)
|
|
Plugin.Framework.Run(() =>
|
|
{
|
|
set(r.Result);
|
|
Apply();
|
|
});
|
|
});
|
|
|
|
ImGui.SameLine();
|
|
if (ImGui.Button($"Reset##{resetId}"))
|
|
{
|
|
reset();
|
|
Apply();
|
|
}
|
|
}
|
|
|
|
private static SingleFontSpec DefaultFont(DalamudAsset asset) =>
|
|
new() { FontId = new DalamudAssetFontAndFamilyId(asset), SizePt = 12.75f };
|
|
}
|