Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using react-intl with es6 classes #99

Closed
johanneslumpe opened this issue Mar 28, 2015 · 42 comments
Closed

Using react-intl with es6 classes #99

johanneslumpe opened this issue Mar 28, 2015 · 42 comments

Comments

@johanneslumpe
Copy link

Are you guys planning on providing a solution for this, like a higher order component for example? Or would you propose a different way of using react-intl without mixins?

How about putting the translation methods into context, together with the already present props? Then a higher order component could just prepare the context and render a given child. But instead of then having to mix in the react-intl mixin, we could just define the proper contextTypes and have access to all the functionality we need.

@gpbl
Copy link

gpbl commented Mar 28, 2015

If you are using flux, you can keep the messages and locales in a store and pass them down to your components as props from a higher order component (I took the idea from this article). I moved getIntlMessage out from the IntlMixin and made it accept the messages as first argument. This way you don't need to use context for react-intl and you can skip the mixin!

@johanneslumpe
Copy link
Author

Yeah I'm using flux. I'm already keeping my messages + locales inside a store, since I want to be able to change languages on the fly. But I most certainly don't want to wrap each translatable component inside a higher order component. Having stuff on context seems a bit more convenient to me. Of course if there is no other way, then a higher order component will have to do. Also I don't necessarily want to copy the libraries functionality. That's why I asked for support from the devs ;)

@gpbl
Copy link

gpbl commented Mar 29, 2015

In my experience skipping context when using flux is not actually that big deal: instead of adding the mixin, you wrap the component. The getIntlMessage is also a simple function. This way you can solve the problem with the context and shouldComponentUpdate (especially if you are changing the language on the fly).

@johanneslumpe
Copy link
Author

Well the context is nice, because I don't want to have to pass down messages explicitly, if from grandparent to grandchild, if the parent does not need the messages. But your idea of externalizing getIntlMessage isn't actually a bad idea. Each component can then just define the required context type and be done with it. That could work :) So thanks for that idea!

Did you personally run into any issues with context and shouldComponentUpdate? There is still some discussion over a the react repo about how to handle that with context.

@ericf
Copy link
Collaborator

ericf commented Mar 30, 2015

This is a good discussion!

I'd like to provide a sans-mixin way of using all the features of React Intl. We're actively working with teams at Yahoo to figure out good patterns for translation fallbacks (for things like missing translations, etc.) Let's keep this discussion going and continue to expiriment with solutions has you two have already.

@johanneslumpe
Copy link
Author

@ericf I went with what @gpbl suggested and externalized the getIntlMessage method. I have a smaller higher order component now, which specifies the required contextTypes and then passes in the messages to the wrapped component, along with a bound getIntlMessage method.

So in the wrapped component translations work rather normally:

render() {
  const getIntlMessage = this.props.getIntlMessage;
  const msg = getIntlMessage('some.message.path');
}

For fallbacks my idea was to always provide a complete default set in a TranslationStore, and then upon language change merge the new language with the default set and return that. That way at least the english version of the message will show up. And if it's missing, then the original english version could even decorated with a clear suffix, that this string is missing (might be useful for dev mode).

Another idea would be to return the path identifier, with some added prefix or suffix whenever something is not defined.

@gpbl
Copy link

gpbl commented Mar 30, 2015

My implementation is a bit different. I'm using Fluxible, so I'm cheating when I say I skip context, since Fluxible does use it :-)

Said I use IntlStore to save locales and messages, this function returns an high order component:

// utils/connectToIntlStore.js
import React from 'react';
import { FluxibleMixin } from 'fluxible';
function connectToIntlStore(Component) {

  const Connection = React.createClass({
    mixins: [FluxibleMixin],
    render() {
      const { messages, locales } = this.getStore('IntlStore').getState();
      return <Component messages={messages} locales={locales} {...this.props} />;
    }
  });

  return Connection;
}

export default connectToIntlStore;

This is a wrapped component:

import { Component } from 'react';
import connectToIntlStore from '../utils/connectToIntlStore';
import getIntlMessage from '../utils/getIntlMessage';

class MyComponent extends Component {

  render() {
    const { messages } = this.props;
    return (
      <p>
        { getIntlMessage(messages, 'MyComponent.helloWorld') }
      </p>
    );
  }
}

export default connectToIntlStore(MyComponent); 
// MyComponent has `messages` and `locales` as props.

Basically, instead of using the react-intl context, I rely on the fluxible's one. A non-isomorphic approach, using stores as singletons, should work without context!

utils/getIntlMessage is the same as in react-intl, but it accepts messages as first argument. The higher order component could listen to IntlStore for changing the language on the fly.

I'm still experimenting with this, anyway.

@johanneslumpe I like the idea of the fallback to the english locale – but how would that work? Would a foreign user download two languages, just because a missing string? I'm convinced the best practice is to stop the build when the locale strings don't match.

The issue with contexts and shouldComponentUpdate is exposed here: I met it in my (non-flux) locale-hot-switch example. It turns out it could be solved using Flux :-)

@johanneslumpe
Copy link
Author

So you're fetching the messages from your store for each component. I'm fetching them once at the top and then I'm relying on the normal context.

Here's what I use as mixin replacement:

export default (Component) => {
  return class Translatable extends React.Component {

    static contextTypes = {
      messages: React.PropTypes.object
    }

    constructor(props, context) {
      super(props, context);

      // we bind `getIntlMessage` so we can just use it normally inside
      // `render`, without having to always pass the component instance
      this.getIntlMessage = getIntlMessage.bind(null, this);
    }

    render() {
      return <Component getIntlMessage={this.getIntlMessage} {...this.props} {...this.state} />;
    }
  };
}

And the usage is as follows:

class Comp extends React.Component {

  render() {
    const getIntlMessage = this.props.getIntlMessage;
    return (
      <div>
          {getIntlMessage('some.path')}
      </div>
    );
  }

}

export default makeTranslatable(Comp);

@gpbl Yeah I've read that thread about the context. I didn't encounter it yet. But if I do, I might have to switch to props, instead of context. But I'm confident that the context issue will be solved in time.

About the fallback: Yeah, a simple version would include both language sets. Another way would be to generate language files on the server, and do the merging prior to serving (potentially cached).

@gpbl
Copy link

gpbl commented Mar 30, 2015

So you're fetching the messages from your store for each component. I'm fetching them once at the top and then I'm relying on the normal context.

Right! Your solution works better for changing the language on the fly: attaching a store listener to each component could be too much :) – on the other side, I am not sure about that getIntlMessage as prop. Also, which role does the Flux store play in your implementation?

But if I do, I might have to switch to props, instead of context. But I'm confident that the context issue will be solved in time.

What about the PureRenderMixin? Are you checking also context in shouldComponentUpdate, to know if messages changed?

Another part I couldn't replace with the high order component was the use of this.formatMessage & co (i needed it to pass a translated string to a component, for rendering the meta tags) – so sometimes I had to use the mixin. The README states they are going to remove those functions from the mixin anyway in the next major version.

@johanneslumpe
Copy link
Author

Yeah don't use those functions, just go with the components. I'm currently not using the PureRenderMixin. So I didn't think about that yet.

My TranslationStore is where I store all the available translations, keyed by locale. So technically a user could load different translation sets and switch between them. My top level component listens to that store and on change, re-renders a component, which - still - implements the IntlMixin so it can set up the proper context. But that mixin is now confined within a single component, so when we figure out a proper solution without a mixin, it will be easier to replace.

I chose to pass getIntlMessage as a prop because the component, which has the messages in the context, is the higher order component. And in my version of getIntlMessage i have to pass the component to use as the first parameter, because the code is the same as the original one. It checks this.props and this.context for a messages prop. And in the wrapped component, there is no way to pass the parent component in, except when receiving it as a prop. But that doesn't make a lot of sense, so I figured that just passing in a bound method is the least problematic version for me right now :D but just like you - I'm experimenting ;)

@gpbl
Copy link

gpbl commented Apr 6, 2015

In my demo app i tried to skip the IntlMixin at all. So there's a store and a connectToIntlStore utils to create an high-order component and always pass messages and locales as props.

Then i got the idea to wrap react-intl components into an high-order component so that they always use the values coming from the store. For example, a <FormatMessage/> that is directly wrapped in the high order component (source).

...but here i have a problem with react-intl contexts, when a wrapped components get another wrapped component as prop, for example here:

<WrappedFormattedMessage 
  message="photo.rating"
  rating={<WrappedFormattedNumber value={rating} />}
/>

where I get a warning from react:

owner-based and parent-based contexts differ (values: `undefined` vs `en`) for key (locales) while mounting FormattedNumber

maybe @ericf could suggest what's going wrong here?

@ericf
Copy link
Collaborator

ericf commented Apr 6, 2015

So I've begun a major refactor to try to address many of the things brought up in this thread and others. I'm still trying to work through the details and flush out an implementation to propose, while also attempting to preserve v1.x backwards compatibility.

Here's the rough set of things I'm trying to address:

  • Remove need to use mixin
  • Provide new imperative API
  • Support message fallbacks
  • Add deprecation warnings
  • Author components as pure ES6 classes

I first attempted to create a new <Intl> component that you'd wrap around your app's root component, or nest further around some sub tree which would filling in the intl-related context. But I ran into @slorber's issue facebook/react#3392 where it's currently impossible to opt-into using parent-based context. To work around this, I kept the <Intl> component (but don't plan to expose it yet) and created a high-order component (HOC) factory (still want a better name than provideIntl(), any ideas?)

import Intl from './components/intl';

export default function provideIntl(Component) {
    return class extends Intl {
        render() {
            return React.createElement(Component, this.props);
        }
    };
}

This approach gets around the current state of React only having owner-based contexts; and it would be used like this:

AppComponent = provideIntl(AppComponent);

React.render(
    <AppComponent locale="en-US" messages={{...}} />,
    document.getElementById('container')
);

This new HOC Intl component would replace the job of IntlMixin — which is to set the intl-related context. @gpbl I would like to investigate shouldComponentUpdate and context further to understand if this will be resolved in a near future version of React where a component will be forced to render when its context changes. I'm also okay with the idea that a full forceUpdate might have to happen when trying to hot-swap locales — the problem is making sure all the components know they need to re-render :-/

@johanneslumpe you're right about adding contextTypes to things. In my current WIP-POC the Intl HOC I talked about above will create an instance of a new Format class which takes locale (singular), messages, and formats (for custom format options). This instance has the new imperative API that covers the main things the mixin provided; e.g., format.number(), format.message(), etc.

I'm then extrapolating these concepts out to provide support for fallbacks. What we realized is that in order to correctly provide support for falling back to the app's default locale when a translation is missing we need to combine locale, messages, and formats together so that the message can be properly formatted. The good thing is, the new Format utility class provides an encapsulation of exactly that!

AppComponent = provideIntl(AppComponent);

React.render(
    <AppComponent locale="fr-FR" messages={{...}}
        fallback={{
            locale: 'en-US',
            messages: {...}
        }} />,
    document.getElementById('container')
);

(Still working on the exact API and naming, but you get the idea.)

So now the Intl HOC can provide two Format instances, one for the current locale the app is in, and one for the app's default locale that can be used as a fallback. This should provide the low-level infrastructure on which we can build out this declarative, fully-componentized approach to embedding the default strings in the components and extracting them with tools to pass off for translation: #89 (comment)

I've also worked on updating the <FormattedMessage> component to automatically handle fallbacks, and get rid of the need for getIntlMessage() (which is still provided on the Format class.) I'm thinking of adding a new key prop, which is the same input as what getIntlMessage() accepts, but it will also check the fallback messages if a translation is missing. This is what I have to handle that:

var format  = this.context.format;
var props   = this.props;
var message = this.props.message;
var key     = this.props.key;

if (typeof message !== 'string') {
    if (!key) {
        throw new Error(
            'A `message` or `key` path to a message must be provided.'
        );
    }

    try {
        message = format.getMessage(key);
    } catch (e) {
        try {
            // Fallback.
            format  = this.context.fallbackFormat;
            message = format.getMessage(key);
        } catch (e) {
            throw new Error(
                'Message could not be located at key: ' + key
            );
        }
    }
}

I'm still unsure if adding key is the right way to go, or if making message also accept a callback function would be better…thoughts?

One other open question I have is around what to do with the props the mixin current provides on all of the <Formatted*> components? Current all of the components accept locales, messages, and formats props. I could wrap all of the <Formatted*> components with the Intl HOC to continue providing that functionality if these props are specified, otherwise it would simply use what's provided via context.

This is sort of a rant at this point, but since you two are already thinking about this stuff, it makes sense to flush some of this out here first before I open a RFC and/or branch to discuss the details future 😄

@johanneslumpe
Copy link
Author

@ericf nice start :) First thing: I don't think you can use key on props anymore. AFAIK it has been removed since 0.12 (https://facebook.github.io/react/blog/2014/10/16/react-v0.12-rc1.html#breaking-change-key-and-ref-removed-from-this.props) But renaming that to keypath would be an easy fix.

As for the HOC name, how about just i18n, internationalize, or makeI18nAware?

Instead of using a HOC factory, we could have a component like the FluxComponent over at https://github.com/acdlite/flummox/ which allows your to define a custom render function as a prop, which then gets executed by the component. It's similar to the solution provided by sebmarkbage over at facebook/react#3392 (comment)

I think with that we could solve the context issue of providing a context to children of the I18n component. Also messages + locales and fallbacks could be made directly available as params to the custom render function (not sure if we need that, but it would be possible), so they could be manually passed down to basically any component inside that render function.

So each time a component needs direct access to the context it would just be rendered within a custom render function provided by the new component.

I'd like the fallback to be configurable. Instead of throwing an error, if there is no message and no fallback, I'd like to be able to specify that just the key gets output again. This would make it easy (while in dev-mode) to see where something is missing, taking a note and continue to check, instead of the app breaking. And in addition to that we could log using console.warn, which specifies more details, like which locale and whether the key is missing on the current locale or on the fallback.

Have no idea about the <Formatted*> components yet. And I have no opinion about providing a function as message prop. But if we did that - then we could actually manually take care of language switching (based on a store for example). But that probably would miss the point ;)

@ericf
Copy link
Collaborator

ericf commented Apr 6, 2015

First thing: I don't think you can use key on props anymore.

Ah good point!

Instead of using a HOC factory, we could have a component like the FluxComponent over at https://github.com/acdlite/flummox/ which allows your to define a custom render function as a prop, which then gets executed by the component.

So you're thinking that we could go with this style:

<Intl locale="en-US" messages={{...}} render={() => {
    return <AppComponent />;
}} />

And then when React switches to parent-based context, the refactor would be to the following?

<Intl locale="en-US" messages={{...}}>
    <AppComponent />
</Intl>

I could make the above "work" today using cloneWithProps(), but that requires a user of React Intl to use React-with-addons — and that's not something I wanted to force, like using FluxComponent does. (I guess there's a pattern where React libs also have addons?)

Also messages + locales and fallbacks could be made directly available as params to the custom render function (not sure if we need that, but it would be possible), so they could be manually passed down to basically any component inside that render function.

Yeah, that's a cool idea! But maybe we'd just pass the format and fallbackFormat instances into the render() callback function?

I'd like the fallback to be configurable. Instead of throwing an error, if there is no message and no fallback, I'd like to be able to specify that just the key gets output again.

Yeah I'd like to figure out a good way to do that which doesn't complicate the story of using React Intl. I just started (locally) with keeping the same error semantics as there currently are.

The other thing I'm trying to figure out is how to keep the <Formatted*> components usable without requiring that you wrapped one of its ancestors with <Intl> to provide the context; e.g., I want this to still work:

<FormattedNumber value={0.95} locales={['en-US', 'en']} style="percent" />

(Note: using the plural locales here because that's what Intl.NumberFormat uses.)

Currently, each <Formatted*> component uses the IntlMixin, therefore the above is possible without ever adding the mixin somewhere upstream — that's what I want to maintain with this refactor as well. I want the <Intl> component and the context it provides to be sugar for keeping uses of the <Formatted*> components DRY.

@PaulLeCam
Copy link

I could make the above "work" today using cloneWithProps(), but that requires a user of React Intl to use React-with-addons — and that's not something I wanted to force, like using FluxComponent does. (I guess there's a pattern where React libs also have addons?)

v0.13 introduces the new React.cloneElement() API so no need for addons.

@ericf
Copy link
Collaborator

ericf commented Apr 14, 2015

@PaulLeCam yeah I was hoping that would work, but it doesn't change the ownership of the element being closed, therefore it won't change the context inheritance chain.

@faassen
Copy link

faassen commented May 7, 2015

I just went down much the same path @ericf went already before if I read his comments correctly.

I created an Intl React component that sets up a context which contains the locales, messages and formats. You use it somewhere on the outside of your application to wrap it, i.e:

<Intl messages={mymessages} locales={mylocales} formats={myformats}>
     ... everything inside ...
 </Intl>

I then created a special wrapper of FormattedMessage which does two things:

  • get its i18n info from the context as set up by Intl
  • takes a messageId argument which can automatically retrieve the appropriate message from messages without having to use getIntlMessage manually.

I ran into the same issue with ownership versus parents for context where I wanted to handle the children of Intl. React.addons.cloneWithProps changes the ownership to be consistent with the parentage while React.cloneElement does not.

Some questions:

  • is it indeed still a goal to make an Intl element that sets up context eventually in the way I described?
  • Is this waiting for React 0.14 so that we can avoid depending on React addons? (assuming that parent based context fixes whatever context confusion we have now)
  • I saw a mention that you want to get rid of the need for getIntlMessage. Does this mean what I think it means and that you can simply pass a messageId to FormattedMessage? Or do you mean something else? I didn't see a reason to require people messing around with getIntlMessage when FormattedMessage can do it automatically for you, but I may be missing use cases.

I'm asking also because I may want to start using this approach faster than react-intl does, but I want to make sure react-intl is actually heading in this direction at all.

@chiefjester
Copy link

+1

@faassen
Copy link

faassen commented May 12, 2015

It's even worse than needing to use React.addons.cloneWithProps to make sure ownership is consistent with parentage. I actually can't get it to work -- I tried my best to replicate what FluxComponent from Flummox does, but I can't get it working. I think to make stuff like this work we need React 0.14 with a proper parent-based context.

@necolas
Copy link

necolas commented May 14, 2015

The changes @ericf is working on sound good and I'd like to be able to upgrade to a future major release without too much trouble. Given that, I'm wondering what those of you who have been working around mixins-with-es6-classes are currently using or would recommend.

@chiefjester
Copy link

@necolas
Copy link

necolas commented May 15, 2015

Thanks. I'm leaning more towards what @johanneslumpe is doing, rather than using a mixin directly on every component. @johanneslumpe please can you elaborate / share more of the implementation if it's working well for you.

@johanneslumpe
Copy link
Author

@necolas Sorry for the late reply - wasn't around. I actually haven't had the chance to continue my research on that topic. The current implementation is working in a way that you have TranslationStore, which always has a default language (English in my case) loaded and then also loads the custom language for the user - if it differs from the default.

I have a single root component, which does use the mixin to set up the context, but every other component which has to be translatable just uses the HoC to enhance itself.

The application itself has a single top level handler, which listens for changes in the TranslationStore and then passes down the new data from the store to the component, which implements the mixin. Further down the hierarchy every component then just uses this.props.getIntlMessage to translate things.

That worked well for me so far. Always loading the default and the custom language set is of course not react-intl specific, but it gives you the nice ability to fall back to a definitely available translation, which allows us to prevent react-intl from going haywire and throwing things at us. (It's also nice for translators, because you can augment the missing strings in a custom merge function so people can easily see what's still missing.

Does that help or do you need more details? :)

@necolas
Copy link

necolas commented May 19, 2015

Hey, thanks for the follow up. Specifically, you have this line in your earlier example:

this.getIntlMessage = getIntlMessage.bind(null, this);

Is this a custom implementation of getIntlMessage?

@johanneslumpe
Copy link
Author

@necolas Oh sorry, forgot to mention that. I probably should have included that up that. It's the getIntlMessage method from the mixin, but refactored into its own file. So I just import it at the top of the HoC file and then bind it to the current instance on construction, so that it is able to find the context/messages.

@necolas
Copy link

necolas commented May 21, 2015

Thanks. I had it working with the mixin method too. Was just curious if there was some extra stuff going on in there. Quite a nice solution for now.

@iam4x
Copy link

iam4x commented May 22, 2015

What I've done to use formatMessage from IntlMixin:

import {assign} from 'lodash';
import {IntlMixin from 'react-intl';

export default class Profile extends React.Component {
  displayName = 'Profile'

  contextTypes = {
    router: React.PropTypes.func
  }

  static propTypes = {
    flux: React.PropTypes.object.isRequired
  }

  _getIntlMessage = IntlMixin.getIntlMessage
  _formatMessage = IntlMixin.formatMessage.bind(assign({}, this, IntlMixin))

...

I can use this._getIntlMessage and this._formatMessage in my component class without problems.

(note: I use babel stage 0)

@chiefjester
Copy link

@ericf since 0.14.0 is around the corner and they switched to parent-based context, maybe if we can have this in anticipation?

<Intl locale="en-US" messages={{...}}>
    <AppComponent />
</Intl>

@slorber
Copy link

slorber commented May 25, 2015

@faassen I like your solution about creating a wrapper around FormattedMessage that looks up directly into the context.

@ericf I think it would be great to have it integrated in the lib directly.

Something like <FormattedMessage messageKey="a.b.c"/> would be great: no need for the mixin anymore, and removes some boilerplate

@gpbl
Copy link

gpbl commented May 25, 2015

@slorber this is similar to what I'm doing now, but I don't use contexts – I wrapped the original FormattedMessage to pass messages and locales props to it (in my case, they are coming from an IntlStore). Now I can write

<FormattedMessage message="some.message" />

https://github.com/gpbl/isomorphic500/blob/master/src/utils/FormattedMessage.js
https://github.com/gpbl/isomorphic500/blob/master/src/utils/connectToIntlStore.js

Here I've explained a bit my approach.

@eriknyk
Copy link

eriknyk commented Aug 27, 2015

would be great if the right way to use ES6 syntax is described in the README file

@AlexJozwicki
Copy link

To be honest, I don't think there's a right way to use the current version with ES6, if you want to have the full access to the API and not just the components.
I struggled for a while with wrappers and finally decided to create a fork, where I have a Intl class serving as the API passed through context.

As all of our applications use react-router, the first route handler is a IntlApp component, injecting the context along with messages and formats, selected for the user locale. We have the same component for all of our applications.
We don't have any trouble this way with parent/owner context clashes so far.

@eriknyk
Copy link

eriknyk commented Aug 28, 2015

Hi @AlexJozwicki, do you have an example of you implementation?
I will appreciate it a lot.

Regards.

@ericf
Copy link
Collaborator

ericf commented Aug 28, 2015

I struggled for a while with wrappers and finally decided to create a fork, where I have a Intl class serving as the API passed through context.

This is what's being worked on in the v2-dev branch.

@chiefjester
Copy link

hey @ericf, I'm looking forward to 2.0 🎉

@jakubsikora
Copy link

sorry for OT, but is there a timeline for releasing 2.0?

@ericf
Copy link
Collaborator

ericf commented Aug 28, 2015

@jakubsikora working on integrating/upgrading it into several Yahoo apps in production before shipping to work out all the kinks. I'm feeling good where it's at so nearing a preview release though.

@jakubsikora
Copy link

@ericf in ver 1 there is a method getIntlMessage, are you going to remove that from 2.0 or replace it and expose something similar. I'm just wondering because currently in some places in my app I get messages like this:

var foo = this.getIntlMessage('foo');

return (
  <div>{foo}</div>
);

@ericf
Copy link
Collaborator

ericf commented Sep 9, 2015

@jakubsikora this will be one area I'll be looking for feedback on. The current design uses a simple, flat, key --> value hash to store the messages, but one of the bigger features for v2 is automatic translations fallbacks, implemented by this algorithm.

@ryan1234
Copy link
Contributor

ryan1234 commented Sep 9, 2015

Just for fun, what we've ended up doing is shipping a default language with the application (English in our case) and having that key/value hash live in a Flux store. Then we dynamically load other languages from S3 and put them into the same Flux store in an array.

If a user wants to use a language other than English, we use lodash's merge function to combine one language key/value hash with English. The premise is that English will always be a step ahead and canonical. So if a key is missing in a newly loaded language, it easily falls back to English as a result of merging the two objects.

@ericf
Copy link
Collaborator

ericf commented Sep 9, 2015

The premise is that English will always be a step ahead and canonical. So if a key is missing in a newly loaded language, it easily falls back to English as a result of merging the two objects.

@ryan1234 yup, this is our experience too! In v2, this idea is baked in, and if you're using the Babel and ES6 modules, then you'll be able to use the forthcoming babel-plugin-react-intl to extract the default English messages from your React Component during your build. The Babel plugin currently leaves the source un-modified, it simply visits and collects the data, in the future I can add an option to remove the metadata and default messages leaving just the message ids.

@ericf
Copy link
Collaborator

ericf commented Sep 11, 2015

See: #162

@ericf ericf closed this as completed Sep 11, 2015
longlho pushed a commit that referenced this issue Apr 27, 2020
Updates the requirements on [@types/fs-extra](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/fs-extra) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/fs-extra)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests