/** * 多语言运行时(1.3.9)。 * * 纯逻辑实现:语言标签归一化、支持列表匹配、用户偏好与系统语言的协商。 * 资源文件仍由 resources/<语言>/element/string.json 提供,本类只决定「用哪个语言」。 * * 协商顺序(对应 I18N-001 设计): * 1) 用户显式选择且在支持列表内 → 用它; * 2) 否则取系统语言,按「完全匹配 → 主语言匹配」找支持项; * 3) 都不匹配 → 回退 fallback(中文简体)。 * * 标签规范:小写化并用 '-' 分隔,如 zh-Hans-CN、en-US;忽略大小写与下划线差异。 */ export class I18nUtil { /** 归一化语言标签:小写、下划线转连字符、去空白。 */ static normalize(tag: string): string { return tag.trim().toLowerCase().replace('_', '-'); } /** 主语言(第一个子标签),如 zh-Hans-CN → zh。 */ static primaryOf(tag: string): string { const normalized: string = I18nUtil.normalize(tag); const idx: number = normalized.indexOf('-'); return idx < 0 ? normalized : normalized.substring(0, idx); } /** 是否在支持列表中(完全匹配,忽略大小写)。 */ static isSupported(tag: string, supported: string[]): boolean { const target: string = I18nUtil.normalize(tag); for (let i = 0; i < supported.length; i++) { if (I18nUtil.normalize(supported[i]) === target) { return true; } } return false; } /** 在支持列表中找到与给定标签最匹配的项;找不到返回 undefined。 */ static match(tag: string, supported: string[]): string | undefined { const target: string = I18nUtil.normalize(tag); for (let i = 0; i < supported.length; i++) { if (I18nUtil.normalize(supported[i]) === target) { return supported[i]; } } const primary: string = I18nUtil.primaryOf(target); for (let i = 0; i < supported.length; i++) { if (I18nUtil.primaryOf(supported[i]) === primary) { return supported[i]; } } return undefined; } /** * 协商最终语言。 * @param systemTag 系统语言,如 zh-Hans-CN * @param userTag 用户偏好(空表示跟随系统) * @param supported 支持列表,顺序即优先级 * @param fallback 回退语言 */ static negotiate(systemTag: string, userTag: string, supported: string[], fallback: string): string { if (userTag.length > 0) { const byUser: string | undefined = I18nUtil.match(userTag, supported); if (byUser !== undefined) { return byUser; } } if (systemTag.length > 0) { const bySystem: string | undefined = I18nUtil.match(systemTag, supported); if (bySystem !== undefined) { return bySystem; } } return fallback; } }