Skip to content

LemoBits/UniversalLocalization

Repository files navigation

Universal Localization

Universal Localization 是一个 Unity 运行时本地化插件。它通过 MelonLoader 加载,在游戏运行时扫描、采集并替换 UGUI / TextMeshPro 文本和 UGUI 图片。

插件本身不受 MelonGame 限制,也不在编译时引用某个游戏的 Assembly-CSharp 类型。游戏特有的翻译表、对象路径和字符串 hook 由 profile 提供。

当前后端支持 Windows x64 + MelonLoader 和 Android arm64 + Lemon Loader 0.6.5,目标游戏均须使用 Unity IL2CPPdo后端 由于 Il2CppInterop 程序集由每个游戏和平台生成,必须针对目标游戏、版本和平台分别构建 DLL。 当前尚不支持 Unity Mono、BepInEx 或非 Unity 游戏

目录

功能概览

  • Harmony 前置拦截 UGUI Text.text 和 TextMeshPro TMP_Text.text,尽量在原文绘制之前完成替换。
  • 场景加载后执行全量扫描,运行时继续扫描新增或变化的文本,覆盖未经 setter 的 Unity 反序列化文本。
  • 支持全局翻译和基于 Unity 对象层级路径的上下文翻译。
  • 自动采集未识别文本,并以直接 UTF-8 字符写入 JSON,不把中文存成 \uXXXX
  • 自动处理“可见前缀 + <color=#00000000> 透明后缀”形式的逐字动画(又称打字机动画)。
  • 可通过 profile 对游戏内打字机方法安装反射 Harmony hook,先翻译完整句子,再交给游戏的打字机。
  • 支持游戏内字体、外部 TTF / OTF、TMP 动态字体资产与按文本/对象路径指定字体。
  • 可导出 UGUI Image / RawImage 原图,并根据稳定文件名加载 PNG 替换图。
  • 提供 capture 采集模式和低写入、低扫描频率的 runtime 发布模式。

快速安装

前置条件

  1. Unity IL2CPP 后端的目标
  2. Windows 目标已安装 MelonLoader;Android 目标已使用 Lemon Loader 修补。
  3. 至少启动过一次游戏,加载器已生成 Il2CppAssemblies/
  4. 从源码构建时需要 .NET SDK。Windows 插件目标框架为 net6.0,Lemon Loader 插件目标框架为 net8.0,测试项目为 net8.0

Windows 目标还应存在:

MelonLoader/net6/MelonLoader.dll
MelonLoader/Il2CppAssemblies/

Android 目标的数据根目录由 Lemon Loader 0.6.5 放在 /sdcard/MelonLoader/<包名>/

使用空白通用 profile

Linux与MacOS⬇️

在仓库根目录执行:

./scripts/install-windows.sh 游戏目录

未指定第二个参数时,脚本使用受 Git 跟踪的 examples/profile-template/。它适合在新游戏中开始采集文本和图片。

Windows⬇️

在仓库根目录执行:

./scripts/install-win.bat 游戏目录

同样,未指定第二个参数时,脚本使用受 Git 跟踪的 examples/profile-template/。它适合在新游戏中开始采集文本和图片。

给 BeastBeat 安装现有中文 profile

./scripts/install-windows.sh \
  "/home/melaton/Games/LutrisLibrary/BeastBeat CN/Windows V0.2.30" \
  "$(pwd)/pack/beastbeat-zh-CN"

安装脚本会:

  1. 使用目标游戏的 MelonLoader / Il2CppInterop 程序集构建 Release DLL。
  2. 把构建产物和所选 profile 复制到 artifacts/windows/
  3. 安装 Mods/UniversalLocalization.dll
  4. 仅在目标数据文件不存在时安装 text.jsonsettings.json,不覆盖用户已有的翻译。
  5. 如果发现旧 Mods/BeastBeatCN.dll,将它改名为 BeastBeatCN.dll.disabled-before-universal,避免新旧两个插件同时加载。
  6. 如果仅存在旧 UserData/BeastBeatCN/,继续使用该目录,不复制或丢弃旧翻译、字体和图片。

Lemon Loader / Android

此为Android部分内容,如无需求请跳过 先使用 Lemon Loader 官方安装器 修补目标 APK,安装后至少启动一次游戏,让加载器生成 MelonLoader/net8/MelonLoader/Il2CppAssemblies/。本仓库的脚本不会修改、重签名或重新安装 APK。

连接已启用 USB 调试的 Android 设备后执行:

./scripts/install-lemon.sh \
  "com.example.game" \
  "$(pwd)/pack/my-game-zh-CN"

连接多个设备时把 ADB serial 作为第三个参数:

./scripts/install-lemon.sh \
  "com.example.game" \
  "$(pwd)/pack/my-game-zh-CN" \
  "DEVICE_SERIAL"

Tips:通过在终端使用adb devices获取设备唯一标识符(需要安装Android Debug套件) 例如本机 BeastBeat Android 0.2.30 的包名是 com.CBoneStudio.BeastBeat,安装现有中文 profile 可执行:

./scripts/install-lemon.sh \
  "com.CBoneStudio.BeastBeat" \
  "$(pwd)/pack/beastbeat-zh-CN"

脚本会从设备的 /sdcard/MelonLoader/<包名>/ 临时拉取该游戏的 Lemon Loader 和 Il2CppInterop 构建依赖,生成 .NET 8 DLL,再安装到:

/sdcard/MelonLoader/<包名>/Mods/UniversalLocalization.dll
/sdcard/MelonLoader/<包名>/UserData/UniversalLocalization/settings.json
/sdcard/MelonLoader/<包名>/UserData/UniversalLocalization/text.json

和 Windows 安装器一样,已有 settings.jsontext.json 不会被覆盖;如果只存在旧 UserData/BeastBeatCN/,脚本与插件会继续使用旧目录。配置包中的 Fonts/Images/Replacement/ 会按相同目录结构自动推送;设备上已有的同名附加资源会被配置包版本更新。

手动安装、升级与卸载

手动安装

针对目标游戏构建后,将文件放到:

<Game>/Mods/UniversalLocalization.dll
<Game>/UserData/UniversalLocalization/settings.json
<Game>/UserData/UniversalLocalization/text.json

settings.jsontext.json 可从一个 profile 目录复制。不要使用为其它 Unity 游戏或明显不同版本构建的 DLL;即使文件能被 MelonLoader 发现,类型也可能不兼容。

Lemon Loader 的手动安装目录是:

/sdcard/MelonLoader/<包名>/Mods/UniversalLocalization.dll
/sdcard/MelonLoader/<包名>/UserData/UniversalLocalization/settings.json
/sdcard/MelonLoader/<包名>/UserData/UniversalLocalization/text.json

Android 必须使用 build-lemon.sh 生成的 .NET 8 DLL,不能复用 artifacts/windows/ 中的 Windows 构建。

升级

  • 覆盖 Mods/UniversalLocalization.dll 即可升级代码。
  • 默认不覆盖 UserData/UniversalLocalization/ 中的用户数据。
  • 只有在明确需要替换整个翻译包时,才应先备份再覆盖 text.json
  • defaultChineseFont 字段可继续读取;在可写的 capture 模式下会迁移为 defaultFont

卸载

  1. 删除或移出 <Game>/Mods/UniversalLocalization.dll
  2. 如果仅想暂时禁用,可将扩展名改为 .dll.disabled
  3. UserData/UniversalLocalization/ 是用户翻译、字体和图片数据;卸载插件不需要删除它。
  4. 若要恢复旧 BeastBeatCN,先移出新 DLL,再将 BeastBeatCN.dll.disabled-before-universal 改回 BeastBeatCN.dll

基本使用

运行时数据目录

新安装默认使用:

<Game>/UserData/UniversalLocalization/

完整结构为:

UserData/UniversalLocalization/
  settings.json
  text.json
  untranslated.jsonl
  Fonts/
    *.ttf
    *.otf
  Images/
    Original/
      *.png
    Replacement/
      *.png
    manifest.json

如果 UniversalLocalization/ 不存在,但存在 UserData/BeastBeatCN/,插件会使用旧目录。当两个目录同时存在时,新目录优先。

两种运行模式

settings.json 中的 mode 控制采集行为:

{
  "mode": "capture"
}
  • capture:开发/翻译模式。应用现有翻译和替换图,同时采集未知文本、导出原图、更新图片清单,并使用更高频率的文本扫描。
  • runtime:发布/日常使用模式。只应用已有翻译、字体规则和替换图,不写入未知文本、不导出原图,并降低兜底扫描频率。

兼容旧名称 translationuse,它们会分别迁移为 captureruntime。修改设置后需重启游戏。

翻译工作流

1. 采集原文

  1. mode 设为 capture
  2. 启动游戏,尽可能遍历菜单、设置、对话、弹窗和游戏流程。
  3. 正常退出游戏,让插件刷新待写入数据。
  4. 检查 text.jsonuntranslated.jsonl

新发现文本会自动加入 translations,值留空:

{
  "translations": {
    "Quest Journal": ""
  }
}

untranslated.jsonl 每行是一个独立 JSON 记录,同时保存对象路径:

{"context":"MainCanvas/Menu/QuestButton/Text","text":"Quest Journal"}

它是定位和上下文参考文件;真正的翻译字典是 text.json

2. 填写全局翻译

把空值替换为目标语言:

{
  "translations": {
    "Quest Journal": "任务日志",
    "Save": "保存",
    "Cancel": "取消"
  }
}

查找顺序是:

  1. contextTranslations
  2. translations
  3. 动画文本的完整原文映射

修改后重启游戏生效。

3. 处理一词多义

全局键只能给一个原文一个翻译。如果 Back 在不同 UI 中需要不同表达,在 contextTranslations 中使用:

对象完整路径|原文

例如:

{
  "translations": {
    "Back": "返回"
  },
  "contextTranslations": {
    "Character/Body/BackLabel|Back": "背部",
    "MainMenu/BackButton/Text|Back": "返回"
  }
}

对象路径可从 untranslated.jsonlImages/manifest.json 查找。路径匹配区分大小写,并保留 Unity 实例名中的 (Clone)

4. 处理富文本、换行和占位符

翻译时应保留游戏所需的结构:

  • 保留 TMP 标签,例如 <color>...</color><size>...</size><sprite=0>
  • 保留换行和尾随空格。JSON 中换行使用 \n
  • 保留格式占位符,例如 {0}{1:N0}%s{playerName}
  • 原文键精确匹配且区分大小写;PlayPLAY 是两个不同键。
  • 不要把已翻译文本再作为原文键添加,除非游戏本身真的会输出它。

5. 动画和打字机文本

对于这种透明后缀状态:

He<color=#00000000>llo</color>

text.json 只需保存完整原文:

{
  "translations": {
    "Hello": "你好"
  }
}

插件会按已显示文本元素数量生成对应的目标语言动画状态。

对于游戏代码持续写入 HHeHelHello 的纯前缀打字机,需要在 settings.json 中同时配置:

  • prefixAnimationContexts:允许在该对象路径中使用前缀匹配并合并采集结果。
  • stringHooks:如果能定位到游戏打字机的完整字符串入口,在该方法执行前翻译。

字体设置

默认字体和回退字符

text.json 的顶层字体设置:

{
  "language": "zh-CN",
  "defaultFont": "MiSans-Regular",
  "fallbackCharacter": ""
}
  • language 是 profile 语言元数据,当前不参与匹配逻辑。
  • defaultFont 是目标文本需要特殊字形时的默认字体名,可以为空。
  • fallbackCharacter 建议设为目标语言的一个代表字符。指定字体不可用时,插件会在游戏已加载字体中寻找可显示该字符的回退字体。

给单独文本指定字体

fontRules 的键使用最终显示文本,也可加上对象路径:

{
  "fontRules": {
    "开始游戏": "MiSans-Regular",
    "MainMenu/Logo/Text|开始游戏": "SourceHanSansSC"
  }
}

“对象路径 + | + 显示文本”规则优先于纯显示文本规则。显式规则指定的字体找不到时,组件保持原有字体;默认字体才允许使用 fallbackCharacter 回退。

外部 TTF / OTF

把字体文件放入:

UserData/UniversalLocalization/Fonts/SourceHanSansSC.ttf

然后使用不带扩展名的文件名:

{
  "defaultFont": "SourceHanSansSC"
}

字体目录在插件启动时建立索引,添加或替换文件后需重启游戏。TMP 可以直接从外部文件生成动态字体资产。Wine / Proton 下的传统 UGUI 优先使用游戏内已支持目标字符的字体,避免外部字体注册污染游戏原有数字图集。

Android UGUI 字体 AssetBundle

Lemon Loader / Android 下,外部 TTF / OTF 可以直接用于 TMP;传统 UGUI 需要额外提供包含同名 UnityEngine.Font 资产的 Android AssetBundle。AssetBundle 必须使用与目标游戏完全一致的 Unity Editor 版本手动编译,不能使用较早的 Unity 6 版本代替。例如目标游戏为 6000.3.9f1 时,必须使用 6000.3.9f1 Editor 并选择 Android 构建目标。

在 Unity 工程中导入字体、设置 AssetBundle 名称并执行 BuildPipeline.BuildAssetBundles(..., BuildTarget.Android),然后将生成的 bundle 及其 .manifest 与原 TTF / OTF 一起放入 profile:

pack/<profile-name>/Fonts/MiSans-Regular.ttf
pack/<profile-name>/Fonts/misans-regular.android.bundle
pack/<profile-name>/Fonts/misans-regular.android.bundle.manifest

bundle manifest 中的字体资产名必须与 defaultFontfontRules 指定的名称一致。Lemon 安装脚本会自动推送这些文件;加载成功时日志会显示 字体资源包已载入已从字体资源包加载 UGUI 字体。未提供匹配版本的 bundle 或加载失败时,UGUI 会回退到游戏内已加载且包含 fallbackCharacter 的字体。

图片导出与替换

导出原图

capture 模式下遍历游戏 UI。插件会将遇到的 UGUI ImageRawImage 导出到:

UserData/UniversalLocalization/Images/Original/

文件名由资产类型、资产名、尺寸和短 SHA-256 摘要构成,例如:

sprite-Menu_Icon_Start-256x128-a1b2c3d4e5.png

Images/manifest.json 记录:

  • 导出文件名
  • Sprite / Texture 类型
  • 原资产名
  • 宽度和高度
  • 该图片出现过的 Unity 对象路径

替换图片

  1. 复制 Images/Original/ 中的 PNG。

  2. 修改图片,保留完整文件名。

  3. 将结果放入:

    UserData/UniversalLocalization/Images/Replacement/
    
  4. 重启游戏。

替换图可以使用不同像素尺寸,但 UI 布局尺寸仍由游戏自身控制。要恢复原图,删除或移出 Replacement/ 中对应文件并重启游戏。

settings.json 完整说明

一个完整示例:

{
  "mode": "capture",
  "features": {
    "text": true,
    "images": true
  },
  "prefixAnimationContexts": [
    "Canvas/Dialog/Content"
  ],
  "stringHooks": [
    {
      "assembly": "Assembly-CSharp",
      "type": "Game.UI.DialogueView",
      "method": "ShowLine",
      "returnType": "Il2CppSystem.Collections.IEnumerator",
      "allowMultiple": false,
      "context": "Canvas/Dialog/Content"
    }
  ]
}

顶层字段

字段 类型 默认值 说明
mode string capture capture 采集模式或 runtime 只读发布模式。
features.text bool true 启用文本、字体、动画和字符串 hook 模块。
features.images bool true 启用图片采集和替换模块。
prefixAnimationContexts string[] [] 允许纯前缀打字机匹配的精确对象路径。
stringHooks object[] [] 在游戏方法进入前翻译其唯一 string 参数。

stringHooks 字段

字段 是否必需 说明
assembly 程序集名,通常是 Assembly-CSharp,不带 .dll
type 类型全名或短名。建议使用包含命名空间的全名,避免同名类型冲突。
method 条件必需 方法名;可以是 "*" 或空字符串表示不按名称限制。methodreturnType 至少有一个非空。
returnType 条件必需 返回类型全名。可为空;用于缩小混淆方法的候选范围。
allowMultiple false 时必须唯一匹配;true 时向所有匹配方法安装同一 hook。
context 传给翻译表的上下文路径,通常与目标文本组件路径一致。

候选方法还必须满足:

  • 方法直接声明在指定类型上。
  • 非抽象方法。
  • 参数列表恰好只有一个 System.String

候选数为 0,或 allowMultiple: false 时候选数不为 1,该配置会安全跳过并写入 MelonLoader 日志。不要在不清楚匹配范围时盲目使用 allowMultiple: true

Profile 与打包发布

Profile 目录结构

每个 profile 至少包含:

pack/my-game-zh-CN/
  settings.json
  text.json

仓库的 pack/ 已加入 .gitignore,用于存放本机游戏 profile 和不适合直接提交的翻译资产。新 profile 可以从受跟踪的空模板创建:

mkdir -p pack
cp -a examples/profile-template pack/my-game-zh-CN

然后编辑 profile 内的两个 JSON 文件。游戏对象路径、类型名、方法名和特有 hook 只应出现在 profile,不应写进通用核心。

从运行时数据整理发布 profile

  1. 备份游戏中的 text.json
  2. 审核 capture 模式收集的所有键。
  3. 补全需要发布的翻译。
  4. 删除测试文本、机器特有文本和不应发布的空键。
  5. 保留已确认的 contextTranslationsfontRulesdefaultFontfallbackCharacter
  6. 将审核后的文件复制到 pack/<profile-name>/text.json
  7. 如果需要发布替换图或字体,应在配置包中保留 Fonts/Images/Replacement/ 目录结构;Lemon 安装脚本会自动推送这些附加资源,构建产物仍只包含 DLL、text.jsonsettings.json

不要未审核就将整个运行时 text.json 覆盖仓库 profile,否则可能带入空翻译、短暂动画帧或仅在当前存档出现的文本。

构建发布产物

./scripts/build-windows.sh \
  "/path/to/MelonLoaderGame" \
  "$(pwd)/pack/my-game-zh-CN"

产物位于:

artifacts/windows/
  UniversalLocalization.dll
  settings.json
  text.json

脚本每次会覆盖 artifacts/windows/ 中这三个同名产物。发布前建议检查:

jq empty \
  artifacts/windows/settings.json \
  artifacts/windows/text.json

dotnet run \
  --project tests/UniversalLocalization.Tests/UniversalLocalization.Tests.csproj

对同一游戏的不同大版本发布时,建议分开保存经过相应版本 Il2CppInterop 程序集构建的 DLL。

Lemon Loader 使用从设备拉取的本地数据镜像构建:

./scripts/build-lemon.sh \
  "/path/to/local/MelonLoader/package-root" \
  "$(pwd)/pack/my-game-zh-CN"

镜像根目录必须包含 MelonLoader/net8/MelonLoader/Il2CppAssemblies/,产物写入 artifacts/lemon/。通常直接使用 install-lemon.sh 即可自动完成临时拉取、构建和安装。

二次开发

项目结构

src/UniversalLocalization/
  AssemblyInfo.cs
  UniversalLocalization.csproj
  UniversalLocalizationMod.cs
  Core/
    JsonDefaults.cs
    PluginPaths.cs
    PluginSettings.cs
    RuntimeModule.cs
    UnityObjectPath.cs
  Compatibility/
    CompatibilityMigrations.cs
  Modules/
    Text/
      AnimatedText.cs
      FontManager.cs
      TextTranslationModule.cs
      TranslationCatalog.cs
    Images/
      ImageFileNames.cs
      ImageManager.cs
      ImageRuntimeModule.cs
docs/
  architecture.md
pack/
  <local-game-profile>/            本机 profile,已被 Git 忽略
examples/
  profile-template/                受 Git 跟踪的空 profile 模板
tests/
  UniversalLocalization.Tests/

核心责任

  • UniversalLocalizationMod:唯一 MelonLoader 入口,负责路径、设置、模块组装和生命周期转发。
  • IRuntimeModule:运行时模块契约,包含 OnSceneLoadedOnUpdateOnLateUpdateDispose
  • TranslationCatalog:翻译查找、动画文本归一化、未知文本采集和 JSON 持久化。
  • TextTranslationModule:Unity 文本扫描、setter hook、profile 字符串 hook 和字体应用。
  • ImageRuntimeModule / ImageManager:图片扫描、导出、manifest 和替换资源生命周期。
  • Compatibility/:只放旧版数据到新通用格式的一次性迁移。

详细设计边界见 docs/architecture.md

本地测试

纯 .NET 回归测试不需要启动游戏:

dotnet run \
  --project tests/UniversalLocalization.Tests/UniversalLocalization.Tests.csproj

当前测试覆盖:

  • 透明后缀动画文本
  • 纯前缀打字机文本
  • 未知文本合并和重复抑制
  • capture / runtime 持久化边界
  • 直接 UTF-8 JSON
  • 旧字段和旧 BeastBeatCN profile 迁移
  • profile 设置读取和归一化
  • 图片文件名稳定性

针对游戏构建

dotnet build \
  src/UniversalLocalization/UniversalLocalization.csproj \
  --configuration Release \
  -p:GameDir="/path/to/MelonLoaderGame"

GameDir 是必需参数。项目从以下目录引用目标游戏程序集:

<GameDir>/MelonLoader/net6/
<GameDir>/MelonLoader/Il2CppAssemblies/

个人开发环境可以在仓库根目录创建不提交的 local.props

<Project>
  <PropertyGroup>
    <GameDir>/absolute/path/to/MelonLoaderGame</GameDir>
  </PropertyGroup>
</Project>

local.props 已被 .gitignore 忽略。

Lemon Loader 构建使用独立的 loader flavor 和 .NET 8:

dotnet build \
  src/UniversalLocalization/UniversalLocalization.csproj \
  --configuration Release \
  -p:LoaderFlavor=lemon \
  -p:GameDir="/path/to/local/LemonLoader/package-root"

该本地根目录对应设备上的 /sdcard/MelonLoader/<包名>/,项目从 MelonLoader/net8/MelonLoader/Il2CppAssemblies/ 引用程序集。

添加新功能模块

  1. Modules/<Feature>/ 中实现 IRuntimeModule
  2. PluginSettingsfeatures 中增加独立开关和默认值。
  3. UniversalLocalizationMod 中根据开关组装模块。
  4. 确保模块可独立关闭,并在 Dispose 中释放 Unity 对象、文件句柄或系统资源。
  5. 对不需要 Unity 运行时的算法和配置增加回归测试。

添加新游戏支持

优先顺序是:

  1. 先使用空 profile 采集内容。
  2. 使用 translationscontextTranslationsfontRules 表达差异。
  3. 需要打字机时使用 prefixAnimationContextsstringHooks
  4. 只有 profile 无法表达时,才新增可复用策略或模块。

通用核心不应:

  • 添加 [assembly: MelonGame(...)]
  • 编译时引用某个游戏的 Assembly-CSharp 类型。
  • 在文本模块中硬编码游戏类型名、方法名或对象路径。
  • 为新游戏复用 BeastBeat 的 profile、翻译表或兼容迁移。

持久化约定

  • 用户 JSON 使用 JsonDefaults.UserData,并保持直接 UTF-8 字符。
  • JSONL 使用 JsonDefaults.JsonLines,每行必须是独立有效 JSON。
  • 重写主 JSON 时先写入 .tmp,再替换正式文件,避免中途崩溃破坏翻译表。
  • runtime 模式必须保持用户数据只读。
  • 新增配置字段必须有安全默认值,并能读取缺少该字段的旧文件。

发布前检查清单

  1. 运行所有回归测试。
  2. 使用目标游戏的互操程序集进行 Release 构建。
  3. 确认 0 警告、0 错误。
  4. 验证 profile JSON。
  5. 检查 DLL 不含 MelonGame 限制或某个游戏入口类。
  6. 在实际游戏中验证加载、场景切换、动态文本、字体、图片和正常退出。
  7. 将发布环境切换为 runtime 并确认用户数据未被改写。

故障排查

构建提示 GameDir is required

传入 -p:GameDir="...",或使用已接受游戏目录参数的 build-windows.sh / install-windows.sh

安装脚本提示未安装 MelonLoader

确认传入的是游戏根目录,并存在:

<Game>/MelonLoader/net6/MelonLoader.dll

如果 MelonLoader 刚安装,先启动一次游戏生成互操程序集。

Lemon 安装脚本无法拉取程序集

  • 确认设备已连接并可由 adb devices 识别;多个设备同时连接时传第三个 serial 参数。
  • 确认包名与 /sdcard/MelonLoader/<包名>/ 完全一致。
  • 修补后至少启动一次游戏,并授予 Lemon Loader 请求的文件权限。
  • 确认设备上已经生成 MelonLoader/net8/MelonLoader.dllMelonLoader/Il2CppAssemblies/

插件没有加载

  • 确认 DLL 位于 <Game>/Mods/UniversalLocalization.dll
  • 查看 <Game>/MelonLoader/Latest.log
  • 确认不存在同时激活的 BeastBeatCN.dll 或第二份 UniversalLocalization DLL。
  • 确认 DLL 是用当前游戏版本的 Il2CppAssemblies 构建。

文本没有被翻译

  • 确认 features.texttrue
  • 确认编辑的是插件实际使用的数据目录。当新旧两个目录都存在时,UniversalLocalization/ 优先。
  • 确认原文键的大小写、空格、换行和富文本标签完全一致。
  • 查看 untranslated.jsonl 中实际采集的文本和路径。
  • 如果是打字机文本,查看日志中 stringHooks 的候选数和安装结果。

中文显示成方块或缺字

  • 设置可用的 defaultFont
  • 把完整中文字体放入 Fonts/
  • fallbackCharacter 设为目标语言代表字符。
  • 查看日志中的字体搜索、TMP 动态图集和缺失字符警告。
  • Wine / Proton 下的 UGUI 外部字体路径与原生 Windows 不同,优先确认游戏内是否已有支持目标语言的字体。

没有导出图片

  • 确认 modecapture
  • 确认 features.imagestrue
  • 必须实际打开包含目标 UGUI 图片的界面。
  • 某些非 UGUI 材质、UI Toolkit、3D 模型纹理或自定义渲染管线图片不在当前图片模块支持范围内。

安装器提示旧插件备份已存在

安装器不会覆盖 BeastBeatCN.dll.disabled-before-universal。先人工确认该备份是否需要保留,将它移到其它备份目录后再重试。

开发状态与兼容性

  • MelonLoader 入口:UniversalLocalizationMod
  • 程序集名:UniversalLocalization.dll
  • 当前版本:1.0.0
  • 当前目标框架:Windows / MelonLoader 为 .NET 6,Android / Lemon Loader 为 .NET 8
  • 当前支持的 UI 文本:UGUI Text、TextMeshPro TMP_Text
  • 当前支持的 UI 图片:UGUI ImageRawImage

该项目的“Universal”表示核心不绑定某一款游戏,并可通过 profile 和模块扩展。它不表示当前一个预编译 DLL 可无条件跨所有游戏、Unity 版本和加载器直接使用。

许可证

本项目以 GNU General Public License v3.0 发布,SPDX 标识为 GPL-3.0-only

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors