三国卡牌客户端基础资源仓库
lcy
5 天以前 205f59d49bc8b59ac5d5f594db000eda80d48dfa
592 多语言适配

1.实现多语言文字适配组件TextLanguageAdapter
2.定军阁 首通奖励 挑战奖励适配多语言
2个文件已添加
309 ■■■■■ 已修改文件
Assets/Editor/UIComponent/TextLanguageAdapterEditor.cs 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/UIComponent/TextLanguageAdapterEditor.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/UIComponent/TextLanguageAdapterEditor.cs
New file
@@ -0,0 +1,298 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
/// <summary>
/// TextLanguageAdapter 自定义编辑器
/// 提供可视化的多语言排版配置界面
/// </summary>
[CustomEditor(typeof(TextLanguageAdapter), true)]
[CanEditMultipleObjects]
public class TextLanguageAdapterEditor : Editor
{
    private Dictionary<string, bool> m_FoldoutStates = new Dictionary<string, bool>();
    private Dictionary<string, string> m_LanguageShowDict;
    private static readonly string[] m_PresetLanguageIds = { TextLanguageAdapter.DefaultLangId, "zh", "ft", "en"};
    private static readonly string[] m_PresetLanguageNames = { "默认", "简体", "繁体", "English" };
    private string m_CopySourceLanguageId = "";
    protected virtual void OnEnable()
    {
        InitLanguageShowDict();
        if (target is TextLanguageAdapter adapter)
        {
            // 确保 default 配置存在
            if (!adapter.HasConfig(TextLanguageAdapter.DefaultLangId))
            {
                adapter.ReadCurrentToConfig(TextLanguageAdapter.DefaultLangId);
                EditorUtility.SetDirty(adapter);
            }
            foreach (var langId in adapter.GetConfiguredLanguages())
            {
                m_FoldoutStates.TryAdd(langId, false);
            }
        }
    }
    public override void OnInspectorGUI()
    {
        TextLanguageAdapter adapter = target as TextLanguageAdapter;
        DrawBasicInfo(adapter);
        EditorGUILayout.Space();
        DrawLanguageConfigs(adapter);
        if (GUI.changed)
        {
            EditorUtility.SetDirty(target);
        }
    }
    private void InitLanguageShowDict()
    {
        if (m_LanguageShowDict != null) return;
        m_LanguageShowDict = new Dictionary<string, string>();
        for (int i = 0; i < m_PresetLanguageIds.Length; i++)
        {
            m_LanguageShowDict[m_PresetLanguageIds[i]] = m_PresetLanguageNames[i];
        }
    }
    private string GetLanguageDisplayName(string languageId)
    {
        if (m_LanguageShowDict != null && m_LanguageShowDict.TryGetValue(languageId, out string name))
        {
            return name;
        }
        return TextLanguageAdapter.GetLanguageShowName(languageId);
    }
    private void DrawBasicInfo(TextLanguageAdapter adapter)
    {
        EditorGUILayout.BeginVertical(EditorStyles.helpBox);
        EditorGUILayout.LabelField("基本信息", EditorStyles.boldLabel);
        EditorGUI.BeginDisabledGroup(true);
        // 使用新开放的 TargetTextComponent 属性,彻底消除反射
        EditorGUILayout.ObjectField("目标组件", adapter.LanguageConfigs.keys.Count > 0 ? adapter.TargetTextComponent : null, typeof(Component), true);
        EditorGUILayout.EnumPopup("组件类型", adapter.TargetTextType);
        EditorGUI.EndDisabledGroup();
        if (GUILayout.Button("刷新组件检测", GUILayout.Width(120)))
        {
            adapter.Editor_ForceRefreshDetection();
        }
        EditorGUILayout.EndVertical();
    }
    private void DrawLanguageConfigs(TextLanguageAdapter adapter)
    {
        EditorGUILayout.BeginVertical(EditorStyles.helpBox);
        EditorGUILayout.LabelField($"语言排版配置 (必须包含 {TextLanguageAdapter.DefaultLangId} 默认配置)", EditorStyles.boldLabel);
        List<string> configuredLanguages = adapter.GetConfiguredLanguages();
        foreach (var langId in configuredLanguages)
        {
            DrawLanguageConfigItem(adapter, langId);
        }
        EditorGUILayout.Space();
        DrawAddLanguageConfig(adapter);
        EditorGUILayout.EndVertical();
    }
    private void DrawLanguageConfigItem(TextLanguageAdapter adapter, string languageId)
    {
        m_FoldoutStates.TryAdd(languageId, false);
        string displayName = GetLanguageDisplayName(languageId);
        string foldoutLabel = string.IsNullOrEmpty(displayName) ? languageId : $"{languageId} ({displayName})";
        EditorGUI.indentLevel++;
        // 高亮默认配置
        if (languageId == TextLanguageAdapter.DefaultLangId)
        {
            GUI.backgroundColor = new Color(1f, 0.9f, 0.7f);
        }
        m_FoldoutStates[languageId] = EditorGUILayout.Foldout(m_FoldoutStates[languageId], foldoutLabel, true);
        GUI.backgroundColor = Color.white;
        if (m_FoldoutStates[languageId])
        {
            EditorGUI.indentLevel++;
            LanguageConfigItem config = adapter.LanguageConfigs.Get(languageId);
            if (config != null)
            {
                DrawConfigItem(config);
                EditorGUILayout.Space();
                DrawConfigItemActions(adapter, languageId);
            }
            EditorGUI.indentLevel--;
        }
        EditorGUI.indentLevel--;
    }
    /// <summary>
    /// 绘制 RectTransform 和指定的文本适配属性
    /// </summary>
    private void DrawConfigItem(LanguageConfigItem config)
    {
        // 1. RectTransform 配置
        EditorGUILayout.LabelField("RectTransform 配置", EditorStyles.miniBoldLabel);
        EditorGUI.BeginChangeCheck();
        config.anchoredPosition = EditorGUILayout.Vector2Field("Anchored Position", config.anchoredPosition);
        config.sizeDelta = EditorGUILayout.Vector2Field("Size Delta", config.sizeDelta);
        config.anchorMin = EditorGUILayout.Vector2Field("Anchor Min", config.anchorMin);
        config.anchorMax = EditorGUILayout.Vector2Field("Anchor Max", config.anchorMax);
        config.pivot = EditorGUILayout.Vector2Field("Pivot", config.pivot);
        config.localScale = EditorGUILayout.Vector3Field("Local Scale", config.localScale);
        config.localRotation = EditorGUILayout.Vector3Field("Local Rotation", config.localRotation);
        EditorGUILayout.Space();
        // 2. 文本排版与适配配置
        EditorGUILayout.LabelField("文本排版与适配配置", EditorStyles.miniBoldLabel);
        config.font = (Font)EditorGUILayout.ObjectField("Font", config.font, typeof(Font), false);
        config.fontStyle = (FontStyle)EditorGUILayout.EnumPopup("Font Style", config.fontStyle);
        config.fontSize = EditorGUILayout.IntField("Font Size", config.fontSize);
        config.lineSpacing = EditorGUILayout.FloatField("Line Spacing", config.lineSpacing);
        config.alignment = (TextAnchor)EditorGUILayout.EnumPopup("Alignment", config.alignment);
        config.alignByGeometry = EditorGUILayout.Toggle("Align By Geometry", config.alignByGeometry);
        config.horizontalOverflow = (HorizontalWrapMode)EditorGUILayout.EnumPopup("Horizontal Overflow", config.horizontalOverflow);
        config.verticalOverflow = (VerticalWrapMode)EditorGUILayout.EnumPopup("Vertical Overflow", config.verticalOverflow);
        config.resizeTextForBestFit = EditorGUILayout.Toggle("Best Fit", config.resizeTextForBestFit);
        if (config.resizeTextForBestFit)
        {
            EditorGUI.indentLevel++;
            config.resizeTextMinSize = EditorGUILayout.IntField("Min Size", config.resizeTextMinSize);
            config.resizeTextMaxSize = EditorGUILayout.IntField("Max Size", config.resizeTextMaxSize);
            EditorGUI.indentLevel--;
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(target);
        }
    }
    private void DrawConfigItemActions(TextLanguageAdapter adapter, string languageId)
    {
        EditorGUILayout.BeginHorizontal();
        GUILayout.Space(EditorGUI.indentLevel * 15f); // 补偿 GUILayout 忽略 indentLevel 的问题
        if (GUILayout.Button("从当前读取", GUILayout.Width(80)))
        {
            Undo.RecordObject(adapter, "Read Current Config");
            adapter.ReadCurrentToConfig(languageId);
        }
        if (GUILayout.Button("应用", GUILayout.Width(60)))
        {
            Undo.RecordObject(adapter, "Apply Config");
            adapter.ApplyConfig(languageId);
        }
        bool isDefault = languageId == TextLanguageAdapter.DefaultLangId;
        if (!isDefault)
        {
            if (GUILayout.Button("复制到默认", GUILayout.Width(80)))
            {
                Undo.RecordObject(adapter, "Copy to Default");
                adapter.SetConfig(TextLanguageAdapter.DefaultLangId, adapter.LanguageConfigs.Get(languageId)?.Clone());
            }
        }
        // Default 不可删除
        GUI.enabled = !isDefault;
        if (GUILayout.Button("删除", GUILayout.Width(50)))
        {
            Undo.RecordObject(adapter, "Remove Config");
            adapter.RemoveConfig(languageId);
            m_FoldoutStates.Remove(languageId);
        }
        GUI.enabled = true;
        EditorGUILayout.EndHorizontal();
    }
    private void DrawAddLanguageConfig(TextLanguageAdapter adapter)
    {
        // === 添加预设语言 ===
        EditorGUILayout.BeginHorizontal();
        GUILayout.Space(15f);
        EditorGUILayout.LabelField("添加预设语言:", GUILayout.Width(100));
        // Inspector 面板的可用总宽度 (减去右侧滚动条的大致宽度)
        float viewWidth = EditorGUIUtility.currentViewWidth - 30f;
        float currentWidth = 115f; // 起始宽度:15(Space) + 100(LabelWidth)
        float buttonWidth = 64f;   // 按钮宽度 60 + 默认边距大约 4
        for (int i = 0; i < m_PresetLanguageIds.Length; i++)
        {
            string langId = m_PresetLanguageIds[i];
            if (!adapter.HasConfig(langId))
            {
                // 检测当前行是否放得下下一个按钮
                if (currentWidth + buttonWidth > viewWidth)
                {
                    // 放不下,结束当前行,开启新的一行
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.BeginHorizontal();
                    // 新行为了美观,缩进对齐上面的按钮
                    GUILayout.Space(115f);
                    currentWidth = 115f;
                }
                if (GUILayout.Button(m_PresetLanguageNames[i], GUILayout.Width(60)))
                {
                    CreateNewLanguageConfig(adapter, langId);
                }
                // 累加当前行的宽度
                currentWidth += buttonWidth;
            }
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space(2f);
        // === 添加自定义语言 ===
        EditorGUILayout.BeginHorizontal();
        GUILayout.Space(15f);
        EditorGUILayout.LabelField("自定义语言ID:", GUILayout.Width(100));
        m_CopySourceLanguageId = EditorGUILayout.TextField(m_CopySourceLanguageId, GUILayout.Width(80));
        if (GUILayout.Button("添加", GUILayout.Width(50)))
        {
            string newLangId = m_CopySourceLanguageId.Trim();
            if (!string.IsNullOrEmpty(newLangId) && !adapter.HasConfig(newLangId))
            {
                CreateNewLanguageConfig(adapter, newLangId);
                m_CopySourceLanguageId = "";
                GUI.FocusControl(null);
            }
        }
        EditorGUILayout.EndHorizontal();
    }
    /// <summary> 辅助方法:封装新建语言配置的复用逻辑 </summary>
    private void CreateNewLanguageConfig(TextLanguageAdapter adapter, string langId)
    {
        Undo.RecordObject(adapter, "Add Language Config");
        LanguageConfigItem newConfig = adapter.HasConfig(TextLanguageAdapter.DefaultLangId)
            ? adapter.LanguageConfigs.Get(TextLanguageAdapter.DefaultLangId).Clone()
            : new LanguageConfigItem();
        adapter.SetConfig(langId, newConfig);
        m_FoldoutStates[langId] = true; // 自动展开新添加的项
    }
}
Assets/Editor/UIComponent/TextLanguageAdapterEditor.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1e0a1735a8abc0489031257cdf9e038
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant: