162 lines
5.7 KiB
C#
162 lines
5.7 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.Localization;
|
||
|
||
namespace AibisDream.MiniGame.Language
|
||
{
|
||
public enum ExpressionParticleUnitMode
|
||
{
|
||
Grapheme,
|
||
Word
|
||
}
|
||
|
||
[Serializable]
|
||
public sealed class ExpressionParticleLocaleSettings
|
||
{
|
||
[SerializeField] private string localeCode = "zh-Hans";
|
||
[SerializeField] private ExpressionParticleUnitMode unitMode =
|
||
ExpressionParticleUnitMode.Grapheme;
|
||
[SerializeField, Min(0.1f)] private float targetFontScale = 1f;
|
||
[SerializeField, Min(0.1f)] private float nonTargetFontScale = 1f;
|
||
[SerializeField, Min(0.1f)] private float floatingFontScale = 1f;
|
||
[SerializeField, Min(0f)] private float nonTargetCountScale = 1f;
|
||
[SerializeField, Min(0f)] private float wordSpacing = 0.18f;
|
||
[SerializeField, Range(0.1f, 1f)] private float minimumReadablePhraseScale = 0.65f;
|
||
|
||
public string LocaleCode => localeCode;
|
||
public ExpressionParticleUnitMode UnitMode => unitMode;
|
||
public float TargetFontScale => targetFontScale;
|
||
public float NonTargetFontScale => nonTargetFontScale;
|
||
public float FloatingFontScale => floatingFontScale;
|
||
public float NonTargetCountScale => nonTargetCountScale;
|
||
public float WordSpacing => wordSpacing;
|
||
public float MinimumReadablePhraseScale => minimumReadablePhraseScale;
|
||
|
||
public int ScaleNonTargetCount(int baseCount)
|
||
{
|
||
if (baseCount < 0)
|
||
return baseCount;
|
||
return Mathf.Max(0, Mathf.RoundToInt(baseCount * nonTargetCountScale));
|
||
}
|
||
|
||
public static ExpressionParticleLocaleSettings CreateFallback()
|
||
{
|
||
return new ExpressionParticleLocaleSettings();
|
||
}
|
||
}
|
||
|
||
[CreateAssetMenu(
|
||
fileName = "ExpressionParticleLanguageProfile",
|
||
menuName = "AIBIS/火山/表达粒子语言配置")]
|
||
public sealed class ExpressionParticleLanguageProfile : ScriptableObject
|
||
{
|
||
[SerializeField] private List<ExpressionParticleLocaleSettings> locales = new();
|
||
|
||
private readonly HashSet<string> warnedFallbackLocales =
|
||
new(StringComparer.OrdinalIgnoreCase);
|
||
|
||
public IReadOnlyList<ExpressionParticleLocaleSettings> Locales => locales;
|
||
|
||
public ExpressionParticleLocaleSettings Resolve(LocaleIdentifier locale)
|
||
{
|
||
string code = locale.Code ?? string.Empty;
|
||
ExpressionParticleLocaleSettings exact = FindExact(code);
|
||
if (exact != null)
|
||
return exact;
|
||
|
||
int separator = code.IndexOf('-');
|
||
string language = separator > 0 ? code.Substring(0, separator) : code;
|
||
ExpressionParticleLocaleSettings prefix = FindLanguage(language);
|
||
if (prefix != null)
|
||
return prefix;
|
||
|
||
if (warnedFallbackLocales.Add(code))
|
||
{
|
||
Debug.LogWarning(
|
||
$"[ExpressionParticleLanguageProfile] Locale '{code}' 未配置;" +
|
||
"回退到 Grapheme 粒子模式。");
|
||
}
|
||
|
||
return ExpressionParticleLocaleSettings.CreateFallback();
|
||
}
|
||
|
||
public List<string> GetValidationErrors()
|
||
{
|
||
var errors = new List<string>();
|
||
var codes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||
if (locales == null || locales.Count == 0)
|
||
{
|
||
errors.Add("表达粒子语言配置没有 Locale 项。");
|
||
return errors;
|
||
}
|
||
|
||
foreach (ExpressionParticleLocaleSettings settings in locales)
|
||
{
|
||
if (settings == null)
|
||
{
|
||
errors.Add("表达粒子语言配置包含空项。");
|
||
continue;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(settings.LocaleCode))
|
||
{
|
||
errors.Add("表达粒子语言配置包含空 Locale Code。");
|
||
continue;
|
||
}
|
||
|
||
if (!codes.Add(settings.LocaleCode))
|
||
errors.Add($"表达粒子语言配置存在重复 Locale Code:{settings.LocaleCode}");
|
||
}
|
||
|
||
return errors;
|
||
}
|
||
|
||
private ExpressionParticleLocaleSettings FindExact(string code)
|
||
{
|
||
if (locales == null)
|
||
return null;
|
||
|
||
foreach (ExpressionParticleLocaleSettings settings in locales)
|
||
{
|
||
if (settings != null &&
|
||
string.Equals(
|
||
settings.LocaleCode,
|
||
code,
|
||
StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return settings;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private ExpressionParticleLocaleSettings FindLanguage(string language)
|
||
{
|
||
if (string.IsNullOrEmpty(language) || locales == null)
|
||
return null;
|
||
|
||
foreach (ExpressionParticleLocaleSettings settings in locales)
|
||
{
|
||
if (settings == null || string.IsNullOrWhiteSpace(settings.LocaleCode))
|
||
continue;
|
||
|
||
string configured = settings.LocaleCode;
|
||
int separator = configured.IndexOf('-');
|
||
string configuredLanguage =
|
||
separator > 0 ? configured.Substring(0, separator) : configured;
|
||
if (string.Equals(
|
||
configuredLanguage,
|
||
language,
|
||
StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return settings;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|
||
}
|