ScalarVector1 / DragonLens

Modern, customizable, and community-driven debugging and cheat mod for TModLoader
24 stars 14 forks source link

Localization Support and CJK Related Optimization #59

Closed Cyrillya closed 1 year ago

Cyrillya commented 1 year ago

TL;DR

Localization

Ported all the displayed text in the mod to .hjson files to make localization easier. This pull request also includes full Chinese localization for the mod.

General

You can get localized texts via vanilla method Language.GetTextValue() surely, but for localized text in DragonLens, you can use LocalizationHelper.GetText() to get them. You don't have to include the prefix Mods.DragonLens. when using this method, shorter and better!

I split localization entries to several .hjson files, which can be found in Localization/ folder.

Tools

Localization entries for a tool's DisplayName, Description and RightClickName are automatically assigned upon tool registration. The key pattern is Mods.DragonLens.Tools.{ToolName}.{DataName}. Here is an example:

Mods: {
    DragonLens: {
        Tools: {
            Magnet: {
                DisplayName: Item magnet
                Description: Toggle to pull all items in the world to you. Right click to enable the void magnet, which will automatically destroy items instead.
                RightClickName: Void magnet (destroys items on pickup)
            }
        }
    }
}

Actually I made tool localization to a single file named {LangName}._Mods.DragonLens.Tools.hjson, so the entries appear like this:

> In en-US_Mods.DragonLens.Tools.hjson
Magnet: {
    DisplayName: Item magnet
    Description: Toggle to pull all items in the world to you. Right click to enable the void magnet, which will automatically destroy items instead.
    RightClickName: Void magnet (destroys items on pickup)
}

When adding the tool, after you create the class you should compile and reload the mod once, then localization entries will automatically show up in localization files (usually in files under Localization\Tools\). No need to write the entries yourself! (though you still have to edit them)

ToolName should be the internal name of the tool by default. It can be changed via overriding LocalizationKey property. In this example, ToolName will be PlayerEditor and the key pattern will be Mods.DragonLens.Tools.PlayerEditor.{DataName}

public override string LocalizationKey => "PlayerEditor";

Keybinds

Tool Keybinds

Each tool gets its keybind, and some of them have right click keybind as well

The localization key pattern is Mods.DragonLens.Keybinds.{ToolName}.DisplayName for left click keybind, and Mods.DragonLens.Keybinds.{ToolName}RightClick.DisplayName for right click keybind. Still, entries will be generated in files under Localization\Keybinds\ when the mod is recompiled and reloaded.

In order for the keybind name to follow the tool name, the value of tool keybinds should be editted only in en-US localization file in this pattern:

ToolName.DisplayName: "{$Mods.DragonLens.Tools.ToolName.DisplayName}"
ToolNameRightClick.DisplayName: "{$Mods.DragonLens.Tools.ToolName.RightClickName}"

You may see commented lines in other languages' localization files. They are auto-generated by tModLoader. Just leave them there.

Extra keybinds

Only keybinds registered in ExtraKeybindSystem.cs should be translated manually. e.g. in en-US_Mods.DragonLens.Keybinds.hjson:

CollapseAll.DisplayName: Collapse All

Corresponding to zh-Hans_Mods.DragonLens.Keybinds.hjson:

CollapseAll.DisplayName: 收起全部侧栏

Filters & Separators

Force using localization keys. For filters, name and description field is gone. Virtual properties, Name and Description, is in replace with them. They are used for filters automatically get their names and descriptions like NPCModFilter, ItemModFilter, etc. Override these two properties to adjust text yourself.

AddSeperator and AddFilter contains localizationKey parameter instead of name and description now. You don't have to include the Mods.DragonLens. prefix for localization keys. Here is an example:

filters.AddSeperator("Tools.DustSpawner.FilterCategories.Mod");
filters.AddFilter(new Filter("DragonLens/Assets/Filters/Vanilla", "Tools.DustSpawner.Filters.Vanilla", n => !(n is DustButton && (n as DustButton).dust.type <= DustID.Count)));

In the localization file, do this:

> en-US_Mods.DragonLens.Tools.hjson
DustSpawner: {
    FilterCategories.Mod: Mod filters
    Filters: {
        Vanilla: {
            Name: Vanilla
            Description: Dusts from the base game
        }
    }
}

Editors

There aren't much changes on them. When declaring them just use LocalizationHelper.GetText() to get the names and descriptions, and for some of them we may use Activator.CreateInstance. Do note that some editors are initialized during mod load and have localized texts. For them we have to update their names and descriptions in methods like Update() and Draw(). Just as what I did in DustSpawner.cs

If they are not updated, then if I change the game language after the mod is loaded, their text will not update.

CJK Related Optimization

Optimization on input method and word-wrapping

Word-Wrapping

Since sentences in Chinese, Japanese and Korean don't include spaces, the old word-wrapping method fails to wrap the sentence. They should not be this long: image I changed how the method works, mainly the way it splits words.

Each character in CJK counts as a "word" now. If a character has a punctuation after it, the character with the punctuation will be considered a "word", therefore no punctuation appears at the beginning of a line. However, if it is a right-opening punctuation (e.g. left bracket ), it will not be connected with the previous character, making it possible to appear at the beginning of the line.

The way it split English (and non-CJK languages) words is slightly changed. The space (if exists) before the word will be included as parts of the "word", since spaces are no longer added to the text when words are combined together to form the final text.

For more detailed changes, see comments in GUIHelper.WrapString()

Input Method

Displaying

In order to type CJK characters, people use input methods (IME). IME shows up like this in the vanilla game: image Two parts of it is missing in DragonLens input bars:

And I added them back image

Bug Fix

Typing with composition string has a bug in vanilla. When you hit backspace, it will delete a character both in the text and the composition string instead of only the one in composition string: dotnet_d8QkUuAmcy I made a fix to this for input bars in DragonLens by force-keeping the typed text when composition string exists. See comments in TextField.cs for a detailed information.

Cyrillya commented 1 year ago

I've done my changes. It is now ready for merging or running the "styling formatter"