alibaba / react-intl-universal

Internationalize React apps. Not only for Component but also for Vanilla JS.
1.34k stars 154 forks source link

react-intl-universal locales data "null" not exists. #144

Closed Bingjiajia closed 3 years ago

Bingjiajia commented 4 years ago

when only use react is ok, but when use redux connect()(MyComponent) with the warning and no result.

class MyComponent extend react.Component{ render(){ return <h1>{intl.get('string')}</h1> } }

cwtuan commented 4 years ago

do you init before render?

Bingjiajia commented 4 years ago

i have do it in index.js

`loadLocales = (lang = 'zh-CN') => { intl.init({ currentLocale: lang, locales, }).then(() => { this.setState({ antdLang: lang === 'zh-CN' ? zh_CN : en_US }) }) }; render() { return (

)

}`

then i use it in <Routers><MyComponent /></Routers>

i use redux connect(MyComponent) i don't init intl in MyComponent again

cwtuan commented 4 years ago

Use debugger to make sure you init before render

davin-mcdonald-rocketlab commented 1 year ago

For anyone that is still experiencing this warning. For me it was because some data objects were in the root of the file. When this happens they initialise externally to the <App/> and ignore the init

So this will throw a warning: const object = { displayText: intl.get('KEY').d('Example text') }

And this won't const exampleFunction = () => { const object = { displayText: intl.get('KEY').d('Example text') } }

i.e. all intl.get() calls need to be within a function

cwtuan commented 1 year ago

Yes, you should call intl.init before render.

For example, if you have some constants like this:

// Wrong: the message in constants.fruits is used before `intl.init(...)`
const constants = {
    fruits : [
        { label: intl.get('banana'), value: 'banana' },
        { label: intl.get('apple'), value: 'apple' },
    ]
}
function MyComponent() {
    return <Select dataSource={constants.fruits} />
}

Solution 1

Make the message object as a function, and call it at render function

const constants = {
    fruits : () => [  // as a function
        { label: intl.get('banana'), value: 'banana' },
        { label: intl.get('apple'), value: 'apple' },
    ]
}
function MyComponent() {
    // fruits is a function which returns message when rendering
    return <Select dataSource={constants.fruits()} />
}

Solution 2

Use getter syntax to make a function call when that property is looked up

const constants = {
  fruits: [
    {
      get label() {
        return intl.get("banana");
      },
      value: "banana",
    },
    {
      get label() {
        return intl.get("apple");
      },
      value: "apple",
    },
  ],
};
function MyComponent() {
  // When "label" property is looked up, it actually make a function call 
  return <Select dataSource={constants.fruits} />;
}
davin-mcdonald-rocketlab commented 1 year ago

Thanks @cwtuan this example will be very helpful for anyone that experiences this in the future

Veveue commented 1 year ago

Yes, you should call intl.init before render.

For example, if you have some constants like this:

// Wrong: the message in constants.fruits is used before `intl.init(...)`
const constants = {
    fruits : [
        { label: intl.get('banana'), value: 'banana' },
        { label: intl.get('apple'), value: 'apple' },
    ]
}
function MyComponent() {
    return <Select dataSource={constants.fruits} />
}

Rewrite it to:

// Correct: make the message as a function, and call it at render function
const constants = {
    fruits : () => [  // as arrow function
        { label: intl.get('banana'), value: 'banana' },
        { label: intl.get('apple'), value: 'apple' },
    ]
}
function MyComponent() {
    // fruits is a function which returns message when rendering
    return <Select dataSource={constants.fruits()} />
}
// global variable
const constants = {
    fruits: [
      {
        get label() {
          return intl.get("banana");
        },
        value: "banana",
      },
      {
        get label() {
          return intl.get("apple");
        },
        value: "apple",
      },
    ],
  };
  function MyComponent() {
    // fruits is a function which returns message when rendering
    return <Select dataSource={constants.fruits} />;
  }
cwtuan commented 1 year ago

@Veveue Yes, use getter is better. Let me modify the example above.

cwtuan commented 1 year ago

This issue's solution is documented in FAQ section.