PHP前端开发

使用 i 翻译你的 React 项目从未如此简单

百变鹏仔 3天前 #JavaScript
文章标签 简单

说疯狂的开发者!

今天我将向您展示,将整个项目翻译成 react 从未像现在这样容易。但首先您需要知道为什么这很重要。

当人们开始编程时,代码文本和消息通常使用葡萄牙语(pt-br)。将项目翻译成其他语言从来都不是优先事项,并且被认为是复杂或不必要的。

那么为什么它会相关呢?

这取决于你的实际情况。以下是您应该考虑此过程的一些原因:

公司需要
可能是您工作的公司或您拥有的某些 saas 开始在另一个国家/地区运营并且有此需求。具有此功能的产品有巨大的差异。

申请国​​际职位空缺
如果您正在申请国际职位空缺,拥有包含国际化项目的作品集可以给您带来引人注目的亮点。这表明您已准备好从事全球项目,并且不像大多数人一样懒惰。

你永远不会学太多
国际化不仅是一种特征,也是一种重要的学习经历。这是您的技能和工具库中的另一种武器。

过去是如何做到的?

项目翻译已经是个老问题了。人们在 html 中选择了该国家的国旗,供人们选择,并在代码中用 if 填充以了解将显示哪些文本。
这是非常被忽视的。网站是用单一语言制作的,翻译是随意添加的。如果是在后端,交易会更糟糕。

随着互联网的全球化,对多语言软件的需求不断增长,带来了针对国际化的特定工具。像 gnu gettext 这样的解决方案出现在后端,随后出现了像 i18next 和 react-intl 这样的前端库。然后疑问就来了...

i18next 对比react-intl:选择哪一个?

  • react-intl:formatjs 项目的一部分,遵循国际 javascript api 标准,确保与现代浏览器的兼容性。

  • 我们将使用哪一个?

    i18下一个我的朋友们!我总是建议阅读文档来开始,但让我们看看 doido 的指南!

    使用 i18next 国际化 react 应用程序

    1. 安装
       npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-i18next 
    1. 配置:创建一个i18n.js来配置i18next。
       import i18n from 'i18next';   import { initreacti18next } from 'react-i18next';   import backend from 'i18next-http-backend';   import languagedetector from 'i18next-browser-languagedetector';   i18n     .use(backend)     .use(languagedetector)     .use(initreacti18next)     .init({ fallbacklng: 'en', interpolation: { escapevalue: false } });   export default i18n;
    1. translations:在 locales/en/translation.json 和 locales/pt/translation.json 中创建翻译文件。
       {     "welcome": "welcome to our application!",     "login": "login"   }
    1. 翻译的使用:在 react 中使用 usetranslation 钩子。
       import react from 'react';   import { usetranslation } from 'react-i18next';   function app() {     const { t } = usetranslation();     return (       <div>         <h1>{t('welcome')}</h1>         <button>{t('login')}</button>       </div>     );   }   export default app;
    1. 语言更改:允许用户更改语言。
       import react from 'react';   import { usetranslation } from 'react-i18next';   function languageswitcher() {     const { i18n } = usetranslation();     const changelanguage = (lng) =&gt; i18n.changelanguage(lng);     return (       <div>         <button onclick="{()"> changelanguage('en')}&gt;english</button>         <button onclick="{()"> changelanguage('pt')}&gt;português</button>       </div>     );   }   export default languageswitcher;

    这就是全部吗?

    当然不是,我现在向您展示我在 crazystack 项目中做了什么。首先,我在 nextjs 中做了一个不同的配置,采用了我在项目本身的公共文件夹中定义的静态 json!看看:

    import i18next from "i18next";import chainedbackend from "i18next-chained-backend";import httpbackend from "i18next-http-backend";import resourcestobackend from "i18next-resources-to-backend";import { initreacti18next } from "react-i18next";import { defaulttexts } from "./defaulttexts";i18next  .use(chainedbackend)  .use(initreacti18next)  .init({    lng: "pt-br",    fallbacklng: "pt-br",    interpolation: {      escapevalue: false,    },    compatibilityjson: "v3",    react: {      //wait: true,//usar no react native      usesuspense: false,    },    backend: {      backends: [httpbackend, resourcestobackend(defaulttexts)],      backendoptions: [        {          loadpath: `${process.env.next_public_url}/{{lng}}/{{ns}}.json`,        },      ],    },  });

    然后我创建了一个上下文 api 来保存语言并在整个项目中访问它。从进口开始

    2. 进口

    import { usetranslation } from "react-i18next";import { createcontext, usestate, usecontext } from "react";

    3. 上下文创建

    const i18ncontext = createcontext({} as any);

    创建上下文来通过 dom 存储和提供数据(例如当前语言)。

    4. 环境检查

    export const isbrowser = typeof window !== "undefined";

    此行检查代码是否在浏览器中运行(而不是在服务器上),这对于处理 localstorage 等特定于客户端的功能至关重要。

    5.i18nprovider组件

    export const i18nprovider = ({ children }: any) =&gt; {  const { i18n } = usetranslation() || {};  const [currentlanguage, setcurrentlanguage] = usestate(    formatlanguagefromi18n(i18n?.language)  );  const changelanguage = (language) =&gt; {    setcurrentlanguage(language);    i18n?.changelanguage?.(formatlanguagefromselect(language));    localstorage.setitem("language", formatlanguagefromselect(language));  };  return (    <i18ncontext.provider value="{{" changelanguage currentlanguage setcurrentlanguage>      {children}    </i18ncontext.provider>  );};

    这个组件是一个provider,它包装了react组件树并提供了语言的当前状态以及更改它的函数。

    6. 挂钩使用i18n

    export const usei18n = () =&gt; {  if (!isbrowser) {    return {      currentlanguage: "pt-br",      setcurrentlanguage: () =&gt; {},      changelanguage: () =&gt; {},    };  }  return usecontext(i18ncontext);};

    这个钩子可以轻松访问任何组件中的国际化上下文。

    7. 转换图

    const countrytolanguage = {  br: "pt-br",  us: "en",};const languagetocountry = {  "pt-br": "br",  en: "us",};

    这些对象将国家/地区代码映射到语言代码,反之亦然,从而可以轻松地在不同约定之间格式化语言代码。

    8. 格式化函数

    export const formatlanguagefromi18n = (language) =&gt; languagetocountry[language];export const formatlanguagefromselect = (language) =&gt; countrytolanguage[language];

    这些函数根据需要格式化语言环境。 formatlanguagefromi18n 将语言代码转换为国家/地区代码,而 formatlanguagefromselect 则进行反向转换。

    完整代码

    "use client";import { usetranslation } from "react-i18next";import { createcontext, usestate, usecontext } from "react";const i18ncontext = createcontext({} as any);export const isbrowser = typeof window !== "undefined";export const i18nprovider = ({ children }: any) =&gt; {  const { i18n } = usetranslation() || {};  const [currentlanguage, setcurrentlanguage] = usestate(    formatlanguagefromi18n(i18n?.language)  );  const changelanguage = (language) =&gt; {    setcurrentlanguage(language);    i18n?.changelanguage?.(formatlanguagefromselect(language));    localstorage.setitem("language", formatlanguagefromselect(language));  };  return (    <i18ncontext.provider value="{{" changelanguage currentlanguage setcurrentlanguage>      {children}    </i18ncontext.provider>  );};export const usei18n = () =&gt; {  if (!isbrowser) {    return {      currentlanguage: "pt-br",      setcurrentlanguage: () =&gt; {},      changelanguage: () =&gt; {},    };  }  return usecontext(i18ncontext);};const countrytolanguage = {  br: "pt-br",  us: "en",};const languagetocountry = {  "pt-br": "br",  en: "us",};export const formatlanguagefromi18n = (language) =&gt; languagetocountry[language];export const formatlanguagefromselect = (language) =&gt; countrytolanguage[language];

    然后我改变了导航栏

    在代码中,我使用国家/地区下拉菜单选择语言。看看:

    "use client";//@ts-nocheckimport { header, flex, logo, profile, notificationsnav, searchbar } from "@/shared/ui";import { usebreakpointvalue, icon, iconbutton, usemediaquery } from "@chakra-ui/react";import { rimenuline } from "react-icons/ri";import { useauth, usesidebardrawer } from "@/shared/libs";import { useeffect, usestate } from "react";import { countrydropdown } from "react-country-region-selector";import { theme } from "@/application/theme";import { formatlanguagefromi18n, usei18n } from "@/application/providers/i18nprovider";import { usetranslation } from "react-i18next";export const navbar = ({ showlogo = true }) =&gt; {  const { isauthenticated } = useauth() || {};  const { i18n } = usetranslation();  const { changelanguage, setcurrentlanguage } = usei18n() || {};  const { onopen = () =&gt; {}, onclose } = usesidebardrawer() || {};  const isdesktopversion = usebreakpointvalue({ base: false, lg: true });  const [country, setcountry] = usestate(formatlanguagefromi18n(i18n?.language));  useeffect(() =&gt; {    return () =&gt; {      onclose?.();    };  }, []);  const dropdown = countrydropdown as any;  useeffect(() =&gt; {    const language = localstorage.getitem("language");    if (language) {      setcountry(formatlanguagefromi18n(language));      setcurrentlanguage(language);      i18n?.changelanguage?.(language);    }  }, []);  return (    <header><flex alignitems='{"center"}' w='{"100%"}'>        {isauthenticated &amp;&amp; !isdesktopversion &amp;&amp; (          <iconbutton aria-label="open sidebar" fontsize="24" icon="{&lt;icon" as="{rimenuline}"></iconbutton>}            variant="unstyled"            onclick={onopen}            mr="1"            mt={2}          /&gt;        )}        <logo marginbottom="{0}"></logo>        {/* {islargerthan560 &amp;&amp; (          <searchbar placeholder="pesquise por nome..." name="search" width="auto"></searchbar>        )} */}        {isauthenticated &amp;&amp; (          <flex align="center" ml="auto">            {/* <notificationsnav></notificationsnav> */}            <dropdown value="{country}" onchange="{(val)"> {                setcountry(val);                changelanguage(val);              }}              labeltype="short"              valuetype="short"              showdefaultoption              defaultoptionlabel="selecione o idioma"              whitelist={["us", "br"]}              style={{                backgroundcolor: theme.colors.secondary[400],                padding: 10,                width: 60,                marginright: 15,                borderradius: 8,              }}            /&gt;            <profile showprofiledata="{isdesktopversion}"></profile></dropdown></flex>        )}      </flex></header>  );};

    导入和初始设置:

    语言下拉菜单:

    1. 语言选择器行为

    以及如何更改文本?

    从一个组件到另一个组件,我都遵循相同的过程。下面的代码展示了如何根据本地化密钥用动态翻译替换静态文本:

    import { Divider } from "@chakra-ui/react";import { IoExitOutline } from "react-icons/io5";import { useRouter } from "next/navigation";import { useTranslation } from "react-i18next";  // Importando o hook useTranslationtype ProfileProps = {  showProfileData?: boolean;};export const Profile = ({ showProfileData }: ProfileProps) =&gt; {  const { t } = useTranslation(["PAGES"]);  // Obtendo a função t para tradução  const { user, logout } = useAuth() || {};  const router = useRouter();  const { showUserMenu, setShowUserMenu } = useProfile();  return (    <box>      {/* Outras partes do componente */}      <flex><ioexitoutline></ioexitoutline><text fontsize="sm">          {t("PAGES:HOME_PAGE.logout", { defaultValue: "Sair" })}  // Chave de tradução com valor padrão        </text></flex></box>  );};

    在此示例中,usetranslation 挂钩用于加载 pages:home_page.logout 翻译键。如果未找到该密钥,将显示默认文本“退出”。

    结论

    这个想法可以应用于任何静态文本组件。只需使用 usetranslation 钩子即可。
    国际化您的应用程序可以打开全球市场的大门,突出您的投资组合并提高您的技能。在 i18next 和 react-intl 之间进行选择取决于您项目的具体需求,但对于那些想要入门的人来说,两者都是很好的选择。

    课程建议

    2022 年,我创建了crazystack 训练营。在其中,我展示了在线服务调度系统的 2 个完整应用程序,应用了设计模式、简洁架构、功能切片设计、solid、ddd 以及单元、集成和 e2e 测试等先进概念。

    在第一个应用程序中,您将学习如何在 node.js 生态系统中构建 rest api。将创建涉及复杂业务规则的用例,例如列出可用时间、根据预订生成订单、忠诚度系统、佣金、付款、客户评论等等。一切都在 typescript 中完成并使用非关系数据库 mongodb。

    在第二个应用程序中,您将学习如何在 react.js 生态系统中构建管理面板来查看图表和操作记录。一切都是通过 typescript 和 next.js 框架完成的。此外,还将使用chakra ui可视化组件库,将原子设计概念应用于创建的组件。要了解更多信息,请访问crazystack.com.br。