Skip to main content

Message Extraction

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

Installation#

npm i -D @formatjs/cli

Extraction#

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: props.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.

TMS--format
Transifex's Structured JSONtransifex
Smartling ICU JSONsmartling
Lingohubsimple
Phrasesimple
Crowdin Chrome JSONcrowdin
Lokalise Structured JSONlokalise
SimpleLocalize JSONsimple