babel-plugin-react-intl-auto
⚠️ DEPRECATED - This plugin is deprecated. React Intl has evolved into FormatJS which now includes automatic ID generation out of the box. For new projects, we recommend using FormatJS directly.
i18n for the component age. Auto management react-intl ID.
React Intl is awesome. But, Global ID management is difficult and confusing.
Many projects, like react-boilerplate, give the ID to the name of the component as a prefix. But it is redundant and troublesome.
This babel-plugin releases you from cumbersome ID management. Based on the file path, this automatically generates a prefixed id.
Also, we strongly encourage you to use extract-react-intl-messages. You can generate json automatically.
Goodbye, global ID!!
Before
import { defineMessages, FormattedMessage } from 'react-intl'
export default defineMessages({
hello: {
id: 'App.Components.Greeting.hello',
defaultMessage: 'hello {name}',
},
welcome: {
id: 'App.Components.Greeting.welcome',
defaultMessage: 'Welcome!',
},
})
const MyComponent = () => (
<FormattedMessage
id="App.Components.Greeting.goodbye"
defaultMessage="goodbye {name}"
/>
)
After
With babel-plugin-react-intl-auto.
import { defineMessages, FormattedMessage } from 'react-intl'
export default defineMessages({
hello: 'hello {name}',
welcome: 'Welcome!',
})
const MyComponent = () => <FormattedMessage defaultMessage="goodbye {name}" />
See examples.
With extract-react-intl-messages
Example usage with extract-react-intl-messages.
$ extract-messages -l=en -o translations 'src/**/*.js'
en.json
{
"components.App.hello": "hello {name}",
"components.App.welcome": "Welcome",
"components.App.189751785": "goodbye {name}" // unique hash of defaultMessage
}
Install
npm
$ npm install --save-dev babel-plugin-react-intl-auto
# Optional: TypeScript support
$ npm install --save-dev @babel/plugin-transform-typescript
yarn
$ yarn add --dev babel-plugin-react-intl-auto
# Optional: TypeScript support
$ yarn add --dev @babel/plugin-transform-typescript
Usage
.babelrc
{
"plugins": [
[
"react-intl-auto",
{
"removePrefix": "app/",
"filebase": false
}
]
]
}
with injectIntl
Input:
import { injectIntl } from 'react-intl'
const MyComponent = ({ intl }) => {
const label = intl.formatMessage({ defaultMessage: 'Submit button' })
return <button aria-label={label}>{label}</button>
}
injectIntl(MyComponent)
↓ ↓ ↓
Output:
import { injectIntl } from 'react-intl'
const MyComponent = ({ intl }) => {
const label = intl.formatMessage({
id: 'App.Components.Button.label',
defaultMessage: 'Submit button',
})
return <button aria-label={label}>{label}</button>
}
injectIntl(MyComponent)
with useIntl
Input:
import { useIntl } from 'react-intl'
const MyComponent = () => {
const intl = useIntl()
const label = intl.formatMessage({ defaultMessage: 'Submit button' })
return <button aria-label={label}>{label}</button>
}
↓ ↓ ↓
Output:
import { useIntl } from 'react-intl'
const MyComponent = () => {
const intl = useIntl()
const label = intl.formatMessage({
id: 'App.Components.Button.label',
defaultMessage: 'Submit button',
})
return <button aria-label={label}>{label}</button>
}
Options
removePrefix
remove prefix.
Type: string | boolean | regexp
Default: ''
if removePrefix is true, no file path prefix is included in the id.
Example (src/components/App/messages.js)
when removePrefix is "src"
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: 'hello world'
});
↓ ↓ ↓ ↓ ↓ ↓
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: {
id: 'components.App.hello',
defaultMessage: 'hello world'
}
});
when removePrefix is "src.components"
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: 'hello world'
});
↓ ↓ ↓ ↓ ↓ ↓
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: {
id: 'App.hello',
defaultMessage: 'hello world'
}
});
when removePrefix is true
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: 'hello world'
});
↓ ↓ ↓ ↓ ↓ ↓
import { defineMessages } from 'react-intl';
export default defineMessages({
hello: {
id: 'hello',
defaultMessage: 'hello world'
}
});
filebase
Type: boolean
Default: false
if filebase is true, generate id with filename.
moduleSourceName
Type: string
Default: react-intl
if set, enables to use custom module as a source for defineMessages etc.
https://github.com/akameco/babel-plugin-react-intl-auto/issues/74#issuecomment-528562743
includeExportName
Type: boolean | 'all'
Default: false
if includeExportName is true, adds named exports as part of the id.
Only works with defineMessages.
Example
export const test = defineMessages({
hello: 'hello {name}',
})
↓ ↓ ↓ ↓ ↓ ↓
export const test = defineMessages({
hello: {
id: 'path.to.file.test.hello',
defaultMessage: 'hello {name}',
},
})
If includeExportName is 'all', it will also add default to the id on default
exports.
extractComments
Use leading comments as the message description.
Only works with defineMessages
Type: boolean
Default: true
Example
export const test = defineMessages({
// Message used to greet the user
hello: 'hello {name}',
})
↓ ↓ ↓ ↓ ↓ ↓
export const test = defineMessages({
hello: {
id: 'path.to.file.test.hello',
defaultMessage: 'hello {name}',
description: 'Message used to greet the user',
},
})
useKey
Only works with intl.formatMessage, FormattedMessage and FormattedHTMLMessage. Instead of
generating an ID by hashing defaultMessage, it will use the key property if
it exists.
Type: boolean
Default: false
Example
intl.formatMessage({
key: 'foobar',
defaultMessage: 'hello'
});
↓ ↓ ↓ ↓ ↓ ↓
intl.formatMessage({
key: 'foobar',
defaultMessage: 'hello',
"id": "path.to.file.foobar"
});
<FormattedMessage key="foobar" defaultMessage="hello" />
↓ ↓ ↓ ↓ ↓ ↓
<FormattedMessage id="path.to.file.foobar" key="foobar" defaultMessage="hello" />
separator
Allows you to specify a custom separator
Type: string
Default: .
Example
when separator is "_"
export const test = defineMessages({
hello: 'hello {name}',
})
↓ ↓ ↓ ↓ ↓ ↓
export const test = defineMessages({
hello: {
id: 'path_to_file_test_hello',
defaultMessage: 'hello {name}',
},
})
relativeTo
Allows you to specify the directory that is used when determining a file's prefix.
This option is useful for monorepo setups.
Type: string
Default: process.cwd()
Example
Folder structure with two sibling packages. packageB contains babel config and depends on packageA.
|- packageA
| |
| -- componentA
|
|- packageB
| |
| -- componentB
| |
| -- .babelrc
Set relativeTo to parent directory in packageB babel config
{
"plugins": [
[
"react-intl-auto",
{
"relativeTo": "..",
// ...
},
],
]
}
Run babel in packageB
cd packageB && babel
Messages in componentA are prefixed relative to the project root
export const test = defineMessages({
hello: 'hello {name}',
})
↓ ↓ ↓ ↓ ↓ ↓
export const test = defineMessages({
hello: {
id: 'packageA.componentA.hello',
defaultMessage: 'hello {name}',
},
})
Support variable
Example
const messages = { hello: 'hello world' }
export default defineMessages(messages)
↓ ↓ ↓ ↓ ↓ ↓
const messages = {
hello: {
id: 'path.to.file.hello',
defaultMessage: 'hello wolrd'
}
};
export default defineMessages(messages);
TypeScript
TypeScript support is bundled with this package. Be sure to include our type
definition and run @babel/plugin-transform-typescript beforehand. This way,
you can also be empowered by extract-react-intl-messages.
tsconfig.json
{
"compilerOptions": {
// ...
"jsx": "preserve"
// ...
},
"include": ["node_modules/babel-plugin-react-intl-auto/**/*.d.ts"]
}
.babelrc
{
"plugins": [["@babel/plugin-transform-typescript"], ["react-intl-auto"]]
}
webpack.config.js
Use babel-loader along with ts-loader when using webpack as well.
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
exclude: [/node_modules/],
use: [
{
loader: 'babel-loader',
},
{
loader: 'ts-loader',
},
],
},
],
},
}
Related
babel-plugin-react-intl-id-hash
If you want short consistent hash values for the ID, you can use react-intl-id-hash in addition to this plugin to help reduce your applications bundle size.
extract-react-intl-messages
Extract react-intl messages.
Contributors
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
License
MIT © akameco