using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// 文本组件类型枚举 public enum TextComponentType { None = 0, Text = 1, TextEx = 2, GradientText = 3 } /// 单个语言的排版和适配数据节点 [Serializable] public class LanguageConfigItem { [Header("RectTransform 配置")] public Vector2 anchoredPosition = Vector2.zero; public Vector2 sizeDelta = new Vector2(100f, 30f); public Vector2 anchorMin = new Vector2(0.5f, 0.5f); public Vector2 anchorMax = new Vector2(0.5f, 0.5f); public Vector2 pivot = new Vector2(0.5f, 0.5f); public Vector3 localScale = Vector3.one; public Vector3 localRotation = Vector3.zero; [Header("Text 排版与适配配置")] public Font font; public FontStyle fontStyle = FontStyle.Normal; public int fontSize = 14; public float lineSpacing = 1f; public HorizontalWrapMode horizontalOverflow = HorizontalWrapMode.Wrap; public VerticalWrapMode verticalOverflow = VerticalWrapMode.Truncate; public bool resizeTextForBestFit = false; public int resizeTextMinSize = 10; public int resizeTextMaxSize = 40; public TextAnchor alignment = TextAnchor.UpperLeft; public bool alignByGeometry = false; public void ApplyToRectTransform(RectTransform rt) { if (rt == null) return; rt.anchorMin = anchorMin; rt.anchorMax = anchorMax; rt.pivot = pivot; rt.anchoredPosition = anchoredPosition; rt.sizeDelta = sizeDelta; rt.localScale = localScale; rt.localRotation = Quaternion.Euler(localRotation); } public void ReadFromRectTransform(RectTransform rt) { if (rt == null) return; anchorMin = rt.anchorMin; anchorMax = rt.anchorMax; pivot = rt.pivot; anchoredPosition = rt.anchoredPosition; sizeDelta = rt.sizeDelta; localScale = rt.localScale; localRotation = rt.localRotation.eulerAngles; } public void ApplyToText(Text txt) { if (txt == null) return; if (font != null) txt.font = font; txt.fontStyle = fontStyle; txt.fontSize = fontSize; txt.lineSpacing = lineSpacing; txt.horizontalOverflow = horizontalOverflow; txt.verticalOverflow = verticalOverflow; txt.resizeTextForBestFit = resizeTextForBestFit; if (resizeTextForBestFit) { txt.resizeTextMinSize = resizeTextMinSize; txt.resizeTextMaxSize = resizeTextMaxSize; } txt.alignment = alignment; txt.alignByGeometry = alignByGeometry; } public void ReadFromText(Text txt) { if (txt == null) return; font = txt.font; fontStyle = txt.fontStyle; fontSize = txt.fontSize; lineSpacing = txt.lineSpacing; horizontalOverflow = txt.horizontalOverflow; verticalOverflow = txt.verticalOverflow; resizeTextForBestFit = txt.resizeTextForBestFit; resizeTextMinSize = txt.resizeTextMinSize; resizeTextMaxSize = txt.resizeTextMaxSize; alignment = txt.alignment; alignByGeometry = txt.alignByGeometry; } public LanguageConfigItem Clone() => (LanguageConfigItem)MemberwiseClone(); } /// 支持 Unity 序列化的字典 [Serializable] public class LanguageConfigDictionary { public List keys = new List(); public List values = new List(); public LanguageConfigItem Get(string key) { if (string.IsNullOrEmpty(key)) return null; int index = keys.IndexOf(key); return index >= 0 ? values[index] : null; } public void Set(string key, LanguageConfigItem value) { int index = keys.IndexOf(key); if (index >= 0) values[index] = value; else { keys.Add(key); values.Add(value); } } public bool ContainsKey(string key) => keys.Contains(key); public void Remove(string key) { int index = keys.IndexOf(key); if (index >= 0) { keys.RemoveAt(index); values.RemoveAt(index); } } } /// 多语言排版适配器 [RequireComponent(typeof(RectTransform))] public class TextLanguageAdapter : MonoBehaviour { public const string DefaultLangId = "default"; [SerializeField, Tooltip("语言配置字典")] private LanguageConfigDictionary m_LanguageConfigs = new LanguageConfigDictionary(); [SerializeField, Tooltip("目标文本组件类型")] private TextComponentType m_TargetTextType = TextComponentType.None; [SerializeField, Tooltip("关联的文本组件引用")] private Component m_TargetTextComponent; private bool m_IsApplied = false; public TextComponentType TargetTextType => m_TargetTextType; public Component TargetTextComponent => m_TargetTextComponent; public LanguageConfigDictionary LanguageConfigs => m_LanguageConfigs; private void Awake() => DetectTargetComponent(); private void OnEnable() { if (!Application.isPlaying || !m_IsApplied) { string langId = Application.isPlaying ? Language.Id : DefaultLangId; ApplyConfig(langId); } } #if UNITY_EDITOR private void Reset() { DetectTargetComponent(); if (!HasConfig(DefaultLangId)) ReadCurrentToConfig(DefaultLangId); } #endif public LanguageConfigItem GetConfig(string languageId) => m_LanguageConfigs.Get(languageId); public void SetConfig(string languageId, LanguageConfigItem config) => m_LanguageConfigs.Set(languageId, config); public void RemoveConfig(string languageId) => m_LanguageConfigs.Remove(languageId); public bool HasConfig(string languageId) => m_LanguageConfigs.ContainsKey(languageId); public List GetConfiguredLanguages() => new List(m_LanguageConfigs.keys); public void ApplyConfig(string languageId) { var config = GetConfig(languageId); if (config == null) return; config.ApplyToRectTransform(GetComponent()); if (m_TargetTextComponent is Text txt) config.ApplyToText(txt); m_IsApplied = true; } public void ReadCurrentToConfig(string languageId) { var config = new LanguageConfigItem(); config.ReadFromRectTransform(GetComponent()); if (m_TargetTextComponent is Text txt) config.ReadFromText(txt); SetConfig(languageId, config); } public static string GetLanguageShowName(string languageId) { if (Language.languageShowDict != null && Language.languageShowDict.TryGetValue(languageId, out string showName)) return showName; return languageId; } private void DetectTargetComponent() { if (m_TargetTextComponent != null) { DetermineTextType(m_TargetTextComponent); return; } m_TargetTextComponent = GetComponent() ?? GetComponentInChildren(true) as Component ?? GetComponent() ?? GetComponentInChildren(true) as Component ?? GetComponent() ?? GetComponentInChildren(true) as Component; DetermineTextType(m_TargetTextComponent); } private void DetermineTextType(Component component) { m_TargetTextType = component switch { GradientText _ => TextComponentType.GradientText, TextEx _ => TextComponentType.TextEx, Text _ => TextComponentType.Text, _ => TextComponentType.None }; } #if UNITY_EDITOR [ContextMenu("刷新组件检测")] public void Editor_ForceRefreshDetection() { DetectTargetComponent(); UnityEditor.EditorUtility.SetDirty(this); } [ContextMenu("读取当前配置")] public void Editor_ReadCurrentConfig() { ReadCurrentToConfig(DefaultLangId); UnityEditor.EditorUtility.SetDirty(this); } [ContextMenu("应用默认配置")] public void Editor_ApplyDefaultConfig() => ApplyConfig(DefaultLangId); #endif }