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
}