Files
pi-agent-integrated/pi-web/lib/i18n/format.ts

61 lines
2.0 KiB
TypeScript

import type { Locale, TranslationParams } from "./types";
type MessagesByLocale = Record<string, Record<string, string>>;
/**
* 替换翻译消息中的简单插值占位符。
* @param message 原始翻译消息
* @param params 插值参数
* @returns 完成参数替换后的消息
*/
export function interpolateMessage(message: string, params: TranslationParams = {}): string {
return message.replace(/\{([\w.-]+)\}/g, (token, name: string) => {
const value = params[name];
return value === undefined ? token : String(value);
});
}
/**
* 从当前语言和英语语言包中解析消息。
* @param locale 当前语言
* @param key 翻译 key
* @param messages 各语言的消息字典
* @param params 可选的插值参数
* @returns 翻译结果,缺失时返回 key
*/
export function translateMessage(
locale: Locale,
key: string,
messages: MessagesByLocale,
params: TranslationParams = {},
): string {
const message = messages[locale]?.[key] ?? messages.en?.[key];
if (message === undefined) {
if (process.env.NODE_ENV !== "production") console.warn(`[i18n] Missing translation: ${key}`);
return key;
}
return interpolateMessage(message, params);
}
/**
* 按当前语言格式化相对时间。
* @param date 要格式化的时间
* @param locale 当前语言
* @param now 用于测试或特殊场景的当前时间
* @returns locale-aware 的相对时间文本
*/
export function formatRelativeTime(date: Date | string, locale: Locale, now = new Date()): string {
const target = date instanceof Date ? date : new Date(date);
const diffMs = target.getTime() - now.getTime();
const absMs = Math.abs(diffMs);
const [unit, divisor] = absMs < 60_000
? ["second", 1_000]
: absMs < 3_600_000
? ["minute", 60_000]
: absMs < 86_400_000
? ["hour", 3_600_000]
: ["day", 86_400_000];
const value = Math.round(diffMs / divisor);
return new Intl.RelativeTimeFormat(locale, { numeric: "always" }).format(value, unit as Intl.RelativeTimeFormatUnit);
}