React項目國際化-React-intl


  npx create-react-app react-intl-demo && cd react-intl-demo,創建react-intl-demo項目。npm install react-intl, 安裝react-intl。使用react-intl時, 首先要提供一個provider,把整個項目包起來。怎么提供呢?使用react-intl的IntlProvider,它有1個必傳參數locale, 設置本地語言,你的app要使用哪種語言進行渲染。你app的用戶使用哪種語言,就要設置local為哪種語言, 比如en-us(美式英語)  zh-cn(簡體中文)。
import {IntlProvider} from "react-intl";

ReactDOM.render(
  <React.StrictMode>
    <IntlProvider locale='en-us'>
      <App />
    </IntlProvider>
  </React.StrictMode>,
  document.getElementById('root')
);
  為什么要提供一個provider呢?就是為了讓React組件能夠使用國際化的函數,翻譯文本。React Intl 使用Provider的模式為組件樹提供i18n(國際化)的上下文。在根組件中提供配置本地語言和翻譯信息,<Formatted*>組件可以直接使用。

  怎么翻譯項目中的文本?翻譯文件放到什么地方?通常來說,會為每一種語言提供一個翻譯文件(json文件),src/translations/zh.json提供中文翻譯 .  en.json file 提供英文翻譯。假設要翻譯App.js中的內容,src/translations/en.json

{
    "app.learn-react-link": "Learn React.",
    "app.text": "Edit <code>src/App.js</code> and save to reload."
}

  src/translations/zh.json

{
    "app.learn-react-link": "學習 React.",
    "app.text": "編輯<code>src/App.js</code>,保存,並刷新頁面"
}

  項目中怎么獲取到翻譯文件? <IntlProvider />有messages屬性, 把locale設置的語言對應的翻譯內容,傳給它,就可以為項目提供翻譯內容。比如locale是en-us,那就要把en.json中的翻譯內容傳遞給messsages. locale是zh-cn,那就把zh.json中的翻譯內容傳遞給messages。怎么傳遞,只能先把json文件引入到項目中,再構建一個以locale為屬性,翻譯內容為值的對象,讓messages的值根據locale來定。index.js中

import zh from './translations/zh.json';
import en from './translations/en.json';

const messages = {
  'en-us': en,
  'zh-cn': zh
}

const locale = 'zh-cn';

ReactDOM.render(
  <React.StrictMode>
    <IntlProvider locale={locale} messages={messages[locale]}>
      <App />
    </IntlProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

  組件中怎么使用翻譯內容?最簡單的方法就是把要翻譯的文本使用<FormattedMessage> 組件來代替。組件有一個必傳屬性id,用來引用翻譯文件。怎么理解id呢?IntlProvider 的messages屬性實際上是一個js對象,包含着項目中每一句文本的翻譯,格式為{"app.learn-react-link": "學習 React."},"app.learn-react-link"可以看作組件中使用翻譯時引用的id,react-intl自動會引用id 對應的翻譯好的文本。<FormattedMessage> 中的id就是引用的這個id,也就是說,id必須和messages中指向json文件中的id一致。App.js

import {FormattedMessage} from 'react-intl';

<p><FormattedMessage id="app.text" /></p>
 
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
    <FormattedMessage id="app.learn-react-link" />
</a>

  npm start, 可以看到項目已經翻譯成中文了。能不能把<code> 去掉呢?FormattedMessage 可以在value屬性中解析出富文本中的XML標簽。FormattedMessage 有一個value屬性

<FormattedMessage id="app.text" 
  values={{
    code: chunks => <code>{chunks}</code>
  }}
>
</FormattedMessage>

  code對應的就是app.text中的<code></code>標簽, 要解析富文本中的哪個標簽,屬性就是哪個標簽。chunks就可解析出標簽中的的內容,在這里就是code標簽中的內容,src/App.js, 返回值就是替換整個標簽及內容。但此時有個問題,如果有一種語言,恰好沒有翻譯呢?比如把locale改成en,

const locale = 'en';

  頁面就只顯示app.text和app.learn-react-link 等Id

 

   這時要用<FormattedMessage />的defaultMessage屬性,設置默認展示的文本。 如果此文本沒有在翻譯文件中找到,就顯示默認文本。它還有一個description: 描述這個文本的作用,主要為翻譯者提供上下文。

<FormattedMessage id="app.text" 
  values={{
    code: chunks => <code>{chunks}</code>
  }}
  defaultMessage="編輯<code>src/App.js</code>,保存,並刷新頁面"
  description="edit text"
>
<FormattedMessage id="app.learn-react-link" 
      defaultMessage="學習 React."
      description="text link"
/>
  但有時候,你不能使用組件,比如輸入框的placeholder, 它只是純文本,這就要用到formatMessage 函數。但使用formatMessage函數時,你需要一個intl的上下文。如果在函數組件中可以使用useIntl。寫一個input輸入框
import React from 'react';
import { useIntl } from 'react-intl';

export function Input() {
    const intl = useIntl();
    const placeholder = intl.formatMessage({id: 'app.placeholder'})
    return <input placeholder={placeholder}></input>
} 

  引入useIntl,在組件中調用它,返回intl上下文,調用formatMessage方法,它接受一個對象作為參數,id屬性就是對應翻譯文件中的id。不要忘了在,json文件中寫

"app.placeholder": "請輸入數字"

  當然,id屬性可以是動態生成的,比如

const intlKey = "something"
const placeholder = intl.formatMessage({ id: `${intlKey}` })
  隨着<FormattedMessage />用的越來越多,頁面結構可能有點混亂,把id, defaultmessage, description 都寫到組件中,太占空間。這時可以使用defineMessages 定義文本,就是用一個變量來指代這一系列的參數。單獨創建一個文件 messages.js
import { defineMessages } from 'react-intl'
 
export default defineMessages({
    text: {
        id: 'app.text',
        defaultMessage: 'Edit <code>src/App.js</code>'
    },
    link: {
        id: 'app.learn-react-link',
        defaultMessage: 'Lerne React',
        description: 'Link on react page'
    },
     placeholder: {
        id: 'app.placeholder'
     }
});

  <FormattedMessage /> and formatMessage()就可以使用message.js中定義的text和link。App.js

import messages from './message.js'
import { FormattedMessage } from 'react-intl'

<p>
  <FormattedMessage {...messages.text}
    values={{
      code: chunks => <code>{chunks}</code>
    }}
  >
  </FormattedMessage>
</p>
 
<a
  className="App-link"
  href="https://reactjs.org"
  target="_blank"
>
  <FormattedMessage {...messages.link} />
</a>

  Input.js

import { useIntl } from 'react-intl';
import messages from './message'

export function Input() {
    const intl = useIntl();
    const placeholder = intl.formatMessage(messages.placeholder)
    return <input placeholder={placeholder}></input>
} 

  如果不能使用useIntl hooks, 在普通函數或類組件中可以使用injectIntl函數提供intl上下文。Input.js

import React from 'react';
import messages from './message.js'
import { injectIntl } from 'react-intl'

function Input({intl}) {
    const placeholder = intl.formatMessage(messages.placeholder)
    return <input placeholder={placeholder}></input>
}

export default injectIntl(Input);

  使用類

import React from 'react';
import messages from './message.js'
import { injectIntl } from 'react-intl'

class Input extends React.Component {
    render() {
        const {intl} = this.props;
        const placeholder = intl.formatMessage(messages.placeholder)
        return <input placeholder={placeholder}></input>
    }
}

export default injectIntl(Input);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM