This is the fourth day of my participation in Gwen Challenge

What is front-end internationalization

To put it simply, it is to translate and switch between Chinese and English, but it is not necessary to put the whole language package into it. It is only necessary to deal with it as needed. Then how to develop an elegant internationalization plan is the focus of research.


assemblyreact-intllibrary

React – Intl is a Yahoo product that you can check out for yourself.

Installation:

    yarn add react-intl
Copy the code

Use:

.import { IntlProvider } from "react-intl"; .class Root extends Component {
    render() {
        const {
        global: { locale },// Enumerable values are "en" and "en"
        } = this.props;
        return (
        <IntlProvider locale={locale} messages={language.getData()[locale]}>
            <App />
        </IntlProvider>); }}Copy the code

Analysis:

  1. The first one I use isIntlProviderWrap it up.
  2. Then pass in two arguments:
    • locale: Current locale
    • messages:A language pack configured on demand(Focus on the following analysis).

So far the basic assembly is enough, other “high play” configuration interested can continue to explore.


Just to highlightConfiguration language packThe way of

The “traditional” model:

Configuration language pack:

Let’s take login as an example:

en-US:

const login = {
  "login.title": "User Center"."login.username": "please enter username"."login.usernameEmpty": "username cannot be empty!"."login.maxLength": "username is no more than 100 characters"};export default login;
Copy the code

zh-CN:

const login = {
  "login.title": User center."login.username": "Please enter user name"."login.usernameEmpty": "User name cannot be empty!"."login.maxLength": "User name must be no more than 100 characters."};export default login;
Copy the code

Development use

./ * introduction * /
import { injectIntl } from "react-intl"; ./* Inject exclusive internationalization data */
@injectIntl
class Login extends React.Component {
    constructor(props) {
        super(props);
        const {
            intl: { formatMessage },
        } = this.props;
        / * * / use
        message.warning(formatMessage({ id: "login.maxLength"}}))... }Copy the code

Analysis:

  1. First on the configuration language package, you need to respectively inen-USandzh-CNTwo files with the same structure and different values are configured in the directory.
  2. Based on the previous assembly, we can passreact-intlTo provide theinjectIntlHigher-order components wrap their components so that they can get internationalization data directly from propsintl.
  3. fromintlgainformatMessage, incoming fragmentid, can get the value of the translation.

But there are drawbacks:

  1. Configuration to configure two groups of roughly the same value is different data, one is repeated, the second is to manually write against each other, this is very disgusting.

  2. All pages can be “used” as a whole 🤔️?? This is not easy to maintain, the permissions are not well controlled, the page will become more and more confused to translate fragments of the dependency, better to learn from mobx like warehouse idea, you rely on what I give you, do not rely on you do not give you.

  3. I need formatMessage to translate every time I use it. It’s ok if there are not many files and fragments. What if there are many? Render each time to execute the translation function, 🌰 :

.render() {
        const {
        intl: { formatMessage },
        } = this.props;
        const { codeImage } = this.state;
        const usernamePlaceholder = formatMessage({ id: "login.username" });
        const usernameEmpty = formatMessage({ id: "login.usernameEmpty" });
        const passwordPlaceholder = formatMessage({ id: "login.password" });
        const passwordEmpty = formatMessage({ id: "login.passwordEmpty" });
        const codePlaceholder = formatMessage({ id: "login.code" });
        const maxLength = formatMessage({ id: "login.maxLength" });
        const pwdMaxLength = formatMessage({ id: "header_pwdMaxLength" });
        const codeEmpty = formatMessage({ id: "login.codeEmpty" });
        return (
        <div className="loginpagewrap">.</div>)}...Copy the code

It doesn’t make sense. Something has to be done.

Optimization mode:

First, optimize each link of traditional mode.

Start with configuration

import BaseIntl from "./baseIntl";

let config = {
  light_searchSelect: {
    en: "searchSelect".zh: "Lenovo select",},light_baseSelect: {
    en: "baseSelect".zh: "Basic select",},light_computeNum: {
    en: "computeNum".zh: "Calculated value",}};export default new BaseIntl({ config });
Copy the code

A file solution, which is good, and baseIntl extension, mainly for it to complement the common translation fragments, which greatly solves the problem of repeated translation fragments.

Then based on thereact-intlCustomize one of our higher-order componentsintlHoc

Before we do this higher-level component, we need to make sure that we are not breaking React-IntL, but extending TA.

Directly on the code:

import React from "react";
import { inject, observer } from "mobx-react";
import { injectIntl } from "react-intl";
import language from "SRC/language";

function hoc(id) {
  return function (WrappedComponent) {
    @injectIntl
    @inject("global")
    class IntlHoc extends React.Component {
      constructor(props) {
        super(props);
        const {
          global: { locale },
        } = this.props;
        this.state = {
          formatedMessage: this.formatMessage(),
          localeFlag: locale,
        };
      }

      formatMessage() {
        const { intl } = this.props;
        const { formatMessage } = intl;
        let targetArr = language.getIntlById(id);
        let trmpArr = {};
        for (let key in targetArr) {
          trmpArr[key] = formatMessage({ id: key });
        }
        return trmpArr;
      }
      shouldComponentUpdate() {
        const {
          global: { locale },
        } = this.props;
        if (this.state.localeFlag ! == locale) {this.setState({
            localeFlag: locale,
            formatedMessage: this.formatMessage(),
          });
        }
        return true;
      }
      render() {
        const { formatedMessage } = this.state;
        const props = Object.assign({}, this.props, {
          intlData: formatedMessage,
        });
        return <WrappedComponent {. props} / >; }}return IntlHoc;
  };
}

export default hoc;
Copy the code

Then replace injectIntl for packaging, chestnut 🌰 :

.import injectInternational from "COMMON/hocs/intlHoc"; . @injectInternational("light")
class TempEdit extends Component {
     const {
            intlData
        } = this.props;
    render(){
        return <div>{intlData.light_editting}</div>}}Copy the code

Analysis:

  1. First, there is no difference in the way higher-order components are packaged.
  2. Instead of using it beforeformatMessageAnd then inject the data into the component props using intlData, which can be obtained directly from “. “, which simplifies the process and avoids redundant execution of functions.
  3. The most important thing is that you can pass in a specific internationalization module for your page, which is very comfortable and maintained separately, which is really nice.

Results show


conclusion

Internationalization is something that will make you headache and pain if you don’t care about TA. It’s like a habit. It’s better to develop it early.

🌰 to implement the internationalization program