javascript国际化需用intl.segmenter切分字素、intl.datetimeformat/numberformat格式化、localecompare排序、intl.messageformat处理占位符,避免基础字符串方法导致unicode和区域设置错误。

JavaScript字符串操作在国际化(i18n)中不能简单依赖.length、.charAt()、.substring()或正则匹配等基础方法,因为这些操作不感知Unicode字符边界,容易在处理emoji、复合文字(如阿拉伯语连字、中文繁简变体)、带音标字符(如é、ç)时出错。
用Intl.Segmenter正确切分用户可见的“字符”
用户感知的“一个字符”可能是多个UTF-16码元(如??由5个码元组成),传统.split('')会将其错误拆开。应使用Intl.Segmenter按视觉字素(grapheme cluster)切分:
- 支持语言感知:对阿拉伯语、泰语、日语等自动识别连写、音标组合
- 示例:
const seg = new Intl.Segmenter('zh', { granularity: 'grapheme' }); Array.from(seg.segment('????')).map(s => s.segment).length // → 1 - 注意兼容性:Node.js ≥19 / Chrome ≥90 / Safari ≥15.4,旧环境需回退到
grapheme-splitter等polyfill
格式化日期、数字、货币必须用Intl.DateTimeFormat / Intl.NumberFormat
避免手动拼接字符串(如year + '/' + month),不同地区顺序、分隔符、千分位、小数点完全不同:
- 日期:
new Intl.DateTimeFormat('ja-JP').format(new Date()) // → '2024/04/05';'en-GB'输出'05/04/2024' - 数字:
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(1234.56) // → '1.234,56 €' - 始终传入明确locale(如
navigator.language或用户设置),不依赖toString()默认行为
文本比较和排序要用String.prototype.localeCompare()
直接用===或.sort()会按UTF-16码点排序,导致德语ä排在z之后、中文按Unicode码位乱序:
- 区分大小写、重音、宽度(全角/半角)都可配置:
'café'.localeCompare('cafe', 'fr', { sensitivity: 'base' }) // → 0 - 排序数组:
['Österreich', 'USA', '日本'].sort((a, b) => a.localeCompare(b, 'de')) - 服务端若用Node.js,确保ICU数据完整(安装full-icu或启用--icu-data-dir)
占位符替换优先用Intl.MessageFormat(或标准模板+safe插值)
避免`Hello ${name}`硬编码结构——不同语言主谓宾顺序、复数形式、性别词形变化差异极大:
- 推荐方案:使用
formatjs(基于Intl.MessageFormat)定义消息:{message: 'You have {count, number} {count, plural, one {item} other {items}}'} - 若轻量级,至少用函数封装插值逻辑,预留翻译键名:
t('cart_items_count', { count: 3 }),而非`已选${n}件商品` - 禁止在翻译文本中嵌入HTML或JS逻辑(如
"Click <a>{link}</a>"),应由组件控制结构,翻译仅提供纯文本
不复杂但容易忽略:所有字符串操作只要涉及用户界面展示、输入处理或本地化内容,都该默认走Unicode-aware和locale-aware路径。把.length换成[...str].length只是权宜之计,真正健壮的i18n需要从API选择开始就尊重语言特性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











