i18next翻译文件加contenthash后如何配置loadPath正确加载
可行实现方案
contenthash是webpack构建阶段基于文件最终产物计算生成的值,运行时代码无法凭空推导得到,必须在构建环节导出「原始翻译文件路径」和「带hash的最终输出路径」的映射关系,供i18next运行时加载使用。
方案1:构建时生成翻译文件映射清单(通用兼容CSR/SSR)
- 第一步:修改copy-webpack-plugin配置,收集所有翻译文件的路径对应关系,构建结束后输出成独立的manifest文件
const path = require('path'); const localeFileMap = {}; // webpack配置里的copy-webpack-plugin配置段 { from: path.resolve(__dirname, 'public/locales/'), to: path.resolve(__dirname, 'dist/locales/[path][name].[contenthash][ext]'), transformPath(targetPath, absolutePath) { // 提取原始文件相对locales目录的路径作为key,比如en/translation.json const relativePath = path.relative(path.resolve(__dirname, 'public/locales/'), absolutePath); // 同目录下仅存带hash的文件名即可 localeFileMap[relativePath] = path.basename(targetPath); return targetPath; } }, // 追加自定义webpack插件,输出映射文件 class ExportLocaleMapPlugin { apply(compiler) { compiler.hooks.afterEmit.tap('ExportLocaleMapPlugin', (compilation) => { const fs = require('fs'); fs.writeFileSync( path.join(compilation.outputOptions.path, 'locales/locale-map.json'), JSON.stringify(localeFileMap) ); }) } } // 记得在webpack插件数组里追加 new ExportLocaleMapPlugin()
- 第二步:i18next初始化时读取映射,配置loadPath
// CSR场景可以在初始化前fetch这个map文件,SSR场景可以直接引入构建后的map文件 const localeMap = require('./dist/locales/locale-map.json'); i18next.use(HttpBackend).init({ backend: { loadPath(lang, ns) { const originFile = `${lang}/${ns}.json`; // 优先取带hash的文件路径,取不到兜底走原始路径 return `/locales/${lang}/${localeMap[originFile] || `${ns}.json`}`; } } })
方案2:SSR场景直接扫描构建目录生成映射
如果是服务端渲染项目,不需要额外生成manifest文件,服务启动时直接扫描构建后的locales目录,通过正则匹配文件名里的语言、命名空间和hash值,在内存里生成映射表传给i18next的loadPath即可,可以减少一次额外的文件输出。
注意:不要在运行时自行计算文件contenthash,webpack生成hash时会结合文件最终编译产物、压缩规则等参数做计算,运行时拿到的文件内容计算出的hash和构建时的hash大概率不一致,会直接触发文件404问题。
内容的提问来源于stack exchange,提问作者Володимир Калиній
相关产品推荐
相关产品推荐

