博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
react 中国际化_从头到尾如何在React中设置国际化
阅读量:2527 次
发布时间:2019-05-11

本文共 15759 字,大约阅读时间需要 52 分钟。

react 中国际化

This post will use react-intl to help you go from create-react-app to setting up the framework to a completed, translated web app!

这篇文章将使用react-intl来帮助您从create-react-app到设置框架,再到完整的已翻译Web应用程序!

I committed code as I wrote this post, so you will be able to look at my commit history to easily see how my code evolved from start to finish.

我在撰写本文时提交了代码,因此您可以查看我的提交历史记录,轻松了解我的代码从头到尾的发展历程。

什么是国际化? (What is Internationalization?)

Given that you decided to click on the link to this post, chances are you at least have some idea what internationalization (i18n) is. Taken right off of the :

鉴于您决定单击此文章的链接,因此您至少有可能了解什么是国际化(i18n)。 从上直接 :

“Internationalization is the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.”

“国际化是产品,应用程序或文档内容的设计和开发, 可以使针对不同文化,地区或语言的目标受众轻松地进行本地化。”

As a developer, you want your content to be easily readable and usable by all kinds of people across the globe. I think everyone agrees with that. But I know what you’re thinking:

作为开发人员,您希望您的内容可以被全球各地的所有人轻松阅读和使用。 我认为每个人都同意这一点。 但我知道您在想什么:

“Developing a web app for people of my own culture/region/language is already difficult enough! I don’t have the time or effort for i18n!”

“为我自己的文化/地区/语言的人们开发Web应用程序已经非常困难! 我没有时间或精力去做i18n!”

You already have the lingo down, I see. Hopefully, this post will help you realize that setting up i18n for your project is not as difficult or time-consuming as it seems.

我知道你已经把行话放下来了。 希望这篇文章可以帮助您认识到为您的项目设置i18n并不像看起来那样困难或费时。

react-intl做什么和不做什么 (What react-intl does and does not do)

If you are new to i18n, you might have some thoughts about what you think a library such as react-intl should and should not be able to do.

如果您是i18n的新手,您可能会对您认为和应该不应该使用的诸如react-intl类的库有一些想法。

It does:

它确实:

  • Help you aggregate all your scattered content, so that it can be easily translated later

    帮助您汇总所有分散的内容,以便以后轻松翻译
  • Help you deal with translating text in addition to dates, numbers, and so on

    帮助您处理日期,数字等文字的翻译
  • Provide an easy way for translations to be imported into your app

    提供一种将翻译导入您的应用程序的简便方法

It does NOT:

它不是:

  • Translate your content for you

    为您翻译内容
  • Tell you how to find out what locale the user wants

    告诉您如何找出用户想要的语言环境
  • Fix that unrelated bug you’ve been dealing with for the last couple hours (bummer, right?)

    修复您最近几个小时一直在处理的不相关的错误(笨蛋,对吧?)

Ok, so let’s get right to it!

好的,让我们开始吧!

设置示例项目 (Setting up the example project)

$ npx create-react-app i18n-example

I’m going to add react router to show how react-intl works with multiple pages.

我将添加react路由器,以显示react-intl如何与多个页面一起工作。

$ cd i18n-example && npm install react-router-dom

My example app will have three React components: one main page, one subpage, and one component that is imported into the subpage. See the file structure and pages below:

我的示例应用程序将包含三个React组件:一个主页,一个子页面和一个导入到子页面中的组件。 请参见下面的文件结构和页面:

/src  /components    Weather.js  /pages    Home.js    Day.js

The state of the project up until this point can be found .

到此为止的项目状态可以在找到。

设置react-intl (Setting up react-intl)

Now, the fun begins. We will install react-intl and get to work!

现在,乐趣开始了。 我们将安装react-intl并开始工作!

$ npm install react-intl

The main goal behind react-intl is to allow support for i18n while minimizing the impact to your normal coding flow. Certainly, you have content in many places all over your web app. You have text, numbers, and dates in paragraphs, tables, and headers.

react-intl背后的主要目标是支持i18n,同时最大程度地减少对常规编码流的影响。 当然,您在Web应用程序的许多地方都有内容。 您在段落,表格和标题中都有文本,数字和日期。

What would you do if you had to build an i18n library? Well, you have these bits and pieces of content all over your web app. And you want it all to be easily translated. If you were going to give your content to a translator, you wouldn’t give them your code and say “good luck, get to work.”

如果必须构建i18n库,该怎么办? 好吧,您在Web应用程序中都有这些零碎的内容。 而且您希望所有内容都易于翻译。 如果您打算将内容提供给翻译人员,则不会给他们您的代码说“祝您好运,开始工作”。

You would want to find a way to put all your content in one file, and then give them that one file. They would translate it into another language, say from English to Spanish, and give you one file with all the Spanish content.

您可能想找到一种将所有内容放在一个文件中,然后再给他们一个文件的方法。 他们会将其翻译成另一种语言,从英语翻译成西班牙语,然后给您一个包含所有西班牙语内容的文件。

Ok, great. So you did that, but now you have to take the Spanish content in that one file and re-distribute it back into its original location. How would you do that programmatically? Perhaps you would assign ids to each bit of content, so that you don’t lose track of the original location of each bit of content.

好的太棒了。 这样就可以了,但是现在您必须在该文件中获取西班牙语内容,然后将其重新分发回其原始位置。 您将如何以编程方式做到这一点? 也许您将为每个内容位分配ID,这样您就不会丢失每个内容位的原始位置。

And that’s pretty much it!

就是这样!

The first step is to wrap your application in the <IntlProvider> component:

第一步是将应用程序包装在<IntlProvid er>组件中:

Now, you need to identify the content for react-intl that will eventually be translated. On the home page of my app, I have the following paragraph:

现在,您需要确定react-intl的内容,这些内容最终将被翻译。 在应用程序的主页上,有以下段落:

It is a beautiful day outside.

I need to tell react-intl that this is content that I want to translate and give it an id, so that it can keep track of this content and its original location:

我需要告诉react-intl这是我要翻译的内容并为其指定ID,以便它可以跟踪此内容及其原始位置:

By default, the text will be outputted in a <span> , so we will need to wrap this in the original <p> if we want it to remain a paragraph.

默认情况下,文本将以<sp an>输出,因此,如果我们希望文本保留为段落,则需要将其包装在原始的<p>

I will now do this for all the content in my web app.

现在,我将对Web应用程序中的所有内容执行此操作。

The state of the project up until now can be found .

到目前为止的项目状态可以在找到。

添加babel-plugin-react-intl (Adding babel-plugin-react-intl)

Now that we have everything set up, you might be wondering how we can easily aggregate all of that content into one file. However, for debugging purposes, it could be helpful to have individual JSON files for each React component. Guess what, there’s a babel plugin for that!

现在我们已经完成了所有设置,您可能想知道我们如何轻松地将所有内容聚合到一个文件中。 但是,出于调试目的,为每个React组件使用单独的JSON文件可能会有所帮助。 猜猜是什么,有一个babel插件!

$ npm install babel-plugin-react-intl

This plugin will make a copy of your src directory, but instead of having your React component files, it will have json files with the message content and id. One for each component file in your src directory. It will do this when you run npm run build .

这个插件将复制您的src目录,但是它没有包含您的React组件文件,而是包含带有消息内容和ID的json文件。 src目录中的每个组件文件一个。 当您运行npm run build时,它将执行此操作。

Now we need to eject from create-react-app, so that we can add our new plugin into our babel configuration. Make sure to commit any changes and then execute:

现在我们需要从create-react-app弹出,以便可以将新插件添加到babel配置中。 确保提交所有更改,然后执行:

$ npm run eject

Now, we will need to add a .babelrc file in our project root with the following contents:

现在,我们需要在项目根目录中添加一个.babelrc文件,其内容如下:

{  "presets":["react-app"],  "plugins": [    ["react-intl", {      "messagesDir": "./public/messages/"    }]  ]}

Now that babel can use our fancy new plugin that we just added, we can move onto our next step: generating those JSON files.

现在,babel可以使用我们刚刚添加的新奇插件,我们可以继续下一步:生成这些JSON文件。

$ npm run build

Once you run this, you should notice that you have a public/messages/src directory that appears to be a clone of your original src directory, except all your component files are actually JSON files.

运行此命令后,您应该注意到您有一个public/messages/src目录,该目录似乎是原始src目录的副本,但所有组件文件实际上都是JSON文件。

/messages  /src    /components      Weather.json    /pages      Home.json      Day.json

Now, let’s see the contents of one of them, Home.json:

现在,让我们看看其中之一的内容,即Home.json:

[  {    "id": "Home.header",    "defaultMessage": "Hello, world!"  },  {    "id": "Home.dayMessage",    "defaultMessage": "It's a beautiful day outside."  },  {    "id": "Home.dayLink",    "defaultMessage": "Click here to find out why!"  }]

The state of the project up until now can be found .

到目前为止的项目状态可以在找到。

结合JSON文件 (Combining the JSON files)

It did just what we thought it would. It can be helpful to have our content organized in this structure, but ultimately we will want it to be in one file, and we need it to include any translations that we will make.

它确实达到了我们的预期。 将我们的内容组织成这种结构可能会有所帮助,但最终我们希望将其保存在一个文件中,并且我们需要它包含我们将进行的所有翻译。

Now we need to make a script that does this for us. Thankfully, the folks at react-intl gave us a good starting point with .

现在,我们需要创建一个脚本来为我们执行此操作。 值得庆幸的是, react-intl的人们使用为我们提供了一个很好的起点。

import * as fs from "fs";import { sync as globSync } from "glob";import { sync as mkdirpSync } from "mkdirp";import last from "lodash/last";const MESSAGES_PATTERN = "./public/messages/**/*.json";const LANG_DIR = "./public/locales/";const LANG_PATTERN = "./public/locales/*.json";// Try to delete current json files from public/localestry {  fs.unlinkSync("./public/locales/data.json");} catch (error) {  console.log(error);}// Merge translated json files (es.json, fr.json, etc) into one object// so that they can be merged with the eggregated "en" object belowconst mergedTranslations = globSync(LANG_PATTERN)  .map(filename => {    const locale = last(filename.split("/")).split(".json")[0];    return { [locale]: JSON.parse(fs.readFileSync(filename, "utf8")) };  })  .reduce((acc, localeObj) => {    return { ...acc, ...localeObj };  }, {});// Aggregates the default messages that were extracted from the example app's// React components via the React Intl Babel plugin. An error will be thrown if// there are messages in different components that use the same `id`. The result// is a flat collection of `id: message` pairs for the app's default locale.const defaultMessages = globSync(MESSAGES_PATTERN)  .map(filename => fs.readFileSync(filename, "utf8"))  .map(file => JSON.parse(file))  .reduce((collection, descriptors) => {    descriptors.forEach(({ id, defaultMessage }) => {      if (collection.hasOwnProperty(id)) {        throw new Error(`Duplicate message id: ${id}`);      }      collection[id] = defaultMessage;    });    return collection;  }, {});// Create a new directory that we want to write the aggregate messages tomkdirpSync(LANG_DIR);// Merge aggregated default messages with the translated json files and// write the messages to this directoryfs.writeFileSync(  `${LANG_DIR}data.json`,  JSON.stringify({ en: defaultMessages, ...mergedTranslations }, null, 2));

We will need to modify it a little bit because, as it stands, that script will generate a fake translation. We don’t want this because it is not practical.

我们需要对其进行一些修改,因为就目前而言,该脚本将生成伪造的翻译。 我们不希望这样做,因为这不切实际。

We are better than that! We want it to read a real translation!

我们比那更好! 我们希望它阅读真实的翻译!

The script we will use to do this is below:

我们将用于执行此操作的脚本如下:

We will need to save this file in our scripts directory and then edit package.json so that it actually runs the script.

我们将需要将此文件保存在scripts目录中,然后编辑package.json ,以使其实际运行脚本。

Before we do that, we will need to do a couple things, so that our ESNext code can be understood. First we will need to add babel-cli to make sure that the script gets transpiled.

在此之前,我们需要做一些事情,以便可以理解我们的ESNext代码。 首先,我们将需要添加babel-cli以确保脚本被编译。

$ npm install --save-dev babel-cli

Next, we need to add the env preset to our .babelrc so that it looks like this:

接下来,我们需要将env预设添加到.babelrc ,使其看起来像这样:

{  "presets":["react-app", "env"],  "plugins": [    ["react-intl", {      "messagesDir": "./public/messages/"    }]  ]}

Lastly, we need to edit our package.json so that it runs our script:

最后,我们需要编辑package.json以使其运行我们的脚本:

{...  "scripts": {    "build:langs": "NODE_ENV='production' babel-node      scripts/mergeMessages.js",    "build": "npm run build:langs && node scripts/build.js",    ...  },  ...}

Note that we are running the mergeMessages script before npm run build . This is because we want to generate our final data.json file in the /public directory before our build script copies it over to /build .

请注意,我们在npm run build之前运行mergeMes​​sages脚本。 这是因为我们要在构建脚本将其复制到/build之前,在/public目录中生成最终的data.json文件。

Alright, now when we run npm run build we should see build/locales/data.json which combines all of our JSON files into one.

好了,现在当我们运行npm run build我们应该看到build/locales/data.json它将所有的JSON文件合并为一个。

The state of the project up until now can be found .

到目前为止的项目状态可以在找到。

是时候开始翻译了 (Time to start translating)

Now that we have made a script that will aggregate our default messages and our translations into one file, let’s make some translations! For this example, we will translate to Spanish. Our script that we just created will read all *.json files from /public/locales so we will need to name our new translation file /public/locales/es.json and add the content below:

现在我们已经制作了一个脚本,它将默认消息和翻译汇总到一个文件中,让我们进行一些翻译! 对于此示例,我们将翻译为西班牙语。 我们刚刚创建的脚本将从/public/locales读取所有*.json文件,因此我们需要命名新的翻译文件/public/locales/es.json并在下面添加内容:

{  "Weather.message": "¡Porque es soleado!",  "Day.homeLink": "Regresar a inicio",  "Home.header": "¡Hola Mundo!",  "Home.dayMessage": "Es un hermoso día afuera.",  "Home.dayLink": "¡Haz clic aquí para averiguar por qué!"}

Now when we run npm run build, our mergeMessages script will create a data.json file in /public/locales , and then it will be copied over to /build/locales. Our final data.json file will look like this:

现在,当我们运行npm run build ,我们的mergeMes​​sages脚本将在/public/locales创建一个data.json文件,然后将其复制到/build/locales 。 我们最终的data.json文件将如下所示:

{  "en": {    "Weather.message": "Because it is sunny!",    "Day.homeLink": "Go back home",    "Home.header": "Hello, world!",    "Home.dayMessage": "It's a beautiful day outside.",    "Home.dayLink": "Click here to find out why!"  },  "es": {    "Weather.message": "¡Porque es soleado!",    "Day.homeLink": "Regresar a inicio",    "Home.header": "¡Hola Mundo!",    "Home.dayMessage": "Es un hermoso día afuera.",    "Home.dayLink": "¡Haz clic aquí para averiguar por qué!"  }}

We’re almost there! The last step is to dynamically load the Spanish version of the text if the user’s browser settings are Spanish. We need to edit index.js to read the browser language settings and then give that information along with the correct translations to <IntlProvider /> and ultimately our app.

我们快到了! 最后一步是如果用户的浏览器设置为西班牙语,则动态加载文本的西班牙语版本。 我们需要编辑index.js来阅读浏览器的语言设置,然后将这些信息以及正确的翻译提供给<IntlProvider />,最后是我们的应用程序。

Our final index.js looks like this:

我们最终的index.js看起来像这样:

import React from "react";import ReactDOM from "react-dom";import "./index.css";import App from "./App";import registerServiceWorker from "./registerServiceWorker";import { BrowserRouter } from "react-router-dom";import { IntlProvider, addLocaleData } from "react-intl";import en from "react-intl/locale-data/en";import es from "react-intl/locale-data/es";import localeData from "./../build/locales/data.json";addLocaleData([...en, ...es]);// Define user's language. Different browsers have the user locale defined// on different fields on the `navigator` object, so we make sure to account// for these different by checking all of themconst language =  (navigator.languages && navigator.languages[0]) ||  navigator.language ||  navigator.userLanguage;// Split locales with a region codeconst languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];// Try full locale, try locale without region code, fallback to 'en'const messages =  localeData[languageWithoutRegionCode] ||  localeData[language] ||  localeData.en;ReactDOM.render(  
, document.getElementById("root"));registerServiceWorker();

(Heavily copied code from ’s gist )

( 从的要旨中复制的代码)

One other small thing we need to do is edit our webpack configs to allow imports outside of src and node_modules .

我们需要做的另一件事是编辑webpack配置,以允许在srcnode_modules之外进行node_modules

Now, if we change our browser settings to Spanish, we should see our content translated into Spanish!

现在,如果将浏览器设置更改为西班牙语,则应该看到内容已翻译成西班牙语!

The final state of the project can be found .

该项目的最终状态可以在找到。

翻译自:

react 中国际化

转载地址:http://mcwzd.baihongyu.com/

你可能感兴趣的文章
最短路径(SP)问题相关算法与模板
查看>>
js算法之最常用的排序
查看>>
Python——交互式图形编程
查看>>
经典排序——希尔排序
查看>>
团队编程项目作业2-团队编程项目代码设计规范
查看>>
英特尔公司将停止910GL、915GL和915PL芯片组的生产
查看>>
Maven配置
查看>>
HttpServletRequest /HttpServletResponse
查看>>
SAM4E单片机之旅——24、使用DSP库求向量数量积
查看>>
从远程库克隆库
查看>>
codeforces Unusual Product
查看>>
hdu4348 - To the moon 可持久化线段树 区间修改 离线处理
查看>>
正则表达式的搜索和替换
查看>>
个人项目:WC
查看>>
地鼠的困境SSL1333 最大匹配
查看>>
flume+elasticsearch+kibana遇到的坑
查看>>
【MM系列】在SAP里查看数据的方法
查看>>
C#——winform
查看>>
CSS3 transform制作的漂亮的滚动式导航
查看>>
《小强升职记——时间管理故事书》读书笔记
查看>>