- LocalizationManager: 新增翻译表(SetFormatted/SetDuration/LocalizeOperateMsg) - LoginPanel: InputField placeholder本地化、字体颜色保持 - HistoryPanel: 用时数据本地化、placeholder本地化 - RecordDetailPanel: 操作详情消息本地化(LanguageChanged重建) - AppraiseWindowBase: 评价等级本地化、操作消息重建 - EditorAppraiser: 所有评估消息改用InjectOperateMsgLocalized - StudentOperateRecorder: 新增InjectOperateMsgLocalized方法 - LocalizationLanguageTestBar: 单例模式、ScreenSpaceOverlay筛选 - 字体切换时保留颜色和verticalOverflow
246 lines
5.4 KiB
C#
246 lines
5.4 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>
|
|
/// Creates the small per-canvas language switcher used to verify UI localization.
|
|
/// The bar is intentionally built from Unity UI primitives so it has no sprite dependency.
|
|
/// </summary>
|
|
public sealed class LocalizationLanguageTestBar : MonoBehaviour
|
|
{
|
|
private const string BarName = "__LocalizationLanguageTestBar";
|
|
private static readonly string[] Labels = { "中文", "EN", "FR", "RU" };
|
|
private static readonly Color[] Colors =
|
|
{
|
|
new Color(0.12f, 0.48f, 0.24f, 0.96f),
|
|
new Color(0.10f, 0.36f, 0.72f, 0.96f),
|
|
new Color(0.48f, 0.20f, 0.64f, 0.96f),
|
|
new Color(0.66f, 0.20f, 0.16f, 0.96f)
|
|
};
|
|
|
|
private static Sprite backgroundSprite;
|
|
private static LocalizationLanguageTestBar instance;
|
|
|
|
public static void EnsureForActiveCanvases()
|
|
{
|
|
// If we already have a bar, just bring it to front and return.
|
|
if (instance != null)
|
|
{
|
|
instance.transform.SetAsLastSibling();
|
|
return;
|
|
}
|
|
|
|
// Find the first valid root ScreenSpace canvas and create one bar there.
|
|
Canvas[] canvases = Resources.FindObjectsOfTypeAll<Canvas>();
|
|
for (int i = 0; i < canvases.Length; i++)
|
|
{
|
|
Canvas canvas = canvases[i];
|
|
if (canvas == null || !canvas.isActiveAndEnabled || !canvas.gameObject.scene.IsValid()) continue;
|
|
// Only place the bar on Screen Space - Overlay canvases.
|
|
if (canvas.renderMode != RenderMode.ScreenSpaceOverlay) continue;
|
|
// Skip sub-canvases (e.g. Dropdown List) to avoid placing debug bars on overlays.
|
|
if (canvas.transform.parent != null && canvas.transform.parent.GetComponentInParent<Canvas>() != null) continue;
|
|
EnsureForCanvas(canvas);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void EnsureForCanvas(Canvas canvas)
|
|
{
|
|
Transform canvasTransform = canvas.transform;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < canvasTransform.childCount; i++)
|
|
{
|
|
LocalizationLanguageTestBar existing = canvasTransform.GetChild(i).GetComponent<LocalizationLanguageTestBar>();
|
|
if (existing != null)
|
|
{
|
|
instance = existing;
|
|
existing.transform.SetAsLastSibling();
|
|
return;
|
|
}
|
|
}
|
|
|
|
GameObject barObject = new GameObject(BarName, typeof(RectTransform), typeof(LocalizationLanguageTestBar));
|
|
barObject.transform.SetParent(canvasTransform, false);
|
|
RectTransform bar = barObject.GetComponent<RectTransform>();
|
|
bar.anchorMin = new Vector2(0f, 1f);
|
|
bar.anchorMax = new Vector2(0f, 1f);
|
|
bar.pivot = new Vector2(0f, 1f);
|
|
bar.sizeDelta = new Vector2(276f, 30f);
|
|
bar.anchoredPosition = new Vector2(8f, -8f);
|
|
|
|
for (int i = 0; i < Labels.Length; i++) CreateButton(bar, Labels[i], i);
|
|
bar.SetAsLastSibling();
|
|
instance = barObject.GetComponent<LocalizationLanguageTestBar>();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (instance == this) instance = null;
|
|
}
|
|
|
|
private static void CreateButton(RectTransform parent, string label, int language)
|
|
{
|
|
GameObject buttonObject = new GameObject("Language_" + label, typeof(RectTransform), typeof(Image), typeof(Button));
|
|
buttonObject.transform.SetParent(parent, false);
|
|
|
|
RectTransform rect = buttonObject.GetComponent<RectTransform>();
|
|
rect.anchorMin = new Vector2(0f, 0.5f);
|
|
rect.anchorMax = new Vector2(0f, 0.5f);
|
|
rect.pivot = new Vector2(0f, 0.5f);
|
|
rect.sizeDelta = new Vector2(66f, 28f);
|
|
rect.anchoredPosition = new Vector2(language * 70f, 0f);
|
|
|
|
if (backgroundSprite == null)
|
|
{
|
|
Texture2D texture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
|
texture.SetPixel(0, 0, Color.white);
|
|
texture.Apply();
|
|
backgroundSprite = Sprite.Create(texture, new Rect(0, 0, 1, 1), new Vector2(0.5f, 0.5f));
|
|
}
|
|
|
|
Image image = buttonObject.GetComponent<Image>();
|
|
image.sprite = backgroundSprite;
|
|
image.color = Colors[language];
|
|
image.raycastTarget = true;
|
|
|
|
Button button = buttonObject.GetComponent<Button>();
|
|
ColorBlock colors = button.colors;
|
|
colors.normalColor = Color.white;
|
|
colors.highlightedColor = new Color(1f, 1f, 1f, 0.86f);
|
|
colors.pressedColor = new Color(1f, 1f, 1f, 0.66f);
|
|
colors.selectedColor = Color.white;
|
|
colors.disabledColor = new Color(1f, 1f, 1f, 0.4f);
|
|
button.colors = colors;
|
|
int languageIndex = language;
|
|
button.onClick.AddListener(() => LocalizationManager.SetLanguage(languageIndex));
|
|
|
|
GameObject textObject = new GameObject("Label", typeof(RectTransform), typeof(Text));
|
|
textObject.transform.SetParent(buttonObject.transform, false);
|
|
RectTransform textRect = textObject.GetComponent<RectTransform>();
|
|
textRect.anchorMin = Vector2.zero;
|
|
textRect.anchorMax = Vector2.one;
|
|
textRect.offsetMin = Vector2.zero;
|
|
textRect.offsetMax = Vector2.zero;
|
|
|
|
Text text = textObject.GetComponent<Text>();
|
|
text.text = label;
|
|
text.font = LocalizationManager.UIFont;
|
|
text.fontSize = 15;
|
|
text.alignment = TextAnchor.MiddleCenter;
|
|
text.color = Color.white;
|
|
text.raycastTarget = false;
|
|
}
|
|
}
|