今天我將向您展示,將整個專案翻譯成 React 從未像現在這樣容易。但首先您需要知道為什麼這很重要。
當人們開始程式設計時,程式碼文字和訊息通常使用葡萄牙語 (pt-BR)。將項目翻譯成其他語言從來都不是優先事項,並且被認為是複雜或不必要的。
這取決於您的實際情況。以下是您應該考慮此過程的一些原因:
公司需要
可能是您工作的公司或您擁有的某些 SaaS 開始在另一個國家/地區運作並且有此需求。具有此功能的產品有巨大的差異。
國際職缺申請
如果您正在申請國際職缺,擁有包含國際化專案的作品集可以為您帶來引人注目的亮點。這表明您已準備好從事全球項目,並且不像大多數人一樣懶惰。
你絕對不會學太多
國際化不僅是一種特徵,也是一種重要的學習經驗。這是您的技能和工具庫中的另一種武器。
專案翻譯已經是個老問題了。人們在 HTML 中選擇了該國家的國旗,供人們選擇,並在程式碼中用 if 填充以了解將顯示哪些文字。
這是非常被忽略的。網站是用單一語言製作的,翻譯是隨意添加的。如果是在後端的話,交易會更糟。
隨著網路的全球化,對多語言軟體的需求不斷增長,帶來了針對國際化的特定工具。像 GNU Gettext 這樣的解決方案出現在後端,隨後出現了像 i18next 和 react-intl 這樣的前端函式庫。這就是疑問所在......
i18next:這個出現於 2011 年,它是一個 npm 包,適用於客戶端的 Node.js 和 SPA。社群採納了它,並最終於2015年在react-i18next lib中製作了React版本。因此,作為正面和負面的觀點,我們有:
react-intl:FormatJS 專案的一部分,遵循國際 JavaScript API 標準,確保與現代瀏覽器的相容性。
i18next 我的朋友們!我總是建議閱讀文件來開始,但讓我們看看 Doido 的指南!
npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-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;
{ "welcome": "Welcome to our application!", "login": "Login" }
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 來保存語言並在整個專案中存取它。從導入開始
import { useTranslation } from "react-i18next"; import { createContext, useState, useContext } from "react";
const I18NContext = createContext({} as any);
建立上下文來透過 DOM 儲存和提供資料(例如當前語言)。
export const isBrowser = typeof window !== "undefined";
Essa linha verifica se o código está sendo executado no navegador (em vez de no servidor), essencial para manipular recursos específicos do cliente, como localStorage.
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> ); };
Este componente é um provider que envolve a árvore de componentes React e fornece o estado atual do idioma e a função para alterá-lo.
export const useI18n = () => { if (!isBrowser) { return { currentLanguage: "pt-br", setCurrentLanguage: () => {}, changeLanguage: () => {}, }; } return useContext(I18NContext); };
Este hook facilita o acesso ao contexto de internacionalização em qualquer componente.
const countryToLanguage = { BR: "pt-br", US: "en", }; const languageToCountry = { "pt-br": "BR", en: "US", };
Esses objetos mapeiam códigos de países para códigos de idiomas e vice-versa, facilitando a formatação dos códigos de idioma entre diferentes convenções.
export const formatLanguageFromi18N = (language) => languageToCountry[language]; export const formatLanguageFromSelect = (language) => countryToLanguage[language];
Essas funções formatam os códigos de idioma conforme necessário. formatLanguageFromi18N converte o código de idioma para o código do país, enquanto formatLanguageFromSelect faz a conversão inversa.
"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];
No código eu tenho um select de idioma utilizando um dropdown de países. Olha só:
"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} />} variant="unstyled" onClick={onOpen} mr="1" mt={2} /> )} <Logo marginBottom={0} /> {/* {isLargerThan560 && ( <SearchBar placeholder="Pesquise por nome..." name="search" width="auto" /> )} */} {isAuthenticated && ( <Flex align="center" ml="auto"> {/* <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} /> </Flex> )} </Flex> </Header> ); };
Importações e Setup Inicial:
Dropdown de Idiomas:
De componente em componente eu fui fazendo o mesmo procedimento. O código abaixo mostra como substituir o texto estático por uma tradução dinâmica baseada na chave de localização:
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 /> <Text fontSize="sm"> {t("PAGES:HOME_PAGE.logout", { defaultValue: "Sair" })} // Chave de tradução com valor padrão </Text> </Flex> </Box> ); };
Neste exemplo, o hook useTranslation é utilizado para carregar a chave de tradução PAGES:HOME_PAGE.logout. Se a chave não for encontrada, o texto padrão "Sair" será exibido.
A ideia pode ser aplicada em qualquer componente de texto estático. Basta usar a hook useTranslation.
Internacionalizar sua aplicação pode abrir portas para mercados globais, destacar seu portfólio e aprimorar suas habilidades. Escolher entre i18next e react-intl depende das necessidades específicas do seu projeto, mas ambos são excelentes opções para quem deseja começar.
Em 2022 eu criei o bootcamp CrazyStack. Nele, eu mostro 2 aplicações completas de um sistema de agendamentos online de serviços aplicando conceitos avançados como Design Patterns, Clean Architecture, Feature Sliced Design, SOLID, DDD, além de Testes unitários, de integração e E2E.
在第一個應用程式中,您將學習如何在 Node.js 生態系統中建立 REST API。將建立涉及複雜業務規則的用例,例如列出可用時間、根據預訂產生訂單、忠誠度系統、佣金、付款、客戶評論等等。一切都在 TypeScript 中完成並使用非關聯式資料庫 MongoDB。
在第二個應用程式中,您將學習如何在 React.js 生態系統中建立管理面板來查看圖表和操作記錄。一切都是透過 TypeScript 和 Next.js 框架完成的。此外,還將使用Chakra UI視覺化元件庫,將原子設計概念應用於已建立的元件。要了解更多信息,請訪問crazystack.com.br。
以上是使用 i 翻譯你的 React 專案從未如此簡單的詳細內容。更多資訊請關注PHP中文網其他相關文章!