Code Monkey home page Code Monkey logo

babel-plugin-react-intl-auto's Introduction

babel-plugin-react-intl-auto

test Coverage Status styled with prettier tested with jest All Contributors babel-plugin-react-intl-auto Dev Token

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.

#74 (comment)

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

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.

Contributors

Thanks goes to these wonderful people (emoji key):


akameco

💻 ⚠️ 👀 📖

Aleksander Heintz

💻 📖

Ryan Leckey

💻

Adam

💻 📖

Guylian Cox

💻 📖 ⚠️

Carl Grundberg

💡 📖

bradbarrow

💻 📖 ⚠️

Mauro Gabriel Titimoli

💻 ⚠️

Stanislav Ermakov

💻

Chitoku

💻

Kouta Kumagai

📖 💻 ⚠️

Shahyar G

💻

Remco Haszing

💻

jmarceli

💻 ⚠️
Dominik Żegleń
Dominik Żegleń

💻 ⚠️
Filip
Filip "Filson" Pasternak

💻
Eric Masiello
Eric Masiello

💻 ⚠️
Josh Poole
Josh Poole

💻 ⚠️

This project follows the all-contributors specification. Contributions of any kind welcome!

License

MIT © akameco

babel-plugin-react-intl-auto's People

Contributors

adam-26 avatar akameco avatar alxandr avatar bradbarrow avatar carlgrundberg avatar chitoku-k avatar dominik-zeglen avatar ephys avatar ericmasiello avatar greenkeeper[bot] avatar jmarceli avatar kuma-kuma avatar mehcode avatar mgtitimoli avatar pooleparty avatar remcohaszing avatar renovate-bot avatar renovate[bot] avatar shahyar avatar stanislav-ermakov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

babel-plugin-react-intl-auto's Issues

Fix dependencies

Hi,

Yarn Plug ‘n’ Play comes with a new dependencies paradigm and is a bit more strict about what is allowed. The error I got is pretty self-explanatory:

Error: babel-plugin-react-intl tried to access @babel/types, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.

Could you kindly update the dependencies accordingly?

Thanks, and have a nice weekend

Breaks with 7.0.0-beta.3

I just past to the last beta and I get the following error:

Module build failed: TypeError: Cannot read property 'imports' of undefined
    at isImportLocalName (node_modules/babel-plugin-react-intl-auto/lib/index.js:58:40)
    at isValidate (node_modules/babel-plugin-react-intl-auto/lib/index.js:109:8)
    at PluginPass.CallExpression (node_modules/babel-plugin-react-intl-auto/lib/index.js:12:14)

Any idea on this ?

Syntax error: [React Intl] `defineMessages()` must be called with an object expression

  • node version: v10.10.0
  • npm (or yarn) version:
    "babel-plugin-react-intl-auto": "^1.1.1",
    "react-intl": "^2.4.0",
    "react-app-rewire-react-intl": "^2.4.0",
    "react-app-rewired": "^1.5.2",

Do you want to request a feature or report a bug?:
Report a bug

What is the current behavior?:
<FormattedMessage /> is generating IDs, but not adding the ID to the component, and when using the defineMessages API, I get an error when compiling.
image 2018-12-04 at 1 28 54 pm

image 2018-12-04 at 1 32 24 pm

What is the expected behavior?:
As per the documentation, I expect to be able to use defineMessages like so:

image 2018-12-04 at 1 35 35 pm

Am I doing something wrong?

I should mention that I'm using react-app-rewired with a config-overrides file to inject Babel plugins without ejecting CRA. This is my config for react-intl-auto:

config = injectBabelPlugin(
    ["react-intl-auto", { removePrefix: "src" }],
    config
  );

Use leading comment as description?

Adding descriptions is cumbersome, leading to a diminished use of them.
It would be nice if leading comments were extracted and used as the description.

IN:

export default defineMessages({
  // message displayed when credentials are invalid
  errorPassword: 'Invalid Password',

  // message displayed when all is ok
  labelSuccess: {
    defaultMessage: 'Logged in',
  },
});

OUT:

export default defineMessages({
  errorPassword: {
    id: 'app.view.Login.errorPassword',
    defaultMessage: 'Invalid Password',
    description: 'message displayed when credentials are invalid',
  },
  labelSuccess: {
    id: 'app.view.Login.labelSuccess',
    defaultMessage: 'Logged in',
    description: 'message displayed when all is ok',
  },
});

It'd also be great if this was configurable, so we can enable it when generating the various locale files but keep it disabled when building the actual app to reduce the bundle size.

Is this something you'd be interesting in adding? Do you want me to write a PR?

useKey option with intl.formatMessage method's descriptor parameter lost key property at typescript.

  • version:
    ^3.3.0

  • node version:
    v13.8.0

  • npm (or yarn) version:
    yarn v1.19.2

Do you want to request a feature or report a bug?:
Maybe a bug.

What is the current behavior?:
My project work with typescript. And I got a TypeScript error at useKey option with intl.formatMessage method's descriptor parameter. Seem the MessageDescriptor interface dose not have a key property . But It worked fine with <FormattedMessage /> component.

Here is my code:

{/* worked fine with FormattedMessage component */}
<p><FormattedMessage key="autoWithComponent" defaultMessage="auto test" /></p>
{/* got Typescript error */}
<p>{intl.formatMessage({key: 'autoWithMethod', defaultMessage: 'auto test'})}</p>

TypeScript error:

No overload matches this call.
  Overload 1 of 2, '(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType> | undefined): string', gave the following error.
    Argument of type '{ key: string; defaultMessage: string; }' is not assignable to parameter of type 'MessageDescriptor'.
      Object literal may only specify known properties, and 'key' does not exist in type 'MessageDescriptor'.
  Overload 2 of 2, '(descriptor: MessageDescriptor, values?: Record<string, string | number | boolean | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)> | Date | FormatXMLElementFn<...> | null | undefined> | undefined): string | ReactNodeArray', gave the following error.
    Argument of type '{ key: string; defaultMessage: string; }' is not assignable to parameter of type 'MessageDescriptor'.
      Object literal may only specify known properties, and 'key' does not exist in type 'MessageDescriptor'.  TS2769

    87 |               <p>{intl.formatMessage({id : 'a.hello'})}</p>
    88 |               <p><FormattedMessage key="autoWithComponent" defaultMessage="auto test" /></p>
  > 89 |               <p>{intl.formatMessage({key: 'autoWithMethod', defaultMessage: 'auto test'})}</p>
       |                                       ^
    90 |               <p>{intl.formatMessage({defaultMessage: 'auto test 02'})}</p>
    91 |               <SubmitButton />
    92 |             </div>

What is the expected behavior?:
No typescript errors.
Sorry I am new to typescript. Is that a way to solve this at tsconfig?
Anyway thanks !

Suggested solution:
Not yet.

/examples/with-flow not working

  • version: ^2.4.0
  • node version: v10.10.0
  • yarn version: 1.12.3

Reporting a bug.

With a clean pull of the example directory, running yarn returns errors, the first of which is:

warning Error running install script for optional dependency: "/Users/Storm/Development/playground/react-intl-auto/node_modules/fsevents: Command failed.

The expected behaviour is to run:

$ yarn
$ npm link babel-plugin-react-intl-auto

and get the example working.

Integration issue with extract-react-intl-messages

  • version: 1.6.0
  • node version: 8.12.0
  • npm (or yarn) version: 6.4.1

Do you want to request a feature or report a bug?:
Report a bug

What is the current behavior?:
As per the suggestion in README, I have tried using extract-react-intl-messages for descriptors' extraction. To achieve this, I took the following steps-

  1. Run babel on my src directory (attached babelrc) -
{
  "presets": [
    [
      "babel-preset-react-app"
    ]
  ],
  "plugins": [
    [
      "react-intl-auto",
      {
        "removePrefix": true,
        "includeExportName": true
      }
    ]
  ]
}
  1. Run extract-messages script to get the json.

This fails to extract the labels defined through JSX elements like Formatted message.

Running babel with intl-auto plugin prior to extract script, converts the JSX elements to React.createElement calls. Running extract script after this, intenally invokes babel-plugin-react-intl which only visits JSXOpeningElement and CallExpression nodes. Since, the JSX nodes are already converted to function calls, it misses on these translations.

What is the expected behavior?:
It should extract labels from JSX defined descriptors too.

Could you please help point out the steps I am missing or executing the wrong way to achieve this integration?

Ids are missing if the FormattedMessage uses the same defaultMessage

  • version: 3.3.0
  • node version:
  • npm (or yarn) version:

Do you want to request a feature or report a bug?:
Bug

What is the current behavior?:
For FormattedMessage if the FormattedMessage is placed directly inside a span, the ID fails to generate for the second component and react-intl will throw the invariant missing ID message when the component is rendered.

This should reproduce the error

<span>
<FormattedMessage defaultMessage='Hi There' />
</span>

What is the expected behavior?:
All FormattedMessages would successfully generate an ID

Suggested solution:
I've worked around this by hardcoding an id in the specific messages that were failing to generate an ID or by using

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Support for <FormattedMessage /> API

Do you want to request a feature or report a bug?:
Feature

What is the current behavior?:
Currently auto-generated id feature is working only for defineMessages API.
If you don't assign id to the <FormattedMessage /> the translation key will be generated by babel-plugin-react-intl-auto but react-intl will raise an error and break the app because the id attribute is required by react-intl.

What is the expected behavior?:
babel-plugin-react-intl-auto should insert the id attribute to <FormattedMessage /> if it's missing similarly as it inserts the id to defineMessages.

Unexpected crash when using useIntl()

  • version: 3.0.1 / 3.1.0
  • node version: v12.14.0
  • npm (or yarn) version: yarn 1.21.1

Do you want to request a feature or report a bug?:

Bug

What is the current behavior?:

Given the following code:

import React from 'react';
import { Helmet } from 'react-helmet';
import { MessageDescriptor, useIntl } from 'react-intl';

export interface HelmIntlProps {
  title: MessageDescriptor;
  titleValues?: Record<string, string>;
}

export default function HelmetIntl({ title, titleValues = {} }: HelmIntlProps): React.ReactElement {
  const intl = useIntl();

  return <Helmet title={intl.formatMessage(title, titleValues)} />;
}

I get the following stack trace from webpack:

ERROR in ./packages/studio/components/HelmetIntl/HelmetIntl.tsx
Module build failed (from ./node_modules/babel-loader/lib/index.js):
TypeError: packages/studio/components/HelmetIntl/HelmetIntl.tsx: Cannot read property 'properties' of undefined
    at NodePath._getKey (node_modules/@babel/traverse/lib/path/family.js:178:25)
    at NodePath.get (node_modules/@babel/traverse/lib/path/family.js:170:17)
    at NodePath._getPattern (node_modules/@babel/traverse/lib/path/family.js:210:21)
    at NodePath.get (node_modules/@babel/traverse/lib/path/family.js:172:17)
    at getObjectProperties (node_modules/babel-plugin-react-intl-auto/lib/utils/index.js:54:37)
    at addIdToFormatMessage (node_modules/babel-plugin-react-intl-auto/lib/visitors/addIdToFormatMessage.js:61:53)
    at PluginPass.CallExpression (node_modules/babel-plugin-react-intl-auto/lib/index.js:21:56)
    at newFn (node_modules/@babel/traverse/lib/visitors.js:179:21)
    at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:55:20)
    at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:42:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:90:31)
    at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:84:19)
    at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:140:19)
    at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:97:18)
    at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitMultiple (node_modules/@babel/traverse/lib/context.js:79:17)
    at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:138:19)
    at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:97:18)
    at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitMultiple (node_modules/@babel/traverse/lib/context.js:79:17)
    at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:138:19)
    at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:97:18)
    at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:84:19)
    at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:140:19)
    at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:97:18)
    at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:84:19)
    at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:140:19)
    at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:97:18)
 @ ./packages/studio/components/HelmetIntl/index.tsx 1:0-39 1:0-39
 @ ./packages/studio/components/ErrorFallback/ErrorFallback.jsx
 @ ./packages/studio/components/ErrorFallback/index.jsx
 @ ./packages/studio/components/App/App.jsx
 @ ./packages/studio/components/App/index.jsx
 @ ./packages/studio/index.jsx
 @ multi ./packages/studio

What is the expected behavior?:

No crash.

Suggested solution:

[feature] support `require()` statements

  • node version: 10.15.3
  • npm (or yarn) version: 6.4.1

Do you want to request a feature or report a bug?:
Feature

What is the current/expected behavior?:
Hi, sorry for opening another issue in such a short amount of time!

I have an issue that currently requires me to run extract-react-intl-messages on files that aren't usually run through Babel. As such, they're currently using defineMessages, but because react-intl is being imported using require() rather than import, the strings don't get exported.

Would adding support for detecting react-intl being imported with require() be outside of the project scope? I'm also unable to upgrade the project in question to Node 12 at the moment due to dependency issues. I would be happy to help contributing, but my experience of working with Babel is very limited.

Inject react-intl-auto to create-react-app doesn't work

  • version: 1.1.0
  • node version: 8.9.1
  • npm (or yarn) version: 5.7.1

I have a bug according to injection react-intl-auto pluging into my create-react-app App. I'm using react-app-rewired and my config is:

const { injectBabelPlugin } = require('react-app-rewired');
const rewireLess = require('react-app-rewire-less');

module.exports = function override(config, env) {
config = injectBabelPlugin(['react-intl-auto', { "removePrefix": "./src/" }], config);
config = rewireLess(config, env);
return config;
};

And I have run-time error with:
The prop id is marked as required in FormattedMessage

I hope I shouldn't do eject to user react-intl-auto
Thanx for any suggestions!

String concatenation causes an error

  • version:
  • node version: v9.4.0
  • npm (or yarn) version: npm 5.6.0 yarn 1.6.0

Do you want to request a feature or report a bug?:
bug

What is the current behavior?:
Following code

import { defineMessages } from 'react-intl'

export default defineMessages({
  successMessage: 'Some long string  string  string  string  string  string  string  string' +
    '  string  string '
})

Produces an error:

[React Intl] An `id` must be provided to format a message.

What is the expected behavior?:
String concatenation should be handled without an error

Suggested solution:
Can't propose a solution for now.

Plugin doesn’t work with `.tsx` files, but does work for `.jsx`

Hello homies,

After some work I got the plugin to work, but only for .jsx files. When I rename a file extension to .tsx, I get a runtime error complaining that Error: [React Intl] An id must be provided to format a message.

  • All dependencies are up-to-date
  • Node v12.10.0
  • Yarn 1.9.4
  • babel-plugin-react-intl: 5.1.16
  • babel-plugin-react-intl-auto: 3.1.0

.babelrc.js

/** Plugins run before presets. Plugin ordering is first to last. */
plugins: [
	['@babel/plugin-transform-runtime', { corejs: 3 }],
	'@babel/plugin-transform-async-to-generator',
	'@babel/plugin-syntax-dynamic-import',
	['@babel/plugin-proposal-decorators', { legacy: true }],
	'@babel/plugin-proposal-class-properties',
	'@babel/plugin-proposal-export-default-from',
	['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }],
	'@babel/plugin-proposal-throw-expressions',
	'@babel/plugin-proposal-object-rest-spread',
	'@babel/plugin-proposal-optional-chaining',
	'@babel/plugin-proposal-numeric-separator',
	['module-resolver', { alias }],
	['@babel/plugin-transform-typescript', { isTSX: true }],
	'react-intl-auto',
	['react-intl', { extractFromFormatMessageCall: true }]
],

/** Presets run after plugins. Preset ordering is reversed (last to first). */
presets: [
	['@babel/preset-env', { corejs: 3, useBuiltIns: 'usage' }],
	'@babel/preset-react'
]

tsconfig.json

{
	"compilerOptions": {
		"allowJs": true,
		"alwaysStrict": true,
		"baseUrl": ".",
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true,
		"jsx": "react",
		"lib": ["dom", "es2017.intl", "es2018.intl", "esnext"],
		"module": "esnext",
		"moduleResolution": "node",
		"noEmitOnError": true,
		"noErrorTruncation": true,
		"noFallthroughCasesInSwitch": true,
		"noImplicitAny": true,
		"noImplicitReturns": true,
		"noImplicitThis": true,
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"resolveJsonModule": true,
		"sourceMap": true,
		"target": "es5",
		"typeRoots": ["node_modules/@types", "@types"]
	},
	"exclude": ["node_modules", "**/*.spec.ts", "**/*.test.ts"],
	"include": ["node_modules/babel-plugin-react-intl-auto/**/*.d.ts"]
}

Webpack config:

const DEV = process.env.NODE_ENV !== 'production'

const BABEL_LOADER = {
	loader: 'babel-loader',
	options: {
		plugins: [['babel-plugin-ramda', { useES: true }]],
		presets: ['@babel/preset-env']
	}
}

/** Webpack settings that are shared between `client.js` and `server.js` */
module.exports = (env, argv) => ({
	context: path.resolve(__dirname, '../../'),
	devtool: DEV ? 'cheap-module-source-map' : 'source-map', // See client.js (*)
	mode: DEV ? 'development' : 'production',
	module: {
		rules: [
			{
				exclude: /node_modules/,
				include,
				test: /\.tsx?$/,
				use: [BABEL_LOADER, { loader: 'ts-loader' }]
			},
			{
				exclude: /node_modules/,
				include,
				test: /\.jsx?$/,
				use: BABEL_LOADER
			}
		]
	},

	plugins: [
		new webpack.WatchIgnorePlugin([
			// /\.js$/, /\.d\.ts$/
			/css\.d\.ts$/
		])
	],

	resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx', '.json', '.scss'] }
})

Any help would be greatly appreciated!

use regex or Array for removePrefix option

Feature request: use regex or Array for removePrefix option
I have messages in different folders and I'd like to remove prefix (which is therefore different for each folder) for all of them.

What is the current behavior?:
We can only set a string.

What is the expected behavior?:
even removePrefix: 'regex'
or removePrefixes: ['string1', 'string2']

Suggested solution:

[feature] Dynamic ids

  • version: 1.1.1
  • node version: 10.13.0
  • npm version: 6.10.2

Hi @akameco ! Thank you for such a great plugin! We are using it for a few years now and it works great.

I want to ask you is it possible to use constant as message id?

import { defineMessages } from 'react-intl'

const CategoryIds = {
  STROLLER: 'STROLLER',
  BABY_CARRIER: 'BABY_CARRIER',
}

export default defineMessages({
  [CategoryIds.STROLLER]: 'Strollers',
  [CategoryIds.BABY_CARRIER]: 'Carriers',
})

When I try to do like this it throws an error requires Object key or string literal.

Intl.formatMessage method not working because it's not extracted?

version: 3.3.0
node version: 11.x
npm (or yarn) version:

Do you want to request a feature or report a bug?: Maybe bug

I think its not a problem with this lib, but I saw here that a pull request added support for intl.formatMessage. But https://formatjs.io/docs/tooling/babel-plugin tooling shows that

The default message descriptors for the app's default language will be extracted from: defineMessages(), defineMessage(), and ; all of which are named exports of the React Intl package.

So apparently intl.formatMessage is not extracted and then auto id does not find the extraction to parse.
So how does the pull request here for intl.formatMessage support should work if format-js does not extract?

Support React Components

Dear maintainers, thanks for your great plugin. I'm thinking of using it in a mid-size project. Do you have any plans (or maybe is there any ongoing work) to start supporting generating the id prop for React components like <FormattedMessage id="generatedID" />?

Issues using with jest and functional components in react-intl 3

I get two crashes just in jest/enzyme when using Functional Components and react-intl3.

    TypeError: Cannot read property 'key' of undefined

      at NodePath._getKey (node_modules/@babel/traverse/lib/path/family.js:186:25)
      at NodePath.get (node_modules/@babel/traverse/lib/path/family.js:178:17)
      at node_modules/babel-plugin-react-intl-auto/lib/index.js:360:16
      at NodePath.find (node_modules/@babel/traverse/lib/path/ancestry.js:49:9)
      at addIdToFormatMessage (node_modules/babel-plugin-react-intl-auto/lib/index.js:359:18)
      at PluginPass.CallExpression (node_modules/babel-plugin-react-intl-auto/lib/index.js:424:9)
      at newFn (node_modules/@babel/traverse/lib/visitors.js:195:21)
      at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:53:20)
      at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:40:17)
      at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:88:12)

If I add the following code i get past that (line 360)

if (arg && arg.node && arg.get('key') && arg.get('key').node) {
      return arg.get('key').node.name === 'id';
    }

and then i get this error

    TypeError: properties[Symbol.iterator] is not a function

      at addIdToFormatMessage (node_modules/babel-plugin-react-intl-auto/lib/index.js:376:54)
      at PluginPass.CallExpression (node_modules/babel-plugin-react-intl-auto/lib/index.js:428:9)
      at newFn (node_modules/@babel/traverse/lib/visitors.js:195:21)
      at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:53:20)
      at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:40:17)
      at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:88:12)
      at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:120:16)
      at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:92:19)
      at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:148:19)
      at Function.traverse.node (node_modules/@babel/traverse/lib/index.js:96:17)

which i can fix by adding this line of code (line 376)

if (!properties[Symbol.iterator]) {
      return
   }

Let me know if you'd like a pull

Allow Id value to only include export name?

Hi,

Nice library. I would like to configure the options so that the generated id value only includes the exportName, resulting in much shorted id values. I'm happy to do the work if you'll accept such a feature as a PR?

I was thinking that this could easily by achieved by allowing the removePrefix option to also allow a value of true when includeExportName is also true. Example .babelrc:

{
  "plugins": [
    ["react-intl-auto", {
      "removePrefix": true,
      "includeExportName": true
    }]
  ]
}

Using the example from the readme, this would result in:

// before
export const test = defineMessages({
  hello: 'hello {name}',
})

// after
export const test = defineMessages({
  hello: {
    id: 'test.hello',
    defaultMessage: 'hello {name}',
  },
})

You might have an preferred alternative, or prefer to add a new property to allow this? Let me know what you think.

Cheers, Adam.

Usage with gatsby-plugin-intl is not working

I want to use this package together with gatsby-plugin-intl

By using gatsby-plugin-intl I always need to make my imports from this plugin.

import { injectIntl } from "gatsby-plugin-intl";

instead of

import { injectIntl } from "react-intl";

Unfortunately this breaks the auto generation of the IDs and I'm getting the error:

[React Intl] An `id` must be provided to format a message.

I fixed this by importing something from the "react-intl" package even if I don't use it in my component.

import { useIntl } from "react-intl";

This way it works but I wonder if there is a better solution how I can fix this?

Different translation output depending on `filebase` flag while having translation keys duplicated on purpose

  • version: 1.1.0
  • node version: 8.10.0
  • yarn version: 1.7.0

Do you want to request a feature or report a bug?:
Feature

What is the current behavior?:
Currently while having default babel-plugin-react-intl-auto configuration, like (package.json):

  "babel": {
   //    ...
    "plugins": ["react-intl-auto"]
  }

If I have the same keys in object in defineMessages used in different files, eg.

// A.js, B.js
defineMessages({
  hello: 'hello {name}',
  welcome: 'Welcome!',
})

While running
"NODE_ENV=development extract-messages -l=en --flat -o src/translations 'src/**/!(*.test).js'"

I'll get:

{
  "src.containers.hello": "hello {name}",
  "src.containers.welcome": "Welcome!"
}

With configuration of a plugin in package.json like:

  "babel": {
   //    ...
    "plugins": [
        "react-intl-auto", {
            "filebase": true
        }
    ]
  }

I'll get:

{
  "src.containers.A.hello": "hello {name}",
  "src.containers.A.welcome": "Welcome!",
  "src.containers.B.hello": "hello {name}",
  "src.containers.B.welcome": "Welcome!"
}

What is the expected behavior?:
I'm not sure but I would expect to either get an error if I have keys duplication or get the keys generated with some hash to be able to distinguish between them.

[feature] Injection API support (intl.formatMessage)

Thanks for this plugin and your time spent on its development.

Do you have any plans for adding Injection API support?

Currently, the following code won't be extracted and id won't be autogenerated:

intl.formatMessage({ defaultMessage: 'Hello' })

As far as I'm aware in babel-plugin-react-intl there is already a PR waiting for a merge with this feature supported (formatjs/babel-plugin-react-intl#165).
I would be happy to help with implementation but I have no experience with Babel plugins development.

defineMessages does not handle number as keys

  • version: 3.0.0
  • node version: 11.15.0
  • yarn version: 1.21.1

Do you want to request a feature or report a bug?: A bug

What is the current behavior?:
Trying to extract messages which keys are defined as numbers result in an error being thrown :
requires Object key or string literal at the getId function

import { defineMessages } from 'react-intl';

export default defineMessages({
  1000: 'foobar'
});

What is the expected behavior?:
Number keys should be treated as string literals

Can't add description

This will fail with error that FormattedMessage has required id prop which isn't provided.

const messages = defineMessages({
  headerTitle: {
    defaultMessage: 'Welcome to dashboard {name}!',
    description: 'Message to greet the user.',
  },
  fourOfour: 'go to 404 page',
});

It would be nice to allow passing description.

defineMessages isn't parsed when saved in a ts file build with parcel-builder

  • version: 2.3.0
  • node version: 8.16.1
  • npm (or yarn) version: 6.11.3

Do you want to request a feature or report a bug?:
BUG

What is the current behavior?:
When running a project that makes use of this plugin with parcel, it throws the error:

Uncaught Invariant Violation: [React Intl] An `id` must be provided to format a message.

When debugging, the messages still show as a string:string dictionary. The strings are not being converted into a message descriptor. So it looks like this plugin isn't being applied.

What is the expected behavior?:
Having transpiled message descriptors.

Plugin attempts to add id to function parameters.

  • version: 3.1.0
  • node version: 12.7.10
  • npm (or yarn) version: npm v6.13.4

Do you want to request a feature or report a bug?:
Bug

What is the current behavior?:

Passing a variable to intl.formatMessage like so: const foo = (intl, msg) => <div>{intl.formatMessage(msg)}</div> results in an error message of the following sort:

Cannot read property 'properties' of undefined
    at NodePath._getKey (<project path>\node_modules\@babel\traverse\lib\path\family.js:178:25)
    at NodePath.get (<project path>\node_modules\@babel\traverse\lib\path\family.js:170:17)
    at NodePath._getPattern (<project path>\node_modules\@babel\traverse\lib\path\family.js:210:21)
    at NodePath.get (<project path>\node_modules\@babel\traverse\lib\path\family.js:172:17)
    at getObjectProperties (<project path>\node_modules\babel-plugin-react-intl-auto\lib\utils\index.js:54:37)
    at addIdToFormatMessage (<project path>\node_modules\babel-plugin-react-intl-auto\lib\visitors\addIdToFormatMessage.js:61:53)
    at PluginPass.CallExpression (<project path>\node_modules\babel-plugin-react-intl-auto\lib\index.js:21:56)
    at newFn (<project path>\node_modules\@babel\traverse\lib\visitors.js:179:21)
    at NodePath._call (<project path>\node_modules\@babel\traverse\lib\path\context.js:55:20)
    at NodePath.call (<project path>\node_modules\@babel\traverse\lib\path\context.js:42:17) {
  code: 'BABEL_TRANSFORM_ERROR'
}

What is the expected behavior?:

For the plugin to not attempt to add a key to a function parameter and thus, not to throw errors when transpiling.

Suggested solution:

Ensure that contents of a formatMessage()-call are actually something the pluygin can process before attempting it.

Possibility to define prefix in leading comment (file scope)

Do you want to request a feature or report a bug?:
feature

Suggested solution:

In source, before first use of defineMessages or FormattedMessage

// @intl some.leading.string.
/* @msg-scope some.leading.string. */
// $intl-namespace some.leading.string.
// #intlPrefix some.leading.string.
// …

I'm not sure about format, but this can be definitely controlled by configurable regular expression

Including comment like this you can control prefix which is by default autogenerated as this module propose.

This can enable more robust application architecture

Also warnings in case that this prefix is used can be enforced;
In contrary warnings in case when leading comment is missing should be possibly turned on too.

What do you think? I'm apologise when I'm not exact…

ID didn't pass to FormattedMessage

  • version: 3.3.0
  • node version: v14.1.0
  • npm (or yarn) version: yarn v1.22.4

Do you want to request a feature or report a bug?:
I use clean React app (via create-react-app), extraction of the messages works, but if I try use it got Error: [React Intl] An id must be provided to format a message.

What is the current behavior?:
My .babelrc

{
  "presets": [ "@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
  "plugins": [["react-intl-auto", { "removePrefix": "src.Components" }]]
}

I use same message files as in the example.

import { defineMessages } from 'react-intl';

export default defineMessages({ en: 'ABBR_EN' });

and in the component:

<a href="#" onClick={handleClick('en')}>
    <FormattedMessage {...messages.en} />
</a>

What is the expected behavior?:
Pass id and defaultMessage into FormattedMessage component

Production build failing when using with create-react-app

  • version:
  • node version: 12.4.0
  • npm (or yarn) version: 6.9.0

Do you want to request a feature or report a bug?:
bug

What is the current behavior?:
I use babel-plugin-react-intl-auto with create-react-app, it works fine using development server. However, when I build the app, I get this error:

TypeError: Cannot read property 'name' of undefined
at Array.find ()

I used to use this syntax: intl.formatMessage({ ...messages.myMessage }) but I have to change it to: intl.formatMessage(messages.myMessage) to make it work.

What is the expected behavior?:
The build work work with no error.

Suggested solution:

Hash Id values to reduce size of translation files

To enable consistently short id values to be generated, provide an option that will hash each message id.

This could be designed to support multiple algorithms, but initially I suggest the murmur3 algorithm due to its low collision rate and 32bit output. An example configuration:

{
  "plugins": [
    ["react-intl-auto", {
      "idHash": "murmur3",
      ...other config
    }]
  ]
}

When used with #13, it allows id hash values to be consistent across builds unless:

  1. The object key name is changed in the original javascript message file
  2. The variable name used to generate the id value changes

Id hash values will not change if the file is renamed or moved, this is good in scenario's where translations have already been performed.

Essentially, its just:

var murmurhashJs = require("murmurhash-js");

// Function to converta 32 bit integer to an array
// https://stackoverflow.com/questions/15761790/convert-a-32bit-integer-into-4-bytes-of-data-in-javascript
function toBytesInt32 (num) {
    arr = new ArrayBuffer(4); // an Int32 takes 4 bytes
    view = new DataView(arr);
    view.setUint32(0, num, false); // byteOffset = 0; litteEndian = false
    return arr;
}

// Generate a short hash for each message id value
const idHash = murmurhashJs('message_identifier');
console.log(Buffer.from(toBytesInt32(idHash)).toString('base64'));

You can run that here with a quick copy & paste.

Would you accept this as a PR?

Adam.

Not generating ids when importing more than 1 component

Do you want to request a feature or report a bug?:
bug

What is the current behavior?:
id is not auto generated in all supported components when importing more than 1 at once
(import {FormattedHTMLMessage, FormattedMessage} from "react-intl";)

What is the expected behavior?:
ids should be generated for all the components, no matter if we are importing 1 or all of them in the same import

Suggested solution:
#42

TypeScript に関するドキュメントの追加

便利なパッケージでとても重宝しています。ありがとうございます。

ドキュメントには特に記述はないものの、少し設定を加えれば TypeScript でもこれと extract-react-intl-messages の組み合わせで使用することができたので良ければドキュメントかサンプルとして追加してはどうかというご提案です。

  • version: v0.11.1
  • node version: v11.5.0
  • npm version: v6.5.0
  1. react-intl の型定義と Babel の TypeScript トランスフォーム用プラグインをプロジェクトに追加します。
$ npm i -D @types/react-intl @babel/plugin-transform-typescript
  1. 文字列値を持つ defineMessages の型定義を追加する必要があるため、プロジェクト側に index.d.ts などとして次のようなファイルを追加します。tsconfig.json 側で読み込まれるように設定されていれば問題ありません。
declare module 'react-intl' {
  interface ExtractableMessage {
    [key: string]: string
  }
  function defineMessages<T extends ExtractableMessage>(messages: T): Messages
}
  1. .babelrc も追記します。
{
  "plugins": [
    ["@babel/plugin-transform-typescript"],
    ["react-intl-auto"]
  ]
}

あとは例どおりに文字列値を持つメッセージを作成して extract-react-intl-messages を実行することで JavaScript と同じように生成されました。

(良さそうであれば PR 出しますがいかがでしょうか)

Add useKey support to intl.formatMessage

  • version: 2.3.0
  • node version: 10.16.1
  • npm (or yarn) version: 6.9.0

Do you want to request a feature or report a bug?:
Feature

What is the current behavior?:
key prop is supported only in <FormattedMessage /> and <FormattedHTMLMessage /> when using useKey option

What is the expected behavior?:
key property could be supported in formatMessage too, e.g.:

props.intl.formatMessage({
  key: 'key'
});

Suggested solution:
Update addIdToFormatMessage visitor to support key property nodePath.

Missing translation when using filebase true

  • version: 3.3.0
  • node version: v10.16.3
  • yarn version: 1.22.4

Do you want to request a feature or report a bug?:
Bug

What is the current behavior?:
To avoid id collisions I'd like to generate ids using the filename, so I've set filebase: true in babel.config.js:

module.exports = function (api) {
  api.cache(true);

  return {
    presets: [
      'module:metro-react-native-babel-preset',
    ],
    plugins: [
      [
        'react-intl-auto',
        {
          removePrefix: 'src/',
          filebase: true,
        },
      ],
    ],
  };
};

Used like this in the TabNavigator-component:

const messages = defineMessages({
  profile: 'Profil',
});

const TabNavigator = () => {
  const {formatMessage} = useIntl();

  return (
    <Tab.Navigator>
      <Tab.Screen
        name="Profile"
        component={Profile}
        options={{
          tabBarLabel: formatMessage(messages.profile)
        }}
      />
  );
}

Running extract-messages -l=en,nb -o src/translations -d nb --flat true --overwriteDefault false 'src/**/*.{ts,tsx}' does actually generate the ids with the filename:

  "navigation.TabNavigator.profile": "Profil",

But React.Intl complains about a missing translation with the id used in formatMessage:
image
(notice the lack of filename in the id)

What is the expected behavior?:
The id used in formatMessage, FormattedMessage etc, includes the filename when filebase is set to true.

Suggested solution:
Not sure what the issue is yet, if it is some fault of mine or an actual bug.

Support adding export name as part of id

I have a few messages.js files that look like this:

export const foo = defineMessages({
  ....
});

export default defineMessages({
  ....
});

I would like for there to be an option for the export name to be part of the generated IDs.

[Windows] not converting \ to .

Hello and thx for this very useful tool.

This is a typical windows issue because of the \ instead of / so the path is incorrectly converted: \ are not converted into dots.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.