IntlProvider未自动为FormattedMessage注入ID的问题求助
问题描述
按照FormatJS的自动ID生成指南配置IntlProvider下的FormattedMessage组件后,运行时未自动注入ID,控制台报错:
An
idmust be provided to format a message. You can either:
- Configure your build toolchain with babel-plugin-formatjs
or @formatjs/ts-transformer
基于create-react-app创建React项目,已集成react-intl并遵循官方安装说明,相关配置如下:
项目配置文件
babel.config.json
{ "plugins": [ [ "formatjs", { "idInterpolationPattern": "[sha512:contenthash:base64:6]", "ast": true } ] ] }
package.json
{ "name": "react-intl-test", "version": "0.1.0", "private": true, "dependencies": { "@types/node": "^16.18.23", "@types/react": "^18.0.35", "@types/react-dom": "^18.0.11", "babel-plugin-formatjs": "^10.4.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-intl": "^6.3.2", "react-scripts": "5.0.1", "typescript": "^4.9.5" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "extract": "formatjs extract src/**/*.ts* --ignore=**/*.d.ts --out-file lang/en-US.json --id-interpolation-pattern [sha512:contenthash:base64:6]", "compile": "formatjs compile lang/en-US.json --ast --out-file src/compiled-lang/en-US.json" }, "eslintConfig": { "extends": "react-app", "plugins": [ "formatjs" ], "rules": { "formatjs/no-offset": "error" } }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@babel/core": "^7.21.4", "@formatjs/cli": "^6.0.4", "babel-plugin-formatjs": "^10.4.0", "eslint": "^8.38.0", "eslint-plugin-formatjs": "^4.9.1" } }
tsconfig.json
{ "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react" }, "include": [ "src" ] }
App.tsx
import React from 'react'; import './App.css'; import { FormattedMessage } from 'react-intl'; function App() { return ( <div className="App"> hello <FormattedMessage description="other part of hello world" defaultMessage='world'></FormattedMessage> </div> ); } export default App;
en-US.json
{ "Oup1TP": [ { "type": 0, "value": "world" } ] }
已启用enforceId lint规则,可匹配到en-US.json中的ID;手动添加ID时应用正常,但自动ID注入未生效。
解决方法
核心原因
create-react-app默认不会加载项目根目录的babel.config.json,导致配置的babel-plugin-formatjs未在编译阶段生效,无法自动为FormattedMessage注入ID。
方案1:用react-app-rewired自定义Babel配置
- 安装依赖:
npm install react-app-rewired customize-cra --save-dev
- 在项目根目录创建
config-overrides.js:
const { override, addBabelPlugin } = require('customize-cra'); module.exports = override( addBabelPlugin([ 'formatjs', { idInterpolationPattern: '[sha512:contenthash:base64:6]', ast: true } ]) );
- 修改
package.json中的启动脚本:
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" }
方案2:使用TypeScript Transformer(适合TS项目)
- 安装依赖:
npm install @formatjs/ts-transformer --save-dev
- 通过craco配置webpack,在ts-loader中添加transformer,创建
craco.config.js:
const { default: formatjsTransformer } = require('@formatjs/ts-transformer'); module.exports = { typescript: { configure: (webpackConfig) => { webpackConfig.module.rules.forEach(rule => { if (rule.oneOf) { rule.oneOf.forEach(oneOfRule => { if (oneOfRule.test?.toString().includes('tsx|ts')) { oneOfRule.options.getCustomTransformers = () => ({ before: [formatjsTransformer({ idInterpolationPattern: '[sha512:contenthash:base64:6]' })] }); } }); } }); return webpackConfig; } } };
- 修改
package.json脚本使用craco启动:
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test" }
方案3:Eject项目(不推荐)
执行npm run eject暴露项目配置后,修改config/webpack.config.js中的babel-loader配置,手动添加formatjs插件。
额外检查
确保IntlProvider正确包裹应用,并加载编译后的语言文件:
import { IntlProvider } from 'react-intl'; import enUS from './compiled-lang/en-US.json'; import App from './App'; ReactDOM.render( <IntlProvider locale="en-US" messages={enUS}> <App /> </IntlProvider>, document.getElementById('root') );
内容的提问来源于stack exchange,提问作者xzist
相关产品推荐
相关产品推荐

