为什么 react-intl 的 defineMessages 在传入对象引用时会抛出错误?
Why does defineMessages from react-intl throw an error when passing in a object reference?
我正在努力从 Yahoo! 中了解 react-intl
i18n 项目,我 运行 遇到了一个奇怪的问题。我的目标是将基本字符串(英文)存储在组件外部的某种 JSON 文件中,以便非开发人员可以对其进行编辑。
这似乎合乎逻辑,我只能 import
它们,然后在组件中使用我需要的部分,但是当我这样做时 defineMessages
函数会导致错误。
编辑:问题似乎与 babel-plugin-react-intl
插件和 "exporting" 默认字符串有关。应用程序 运行 没问题,但是当 npm run build
命令是 运行 时会发生错误。
.babelrc:
{
"presets": [
"es2015",
"react"
],
"plugins": [
["react-intl", {
"messagesDir": "./build/messages/"
}]
]
}
webpack-config:
module.exports = {
entry: './src/app.js', // The startingpoint of the app
output: {
filename: 'bundle.js', // Name of the "compiled" JavaScript.
path: './dist', // Which dir to put it on disk.
publicPath: '/', // Which relative path to fetch code from on the client.
},
module: {
loaders:[
{
test: /\.jsx?$/, // Convert ES2015/React-code into ES5.
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.json$/, // Load JSON-files into code base.
exclude: /node_modules/,
loader: 'json',
},
]
},
};
package.json:
{
"name": "intl3",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"dependencies": {
"babel-core": "^6.14.0",
"babel-loader": "^6.2.5",
"babel-plugin-react-intl": "^2.2.0",
"babel-preset-es2015": "^6.14.0",
"babel-preset-react": "^6.11.1",
"eslint": "^3.3.1",
"eslint-loader": "^1.5.0",
"eslint-plugin-babel": "^3.3.0",
"eslint-plugin-react": "^6.1.2",
"json-loader": "^0.5.4",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-intl": "^2.1.5",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.1"
},
"devDependencies": {
"babel-plugin-react-intl": "^2.2.0",
"babel-preset-react": "^6.16.0",
"json-loader": "^0.5.4"
},
"scripts": {
"start:dev": "webpack-dev-server --content-base ./ --config webpack.config.js",
"prebuild": "cp index.html ./dist/index.html",
"build": "webpack --config webpack.config.js",
"start": "http-server dist"
},
"keywords": [],
"author": "",
"license": "ISC"
}
有效代码:
import React from 'react';
import { FormattedMessage, defineMessages } from 'react-intl';
const strings = defineMessages({
"title": {
"id": "TITLE",
"description": "Title of the app.",
"defaultMessage": "Intl Company, Inc."
},
"menu": {
"id": "MENU",
"description": "Word for 'menu'.",
"defaultMessage": "Menu"
}
});
const Header = (props) => {
return (
<header>
<div>
<FormattedMessage {...strings.title} values={ { name: 'World' } } />
</div>
</header>
);
};
export default Header;
失败的代码:
const headerStrings = {
"title": {
"id": "TITLE",
"description": "Title of the app.",
"defaultMessage": "Intl Company, Inc."
},
"menu": {
"id": "MENU",
"description": "Word for 'menu'.",
"defaultMessage": "Menu"
}
};
const strings = defineMessages(headerStrings);
尝试传递引用而不是直接传递对象时收到的错误消息:
./src/components/Header.js
Module build failed: SyntaxError: [React Intl] `defineMessages()` must be called with an object expression with values that are React Intl Message Descriptors, also defined as object expressions.
17 | };
18 |
> 19 | const strings = defineMessages(headerStrings);
| ^
20 |
21 | const Header = (props) => {
22 | return (
BabelLoaderError: SyntaxError: [React Intl] `defineMessages()` must be called with an object expression with values that are React Intl Message Descriptors, also defined as object expressions.
17 | };
18 |
> 19 | const strings = defineMessages(headerStrings);
| ^
20 |
21 | const Header = (props) => {
22 | return (
如果您将 babel-plugin-react-intl
与 webpack 一起使用,请确保您只加载一次 babel 插件,通过 .babelrc
或 webpack.config.js
,但不要同时加载,因为它 causes the plugin to be loaded 多次,在尝试通过 webpack 运行 时导致完全相同的错误。
defineMessages
的行为不是错误。此函数是 "scrape" 来自组件的默认消息的挂钩。如果您想包含来自 JSON import
的字符串,则不需要 defineMessages
,因为它的目的是导出您的默认消息以传递给翻译人员。
在搜索相同问题时发现了这个,我想我会留下对我帮助最大的答案(基于这个问题的标题)。 defineMessages
旨在与 babel-plugin-react-intl
一起使用,我认为 this issue 更好地描述了预期的功能以及为什么传入先前定义的 object 不起作用以及为什么必须定义defineMessages
调用中的消息
引用 Eric 的回复:
Since Babel is a compiler and not a JavaScript interpreter or runtime you'll need to define the messages you want extracted at the defineMessages() call site. This means that defineMessages() should only be used where the message is actually defined, and you shouldn't use it where the message is referenced.
The whole point of this plugin is to extract the messages from source code and defineMessages() is a hook for this and it's expected that the message descriptor exists within the call site. defineMessages() is an identify function and returns the object passed in, so the most common use case is:
const messages = defineMessages({
greeting: {
id: 'home.greeting',
defaultMessage: 'Hello, {name}!'
}
});
<FormattedMessage {...messages.greeting}/>
我正在努力从 Yahoo! 中了解 react-intl
i18n 项目,我 运行 遇到了一个奇怪的问题。我的目标是将基本字符串(英文)存储在组件外部的某种 JSON 文件中,以便非开发人员可以对其进行编辑。
这似乎合乎逻辑,我只能 import
它们,然后在组件中使用我需要的部分,但是当我这样做时 defineMessages
函数会导致错误。
编辑:问题似乎与 babel-plugin-react-intl
插件和 "exporting" 默认字符串有关。应用程序 运行 没问题,但是当 npm run build
命令是 运行 时会发生错误。
.babelrc:
{
"presets": [
"es2015",
"react"
],
"plugins": [
["react-intl", {
"messagesDir": "./build/messages/"
}]
]
}
webpack-config:
module.exports = {
entry: './src/app.js', // The startingpoint of the app
output: {
filename: 'bundle.js', // Name of the "compiled" JavaScript.
path: './dist', // Which dir to put it on disk.
publicPath: '/', // Which relative path to fetch code from on the client.
},
module: {
loaders:[
{
test: /\.jsx?$/, // Convert ES2015/React-code into ES5.
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.json$/, // Load JSON-files into code base.
exclude: /node_modules/,
loader: 'json',
},
]
},
};
package.json:
{
"name": "intl3",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"dependencies": {
"babel-core": "^6.14.0",
"babel-loader": "^6.2.5",
"babel-plugin-react-intl": "^2.2.0",
"babel-preset-es2015": "^6.14.0",
"babel-preset-react": "^6.11.1",
"eslint": "^3.3.1",
"eslint-loader": "^1.5.0",
"eslint-plugin-babel": "^3.3.0",
"eslint-plugin-react": "^6.1.2",
"json-loader": "^0.5.4",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-intl": "^2.1.5",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.1"
},
"devDependencies": {
"babel-plugin-react-intl": "^2.2.0",
"babel-preset-react": "^6.16.0",
"json-loader": "^0.5.4"
},
"scripts": {
"start:dev": "webpack-dev-server --content-base ./ --config webpack.config.js",
"prebuild": "cp index.html ./dist/index.html",
"build": "webpack --config webpack.config.js",
"start": "http-server dist"
},
"keywords": [],
"author": "",
"license": "ISC"
}
有效代码:
import React from 'react';
import { FormattedMessage, defineMessages } from 'react-intl';
const strings = defineMessages({
"title": {
"id": "TITLE",
"description": "Title of the app.",
"defaultMessage": "Intl Company, Inc."
},
"menu": {
"id": "MENU",
"description": "Word for 'menu'.",
"defaultMessage": "Menu"
}
});
const Header = (props) => {
return (
<header>
<div>
<FormattedMessage {...strings.title} values={ { name: 'World' } } />
</div>
</header>
);
};
export default Header;
失败的代码:
const headerStrings = {
"title": {
"id": "TITLE",
"description": "Title of the app.",
"defaultMessage": "Intl Company, Inc."
},
"menu": {
"id": "MENU",
"description": "Word for 'menu'.",
"defaultMessage": "Menu"
}
};
const strings = defineMessages(headerStrings);
尝试传递引用而不是直接传递对象时收到的错误消息:
./src/components/Header.js
Module build failed: SyntaxError: [React Intl] `defineMessages()` must be called with an object expression with values that are React Intl Message Descriptors, also defined as object expressions.
17 | };
18 |
> 19 | const strings = defineMessages(headerStrings);
| ^
20 |
21 | const Header = (props) => {
22 | return (
BabelLoaderError: SyntaxError: [React Intl] `defineMessages()` must be called with an object expression with values that are React Intl Message Descriptors, also defined as object expressions.
17 | };
18 |
> 19 | const strings = defineMessages(headerStrings);
| ^
20 |
21 | const Header = (props) => {
22 | return (
如果您将 babel-plugin-react-intl
与 webpack 一起使用,请确保您只加载一次 babel 插件,通过 .babelrc
或 webpack.config.js
,但不要同时加载,因为它 causes the plugin to be loaded 多次,在尝试通过 webpack 运行 时导致完全相同的错误。
defineMessages
的行为不是错误。此函数是 "scrape" 来自组件的默认消息的挂钩。如果您想包含来自 JSON import
的字符串,则不需要 defineMessages
,因为它的目的是导出您的默认消息以传递给翻译人员。
在搜索相同问题时发现了这个,我想我会留下对我帮助最大的答案(基于这个问题的标题)。 defineMessages
旨在与 babel-plugin-react-intl
一起使用,我认为 this issue 更好地描述了预期的功能以及为什么传入先前定义的 object 不起作用以及为什么必须定义defineMessages
引用 Eric 的回复:
Since Babel is a compiler and not a JavaScript interpreter or runtime you'll need to define the messages you want extracted at the defineMessages() call site. This means that defineMessages() should only be used where the message is actually defined, and you shouldn't use it where the message is referenced.
The whole point of this plugin is to extract the messages from source code and defineMessages() is a hook for this and it's expected that the message descriptor exists within the call site. defineMessages() is an identify function and returns the object passed in, so the most common use case is:
const messages = defineMessages({
greeting: {
id: 'home.greeting',
defaultMessage: 'Hello, {name}!'
}
});
<FormattedMessage {...messages.greeting}/>