說瘋狂的開發者!
今天我將向您展示,將整個項目翻譯成 react 從未像現在這樣容易。但首先您需要知道為什么這很重要。
當人們開始編程時,代碼文本和消息通常使用葡萄牙語(pt-br)。將項目翻譯成其他語言從來都不是優先事項,并且被認為是復雜或不必要的。
那么為什么它會相關呢?
這取決于你的實際情況。以下是您應該考慮此過程的一些原因:
公司需要
可能是您工作的公司或您擁有的某些 saas 開始在另一個國家/地區運營并且有此需求。具有此功能的產品有巨大的差異。
申請國??際職位空缺
如果您正在申請國際職位空缺,擁有包含國際化項目的作品集可以給您帶來引人注目的亮點。這表明您已準備好從事全球項目,并且不像大多數人一樣懶惰。
你永遠不會學太多
國際化不僅是一種特征,也是一種重要的學習經歷。這是您的技能和工具庫中的另一種武器。
過去是如何做到的?
項目翻譯已經是個老問題了。人們在 html 中選擇了該國家的國旗,供人們選擇,并在代碼中用 if 填充以了解將顯示哪些文本。
這是非常被忽視的。網站是用單一語言制作的,翻譯是隨意添加的。如果是在后端,交易會更糟糕。
隨著互聯網的全球化,對多語言軟件的需求不斷增長,帶來了針對國際化的特定工具。像 gnu gettext 這樣的解決方案出現在后端,隨后出現了像 i18next 和 react-intl 這樣的前端庫。然后疑問就來了…
i18next 對比react-intl:選擇哪一個?
i18next:這個出現于 2011 年,它是一個 npm 包,適用于客戶端的 node.js 和 spa。社區采納了它,并最終于2015年在react-i18next lib中制作了react版本。因此,作為積極和消極的點,我們有:
優點:靈活性、路上時間(自 2011 年起)、龐大的生態系統(一次學習,隨處翻譯)和自動回退。
缺點:學習曲線。有很多文檔需要閱讀,但并不是您需要的所有內容都在那里。
react-intl:formatjs 項目的一部分,遵循國際 javascript api 標準,確保與現代瀏覽器的兼容性。
優點:與 ecmascript 標準保持一致,集成簡單。
缺點:靈活性較差,插件支持較少。
我們將使用哪一個?
i18下一個我的朋友們!我總是建議閱讀文檔來開始,但讓我們看看 doido 的指南!
使用 i18next 國際化 react 應用程序
安裝:
npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-i18next
登錄后復制
配置:創建一個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;
登錄后復制
translations:在 locales/en/translation.json 和 locales/pt/translation.json 中創建翻譯文件。
{ "welcome": "welcome to our application!", "login": "login" }
登錄后復制
翻譯的使用:在 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;
登錄后復制
語言更改:允許用戶更改語言。
import react from 'react'; import { usetranslation } from 'react-i18next'; function languageswitcher() { const { i18n } = usetranslation(); const changelanguage = (lng) => i18n.changelanguage(lng); return ( <div> <button onclick="{()"> changelanguage('en')}>english</button> <button onclick="{()"> changelanguage('pt')}>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";
登錄后復制
usetranslation:react-i18next 掛鉤來訪問翻譯功能。在這里,您將在項目中幾乎每個 jsx 組件中使用它。
createcontext、usestate、usecontext:用于創建和使用上下文以及管理狀態的 react 函數。
3. 上下文創建
const i18ncontext = createcontext({} as any);
登錄后復制
創建上下文來通過 dom 存儲和提供數據(例如當前語言)。
4. 環境檢查
export const isbrowser = typeof window !== "undefined";
登錄后復制
此行檢查代碼是否在瀏覽器中運行(而不是在服務器上),這對于處理 localstorage 等特定于客戶端的功能至關重要。
5.i18nprovider組件
export const i18nprovider = ({ children }: any) => { const { i18n } = usetranslation() || {}; const [currentlanguage, setcurrentlanguage] = usestate( formatlanguagefromi18n(i18n?.language) ); const changelanguage = (language) => { setcurrentlanguage(language); i18n?.changelanguage?.(formatlanguagefromselect(language)); localstorage.setitem("language", formatlanguagefromselect(language)); }; return ( <i18ncontext.provider value="{{" changelanguage currentlanguage setcurrentlanguage> {children} </i18ncontext.provider> ); };
登錄后復制
這個組件是一個provider,它包裝了react組件樹并提供了語言的當前狀態以及更改它的函數。
usetranslation:從react-i18next庫中檢索i18n對象,其中包含有關當前語言的信息。
currentlanguage:存儲當前語言的state,根據i18n檢測到的語言進行初始化。
changelanguage:更改語言的函數,這也會將選擇保存在 localstorage 中,以便在頁面重新加載之間保持持久性。
6. 掛鉤使用i18n
export const usei18n = () => { if (!isbrowser) { return { currentlanguage: "pt-br", setcurrentlanguage: () => {}, changelanguage: () => {}, }; } return usecontext(i18ncontext); };
登錄后復制
這個鉤子可以輕松訪問任何組件中的國際化上下文。
檢查您是否在瀏覽器中(isbrowser)。如果沒有,則返回默認值,以避免服務器端出錯。
如果在瀏覽器中,則消耗并返回 i18ncontext 上下文。
7. 轉換圖
const countrytolanguage = { br: "pt-br", us: "en", }; const languagetocountry = { "pt-br": "br", en: "us", };
登錄后復制
這些對象將國家/地區代碼映射到語言代碼,反之亦然,從而可以輕松地在不同約定之間格式化語言代碼。
8. 格式化函數
export const formatlanguagefromi18n = (language) => languagetocountry[language]; export const formatlanguagefromselect = (language) => 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) => { const { i18n } = usetranslation() || {}; const [currentlanguage, setcurrentlanguage] = usestate( formatlanguagefromi18n(i18n?.language) ); const changelanguage = (language) => { setcurrentlanguage(language); i18n?.changelanguage?.(formatlanguagefromselect(language)); localstorage.setitem("language", formatlanguagefromselect(language)); }; return ( <i18ncontext.provider value="{{" changelanguage currentlanguage setcurrentlanguage> {children} </i18ncontext.provider> ); }; export const usei18n = () => { if (!isbrowser) { return { currentlanguage: "pt-br", setcurrentlanguage: () => {}, changelanguage: () => {}, }; } return usecontext(i18ncontext); }; const countrytolanguage = { br: "pt-br", us: "en", }; const languagetocountry = { "pt-br": "br", en: "us", }; export const formatlanguagefromi18n = (language) => languagetocountry[language]; export const formatlanguagefromselect = (language) => countrytolanguage[language];
登錄后復制
然后我改變了導航欄
在代碼中,我使用國家/地區下拉菜單選擇語言。看看:
"use client"; //@ts-nocheck import { 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 }) => { const { isauthenticated } = useauth() || {}; const { i18n } = usetranslation(); const { changelanguage, setcurrentlanguage } = usei18n() || {}; const { onopen = () => {}, onclose } = usesidebardrawer() || {}; const isdesktopversion = usebreakpointvalue({ base: false, lg: true }); const [country, setcountry] = usestate(formatlanguagefromi18n(i18n?.language)); useeffect(() => { return () => { onclose?.(); }; }, []); const dropdown = countrydropdown as any; useeffect(() => { const language = localstorage.getitem("language"); if (language) { setcountry(formatlanguagefromi18n(language)); setcurrentlanguage(language); i18n?.changelanguage?.(language); } }, []); return ( <header><flex alignitems='{"center"}' w='{"100%"}'> {isauthenticated && !isdesktopversion && ( <iconbutton aria-label="open sidebar" fontsize="24" icon="{<icon" as="{rimenuline}"></iconbutton>} variant="unstyled" onclick={onopen} mr="1" mt={2} /> )} <logo marginbottom="{0}"></logo> {/* {islargerthan560 && ( <searchbar placeholder="pesquise por nome..." name="search" width="auto"></searchbar> )} */} {isauthenticated && ( <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, }} /> <profile showprofiledata="{isdesktopversion}"></profile></dropdown></flex> )} </flex></header> ); };
登錄后復制
導入和初始設置:
useauth:檢查用戶是否經過身份驗證。
usebreakpointvalue:根據屏幕大小決定是否顯示桌面版本。
usestate:設置國家/語言(國家)的初始狀態,使用formatlanguagefromi18n函數格式化i18n的當前語言
useeffect:第一個效果是在卸載組件時清除側邊欄(onclose)。第二個效果檢查語言是否保存在 localstorage 中,如果是,則更新國家/地區狀態并更改應用程序中的語言。
語言下拉菜單:
下拉列表是使用react-country-region-selector庫的countrydropdown組件實現的,該組件被定制為用作語言選擇器。
value={country}:下拉列表中選擇的值由國家/地區控制。
onchange={(val) => { … }}:當下拉值改變時,更新國家狀態,并調用changelanguage函數更改應用程序語言。
whitelist={[“us”, “br”]}:將下拉選項限制為“us”(英語)和“br”(葡萄牙語)。
style={…}:下拉菜單的自定義內聯樣式,使用主題的顏色和間距。
語言選擇器行為:
下拉列表允許用戶選擇首選語言,并且此選擇會保留在 localstorage 中。
更改語言時,下拉列表會反映此更改,并且應用程序會更新為使用新選擇的語言。
要在文章中包含您在圖像中提供的代碼片段,您可以遵循以下格式:
以及如何更改文本?
從一個組件到另一個組件,我都遵循相同的過程。下面的代碼展示了如何根據本地化密鑰用動態翻譯替換靜態文本:
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 useTranslation type ProfileProps = { showProfileData?: boolean; }; export const Profile = ({ showProfileData }: ProfileProps) => { 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。