Maison  >  Article  >  interface Web  >  TRADUIRE votre projet React avec i n'a jamais été aussi simple

TRADUIRE votre projet React avec i n'a jamais été aussi simple

王林
王林original
2024-08-24 11:04:05589parcourir

Nunca foi tão fácil TRADUZIR seu projeto React com i

Dites développeur fou !

Aujourd'hui, je vais vous montrer que traduire un projet ENTIER dans React n'a jamais été aussi simple qu'aujourd'hui. Mais vous devez d’abord savoir pourquoi cela serait important.

Lorsque les gens commencent à programmer, il est courant que les textes de code et les messages soient en portugais (pt-BR). Traduire le projet dans d’autres langues n’est jamais une priorité et est considéré comme complexe ou inutile.

Alors pourquoi serait-ce pertinent ?

Cela dépend de votre réalité. Voici quelques raisons pour lesquelles vous devriez envisager ce processus :

L'entreprise en a besoin
Il se peut que l'entreprise dans laquelle vous travaillez ou un SaaS que vous possédez commence à opérer dans un autre pays et ait ce besoin. Un produit doté de cette fonctionnalité a une ÉNORME différence.

Candidature à un poste vacant à l'international
Si vous postulez à des postes vacants à l’international, disposer d’un portefeuille de projets déjà internationalisés peut vous offrir un atout marquant. Cela montre que vous êtes prêt à travailler sur un projet global et que vous n'êtes pas paresseux comme la plupart.

On ne peut jamais trop apprendre
L'internationalisation n'est pas seulement une caractéristique, mais aussi une expérience d'apprentissage importante. C'est une autre arme que vous incluez dans votre arsenal de compétences et d'outils.

Comment cela se faisait-il dans le passé ?

La traduction de projets est déjà un vieux problème. Les gens ont fait cette sélection dans le HTML avec le drapeau du pays pour que les gens puissent le sélectionner et l'ont rempli avec si dans le code pour savoir quel texte serait affiché.
Cela a été très négligé. Les sites Web étaient créés dans une seule langue et les traductions étaient ajoutées au hasard. Si c'était dans le backend, l'affaire serait encore pire.

Avec la mondialisation d'Internet, la demande de logiciels multilingues s'est accrue, apportant des outils spécifiques pour i18n. Des solutions comme GNU Gettext ont émergé sur le backend, suivies par des bibliothèques comme i18next et réagissent-intl pour le frontend. C'est là qu'intervient le doute...

i18next contre. réagir-intl : Lequel choisir ?

  • i18next : Celui-ci est apparu en 2011, c'était un package npm qui fonctionnait à la fois pour Node.js et SPA côté client. La communauté l'a adopté et a finalement réalisé la version React dans la libreact-i18next en 2015. Par conséquent, comme points positifs et négatifs nous avons :

    • Avantages : Flexibilité, temps de trajet (depuis 2011), vaste écosystème (apprendre une fois traduire partout) et repli automatique.
    • Inconvénients : Courbe d'apprentissage. Il y a beaucoup de documents à lire, mais tout ce dont vous avez besoin n'y est pas.
  • react-intl : fait partie du projet FormatJS, suit les normes internationales de l'API JavaScript, garantissant la compatibilité avec les navigateurs modernes.

    • Avantages : Aligné sur les normes ECMAScript, simplicité d'intégration.
    • Inconvénients : Moins flexible et moins de prise en charge des plugins.

Et lequel allons-nous utiliser ?

i18next mes amis ! Je recommande toujours de lire la documentation pour commencer, mais passons au guide de Doido !

Internationaliser une application React avec i18next

  1. Installation :
   npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-i18next 

  1. Configuration : Créez un i18n.js pour configurer 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. Traductions : créez des fichiers de traduction dans locales/en/translation.json et locales/pt/translation.json.
   {
     "welcome": "Welcome to our application!",
     "login": "Login"
   }
  1. Utilisation des traductions : utilisez le hook useTranslation dans React.
   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. Changement de langue : Autoriser les utilisateurs à changer la langue.
   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;

C'est tout ?

Bien sûr que non, je vais maintenant vous montrer ce que j'ai fait dans le projet CrazyStack. J'ai d'abord fait une configuration différente dans Nextjs en prenant un JSON statique que j'ai défini dans le dossier public du projet lui-même ! Jetez un oeil :

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`,
        },
      ],
    },
  });

Ensuite j'ai créé une API de contexte pour sauvegarder le langage et y accéder tout au long du projet. Commençons par les importations

2. Importations

import { useTranslation } from "react-i18next";
import { createContext, useState, useContext } from "react";
  • useTranslation : hook React-i18next pour accéder aux fonctionnalités de traduction. Ici, vous l'utiliserez dans pratiquement tous les composants JSX que vous avez dans le projet.
  • createContext, useState, useContext : fonctions React pour créer et consommer des contextes, ainsi que pour gérer l'état.

3. Création de contexte

const I18NContext = createContext({} as any);

Un contexte est créé pour stocker et fournir des données (telles que la langue actuelle) via le DOM.

4. Verificação do Ambiente

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.

5. Componente 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>
  );
};

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.

  • useTranslation: Recupera o objeto i18n da biblioteca react-i18next, que contém informações sobre o idioma atual.
  • currentLanguage: Estado que armazena o idioma atual, inicializado com base no idioma detectado pelo i18n.
  • changeLanguage: Função para alterar o idioma, que também salva a escolha no localStorage para persistência entre recargas da página.

6. Hook useI18n

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.

  • Verifica se está no navegador (isBrowser). Se não estiver, retorna valores padrão para evitar erros no server side.
  • Se estiver no navegador, consome e retorna o contexto I18NContext.

7. Mapas de Conversão

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.

8. Funções de Formatação

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.

Código completo

"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];

Depois eu mexi na Navbar

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:

  • useAuth: Verifica se o usuário está autenticado.
  • useBreakpointValue: Determina se a versão desktop deve ser exibida com base no tamanho da tela.
  • useState: Define o estado inicial do país/língua (country) usando a função formatLanguageFromi18N para formatar a língua atual do i18n.
  • useEffect: Primeiro efeito limpa o sidebar ao desmontar o componente (onClose). O segundo efeito verifica se o idioma está salvo no localStorage e, caso esteja, atualiza o estado country e muda o idioma na aplicação.

Dropdown de Idiomas:

  • O dropdown é implementado usando o componente CountryDropdown da biblioteca react-country-region-selector, que é customizado para servir como um seletor de idioma.
  • value={country}: O valor selecionado no dropdown é controlado pelo estado country.
  • onChange={(val) => { ... }}: Quando o valor do dropdown é alterado, o estado country é atualizado, e a função changeLanguage é chamada para alterar o idioma da aplicação.
  • whitelist={["US", "BR"]}: Restringe as opções do dropdown a "US" (inglês) e "BR" (português).
  • style={...}: Estilização inline personalizada para o dropdown, utilizando cores e espaçamentos do tema theme.
  1. Comportamento do Seletor de Idioma:
    • O dropdown permite que o usuário selecione o idioma preferido, e essa seleção é persistida no localStorage.
    • Ao mudar o idioma, o dropdown reflete essa mudança, e a aplicação é atualizada para usar o novo idioma selecionado. Para incluir o trecho de código que você forneceu na imagem no seu artigo, você pode seguir este formato:

E como mudar os textos?

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.

Conclusão

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.

Sugestão de cursos

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.

Dans la première application, vous apprendrez à créer une API REST dans l'écosystème Node.js. Des cas d'utilisation seront créés impliquant des règles commerciales complexes telles que la liste des heures disponibles, la génération de commandes à partir de rendez-vous réservés, les systèmes de fidélisation, les commissions, les paiements, les avis clients et bien plus encore. Tout est fait en TypeScript et en utilisant la base de données non relationnelle MongoDB.

Dans la deuxième application, vous apprendrez à créer un panneau d'administration dans l'écosystème React.js pour afficher des graphiques et manipuler des enregistrements. Tout est fait avec TypeScript et en utilisant le framework Next.js. De plus, la bibliothèque de composants visuels Chakra UI sera utilisée, appliquant le concept Atomic Design aux composants créés. Pour en savoir plus, visitez crazystack.com.br.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn