如何使用RelativeTimeFormat.formatToParts实现本地化时长展示?
如何提取RelativeTimeFormat中的本地化单位(剥离方向词)
这个问题确实戳中了Intl.RelativeTimeFormat的一个小痛点——它的formatToParts方法并没有把方向词(比如英文的"in"/"ago"、中文的"前"/"后")和单位词("秒"/"second")分开标记,导致我们没法直接提取纯粹的本地化单位。不过别担心,我们可以利用多语言下时间表述的共性来解决这个问题。
核心思路
对于任意语言,同一个时间单位的“未来”和“过去”表述,差异只在方向词,单位词是完全一致的。比如:
- 英文:未来是
in 1 second,过去是1 second ago→ 共同单位是second - 中文:未来是
1秒后,过去是1秒前→ 共同单位是秒 - 西班牙语:未来是
en 1 minuto,过去是hace 1 minuto→ 共同单位是minuto
我们可以利用这个共性,通过以下步骤提取单位:
- 用
Intl.NumberFormat生成本地化的数字字符串(比如英文的"1"、阿拉伯语的"١") - 用
RelativeTimeFormat分别生成未来(+1单位)和过去(-1单位)的完整字符串 - 从两个字符串中移除本地化数字,得到仅包含方向词和单位的部分
- 找出这两部分的最长公共子串,就是我们需要的本地化单位
代码实现
function getLocalizedDurationUnit(locale, unit) { // 生成本地化的数字"1" const numFormatter = new Intl.NumberFormat(locale); const localizedNum = numFormatter.format(1); // 初始化RelativeTimeFormat(确保numeric为always,避免"a second"这类非数字表述) const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'always' }); const futureStr = rtf.format(1, unit); const pastStr = rtf.format(-1, unit); // 移除数字部分,得到方向词+单位的组合 const futureWithoutNum = futureStr.replace(localizedNum, '').trim(); const pastWithoutNum = pastStr.replace(localizedNum, '').trim(); // 寻找两个字符串的最长公共子串(即单位词) function longestCommonSubstring(strA, strB) { let longestMatch = ''; for (let i = 0; i < strA.length; i++) { for (let j = i + 1; j <= strA.length; j++) { const substring = strA.slice(i, j); if (strB.includes(substring) && substring.length > longestMatch.length) { longestMatch = substring; } } } return longestMatch.trim(); } return longestCommonSubstring(futureWithoutNum, pastWithoutNum); } // 测试示例 console.log(getLocalizedDurationUnit('en-US', 'second')); // "second" console.log(getLocalizedDurationUnit('zh-CN', 'second')); // "秒" console.log(getLocalizedDurationUnit('es-ES', 'minute')); // "minuto" console.log(getLocalizedDurationUnit('ar-SA', 'hour')); // "ساعة"
适配你的页面生成时间场景
当你需要展示“页面生成时间:X秒”这类内容时,可以这样组合使用:
const userLocale = navigator.language; // 获取用户浏览器的本地化语言 const pageLoadTime = 2; // 实际页面生成时长(秒) const timeUnit = 'second'; // 获取本地化单位 const localizedUnit = getLocalizedDurationUnit(userLocale, timeUnit); // 生成本地化数字 const localizedNum = new Intl.NumberFormat(userLocale).format(pageLoadTime); // 处理复数(部分语言需要,比如英文的"second"/"seconds") const rtf = new Intl.RelativeTimeFormat(userLocale, { numeric: 'always' }); const fullPastStr = rtf.format(-pageLoadTime, timeUnit); const pastWithoutNum = fullPastStr.replace(localizedNum, '').trim(); // 剥离方向词,得到带复数的单位组合 const durationStr = fullPastStr.replace(pastWithoutNum, ''); // 最终展示字符串 const displayText = `页面生成时间:${durationStr}`; console.log(displayText); // 英文输出:页面生成时间:2 seconds // 中文输出:页面生成时间:2秒
这个方案完全依赖浏览器原生的Intl API,不需要维护多语言单位词库,能完美适配各种本地化场景。
内容的提问来源于stack exchange,提问作者Sora2455
相关产品推荐
相关产品推荐

