Search code examples
reactjswebpackbabeljsreact-intlbabel-plugin-react-intl

Why does defineMessages from react-intl throw an error when passing in a object reference?


I am trying to get my head around react-intl from the Yahoo! i18n project and I am running into a weird issue. My goal is to store the base string (English) in some sort of JSON files outside the components so they can be edited by non-devs.

It seems logical than I can just import them and then use the parts I need in the component, but the defineMessages function causes an error when I do this.

Edit: The issue seems to be around the babel-plugin-react-intl plugin and "exporting" the default strings. The app runs fine, but when the npm run build command is run the error occurs.

.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"
}

Code that works:

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;

Code that fails:

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);

Error message I get when trying to pass a reference instead of object directly:

./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 (

Solution

  • The behavior of defineMessages is not a bug. This function is a hook to "scrape" the default messages from the component. If you want to include your strings from a JSON import, defineMessages is not necessary since it's purpose is to export your default messages to pass off to a translator.