react-intl v3 Upgrade

· 3 min read

Taking advantage of the weekend to upgrade the react-intl library. The current latest version is v4.6.9, while the project is using version v2.3.18. I’ve decided to upgrade to v3@latest.

Benefits of the Upgrade

  1. Fixes known bugs - in the previous version, when I passed de-de, internationalization would fail. The workaround at the time was to always set the localData key to ’en'
  2. Reduces bundle size for the localeData portion, as it now uses the browser’s built-in Intl APIs
  3. Migration from withRef to forwardRef, which is the current standard way for component reference passing, beneficial for consistency
  4. Since React, Redux, and other major libraries have already been upgraded, upgrading Intl helps with future iteration upgrades for the overall framework
  5. Previous internationalization methods like formatMessage returned Node elements (containing Span tags), while v3 returns text. Strictly speaking, rendering will also reduce browser overhead since there are fewer nodes. Of course, for places that only need simple text, this directly satisfies the requirement

Open source may be free, but version upgrades require caution. However, staying stagnant is detrimental to both evolving web technologies and the product project itself, so progressive upgrades are necessary.

Upgrade Details

The official documentation provides a v2 to v3 upgrade guide, but upgrades are never completely smooth. Here I’ll explain the key points one by one.

Configuration

How to upgrade? Look here - I’ve listed the main key points. For things like values type files, etc., just directly replace and modify based on the error prompts.

package.json

"react-intl": "^3.12.1"

Note

v3 comes with built-in TypeScript type definitions, so the previous @types/react-intl needs to be removed

tsconfig.json


"lib": ["es2015", "es2017", "dom", "es2018.intl", "esnext.intl"]

typings.d.ts

Because I extend the global window property by assigning the intl instance to it, I need the following definition:

import { IntlShape } from 'react-intl';

declare global {
  interface Window {
    intl: IntlShape;
  }
}

Note

  • If not needed, skip this configuration
  • There’s a conflict between declare module '*.svg'; and declare global module declarations - they need to be physically separated into two declaration files. If the global declaration has no imports, then declare global can be omitted

Unit Tests

The intl upgrade also affects unit tests, mainly in the utility functions. Configuration is as follows:

import { mount, render, shallow } from 'enzyme';
import React from 'react';
import { createIntl, IntlProvider } from 'react-intl';
import renderer from 'react-test-renderer';

const messages = {}; // en.json

const intl = createIntl({ locale: 'en', messages, onError: () => '' });

function nodeWithIntlProp(node) {
  return React.cloneElement(node, { intl });
}

export function mountWithIntl(node) {
  return mount(node, {
    // @ts-ignore
    wrappingComponent: IntlProvider,
    wrappingComponentProps: {
      locale: 'en',
      defaultLocale: 'en',
      messages
    }
  });
}

export function renderWithIntl(node) {
  return render(<IntlProvider locale='en' messages={messages} onError={() => ''}>{node}</IntlProvider>);
}

export function rendererWithIntl(node) {
  return renderer.create(<IntlProvider locale='en' messages={messages} onError={() => ''}>{node}</IntlProvider>);
}

Interface Definition Changes

InjectedIntlProps => WrappedComponentProps, withRef => forwardRef

You can do a global replace, but be careful not to make mistakes.

Final Thoughts

With the above configuration, the upgrade can be completed. Of course, considering system stability, I didn’t upgrade directly from v2 to v4, but after a quick look, the changes from 3 to 4 are relatively minor. So I’ll wait for the system to stabilize for a while before doing the next upgrade.

Reference Documentation