data-i18n更新后页面不刷新的正确方案是:优先用textContent更新纯文本,含HTML时确保语言包已转义再用innerHTML;同步设置document.documentElement.lang;跳过input/select/textarea的value等受控状态属性,仅更新placeholder、title等;Intl格式化实例需重建。

data-i18n 属性更新后页面不刷新?别直接 innerHTML 替换
用 data-i18n 标记元素后,语言切换时若直接用 innerHTML 写入翻译值,容易丢失事件监听器、破坏已挂载的 Web Component 或清空用户正在输入的表单内容。这不是“没生效”,而是 DOM 被暴力重建了。
正确做法是:优先用 textContent 更新纯文本节点;若翻译值含 HTML(如带 <strong></strong> 的提示语),必须确保 JSON 语言包中该字段已做 HTML 转义(例如 "common.required": "请填写 <strong>必填项</strong>"),再用 innerHTML 安全写入——且仅限该节点本身,不递归替换子树。
- 检查是否遗漏了
document.documentElement.lang = langCode,否则屏幕阅读器和 CSS 的:lang()伪类不会响应 - 避免在
body上调用innerHTML = ...——这会销毁所有绑定的事件和状态 - 对
input、textarea等控件,只更新其placeholder或title,不碰value
切换语言时表单输入值丢失?同步要绕过 value 属性
用户正在填写的表单字段(value、checked、selected)属于“受控状态”,不是 DOM 属性,而是 JavaScript 运行时状态。语言切换脚本若遍历所有 data-i18n 元素并统一设 textContent,会误伤这些字段。
实操建议:语言刷新逻辑应明确跳过 input、select、textarea 的 value,只处理它们的 placeholder、aria-label、title 和父级说明文字(如 label)。可加白名单过滤:
立即学习“前端免费学习笔记(深入)”;
- 匹配
[data-i18n]:not(input):not(select):not(textarea)更新textContent - 单独处理
input[data-i18n]→ 更新placeholder - 遇到
label[for],先查对应控件是否已填值,再决定是否更新其文本
JSON 语言包怎么拆分才好维护?别堆在一个 big.json 里
把全部翻译塞进一个 zh.json 文件,会导致协作冲突频繁、加载慢、无法按需加载。模块化拆分不是为了炫技,是为了解决真实工程问题。
推荐按功能域拆:比如 common.json(按钮、提示)、form.json(校验消息、字段名)、error.json(API 错误码映射)。加载时用 Promise.all 并行拉取,但首次渲染只等 common.json,其余异步补全。
- 键名用点分隔(
form.email.required),避免嵌套过深导致 JS 查找慢 - 不要用中文作 key(如
"首页": "Home"),键名必须稳定,不随翻译变动 - CI 流程中加入 JSON Schema 校验,确保各语言包 key 集一致,缺失 key 报 warning 而非静默 fallback
Live Server 刷新后语言重置?静态文件服务不等于 i18n 环境
用 lite-server 或 VS Code 的 Live Server 插件启动本地服务时,页面每次刷新都会走完整加载流程:JS 重新执行、navigator.language 重新读取、语言包重新请求。如果你没持久化用户选择(比如存到 localStorage),就必然回到浏览器默认语言。
调试阶段可临时硬编码语言:
const userLang = localStorage.getItem('preferred-lang') || 'zh';
// 启动时立即设置 document.documentElement.lang
document.documentElement.lang = userLang;
更关键的是:确保语言切换函数调用后,也同步写入 localStorage,而不是只改内存变量。
容易被忽略的一点:日期/数字格式化(Intl.DateTimeFormat)必须在语言切换后重建实例,不能复用旧的——否则时间显示仍是上一种语言的格式。



















