localization

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
This guide covers setting up and configuring Unity Localization, including locales, String and Asset Tables, Addressables integration, and CJK font support via Asset Tables.
本指南涵盖Unity Localization的设置与配置,包括区域设置、字符串与资源表、Addressables集成,以及通过资源表实现CJK字体支持。

0. Package Installation Check

0. 包安装检查

Before doing anything else, verify that the Localization packages is installed. Many APIs in this skill will fail silently or throw confusing errors if the package isn't present.
  1. Check: Use
    UnityEditor.PackageManager.Client.List(true)
    to check for
    com.unity.localization
    .
  2. Install: If missing, use
    Client.Add("com.unity.localization")
    .
  3. Wait: Do not proceed until
    Client.List
    confirms installation.
在进行任何操作前,请确认已安装Localization包。若未安装,本技能中的许多API会静默失败或抛出难以理解的错误。
  1. 检查: 使用
    UnityEditor.PackageManager.Client.List(true)
    检查是否存在
    com.unity.localization
  2. 安装: 若缺失,使用
    Client.Add("com.unity.localization")
    进行安装。
  3. 等待: 必须等到
    Client.List
    确认安装完成后再继续操作。

1. Localization Settings & Locales

1. 本地化设置与区域设置(Locales)

If
LocalizationEditorSettings.ActiveLocalizationSettings
is null, you must find or create it:
  1. Find: Use
    AssetDatabase.FindAssets("t:LocalizationSettings")
    . If found, load the first one and assign it to
    LocalizationEditorSettings.ActiveLocalizationSettings
    .
  2. Create: If not found, create a new instance and save it to
    Assets/Localization/LocalizationSettings.asset
    . Use
    ScriptableObject.CreateInstance<LocalizationSettings>()
    followed by
    AssetDatabase.CreateAsset()
    .
  3. Activate: Set
    LocalizationEditorSettings.ActiveLocalizationSettings = settings
    .
  4. Locales: Ensure locales (en, fr, de, etc.) exist. Create them if missing and add them to settings using
    LocalizationEditorSettings.AddLocale(locale)
    .
LocalizationEditorSettings.ActiveLocalizationSettings
为空,需查找或创建该设置:
  1. 查找: 使用
    AssetDatabase.FindAssets("t:LocalizationSettings")
    。若找到,加载第一个结果并将其赋值给
    LocalizationEditorSettings.ActiveLocalizationSettings
  2. 创建: 若未找到,创建新实例并保存至
    Assets/Localization/LocalizationSettings.asset
    。使用
    ScriptableObject.CreateInstance<LocalizationSettings>()
    ,随后调用
    AssetDatabase.CreateAsset()
  3. 激活: 设置
    LocalizationEditorSettings.ActiveLocalizationSettings = settings
  4. 区域设置: 确保已存在所需区域设置(如en、fr、de等)。若缺失则创建,并使用
    LocalizationEditorSettings.AddLocale(locale)
    添加到设置中。

2. Modifying Localization Tables

2. 修改本地化表

Programmatic changes to String or Asset tables require notification to the Editor. Always create the required asset tables, unless there is already an existing one in the project.
对字符串或资源表进行程序化修改时,需通知编辑器。 除非项目中已存在对应的资源表,否则务必创建所需的资源表。

Safe Population Pattern

安全填充模式

When populating tables from a dataset, match by
Locale.Identifier.Code
explicitly. The order of
GetLocales()
is not guaranteed to match your input data array — assuming it does will cause silent data mismatches that are very hard to debug. For Asset Tables, use the GUID of the asset:
table.GetEntry(sharedId) ?? table.AddEntry(sharedId, guid);
.
从数据集填充表时,需显式匹配
Locale.Identifier.Code
GetLocales()
的返回顺序无法保证与输入数据数组一致——若假设顺序一致,会导致难以调试的静默数据不匹配问题。 对于资源表,使用资源的GUID:
table.GetEntry(sharedId) ?? table.AddEntry(sharedId, guid);

Refresh & Notification

刷新与通知

After any modification (adding keys, updating values), notify the Editor so it can refresh its internal state. Skipping this will leave the Editor showing stale data until the next reimport.
  1. Call
    EditorUtility.SetDirty(collection)
    ,
    EditorUtility.SetDirty(collection.SharedData)
    , on each modified
    Table
    .
  2. Unity 6+ Notification:
    LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(sender, collection);
  3. Always call
    AssetDatabase.SaveAssets()
    at the end.
完成任何修改(添加键、更新值)后,需通知编辑器以刷新其内部状态。跳过此步骤会导致编辑器显示陈旧数据,直到下次重新导入。
  1. 对每个修改过的
    Table
    ,调用
    EditorUtility.SetDirty(collection)
    EditorUtility.SetDirty(collection.SharedData)
  2. Unity 6+ 通知:
    LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(sender, collection);
  3. 最后务必调用
    AssetDatabase.SaveAssets()

3. UI Localization and Layout

3. UI本地化与布局

Namespacing & Conflicts

命名空间与冲突

  • Always qualify names: Use
    UnityEngine.UI.Image
    ,
    UnityEngine.UI.VerticalLayoutGroup
    ,
    UnityEngine.UI.ScrollRect
    ,
    UnityEngine.UI.Mask
    ,
    UnityEngine.UI.CanvasScaler
    ,
    UnityEngine.UI.GraphicRaycaster
    ,
    UnityEngine.UI.ContentSizeFitter
    ,
    UnityEngine.UI.LayoutRebuilder
    , etc.
  • UnityEngine.UI
    is both a namespace and a class container, so unqualified names produce
    CS0118
    (namespace used like a type). Full qualification avoids this entirely.
  • Single Instance: Always check
    GameObject.Find("YourCanvasName")
    and destroy the old one before creating a new one.
  • No Debug Dropdown: NEVER create a manual UI dropdown or debug menu to change the locale. The Localization package has a built-in way to do this properly (e.g., via the "Localization Scene Controls" window for previews).
  • 始终限定名称: 使用
    UnityEngine.UI.Image
    UnityEngine.UI.VerticalLayoutGroup
    UnityEngine.UI.ScrollRect
    UnityEngine.UI.Mask
    UnityEngine.UI.CanvasScaler
    UnityEngine.UI.GraphicRaycaster
    UnityEngine.UI.ContentSizeFitter
    UnityEngine.UI.LayoutRebuilder
    等完整限定名。
  • UnityEngine.UI
    既是命名空间也是类容器,使用非限定名会导致
    CS0118
    错误(命名空间被当作类型使用)。使用完整限定名可完全避免此问题。
  • 单实例: 创建新实例前,务必检查
    GameObject.Find("YourCanvasName")
    并销毁旧实例。
  • 禁止调试下拉菜单: 绝不要手动创建UI下拉菜单或调试菜单来切换区域设置。Localization包已提供正确的内置方式(例如,通过“Localization Scene Controls”窗口进行预览)。

Localized String Events (Robust Binding)

本地化字符串事件(可靠绑定)

  • Check Component Type: Identify if the target is
    TextMeshPro
    or legacy
    UnityEngine.UI.Text
    .
  • Bind Correctly: add the public
    UnityEngine.Localization.Components.LocalizeStringEvent
    component and wire it yourself — set
    StringReference
    to the table entry, then add an
    OnUpdateString
    listener that assigns the value to the text component (
    TMP_Text.text
    for TextMeshPro,
    UnityEngine.UI.Text.text
    for legacy Text).
    Do not reflect into
    UnityEditor.Localization.Plugins.TMPro.LocalizeComponent_TMPro
    or its UGUI counterpart. Those are
    internal
    (measured on Localization 1.5.12), so reaching them means routing around access control to reach an API Unity makes no stability commitment about — it can change or disappear in any package release.
    LocalizeStringEvent
    is public and does the same job with the wiring made explicit.
  • Layout Rebuild: After setting localized text or populating a list, call
    UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(parentTransform)
    to ensure dimensions update.
  • 检查组件类型: 识别目标组件是
    TextMeshPro
    还是旧版
    UnityEngine.UI.Text
  • 正确绑定: 添加公开的
    UnityEngine.Localization.Components.LocalizeStringEvent
    组件并自行完成连线——将
    StringReference
    设置为表条目,然后添加
    OnUpdateString
    监听器,将值赋值给文本组件(TextMeshPro使用
    TMP_Text.text
    ,旧版文本使用
    UnityEngine.UI.Text.text
    )。
    请勿反射调用
    UnityEditor.Localization.Plugins.TMPro.LocalizeComponent_TMPro
    或其UGUI对应组件。这些组件是
    internal
    (基于Localization 1.5.12版本),调用它们意味着绕过访问控制使用Unity未承诺稳定性的API——该API可能在任何包版本更新中变更或消失。
    LocalizeStringEvent
    是公开API,可完成相同工作且连线逻辑清晰。
  • 布局重建: 设置本地化文本或填充列表后,调用
    UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(parentTransform)
    以确保尺寸更新。

4. Asian Language Font Support (CJK)

4. 亚洲语言字体支持(CJK)

Avoid TMP Fallback Fonts for CJK locales. Use Asset Table Font Swapping for each specific locale instead — fallbacks are unreliable and hard to debug when glyphs are missing.
  1. Use locale-specific fonts: Western fonts like Arial or Liberation Sans don't contain CJK glyphs, which results in "tofu" (square blocks). Always use a font designed for the target language:
    • For Simplified Chinese (zh-Hans): Use
      msyh.ttc
      (Microsoft YaHei) or equivalent.
    • For Japanese (ja): Use
      msgothic.ttc
      (MS Gothic) or equivalent.
    • For Korean (ko): Use
      malgun.ttf
      (Malgun Gothic) or equivalent.
    • If system font copying fails, stop and report it. Do not substitute with a Western font.
  2. Robust Font Creation: Create dynamic
    TMP_FontAsset
    from imported fonts.
  3. Multi-Atlas & Dynamic: CJK character sets are too large for static atlases; a single atlas will run out of space immediately.
    • fontAsset.atlasPopulationMode = AtlasPopulationMode.Dynamic;
    • fontAsset.isMultiAtlasTexturesEnabled = true;
  4. Sub-Assets: Save atlas and material as sub-assets, or they'll be lost on reimport:
    AssetDatabase.AddObjectToAsset(fontAsset.atlasTexture, fontAsset);
    .
    • Explicitly link the material's texture:
      fontAsset.material.mainTexture = fontAsset.atlasTexture;
      and set both as dirty before saving.
  5. Addressables: Every asset referenced in an Asset Table must be marked as Addressable.
    • Do not reference assets inside a
      Resources/
      folder in an Asset Table. This causes
      OperationException: Failed to load sub-asset
      errors. If an asset is in
      Resources/
      , copy it to
      Assets/Fonts/
      or similar before making it Addressable.
    • If a font asset is deleted and recreated, the new GUID must be manually updated in the Asset Table and re-added to Addressables.
  6. Specialized Types: For TextMesh Pro font swapping, prefer
    LocalizedTmpFont
    over
    LocalizedAsset<TMP_FontAsset>
    to avoid implicit conversion errors.
  7. Build Requirement: After updating Asset Tables or Addressable groups, trigger a build:
    AddressableAssetSettings.BuildPlayerContent();
    .
针对CJK区域设置,避免使用TMP fallback字体。改为为每个特定区域设置使用资源表字体切换——fallback字体不可靠,且当字形缺失时难以调试。
  1. 使用区域特定字体: Arial或Liberation Sans等西文字体不包含CJK字形,会导致出现“tofu”(方块空白)。务必使用为目标语言设计的字体:
    • 简体中文(zh-Hans): 使用
      msyh.ttc
      (微软雅黑)或等效字体。
    • 日语(ja): 使用
      msgothic.ttc
      (MS Gothic)或等效字体。
    • 韩语(ko): 使用
      malgun.ttf
      (Malgun Gothic)或等效字体。
    • 若系统字体复制失败,需停止操作并报告,切勿用西文字体替代。
  2. 可靠创建字体: 从导入的字体创建动态
    TMP_FontAsset
  3. 多图集与动态模式: CJK字符集过大,无法放入静态图集;单个图集会立即耗尽空间。
    • 设置
      fontAsset.atlasPopulationMode = AtlasPopulationMode.Dynamic;
    • 设置
      fontAsset.isMultiAtlasTexturesEnabled = true;
  4. 子资源: 将图集和材质保存为子资源,否则重新导入时会丢失:
    AssetDatabase.AddObjectToAsset(fontAsset.atlasTexture, fontAsset);
    • 显式关联材质的纹理:
      fontAsset.material.mainTexture = fontAsset.atlasTexture;
      ,并在保存前将两者标记为脏数据。
  5. Addressables: 资源表中引用的所有资源必须标记为Addressable。
    • 请勿在资源表中引用
      Resources/
      文件夹内的资源,这会导致
      OperationException: Failed to load sub-asset
      错误。若资源位于
      Resources/
      中,需先复制到
      Assets/Fonts/
      或类似目录,再标记为Addressable。
    • 若字体资源被删除并重新创建,必须手动更新资源表中的新GUID,并重新添加到Addressables中。
  6. 专用类型: 对于TextMesh Pro字体切换,优先使用
    LocalizedTmpFont
    而非
    LocalizedAsset<TMP_FontAsset>
    ,以避免隐式转换错误。
  7. 构建要求: 更新资源表或Addressable组后,触发构建:
    AddressableAssetSettings.BuildPlayerContent();

Verification Step

验证步骤

Before concluding any CJK localization task:
  1. The Tofu Check: Switch the editor locale to
    zh-Hans
    ,
    ja
    , and
    ko
    . Inspect the UI. If any characters appear as squares (tofu), the font setup has FAILED.
  2. Asset Table Check: Verify that the
    AssetTable
    for the CJK locale points to the correct CJK
    TMP_FontAsset
    , NOT a default Western font.
  3. Multi-Atlas Check: Confirm
    isMultiAtlasTexturesEnabled
    is
    true
    on the CJK font assets.
完成任何CJK本地化任务前,请执行以下验证:
  1. 方块字符检查: 将编辑器区域设置切换为
    zh-Hans
    ja
    ko
    ,检查UI。若任何字符显示为方块(tofu),则字体设置失败。
  2. 资源表检查: 确认CJK区域设置的
    AssetTable
    指向正确的CJK
    TMP_FontAsset
    ,而非默认西文字体。
  3. 多图集检查: 确认CJK字体资源的
    isMultiAtlasTexturesEnabled
    设置为
    true

5. Automatic Layout (UGUI)

5. 自动布局(UGUI)

  • Parent:
    VerticalLayoutGroup
    with
    Child Control Height: True
    ,
    Child Force Expand Height: False
    .
  • Labels: Each label must have a
    ContentSizeFitter
    set to
    Vertical Fit: Preferred Size
    .
  • TMP: Set
    Enable Word Wrapping: True
    and
    Overflow: Overflow
    .
  • 父容器: 使用
    VerticalLayoutGroup
    ,设置
    Child Control Height: True
    Child Force Expand Height: False
  • 标签: 每个标签必须添加
    ContentSizeFitter
    ,设置
    Vertical Fit: Preferred Size
  • TMP: 设置
    Enable Word Wrapping: True
    Overflow: Overflow

Notes when translating an existing project

现有项目本地化注意事项

  • Minimal Code Changes: Never modify code unrelated to localization. Use a static helper class (e.g.,
    L10n
    ) to wrap
    LocalizationSettings.StringDatabase.GetLocalizedString
    for easy injection into existing scripts.
  • Robust Mapping Strategy: When mapping existing UI text to keys, sort keys by string length (descending) and match longest strings first. This prevents short strings (like "NO") from matching parts of longer sentences. Use case-insensitive matching where appropriate.
  • Component Event Listeners: When setting up
    LocalizeStringEvent
    via script, avoid
    UnityEventTools.AddPersistentListener
    as it often fails to set the dynamic mode (Mode 0) correctly. Instead, use the SerializedObject Pattern described in Section 3 to explicitly set
    m_MethodName
    to
    set_text
    and
    m_Mode
    to
    0
    . Persistent listeners MUST point to a method on a
    UnityEngine.Object
    ; lambdas will fail.
  • Initialization & Refresh:
    • LocalizationEditorSettings.CreateStringTableCollection
      expects a directory path (e.g.,
      Assets/Localization
      ), not a full asset path.
    • Always call
      lEvent.RefreshString()
      after assigning a
      LocalizedString
      reference programmatically to update the UI immediately.
    • Ensure keys are added to all tables in a collection (en, de, ja, etc.) to avoid "No translation found" errors.
  • Namespaces & Linq: Always include
    using System.Linq;
    when searching collections and
    using UnityEngine.Localization;
    when working with locales or tables.
  • Verification: After modifying tables or addressables, run
    AddressableAssetSettings.BuildPlayerContent()
    and switch the Editor locale to verify changes. Check
    LocalizationSettings.Instance
    status after activation.
  • Smart Strings: Set up smart strings where needed. Inspect the context of each string by taking the entire UI it is on, and any scripts that affect it, into account. Set the context on the string table to ensure translations make sense.
  • 最小化代码变更: 绝不修改与本地化无关的代码。使用静态辅助类(如
    L10n
    )封装
    LocalizationSettings.StringDatabase.GetLocalizedString
    ,以便轻松注入现有脚本。
  • 可靠映射策略: 将现有UI文本映射到键时,按字符串长度降序排序,优先匹配最长字符串。这可防止短字符串(如“NO”)匹配长句子的部分内容。在合适场景使用不区分大小写的匹配。
  • 组件事件监听器: 通过脚本设置
    LocalizeStringEvent
    时,避免使用
    UnityEventTools.AddPersistentListener
    ,因为它常无法正确设置动态模式(Mode 0)。 而是使用第3节中描述的序列化对象模式,显式将
    m_MethodName
    设置为
    set_text
    m_Mode
    设置为
    0
    。持久监听器必须指向
    UnityEngine.Object
    上的方法;使用lambda会失败。
  • 初始化与刷新:
    • LocalizationEditorSettings.CreateStringTableCollection
      需要目录路径(如
      Assets/Localization
      ),而非完整资源路径。
    • 通过编程方式分配
      LocalizedString
      引用后,务必调用
      lEvent.RefreshString()
      以立即更新UI。
    • 确保键添加到集合中的所有表(en、de、ja等),避免出现“未找到翻译”错误。
  • 命名空间与Linq: 搜索集合时务必包含
    using System.Linq;
    ,处理区域设置或表时务必包含
    using UnityEngine.Localization;
  • 验证: 修改表或Addressables后,运行
    AddressableAssetSettings.BuildPlayerContent()
    并切换编辑器区域设置以验证变更。激活后检查
    LocalizationSettings.Instance
    状态。
  • 智能字符串(Smart Strings): 按需设置智能字符串。需结合字符串所在的整个UI及所有影响它的脚本,检查每个字符串的上下文。在字符串表中设置上下文,确保翻译符合预期含义。

6. Recommended Translation Strategy

6. 推荐翻译策略

To efficiently translate an existing project, follow this multi-step workflow:
  1. Extraction & Component Setup:
    • Find all occurrences: Scan all scenes and prefabs for strings in code and UI components (Legacy
      UnityEngine.UI.Text
      ,
      TextMeshPro
      , buttons, etc.).
    • Shared Table: Create a central String Table (e.g.,
      UIStrings
      ) with the base language and a "Context" column for each key to guide translators.
    • Attach Components: For every UI element found, attach a
      LocalizeStringEvent
      (for text) and a
      LocalizedFont
      helper (for font swapping).
    • Validation: Ensure these components are set up with persistent listeners (
      EditorAndRuntime
      ) so they update in the Editor immediately when the locale changes.
  2. Context-Aware Translation:
    • Translate: Once the table is populated, provide translations for each locale.
    • Context is King: Always refer to the "Context" column or inspect the UI layout to ensure the translation fits the intended meaning and space.
    • Grammar & Tone: Ensure the tone matches the game's style. For example, use imperative verbs for buttons (e.g., German: "Lauf!" instead of "Laufen") and correct pluralization for labels (e.g., "Punkte" instead of "Punkt").
  3. Quality Assurance (QA):
    • Scene Controls: Use
      Window > Asset Management > Localization Scene Controls
      or script:
      LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.GetLocale("de");
      .
    • Visual Inspection: Methodically inspect every prefab and scene in the base language and all target languages.
    • Layout Fit: Check for text overflows or "tofu" (missing glyphs). Adjust font sizes or use
      ContentSizeFitter
      if strings are too long.
要高效本地化现有项目,请遵循以下多步骤工作流:
  1. 提取与组件设置:
    • 查找所有实例: 扫描所有场景和预制体,查找代码和UI组件(旧版
      UnityEngine.UI.Text
      TextMeshPro
      、按钮等)中的字符串。
    • 共享表: 创建一个中心字符串表(如
      UIStrings
      ),包含基础语言,并为每个键添加“Context”列以指导翻译人员。
    • 附加组件: 为每个找到的UI元素附加
      LocalizeStringEvent
      (用于文本)和
      LocalizedFont
      辅助组件(用于字体切换)。
    • 验证: 确保这些组件设置了持久监听器(
      EditorAndRuntime
      ),以便区域设置变更时编辑器能立即更新。
  2. 上下文感知翻译:
    • 翻译: 表填充完成后,为每个区域设置提供翻译。
    • 上下文优先: 始终参考“Context”列或检查UI布局,确保翻译符合预期含义和空间要求。
    • 语法与语气: 确保语气匹配游戏风格。例如,按钮使用祈使动词(如德语:“Lauf!”而非“Laufen”),标签使用正确的复数形式(如“Punkte”而非“Punkt”)。
  3. 质量保证(QA):
    • 场景控制: 使用
      Window > Asset Management > Localization Scene Controls
      或脚本:
      LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.GetLocale("de");
    • 视觉检查: 有条理地检查基础语言和所有目标语言下的每个预制体和场景。
    • 布局适配: 检查文本溢出或“tofu”(缺失字形)问题。若字符串过长,调整字体大小或使用
      ContentSizeFitter

API Reference

API参考

For detailed API usage, common namespace conflicts, Addressables patterns, and font repair steps, see references/api-notes.md.
如需详细API用法、常见命名空间冲突、Addressables模式及字体修复步骤,请参阅references/api-notes.md

7. Accelerated Localization Workflow

7. 加速本地化工作流

To localize an entire project efficiently, use a batch processing script that handles all scenes in one pass.
Ask before acting: Before running any batch operation, confirm with the user:
"This will open every scene in the project, attach
LocalizeStringEvent
components, and save all modified scenes. This cannot be undone automatically. Shall I proceed?"
Only proceed once the user has confirmed. The batch processor template is in resources/L10nBatchProcessor.cs.
要高效本地化整个项目,可使用批处理脚本一次性处理所有场景。
操作前确认: 运行任何批处理操作前,需与用户确认:
"这将打开项目中的所有场景,附加
LocalizeStringEvent
组件,并保存所有修改后的场景。此操作无法自动撤销。是否继续?"
仅在用户确认后再执行。批处理处理器模板位于resources/L10nBatchProcessor.cs

Technical Tips for Speed

提速技术提示

  • Table References: Use
    TableReference
    names (strings) instead of GUIDs — they are easier to read and maintain.
  • Batch Refresh: Use
    LocalizationSettings.Instance.ForceRefresh()
    after modifications to force the UI to update in the editor.
  • Font Swap Automation: Create the
    GameAssets
    table once and use a script to re-assign
    LocalizeFontEvent
    to all labels in one pass.
  • LocalizedFontAsset component: The template is in resources/LocalizedFontAsset.cs.
  • 表引用: 使用
    TableReference
    名称(字符串)而非GUID——更易阅读和维护。
  • 批量刷新: 修改后使用
    LocalizationSettings.Instance.ForceRefresh()
    强制编辑器更新UI。
  • 字体切换自动化: 创建一次
    GameAssets
    表,使用脚本一次性为所有标签重新分配
    LocalizeFontEvent
  • LocalizedFontAsset组件: 模板位于resources/LocalizedFontAsset.cs。",