国际化与本地化代码规范

共 19 题
📑 题目列表 19 题
#
★★★

1. 代码中的用户可见字符串硬编码为什么是质量问题,i18n 资源管理与占位符规范如何设计?

代码中的用户可见字符串硬编码为什么是质量问题?i18n 资源管理与占位符规范如何设计?

  • 用户可见字符串硬编码的弊端
  • i18n 资源文件(key-value)管理
  • 占位符(placeholder)规范

(1)硬编码弊端:用户可见字符串硬编码在代码里,会导致:a) 无法多语言适配,改语言需改代码;b) 文案与代码耦合,视觉/文案调整要走发布流程;c) 多语言团队维护时重复、不一致;d) 无法复用与统一管理。

(2)资源管理:把用户可见字符串抽到资源文件(如 messages.properties、JSON、resx),用 key-value 组织,key 用语义化命名(如 order.confirm),值按语言分文件。代码只引用 key,不直接写文案。

(3)占位符规范:带变量的文案用占位符(如 ICU MessageFormat 的 {name}printf%s),避免字符串拼接;占位符命名语义化,值由运行时传入,服务端渲染或客户端渲染按需。

(4)落地:a) lint 禁止在代码中硬编码用户可见字符串(如 ESLint 的 no-hardcoded-strings);b) 资源文件纳入版本管理与翻译流程;c) 占位符与语言规则(复数、性别)配合。

硬编码的根因是'文案与代码耦合'。i18n 资源管理把文案解耦为 key-value,语义化 key 稳定、占位符处理变量,lint 兜底禁止硬编码。这样多语言、文案调整都不动代码。

// 反例:硬编码

alert("订单已提交");

// 正例:资源 key + 占位符

alert(t("order.submitted", { orderId }));

// messages/zh-CN.json

{ "order": { "submitted": "订单 {orderId} 已提交" } }

#
★★★

2. 国际化(i18n)与本地化(l10n)的区别中代码层如何做到"一次开发多语言适配",资源文件与硬编码的边界?

国际化(i18n)与本地化(l10n)的区别是什么?代码层如何做到'一次开发多语言适配'?资源文件与硬编码的边界在哪?

  • i18n(国际化)与 l10n(本地化)的区别
  • 代码层多语言适配(一次开发多语言)
  • 资源文件与硬编码的边界

(1)区别:i18n(internationalization)是'设计层面让产品支持多语言'的能力,涉及架构、编码、资源隔离;l10n(localization)是'针对特定语言/地区做适配',涉及翻译、格式、本地习俗。i18n 是 l10n 的前提。

(2)一次开发多语言:代码层不写死文案,用 key 引用资源;用 locale 上下文选择语言资源;日期、数字、货币用国际标准格式(ICU/ECMA-402)由运行时格式化。这样一套代码支持多语言。

(3)资源文件与硬编码边界:凡是用户可见的文本都应进资源文件;硬编码仅限代码内部不可见、不需翻译的字符串(如内部日志、枚举值、技术标识)。边界是'用户是否看得到、是否需要翻译'。

(4)落地:a) 用资源文件 + locale 机制实现多语言;b) 格式化用标准库而非硬编码;c) 用 lint 约束硬编码边界。

i18n 是'能力/架构',l10n 是'内容/适配'。代码层做到多语言靠'资源隔离 + locale 机制 + 标准格式化'。资源文件与硬编码的边界是'用户可见性':可见文本进资源,内部技术字符串可硬编码。

// locale 上下文选择语言资源

const messages = { 'zh-CN': zhCN, 'en-US': enUS }

const t = messages[locale]

// 日期格式化用标准库

new Intl.DateTimeFormat(locale).format(date)  // 非硬编码

#
★★★

3. 多语言文案的发布解耦中资源文件如何独立于代码发布与热更新,文案变更的审批与生效节奏如何设计?

多语言文案的发布解耦:资源文件如何独立于代码发布与热更新?文案变更的审批与生效节奏如何设计?

  • 资源文件独立于代码的发布与热更新
  • 文案变更的审批流程
  • 生效节奏设计

(1)独立发布:资源文件与代码解耦,可独立发布与热更新。做法:资源文件存于配置中心/远程资源服务(如 i18n 平台、CDN),运行时按需拉取,无需发版即可更新文案。

(2)热更新机制:客户端/服务端按版本或缓存失效策略拉取最新资源;服务端下发文案,客户端缓存与刷新;用版本号或 hash 校验资源更新。

(3)审批流程:文案变更需审批(涉及翻译质量、合规、品牌),建立文案变更的提交-翻译-评审-发布流程,避免随意改动。

(4)生效节奏:文案变更可即时生效(热更新)或随版本生效;重要文案(法律、合规)需走审批与灰度,避免错误文案损害品牌。

文案发布解耦的核心是'资源与代码分离'。资源可独立热更新、无需发版,文案变更走审批流程保证质量,生效节奏按文案重要性分即时/灰度。这样文案迭代快且可控。

// 运行时拉取资源 + 版本校验

const res = await fetch(`/i18n/${locale}.json?v=${version}`)

const messages = await res.json()

// 资源独立于代码,可热更新

#
★★

4. 文本长度、排序与大小写转换在中文/日文/阿拉伯文等语言下的差异如何处理?

文本长度、排序与大小写转换在中文/日文/阿拉伯文等语言下的差异如何处理?

  • 各语言文本长度(字符 vs 字节 vs 显示宽度)
  • 排序(collation)差异
  • 大小写转换的语言差异

(1)文本长度:中文按字符,日文含全角/半角,阿拉伯文含组合字符;长度计算需区分字符、字节、显示宽度(CJK 全角占 2 列)。UI 截断、字段长度校验要按语言正确计算。

(2)排序:各语言排序规则不同(中文按拼音/笔画/部首,日文按五十音,德文含变音,阿拉伯文按字母顺序)。用 ICU Collator 按 locale 排序,勿用默认字节序(会得到错误顺序)。

(3)大小写转换:土耳其语等语言有特殊大小写规则(如土耳其语 i/İ、ı/I),用 locale 感知的转换(toLocaleUpperCase),勿用默认 ASCII 转换。

(4)落地:文本长度用 Unicode 感知的度量;排序用 ICU collation;大小写转换用 locale 感知 API。测试覆盖 CJK、阿拉伯文、土耳其文等。

多语言文本处理的差异源于'字符模型与排序规则'。长度按 Unicode 字符/显示宽度、排序用 ICU collation、大小写用 locale 感知 API,避免默认实现(字节序、ASCII case)在 CJK/阿拉伯文/土耳其文下出错。

// locale 感知排序

['ä','b','a'].sort((x,y) => x.localeCompare(y, 'de'))

// locale 感知大小写

'i'.toLocaleUpperCase('tr-TR')  // 土耳其语 -> İ

#
★★

5. 本地化消息中的复数、性别与占位符在中文/英文/阿拉伯语下的差异,ICU MessageFormat 如何设计?

本地化消息中的复数、性别与占位符在中文/英文/阿拉伯语下的差异如何?ICU MessageFormat 如何设计?

  • 复数规则(中文/英文/阿拉伯语差异)
  • 性别与占位符
  • ICU MessageFormat 的语法定制

(1)复数规则:英文只有单复数(one/other),中文没有语法复数(复数表达与单数相同),阿拉伯语有多类复数(zero/one/two/few/many/other)。不能简单用'单复数'判断,需按语言规则。

(2)性别:部分语言(如法语、德语、俄语)有语法性别,影响形容词/动词变化;ICU MessageFormat 支持 select 按性别选择。

(3)占位符:带变量的文案用 {n} 占位符,结合复数 plural 与性别 select 选择器。

(4)ICU MessageFormat 设计:使用 {count, plural, one{...} other{...}}{gender, select, male{...} female{...} other{...}} 表达复数与性别,变量占位符 {name}。由引擎按 locale 规则渲染,翻译只需提供分支文案。

ICU MessageFormat 把'语言规则'(复数、性别)交给引擎,翻译只需提供各分支文案。它用 plural/select 选择器表达复数与性别差异,占位符 {n} 传变量,避免程序员硬编码复数逻辑。

// ICU MessageFormat:复数 + 性别

'{count, plural, one{# 条消息} other{# 条消息}}'

'{gender, select, male{他} female{她} other{TA}}'

// 阿拉伯语:多类复数

'{count, plural, zero{...} one{...} two{...} few{...} many{...} other{...}}'

#
★★

6. RTL 语言(阿拉伯语/希伯来语)的布局镜像与混合文本方向(bidi)在代码层如何支持?

RTL 语言(阿拉伯语/希伯来语)的布局镜像与混合文本方向(bidi)在代码层如何支持?

  • RTL 布局镜像(布局反转)
  • 混合文本方向(bidi)处理
  • 代码层支持(dir 属性、逻辑属性)

(1)布局镜像:RTL 语言要求布局水平镜像(文本右对齐、边距/图标/箭头方向反转)。用 CSS 的 direction: rtl 与逻辑属性(margin-inline-start 等)而非物理属性(margin-left),避免硬编码方向。

(2)bidi 处理:混合文本(阿拉伯语 + 数字/英文)方向由 Unicode Bidirectional Algorithm 决定,需正确处理;用 bdi 元素或 unicode-bidi 隔离,防止方向错乱。

(3)代码层支持:a) 用逻辑属性(inline/block)而非物理(left/right);b) 设 dir 属性(html 或组件级);c) 图标/箭头用可翻转或逻辑方向;d) 测试 RTL 布局。

(4)测试:用 RTL 语言冒烟测试,检查文本方向、对齐、交互元素位置。

RTL 支持的核心是'避免硬编码方向'。用逻辑属性、dir 属性、bidi 隔离实现镜像与混合方向,程序不写死 left/right。这样一套布局代码自动适配 LTR/RTL。

/* 逻辑属性而非物理属性 */

.nav { margin-inline-start: 16px; }  /* 自动适配 LTR/RTL */

html { direction: rtl; }  /* 整体 RTL */

#
★★

7. Unicode 与编码处理中 UTF-8/UTF-16 的区别、代理对(surrogate pair)、规范化(NFC/NFD)在代码中的注意点?

Unicode 与编码处理中,UTF-8/UTF-16 的区别、代理对(surrogate pair)、规范化(NFC/NFD)在代码中的注意点是什么?

  • UTF-8/UTF-16 编码差异
  • 代理对(surrogate pair)与码点
  • Unicode 规范化(NFC/NFD)

(1)UTF-8/UTF-16:UTF-8 变长(1-4 字节),ASCII 兼容、网络友好;UTF-16 变长(2-4 字节,用代理对表示增补平面字符)。注意:String.length 在 JS 按 UTF-16 码元(code unit)计,与字符数不同。

(2)代理对:增补平面字符(如 emoji、部分生僻字)用两个 UTF-16 码元(代理对)表示。遍历/操作时需按码点(code point)而非码元,或用 Array.fromIntl.Segmenter 处理,避免截断半个代理对。

(3)规范化:同一字符可有不同表示(如 é 可由 e+ 组合重音 或 预组合 é),NFC/NFD 是两种规范化形式。比较/存储时需统一规范化,避免看似相同却不同。

(4)注意点:a) 长度用码点/字符数而非码元;b) 处理代理对用码点遍历;c) 比较/哈希前做 NFC 规范化。

Unicode 处理的坑在'码元 vs 码点'与'规范化'。UTF-16 的代理对让 length 不等于字符数,需按码点处理;NFC/NFD 统一规范化避免比较歧义。这些是文本处理正确性的基础。

// 按码点遍历(而非码元)

const chars = [...'emoji😀']  // 数组按码点切分

// 规范化

'é'.normalize('NFC') === 'é'.normalize('NFC')  // true

#
★★

8. 日期、时间、数字与货币格式中时区处理、夏令时、ICU/ECMA-402 的正确用法,为何格式化不能在前端硬编码、服务端如何下发?

日期、时间、数字与货币格式:时区处理、夏令时、ICU/ECMA-402 的正确用法,为何格式化不能在前端硬编码、服务端如何下发?

  • 时区与夏令时处理
  • ICU/ECMA-402 的正确格式化
  • 格式化不能前端硬编码、服务端下发格式

(1)时区与夏令时:时间应存 UTC,展示时按用户时区转换;夏令时(DST)会让本地时间跳变,存储与计算用 UTC,仅展示时转换。避免用本地时间做存储/计算。

(2)ICU/ECMA-402:用 Intl.DateTimeFormatIntl.NumberFormatIntl.RelativeTimeFormat 按 locale 格式化日期、数字、货币,正确处理时区、小数、货币符号。

(3)为何不能前端硬编码:前端硬编码格式(如 YYYY-MM-DD%.2f)无法适配多 locale、货币与语言差异,且与服务端规则不一致。格式化应交给标准库/服务端。

(4)服务端下发:服务端下发数据(时间戳、数值)与格式规则/本地化配置,前端用标准库按 locale 渲染;货币四舍五入、精度规则由服务端确定。

时间/数字格式化的正确姿势是'存标准、展示按 locale'。时间存 UTC 处理夏令时,格式化用 ICU/ECMA-402 按 locale 渲染,前端不硬编码格式,服务端下发规范数据与规则。

// 按 locale 格式化

new Intl.DateTimeFormat('zh-CN', { timeZone: 'Asia/Shanghai' }).format(date)

new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1000)

// 时间存 UTC,展示时转换

#
★★

9. 本地化测试与回归中语言切换、翻译缺失、文案截断、字数膨胀的自动化验证,伪本地化(pseudo-localization)如何纳入 CI?

本地化测试与回归:语言切换、翻译缺失、文案截断、字数膨胀的自动化验证,伪本地化(pseudo-localization)如何纳入 CI?

  • 本地化测试项(语言切换、翻译缺失、截断、字数膨胀)
  • 自动化验证
  • 伪本地化(pseudo-localization)纳入 CI

(1)测试项:a) 语言切换——验证 UI 能正确切换语言且不崩溃;b) 翻译缺失——校验资源 key 是否都有翻译;c) 文案截断——验证长文案(德文/法文更长)在 UI 中不溢出;d) 字数膨胀——某些语言文本长度膨胀 30-50%,需验证布局。

(2)自动化验证:a) 资源文件完整性检查(所有 locale 的 key 一致,无缺失 key);b) 用 lint 校验资源文件;c) 布局测试用快照/截图比对长文案。

(3)伪本地化:把源文本替换为膨胀的伪本地化文本(如把字符替换为带重音的变体并加长),用于测试布局、硬编码、编码问题,无需真实翻译。

(4)纳入 CI:伪本地化作为构建/测试任务,CI 中运行伪本地化构建并跑布局/冒烟测试,发现硬编码字符串、截断、编码问题。

本地化回归靠'伪本地化 + 资源完整性检查'自动化。伪本地化用膨胀文本暴露布局/编码/硬编码问题,无需翻译;资源校验保证 key 一致性。这两者纳入 CI 能低成本发现本地化缺陷。

// 伪本地化:字符替换 + 加长

function pseudoLocalize(s) { return s.replace(/[a-z]/gi, c => c + 'í').padEnd(s.length * 1.5, '_') }

// CI:伪本地化构建 + 布局测试

#
★★

10. 多语言文案的 key 设计规范中语义化 key vs 展示文本作 key 的取舍,key 命名空间与占位符参数如何管理?

多语言文案的 key 设计规范:语义化 key vs 展示文本作 key 的取舍,key 命名空间与占位符参数如何管理?

  • 语义化 key vs 展示文本作 key
  • key 命名空间(namespace)
  • 占位符参数管理

(1)语义化 key vs 展示文本作 key:用语义化 key(如 order.confirm)而非展示文本(如 确认订单)。展示文本作 key 会随文案修改失效、各语言 key 不一致、难以管理。语义化 key 稳定、表达业务概念。

(2)key 命名空间:key 用层级命名空间(如 order.submit.successerrors.validation),按模块/域组织,避免冲突、便于查找与维护。

(3)占位符参数管理:key 对应文案中的变量用占位符({name}),参数名语义化,由调用方传入;参数类型与必填在资源/文档中约定。

(4)规范落地:用 i18n lint 校验 key 唯一性、命名空间、占位符一致性;禁止硬编码展示文本;key 与术语表联动。

key 设计是'稳定标识 + 层级组织 + 参数化'。语义化 key 表达业务概念、抗文案变化,命名空间组织避免冲突,占位符参数化处理变量。用 lint 固化这套规范。

// 语义化 key + 命名空间

t("order.submit.success", { orderId })

// messages/zh-CN.json

{ "order": { "submit": { "success": "订单 {orderId} 提交成功" } } }

#
★★

11. i18n 框架选型中 ICU MessageFormat、gettext、resx、i18next 等按团队场景如何选择,与构建、发布流程如何集成?

i18n 框架选型:ICU MessageFormat、gettext、resx、i18next 等按团队场景如何选择?与构建、发布流程如何集成?

  • 主流 i18n 框架(ICU MessageFormat、gettext、resx、i18next)
  • 按团队场景选型
  • 与构建、发布流程集成

(1)框架特性:ICU MessageFormat(标准、复数/性别强,跨语言通用);gettext(POSIX 传统、翻译工具成熟,适合 C/Python 等);resx(.NET 原生,XML 资源);i18next(JS 生态,功能丰富、插件多、适合前端)。

(2)选型依据:a) 技术栈(Java/.NET/JS/多语言);b) 复数/性别复杂度(ICU 强);c) 生态与工具链(gettext 有 poedit、i18next 有检测/回退);d) 与构建发布集成。

(3)构建集成:a) 资源文件纳入构建,编译期校验 key 完整性;b) 打包时按 locale 切分资源;c) lint 校验资源。

(4)发布集成:a) 资源可独立发布/热更新;b) 翻译流程(平台/CI)接入资源生成;c) 版本管理资源。

i18n 框架选型按'技术栈、复数/性别复杂度、生态工具'决定。ICU 标准强大、gettext 传统成熟、resx 绑定 .NET、i18next 面向 JS。选型后要与构建(资源校验、打包)和发布(独立更新、翻译流程)集成。

// i18next 前端示例

i18next.init({ lng: 'zh-CN', resources: { 'zh-CN': { translation: { "order.submit": "提交订单" } } } })

i18next.t('order.submit')

#
★★

12. 翻译缺失的运行时回退链中 locale 到语言、默认语言再到 key 的降级顺序与缺失告警如何设计?

翻译缺失的运行时回退链:locale 到语言、默认语言再到 key 的降级顺序与缺失告警如何设计?

  • 翻译回退链(locale → 语言 → 默认语言 → key)
  • 降级顺序设计
  • 缺失告警

(1)回退链:展示文本时按粒度降级查找:a) 完整 locale(如 zh-CN)→ b) 语言(如 zh)→ c) 默认语言(如 en)→ d) 原始 key(兜底,展示 key 本身)。保证任何缺失都有可见结果。

(2)降级顺序:优先精确 locale,逐级回退到通用语言、默认语言,最后 key 兜底。避免直接跳过到默认语言导致丢失地区差异。

(3)缺失告警:回退链末端(用到 key 兜底)时记录缺失告警(日志/监控),上报给翻译/开发,驱动补齐;测试环境可让缺失在 UI 显式显示(如醒目标记)便于发现。

(4)设计:a) 回退链逻辑集中封装(t() 函数);b) 缺失告警带 key 与 locale;c) 生产可配置是否展示 key 或默认文案。

回退链保证'任何 locale 都有可展示结果',降级顺序从精确到通用。缺失末级要用 key 兜底并告警,形成闭环推动补齐。集中封装 t() 让回退与告警统一。

function t(key, locale) {

  const chain = [locale, locale.split('-')[0], 'en', key]

  for (const l of chain) {

    if (resources[l] && resources[l][key]) return resources[l][key]

  }

  reportMissing(key, locale)  // 缺失告警

  return key

}

#
★★

13. 本地化消息中的富文本与链接安全中翻译文案含 HTML 或 URL 时如何避免注入,占位符与富文本如何分离?

本地化消息中的富文本与链接安全:翻译文案含 HTML 或 URL 时如何避免注入,占位符与富文本如何分离?

  • 翻译文案含 HTML/URL 的注入风险
  • 避免 XSS 注入
  • 占位符与富文本分离

(1)注入风险:翻译文案若含 HTML/URL,直接渲染可能引入 XSS(恶意翻译或翻译内容含脚本)。文案是用户输入或第三方翻译,不可信。

(2)避免注入:a) 默认对文案做转义/HTML 编码,不直接当 HTML 渲染;b) 确实需要富文本时,用受控的富文本语法(如 Markdown、ICU 的 {variable} 占位 + 白名单标签),渲染前清理;c) 链接 URL 用白名单协议(http/https)校验。

(3)占位符与富文本分离:把'内容'(变量值)与'格式'(富文本)分离。变量值经转义后插入,富文本标签由受控模板提供,不信任翻译内容里的标签。

(4)落地:a) 渲染用转义 API;b) 富文本用安全的富文本组件(sanitize);c) 链接 URL 校验协议;d) 测试覆盖恶意翻译的注入。

本地化富文本的安全核心是'不信任翻译内容'。默认转义,富文本用受控语法 + 白名单清化,URL 校验协议,占位符与富文本分离。这样翻译内容无法注入脚本。

// 默认转义,富文本受控

message = escapeHtml(t('notice', { name }))  // 变量转义

// 富文本用白名单 HTML(sanitize)

safeHtml = sanitizeHtml(translated, { allowedTags: ['b','a'] })

#

14. RTL(从右到左)布局与混合文本方向(bidi)在代码层面如何支持,镜像、对齐与测试要点是什么?

RTL(从右到左)布局与混合文本方向(bidi)在代码层面如何支持?镜像、对齐与测试要点是什么?

  • RTL 布局镜像与对齐
  • bidi 混合文本方向
  • 镜像与测试要点

(1)镜像:RTL 布局整体水平镜像,文本右对齐、图标/箭头/边距方向反转。用逻辑属性(inline/block)与 direction: rtl 实现,避免硬编码 left/right。

(2)对齐:文本/组件用逻辑对齐(text-align: start/end),图标与箭头用可翻转(transform: scaleX(-1))或逻辑方向。

(3)bidi:混合文本(阿拉伯语 + 数字/英文)方向由 Unicode Bidi 算法处理,用 bdi 隔离或 unicode-bidi 防止方向错乱。

(4)测试要点:a) 加载 RTL 语言验证布局镜像;b) 检查文本方向、对齐、交互元素位置;c) 验证混合文本(数字、URL、邮箱)显示正确;d) 截图/视觉回归。

RTL 支持的关键是'逻辑化而非物理化'。用逻辑属性、direction、bidi 隔离实现镜像与混合方向,测试覆盖 RTL 布局与混合文本。这样一套代码适配 LTR/RTL。

.card { text-align: start; }  /* 逻辑对齐 */

.arrow { transform: scaleX(-1); }  /* RTL 镜像箭头 */

<bdi>{userName}</bdi>  /* 隔离混合方向 */

#

15. 国际化回归测试中伪本地化(pseudo-localization)与语言切换冒烟如何纳入 CI?

国际化回归测试:伪本地化(pseudo-localization)与语言切换冒烟如何纳入 CI?

  • 伪本地化测试
  • 语言切换冒烟测试
  • 纳入 CI

(1)伪本地化:把源文本替换为膨胀的伪本地化文本(加长、加重音),用于暴露布局溢出、硬编码字符串、编码问题,无需真实翻译。

(2)语言切换冒烟:在 CI 中跑各语言(至少 LTR + RTL 代表)的冒烟测试,验证语言切换正确、页面不崩溃、关键元素可见。

(3)纳入 CI:a) 伪本地化作为构建变体,CI 运行伪本地化构建 + 布局/冒烟测试;b) 语言切换冒烟用 E2E 加载多个 locale 并断言关键文案出现;c) 资源完整性校验(key 一致、无缺失)。

(4)价值:无需真实翻译即可在 CI 中发现本地化回归,成本低、反馈快。

国际化回归靠'伪本地化 + 语言切换冒烟'自动化。伪本地化暴露布局/硬编码/编码问题,语言切换冒烟验证多 locale 可用,配合资源完整性校验纳入 CI,低成本防回归。

// E2E:多 locale 冒烟

for (const locale of ['zh-CN', 'en-US', 'ar']) {

  await page.goto(`/?locale=${locale}`)

  await expect(page.locator('h1')).toBeVisible()

}

#

16. 字符串硬编码的治理中资源文件与 key 命名?

字符串硬编码的治理:资源文件与 key 命名如何设计?

  • 字符串硬编码的治理
  • 资源文件组织
  • key 命名规范

(1)治理目标:把用户可见字符串从代码中抽离到资源文件,lint 禁止硬编码,实现多语言与文案管理。

(2)资源文件组织:按模块/域组织资源(如 order.jsonerrors.json),每个 locale 一套文件,key-value 结构。

(3)key 命名:用语义化、层级命名(order.submit.success),表达业务概念与层级,避免展示文本作 key;占位符参数化。

(4)落地:a) lint 规则禁止硬编码用户可见字符串(no-hardcoded-strings);b) 资源 key 完整性校验纳入 CI;c) 新代码强制用资源 key。

硬编码治理的核心是'资源化 + key 规范化'。资源文件按模块组织、语义化 key 命名、lint 禁止硬编码,让多语言与文案管理成为默认。

// 反例:硬编码

const msg = '保存失败'

// 正例:资源 key

const msg = t('errors.save.failed')

#

17. RTL 与多语言布局中文本方向的处理?

RTL 与多语言布局:文本方向(text direction)如何处理?

  • 文本方向(LTR/RTL)处理
  • 布局镜像
  • 多语言布局适配

(1)文本方向:用 dir 属性(html dir="rtl" 或组件级)设置文本/布局方向,LTR 默认,RTL 用于阿拉伯语/希伯来语。

(2)布局镜像:RTL 布局整体镜像,用逻辑属性(margin-inline-start、text-align: start)而非物理属性,实现自动适配。

(3)多语言布局适配:CJK 文本可能更长、阿拉伯文更紧凑,需验证布局不溢出;图标、间距用逻辑方向。

(4)实现:a) 逻辑属性 + direction;b) 测试 LTR 与 RTL 布局;c) 用视觉回归保证一致性。

文本方向处理的核心是'逻辑化'。用 dir 设置方向、逻辑属性实现镜像,避免硬编码左右。布局适配 LTR/RTL 用一套代码,测试覆盖两种方向。

<html dir="rtl">

<!-- 逻辑属性自动适配 -->

.menu { padding-inline-start: 8px; }

#

18. 多语言数据的排序与搜索中 collation、大小写、分词差异在数据库与搜索引擎中的处理,如何避免排序结果随语言环境出错?

多语言数据的排序与搜索:collation、大小写、分词差异在数据库与搜索引擎中的处理,如何避免排序结果随语言环境出错?

  • 多语言排序(collation)
  • 大小写与分词差异
  • 数据库与搜索引擎的处理

(1)collation:数据库排序用 locale 感知的 collation(如 PostgreSQL 的 ICU collation、MySQL 的 utf8mb4_unicode_ci),而非默认字节序,否则中文/日文/德文排序错误。

(2)大小写:部分语言大小写折叠规则特殊(如土耳其语),搜索时用正确的大小写折叠/归一化,避免大小写差异导致漏匹配。

(3)分词:中文、日文无空格分词,搜索需用分词器(如 Elasticsearch 的 IK、Kuromoji 分析器),而非简单按空格切词;阿拉伯文有连字符变化。

(4)避免语言环境出错:a) 数据库用 locale collation;b) 搜索引擎用语言分词器;c) 排序/搜索显式指定 locale,避免依赖服务器默认环境导致结果不一致。

多语言排序搜索的坑在'collation、大小写、分词'。数据库用 locale collation、搜索用语言分词器、大小写按 locale 折叠,并显式指定 locale,避免结果随运行环境变化。

-- 用 locale collation 排序

SELECT name FROM users ORDER BY name COLLATE "zh-CN-x-icu"

// Elasticsearch 中文分词

{ "analyzer": "ik_max_word" }

#

19. 术语表治理中跨语言术语一致性如何用 glossary 与翻译平台保证,代码 key 与术语表如何联动?

术语表治理:跨语言术语一致性如何用 glossary 与翻译平台保证?代码 key 与术语表如何联动?

  • 术语表(glossary)
  • 翻译平台保证术语一致性
  • 代码 key 与术语表联动

(1)glossary:建立术语表,定义核心业务术语的统一译法(如 'order' 统一译'订单'),避免同一术语在不同位置译法不一致。

(2)翻译平台:用翻译平台(如 Lokalise、Phrase、Transifex)的 glossary 功能,翻译时强制术语一致,术语表变更自动提示受影响文案。

(3)代码 key 与术语表联动:key 的语义命名与术语表术语一致(如 order.submitorder 对应术语表'订单'),保证代码、翻译、业务术语三方一致。

(4)落地:a) 术语表纳入翻译流程与 lint 校验;b) 新文案必须匹配术语表;c) key 命名参考术语表,防止漂移。

术语一致性靠'glossary + 翻译平台'。术语表定义统一译法,翻译平台强制应用,代码 key 与术语表联动保证三方一致。这样翻译与代码不产生术语漂移。

// 术语表

{ "order": { "zh": "订单", "en": "order", "ja": "注文" } }

// key 命名与术语表一致

t("order.submit")  // order 对应术语表'订单'