Skip to main content

Message Extraction

Now that you've declared some messages, it's time to extract them.


npm i -D @formatjs/cli


Add the following command to your package.json scripts:

{  "scripts": {    "extract": "formatjs extract"  }}

and execute with npm:

npm run extract -- 'src/**/*.ts*' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'
ID Interpolation Pattern

Make sure this pattern matches idInterpolationPattern when you use babel-plugin-formatjs or @formatjs/ts-transformer in Bundling with formatjs or you'll get a MISSING_TRANSLATION error.

Given a file that has the following messages:

import * as React from 'react'import {FormattedMessage, useIntl, injectIntl} from 'react-intl'
class PasswordChangeWithIntl extends React.Component {  render() {    const {intl} = this.props    return (      <li>        <input          placeholder={intl.formatMessage({            defaultMessage: 'New Password',            description: 'placeholder text',          })}        />        <input          placeholder={intl.formatMessage({            id: 'explicit-id',            defaultMessage: 'Confirm Password',            description: 'placeholder text',          })}        />      </li>    )  }}
const PasswordChange = injectIntl(PasswordChangeWithIntl)
export function List(props) {  const intl = useIntl()  return (    <section>      <header>        <FormattedMessage          defaultMessage="Control Panel"          description="title of control panel section"        />      </header>      <ul>        <li>          <button>            <FormattedMessage              defaultMessage="Delete user {name}"              description="Delete button"              values={{                name:,              }}            />          </button>        </li>        <PasswordChange />      </ul>    </section>  )}

running the above command will create a file called lang/en.json:

{  "hak27d": {    "defaultMessage": "Control Panel",    "description": "title of control panel section"  },  "haqsd": {    "defaultMessage": "Delete user {name}",    "description": "delete button"  },  "19hjs": {    "defaultMessage": "New Password",    "description": "placeholder text"  },  "explicit-id": {    "defaultMessage": "Confirm Password",    "description": "placeholder text"  }}
Message ID

During extraction, we'll preserve explicit declared IDs and insert a hash as an ID for messages without. We recommend against explicit IDs since it can cause collision.

Automatic ID Generation#

Since manual IDs are discouraged, we've provided a babel plugin and a TypeScript AST transformer that will automatically insert message IDs in your transpiled code. For more details please visit Bundling with formatjs.

Translation Management System (TMS) Integration#

The default format generated from @formatjs/cli might not work with the specific TMS/vendor you're working with. You can specify a custom formatter with --format <formatFile> that allows you to convert that format into something tailored to your TMS. For example:

If your vendor accepts the format like

{  "[id]": {    "string": "[message]",    "comment": "[description]"  }}

you can run

npm run extract -- "src/**/*.{ts,tsx,vue}" --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format formatter.js

where formatter.js is:

exports.format = function (msgs) {  const results = {}  for (const [id, msg] of Object.entries(msgs)) {    results[id] = {      string: msg.defaultMessage,      comment: msg.description,    }  }  return results}

We also provide several builtin formatters to integrate with 3rd party TMSes so feel free to create PRs to add more.

Transifex's Structured JSONtransifex
Smartling ICU JSONsmartling
Crowdin Chrome JSONcrowdin
Lokalise Structured JSONlokalise
SimpleLocalize JSONsimple