78 lines
2.8 KiB
Plaintext
78 lines
2.8 KiB
Plaintext
/**
|
|
* 多语言运行时(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;
|
|
}
|
|
}
|