项目中国际化的实现

380 阅读1分钟

国际化

国际化的目的

  1. 让h5页面在不同的语言环境下打开, 使用相应的语言
  2. 奔驰大老板来中国出差旅游要用的,秘书给他在外国装好app来国内用(初心)

国际化的本质

  1. 根据语言来加载不同的json文件. json文件的内容是对各种文案和资源的配置.

国际化的语言判断(判断用户所属区域 或者 用户所选择语言)

  1. 入口 URL 附带相关参数(目前我们所选择的方案, 视业务而定)
  2. 通过 IP 地址进行判断

国际化的使用

  1. LocaleProvider 使用 React 的 context 特性,只需在应用外围包裹一次即可全局生效。
const args = getUrlParam();
const lang = args.lang || 'zh_CN';
const langFile = require(`./components/locale-provider/${lang}`).default;

<LocaleProvider locale={langFile}>
  <Router history={history} routes={routes} />
</LocaleProvider>
  1. 编写语言配置
//zh_CN.js
export default {
  locale: 'zh-cn',
  global: {},
  multi: {
    text: '你好',
  }
}

//en_US.js
export default {
  locale: 'en-us',
  // 全局: 比如 xx小时xx分钟 该怎么转成英文
  global: {},
  multi: {
    text: 'hello',
  }
}
  1. 将语言配置注入组件中
import React, { Component } from 'react';
import { injectLocale } from '@/components/locale-provider';

@injectLocale()
export default class MultiLang extends Component {
  render() {
    const { locale: { multi } } = this.props;
    return <div className="multi">{multi.text}</div>;
  }
}

// 等价于
//export default injectLocale()(MultiLang);

国际化的实现

  1. LocaleProvider(本质是高阶组件)

三种实现方式:

  1. 组合props
  2. 继承
  3. 以函数作为children
// locale-provider/index.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class LocaleProvider extends Component {
  getChildContext() {
    return {
      locale: { ...this.props.locale },
    };
  }

  render() {
    return React.Children.only(this.props.children);
  }
}

LocaleProvider.propTypes = {
  locale: PropTypes.object,
};

LocaleProvider.defaultProps = {
  locale: PropTypes.object,
};

LocaleProvider.childContextTypes = {
  locale: PropTypes.object,
};

export { default as injectLocale } from './injectLocale';
  1. injectLocale
import { Component, createElement } from 'react';
import PropTypes from 'prop-types';
import hoistStatics from 'hoist-non-react-statics';

export default function injectLocale(defaultLocale = {}) {
  return function wrapWithLocale(WrappedComponent) {
    class Inject extends Component {
      static contextTypes = {
        locale: PropTypes.object,
      };

      getLocale = () => {
        const { locale } = this.context;
        const localeFromContext = locale;
        return {
          ...localeFromContext,
          ...defaultLocale,
        };
      }

      addLocaleProps = () => ({ ...this.props, locale: this.getLocale() })

      render() {
        return createElement(WrappedComponent, this.addLocaleProps());
      }
    }

    return hoistStatics(Inject, WrappedComponent);
  };
}

题外话: decorator

什么是装饰器

  1. ES7的语法, Object.defineProperty的语法糖
  2. 对类和**方法(不能修饰函数)**进行修饰, 在不改变原有接口的前提下, 增强它的功能(想象一下钢铁侠, 在不改变他是个人的前提下, 给他装饰了很多武器, 使之无比强大)
  3. 装饰器的实现
@testable
class A {}

function testable(target) {
  target.isTestable = true;
}

MyTestableClass.isTestable // true

// 等同于

class A {}
A = testable(A) || A;
class Person {
  @readonly
  name() { return `${this.first} ${this.last}` }
}

function readonly(target, name, descriptor){
  // descriptor对象原来的值如下
  // {
  //   value: specifiedFunction,
  //   enumerable: false,
  //   configurable: true,
  //   writable: true
  // };
  descriptor.writable = false;
  return descriptor;
}

readonly(Person.prototype, 'name', descriptor);
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor);

Tip: 这代码是几个月前写的, 同时这是我第一次发表文章, 大家给新人一点鼓励哈~