1. 程式人生 > 程式設計 >react-intl實現React國際化多語言的方法

react-intl實現React國際化多語言的方法

本文主要介紹了react-intl實現React國際化多語言的方法,分享給大家,具體如下:

效果預覽

react-intl實現React國際化多語言的方法

React Intl 國際化步驟

  • 建立國際化資原始檔
  • 根據語言獲取國際化資源
  • 引入 react-intl 的 local data
  • 建立 LocaleProvider 國際化上下文元件
  • 建立 react-intl 國際化上下文元件
  • 使用 react-intl's components & apis,進行國際化開發

1. 建立國際化資原始檔

目前我們管理資原始檔的方式是在 src/locales 資料夾下:

.
├── en-US.js
├── en-US.messages.js
├── zh-Hans.js
└── zh-Hans.messages.js

*.messages.js 是我們的資原始檔(這裡我們採用了 js 格式,你也可以使用 json 等等),返回的是一個物件,key 為我們翻譯用的 id,value 為具體語言的翻譯,內容是:

export default {
 'page.localeProvider.react': '{ name },a JavaScript library for building user interfaces.','page.localeProvider.react.html': '<p>{ name } makes it painless to create interactive UIs. Design simple views for each state in your application,and { name } will efficiently update and render just the right components when your data changes.</p><p>Declarative views make your code more predictable and easier to debug.</p>','page.localeProvider.unreadCount': 'You have {unreadCount} new {notifications}','page.localeProvider.title.date': 'Current date: ','page.localeProvider.title.time': 'Current time: ','page.localeProvider.title.relative': 'Relative current time: ','page.localeProvider.title.number': 'Comma number: ','page.localeProvider.title.price': 'Price: ','page.localeProvider.title.percent': 'Percent: ',};

en-US.js 檔案封裝了 messages、locale 等國際化上下文元件需要的內容:

import appLocaleData from 'react-intl/locale-data/en';
// 引入元件多語言
import paginationLocale from '@/components/pagination/locales/en-US';
import messages from './en-US.messages';

window.appLocale = {
 // 合併所有 messages,加入元件的 messages
 messages: Object.assign({},messages,{
  Pagination: paginationLocale,}),// locale
 locale: 'en-US',// react-intl locale-data
 data: appLocaleData,// 自定義 formates
 formats: {
  date: {
   normal: {
    hour12: false,year: 'numeric',month: '2-digit',day: '2-digit',hour: '2-digit',minute: '2-digit',},// 貨幣
  money: {
   currency: 'USD',};

export default window.appLocale;

有了這些資原始檔以及相關的封裝之後,我們就可以在 LocaleProvider 和 InltProvider 中使用了。

2. 根據語言載入國際化資源

上一步我們建立了不同語言版本的國際化資原始檔,我們還需要一個函式能夠根據語言,載入對應的資原始檔:

/**
 * 獲取國際化資原始檔
 *
 * @param {any} lang
 * @returns
 */
function getLocale(lang) {
 let result = {};
 switch (lang) {
  case 'zh-CN':
   result = require('./locales/zh-Hans');
   break;
  case 'en-US':
   result = require('./locales/en-US');
   break;
  default:
   result = require('./locales/zh-Hans');
 }

 return result.default || result;
}

3. 引入 react-intl 的 local data

import { addLocaleData } from 'react-intl';
...

render() {
 const appLocale = getLocale('en-US');
 addLocaleData(...appLocale.data);
 ...
}

react-intl 在做國際化的時候需要一些特有的 local data,主要是進行相對時間翻譯時,比如昨天、今天、明天、幾分鐘前、幾個月前之類的。我們通過 addLocaleData 這個方法載入相關內容,大家可以根據實際情況載入需要的 locale-data。

4. 建立 LocaleProvider 國際化上下文元件

為了元件能夠國際化資源資訊,我們需要一個 LocaleProvider 元件,用它來提供國際化的上下文,具體用法:

export default class LocaleProvider extends React.Component {
 static propTypes = {
  children: PropTypes.any,locale: PropTypes.object,};

 static childContextTypes = {
  // 語言資訊
  locale: PropTypes.object,};

 getChildContext() {
  return {
   locale: {
    ...this.props.locale,};
 }

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

5. 建立 react-intl 國際化上下文元件

為了能夠使用 react-intl 進行國際化,跟 redux 這些框架一樣,我們需要一個 Provider Component,用它來提供國際化的上下文,具體用法:

...
import { addLocaleData,IntlProvider } from 'react-intl';
import LocaleProvider from '@/components/locale-provider';
import Home from '@/views/home';
...

render() {
 // 根據語言獲取國際化資源
 const appLocale = getLocale('en-US');
 addLocaleData(...appLocale.data);

 return (
  <LocaleProvider locale={appLocale}>
   <IntlProvider
    locale={appLocale.locale}
    messages={appLocale.messages}
    formats={appLocale.formats}
   >
    <Home />
   </IntlProvider>
  </LocaleProvider>
 );
}

LocaleProvider 有三個配置引數:

  • locale,<object>,國際化資源.

IntlProvider 有三個配置引數:

  • locale,<string>,語言標記,例如 'zh-CN' 'en-US'
  • messages,國際化所需的 key-value 物件
  • formats,自定義 format,比如日期格式、貨幣等

在定義好 IntlProvider 之後,我們就可以在頁面使用它提供的 api 或者元件來進行國際化了。

6. 使用 react-intl's components & apis

react-intl 提供了豐富的元件和 api 來完成頁面部分的國際化。

字串的格式化

a. <FormattedMessage /> 這個元件用於格式化字串,是所有的元件中使用頻率最高的元件。除了可以根據配置輸出不同語言的簡單字串之外,還可以輸出包含動態變化的引數的複雜字串,具體的用法在後面的例子中會慢慢敘述。

比如我們在 *.message.js 配置檔案中寫了如下內容:

export default {
 'page.localeProvider.react': '{ name },};

使用這個元件的時候,我們這麼寫:

<FormattedMessage
 tagName="p"
 id="page.localeProvider.react"
 values={{
  name: 'React',}}
 defaultMessage="{name} 是一個用於構建使用者介面的 JAVASCRIPT 庫。"
 description="{name} 是什麼?"
/>
  • id 指代的是這個字串在配置檔案中的屬性名
  • description 指的是對於這個位置替代的字串的描述,便於維護程式碼,不寫的話也不會影響輸出的結果
  • defaultMessage 當在locale配置檔案中沒有找到這個id的時候,輸出的預設值
  • tagName 實際生成的標籤,預設是 span
  • values 動態引數. 格式為物件

輸出的結果:

<p>React,a JavaScript library for building user interfaces.</p>

b. <FormattedHTMLMessage />這個元件的用法和完全相同,唯一的不同就是輸出的字串可以包含HTML標籤。

日期時間

a. <FormattedDate /> 用於格式化日期,能夠將一個時間戳格式化成不同語言中的日期格式。

傳入時間戳作為引數:

<FormattedDate 
 value={new Date(1459832991883)}
/>

輸出結果:

<!-- 英文 -->
<span>4/5/2016</span>

<!-- 中文 -->
<span>2016/5/4</span>

b. <FormattedTime> 用於格式化時間,效果與<FormattedDate />相似。

傳入時間戳作為引數:

<FormattedTime 
 value={new Date(1459832991883)}
/>

輸出結果:

<!-- 英文 -->
<span>1:09 AM</span>

<!-- 中文 -->
<span>上午1:09</span>

c. <FormattedRelative /> 通過這個元件可以顯示傳入元件的某個時間戳和當前時間的關係,比如“10 minutes ago”。

傳入時間戳作為引數:

<FormattedRelative 
 value={Date.now()}
/>

輸出結果:

<!-- 英文 =>> 執行時的輸出結果: -->
<span>now</span>

<!-- 英文 =>> 10秒之後的輸出結果: -->
<span>10 seconds ago</span>

<!-- 英文 =>> 1分鐘之後的輸出結果: -->
<span>1 minute ago</span>

<!-- 中文 =>> 執行時的輸出結果: -->
<span>現在</span>

<!-- 中文 =>> 10秒之後的輸出結果: -->
<span>10秒前</span>

<!-- 中文 =>> 1分鐘之後的輸出結果: -->
<span>1分鐘前</span>

數字量詞

a. <FormattedPlural /> 這個元件可用於格式化量詞,在中文的語境中,其實不太會用得到,比如我們說一個雞腿,那麼量詞就是‘個',我們說兩個雞腿,量詞還是‘個',不會發生變化。但是在英文的語言環境中,描述一個蘋果的時候,量詞是apple,當蘋果數量為兩個時,就會變成apples,這個元件的作用就在於此。

傳入元件的引數中,value為數量,其他的為不同數量時對應的量詞,在下面的例子中,一個的時候量詞為message,兩個的時候量詞為messages。實際上可以傳入元件的量詞包括 zero,one,two,few,many,other 已經涵蓋了所有的情況。

結合 <FormattedMessage />運用:

const unreadCount = 10;
const unreadCount2 = 1;
... 

<p>
 <FormattedMessage
  id="page.localeProvider.unreadCount"
  defaultMessage={'你有{ unreadCount }條新資訊'}
  values={{
   unreadCount: (
    <strong
     style={{
      color: '#f30',fontWeight: 'normal',}}
    >
     <FormattedNumber
      value={unreadCount}
     />
    </strong>
   ),notifications: (
    <FormattedPlural
     value={unreadCount}
     one="notification"
     other="notifications"
    />
   ),}}
 />
</p>
<p>
 <FormattedMessage
  id="page.localeProvider.unreadCount"
  defaultMessage={'你有{ unreadCount2 }條新資訊'}
  values={{
   unreadCount: (
    <strong
     style={{
      color: '#f30',}}
    >
     <FormattedNumber
      value={unreadCount2}
     />
    </strong>
   ),notifications: (
    <FormattedPlural
     value={unreadCount2}
     one="notification"
     other="notifications"
    />
   ),}}
 />
</p>

輸出結果:

<!-- 英文 -->
<p>You have 10 new notifications</p>
<p>You have 1 notification</p>

<!-- 中文 -->
<p>你有10條新資訊</p>
<p>你有1條新資訊</p>

b. <FormattedNumber /> 這個元件最主要的用途是用來給一串數字標逗號,比如10000這個數字,在中文的語言環境中應該是1,0000,是每隔4位加一個逗號,而在英語的環境中是10,000,每隔3位加一個逗號。

傳入數字作為引數:

<FormattedNumber 
 value={1000}
/>

輸出結果:

<span>1,000</span>

<FormattedNumber /> 輸出百分比

傳入小數作為引數:

<FormattedNumber
 value={0.5}
 style="percent"
/>

輸出結果:

<span>50%</span>

<FormattedNumber /> 輸出貨幣

傳入數字作為引數:

// locale.formats.money.currency 是 /locales/*.js 國際化資源配置的貨幣資訊。中文: 'CNY'; 英文: 'USD'

<FormattedNumber
 value={123456.78}
 style="currency"
 currency={locale.formats.money.currency}
/>

輸出結果:

<!-- 英文 -->
<span>$123,456.78</span>

<!-- 中文 -->
<span>¥123,456.78</span>

注:專案在中文情況下也是每隔3位加一個逗號,具體原因詳,如果有知道原因的請告知。

元件國際化

1. 建立獲取上下文國際化資源函式

/**
 * 獲取 元件的語言配置
 *
 * @param {any} props 屬性
 * @param {any} context 上下文
 * @param {any} componentName 元件名. 對應 context.locale.messages 中的 key 值
 * @param {any} getDefaultLocale
 */
function getComponentLocale(props,context,componentName,getDefaultLocale) {
 let locale = {};

 // 如果 context 上下文中有多語言配置. 則取 context 上下文中的多語言值.
 // 否則,取預設值的多語言值.
 if (context && context.locale && context.locale.messages[componentName]) {
  locale = context.locale.messages[componentName];
 } else {
  const defaultLocale = getDefaultLocale();
  locale = defaultLocale.default || defaultLocale;
 }

 let result = {
  ...locale,};

 // 如果屬性有語言配置項,則合併.
 if (props.locale) {
  result = {
   ...result,...props.locale,};

  if (props.locale.lang) {
   result.lang = {
    ...locale.lang,...props.locale.lang,};
  }
 }

 return result;
}

2. 建立國際化的元件

...
import { getComponentLocale } from '../_utils/getLocale';
...

export default class Pagination extends React.Component {
 // context 上下文
 static contextTypes = {
  locale: PropTypes.object,};

 render() {
  const currentlocale = getComponentLocale(this.props,this.context,'Pagination',() => {
   require('./locales/zh-CN');
  });

  return (
   <div className="pagination">
    <div className="pagination__wrapper">
     <div className="pagination__button__prev">
      <a>{currentlocale.prevText}</a>
     </div>
     <div className="pagination__button__next">
      <a>{currentlocale.nextText}</a>
     </div>
    </div>
   </div>
  );
 }
}

國際化規範附錄

React Intl 編寫規範

  • 必須填寫 defaultMessage,並將 defaultMessage 作為中文翻譯
  • id 不得重複
  • 在使用 intl.formatMessage() 時,必須使用 defineMessages,預定義訊息

原始碼

整個專案原始碼

資料

  • API
  • 國際化方案
  • Intl.NumberFormat

到此這篇關於react-intl實現React國際化多語言的方法的文章就介紹到這了,更多相關React國際化多語言內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!