「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > i を使用した React プロジェクトの翻訳がかつてないほど簡単になりました

i を使用した React プロジェクトの翻訳がかつてないほど簡単になりました

2024 年 11 月 1 日に公開
ブラウズ:217

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

Fala dev doido!

Hoje eu vou mostrar que nunca foi tão fácil traduzir um projeto INTEIRO em React que nem é hoje em dia. Mas antes vc precisa saber pra que isso seria importante.

Quando a galera começa a programar, é comum que os textos e mensagens do código sejam em português (pt-BR). Traduzir o projeto para outros idiomas nunca é prioridade, sendo considerado complexo ou desnecessário.

Então porque seria relevante?

Depende da sua realidade. Aqui estão algumas razões pelas quais você deveria considerar esse processo:

A empresa precisa
Pode ser que a empresa onde vc trampa ou algum SaaS que vc tenha comece a operar em outro país e tenha essa necessidade. Um produto que tem essa funcionalidade possui um diferencial ENORME.

Candidatura em vaga internacional
Se você está aplicando para vagas internacionais, ter um portfólio com projetos já internacionalizados pode te dar um destaque fulminante. Mostra que você tá preparado para trampar em projeto global e não é preguiçoso como a maioria.

Aprendizado nunca é demais
Internacionalização não é apenas uma funcionalidade, mas também um aprendizado importante. É uma arma a mais que vc inclui no seu arsenal de skills e ferramentas.

Como era feito antigamente?

Tradução de projeto já é um problema antigo. A galera fazia aquele select no HTML com a bandeirinha do país pra pessoa selecionar e ia enchendo de if no código pra saber qual texto ia ser exibido.
Era muito negligenciado. Sites eram feitos em um único idioma, e traduções eram adicionadas de forma cagada. Se fosse no backend era pior ainda o negócio.

Com a globalização da internet, a demanda por software multilingue cresceu, trazendo ferramentas específicas para i18n. Soluções como GNU Gettext surgiram no backend, seguidas por libs como i18next e react-intl para o frontend. Eaí entra a dúvida...

i18next vs. react-intl: Qual Escolher?

  • i18next: Essa surgiu em 2011, era um pacote npm que funcionava tanto pra Node.js quanto pra SPA no client side. A comunidade foi adotando e finalmente fizeram em 2015 a versão pra React na lib react-i18next. Portanto como pontos positivos e negativos temos:

    • Prós: Flexibilidade, tempo de estrada (desde 2011), vasto ecossistema (learn once translate everywhere) e fallback automático.
    • Contras: Curva de aprendizado. Tem muita doc pra ler, mas nem tudo o que ta lá vc precisa.
  • react-intl: Parte do projeto FormatJS, segue padrões da API Internacional do JavaScript, garantindo compatibilidade com navegadores modernos.

    • Prós: Alinhado aos padrões ECMAScript, simplicidade na integração.
    • Contras: Menos flexível e com menos suporte a plugins.

E qual iremos usar?

i18next meus amigos! Recomendo sempre a leitura das docs pra iniciar, mas vamos pro guia do Doido!

Internacionalizando uma Aplicação React com i18next

  1. Instalação:
   npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-i18next 

  1. Configuração: Crie um i18n.js para configurar o 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. Traduções: Crie arquivos de tradução em locales/en/translation.json e locales/pt/translation.json.
   {
     "welcome": "Welcome to our application!",
     "login": "Login"
   }
  1. Uso das Traduções: Use o hook useTranslation no React.
   import React from 'react';
   import { useTranslation } from 'react-i18next';

   function App() {
     const { t } = useTranslation();

     return (
       

{t('welcome')}

); } export default App;
  1. Mudança de Idioma: Permita que os usuários mudem o idioma.
   import React from 'react';
   import { useTranslation } from 'react-i18next';

   function LanguageSwitcher() {
     const { i18n } = useTranslation();

     const changeLanguage = (lng) => i18n.changeLanguage(lng);

     return (
       
); } export default LanguageSwitcher;

É só isso?

Claro que não, eu vou mostrar agora o que eu fiz no projeto do CrazyStack. Primeiro eu fiz uma config diferente no Nextjs pegando de um JSON estático que eu defini na pasta public do próprio projeto! Dá uma olhada:

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

Depois fiz um context API pra salvar o idioma e acessar no projeto todo. Começando pelos imports

2. Importações

import { useTranslation } from "react-i18next";
import { createContext, useState, useContext } from "react";
  • useTranslation: Hook do react-i18next para acessar funcionalidades de tradução. Isso aqui vc vai usar em praticamente todo componente JSX que tiver no projeto.
  • createContext, useState, useContext: Funções do React para criar e consumir contextos, além de gerenciar estado.

3. Criação do Contexto

const I18NContext = createContext({} as any);

Um context é criado para armazenar e fornecer os dados (como o idioma atual) através da 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 (
    
      {children}
    
  );
};

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 (
    
      {children}
    
  );
};

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 (
    
{isAuthenticated && !isDesktopVersion && ( } variant="unstyled" onClick={onOpen} mr="1" mt={2} /> )} {/* {isLargerThan560 && ( )} */} {isAuthenticated && ( {/* */} { 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, }} /> )}
); };

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 (
    
      {/* Outras partes do componente */}
      
          {t("PAGES:HOME_PAGE.logout", { defaultValue: "Sair" })}  // Chave de tradução com valor padrão
        
  );
};

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.

Na primeira aplicação, você aprenderá a construir uma API REST no ecossistema Node.js. Serão criados casos de uso envolvendo regras de negócio complexas como listagem de horários disponíveis, geração de pedidos a partir de agendamentos efetivados, sistema de fidelidade, comissões, pagamentos, avaliações dos clientes e muito mais. Tudo feito em TypeScript e utilizando o banco de dados não relacional MongoDB.

Na segunda aplicação, você aprenderá a construir no ecossistema React.js um painel de administração para visualizar gráficos e manipular os registros. Tudo feito com TypeScript e usando o framework Next.js. Além disso, será utilizada a biblioteca de componentes visuais Chakra UI aplicando o conceito de Atomic Design nos componentes criados. Para saber mais, acesse crazystack.com.br.

リリースステートメント この記事は次の場所に転載されています: https://dev.to/devdoido/nunca-foi-tao-facil-traduzir-seu-projeto-react-com-i18n-177i?1 侵害がある場合は、study_golang@163 までご連絡ください。 .comを削除してください
最新のチュートリアル もっと>
  • C++ で std::locale を使用して数値をカンマでフォーマットする方法
    C++ で std::locale を使用して数値をカンマでフォーマットする方法
    C でのカンマを使用した数値の書式設定 C では、 std::locale クラスは、カンマを使用して数値を書式設定するロケール依存の方法を提供します。 .std::locale with std::stringstream数値をカンマ付きの文字列としてフォーマットするには、std::locale ...
    プログラミング 2024 年 11 月 7 日に公開
  • Python で素数シーケンス内の奇数の出力を回避するには?
    Python で素数シーケンス内の奇数の出力を回避するには?
    Python で一連の素数を出力する方法多くのプログラマは、Python で素数を正確に出力する関数を作成するのに苦労しています。よくある問題の 1 つは、代わりに奇数のリストを出力することです。この問題を修正するには、素数のプロパティを完全に理解し、コードを変更することが不可欠です。素数は 1 と...
    プログラミング 2024 年 11 月 7 日に公開
  • Pygameでマウスの方向に弾丸を発射するにはどうすればよいですか?
    Pygameでマウスの方向に弾丸を発射するにはどうすればよいですか?
    Pygame でマウスの方向に弾丸を発射する方法Pygame では、マウスの方向に発射される弾丸を作成できます。これを行うには、弾丸を表すクラスを作成し、マウスの位置に基づいてその初期位置と方向を設定する必要があります。弾丸のクラスまず、弾丸のクラスを作成します。このクラスには、弾丸の位置、サイズ、...
    プログラミング 2024 年 11 月 7 日に公開
  • パフォーマンスを最適化するための GG コーディングのヒント: コードの高速化
    パフォーマンスを最適化するための GG コーディングのヒント: コードの高速化
    ソフトウェア開発の世界では、ユーザーが好む高速で応答性の高いアプリケーションを提供するには、コードのパフォーマンスを最適化することが重要です。フロントエンドで作業しているかバックエンドで作業しているかに関係なく、効率的なコードの書き方を学ぶことが不可欠です。この記事では、時間の複雑さの軽減、キャッシ...
    プログラミング 2024 年 11 月 7 日に公開
  • PHP の strtotime() 関数を使用して特定の曜日の日付を見つけるにはどうすればよいですか?
    PHP の strtotime() 関数を使用して特定の曜日の日付を見つけるにはどうすればよいですか?
    特定の曜日(月曜日、火曜日など)の日付を決定する日付スタンプを確認する必要がある場合月曜日、火曜日、その他の平日など、特定の曜日には strtotime() 関数を使用できます。この関数は、今週中に指定された日がまだ発生していない場合に特に便利です。たとえば、次の火曜日の日付スタンプを取得するには、...
    プログラミング 2024 年 11 月 7 日に公開
  • Socket.io と Redis を使用してチャット アプリケーションを構築し、デプロイします。
    Socket.io と Redis を使用してチャット アプリケーションを構築し、デプロイします。
    このチュートリアルでは、Web ソケットを使用してチャット アプリケーションを構築します。 Web ソケットは、リアルタイムのデータ転送を必要とするアプリケーションを構築する場合に非常に役立ちます。 このチュートリアルを終えると、独自のソケット サーバーをセットアップし、リアルタイムでメッセージを送...
    プログラミング 2024 年 11 月 7 日に公開
  • 内部 SQL 結合
    内部 SQL 結合
    SQL 結合はデータベースのクエリの基本であり、ユーザーは指定された条件に基づいて複数のテーブルのデータを結合できます。結合は、論理結合と物理結合の 2 つの主なタイプに分類されます。論理結合はテーブルのデータを組み合わせる概念的な方法を表し、物理結合は RDS (リレーショナル データベース サー...
    プログラミング 2024 年 11 月 7 日に公開
  • 知っておくべきJavaScriptの機能
    知っておくべきJavaScriptの機能
    この記事では、未定義または null の可能性があるデータにアクセスしようとするときにエラーを防ぐ方法を検討し、できる方法を見ていきます。 必要に応じてデータを効果的に管理するために使用します. オプションのチェーンによる安全なアクセス JavaScript で、入れ子になったオブジ...
    プログラミング 2024 年 11 月 7 日に公開
  • JavaScript の約束: 非同期コードの理解、処理、および習得
    JavaScript の約束: 非同期コードの理解、処理、および習得
    イントロ 私は Java 開発者として働いていましたが、JavaScript の Promise に初めて触れたときのことを覚えています。コンセプトは単純そうに見えましたが、Promise がどのように機能するのかを完全に理解することはできませんでした。プロジェクトでそれらを使用し...
    プログラミング 2024 年 11 月 7 日に公開
  • パスキーを Java Spring Boot に統合する方法
    パスキーを Java Spring Boot に統合する方法
    Java Spring Boot のパスキーの概要 パスキーは、従来のパスワードに依存せずにユーザーを認証する最新の安全な方法を提供します。このガイドでは、Thymeleaf をテンプレート エンジンとして使用して、Java Spring Boot アプリケーションにパスキーを統合...
    プログラミング 2024 年 11 月 7 日に公開
  • グアテマラの前環境大臣としてのマリオ・ロベルト・ロハス・エスピノの影響
    グアテマラの前環境大臣としてのマリオ・ロベルト・ロハス・エスピノの影響
    マリオ・ロベルト・ロハス・エスピノはグアテマラの元環境大臣として、国の持続可能な発展に貢献した環境政策の実施において重要な役割を果たしました。同省長官としての彼の経営は、特に環境立法や保全プロジェクトの面で重要な遺産を残した。この記事では、彼の影響力と、任期中に彼が推進した主な政策について探ります。...
    プログラミング 2024 年 11 月 7 日に公開
  • データ収集のためにクラスのすべてのインスタンスを追跡してアクセスするにはどうすればよいですか?
    データ収集のためにクラスのすべてのインスタンスを追跡してアクセスするにはどうすればよいですか?
    データ収集のためのクラス インスタンスの追跡プログラムの終わりに近づいており、複数の変数から特定の変数を抽出する必要があると想像してください。クラスのインスタンスを使用して辞書を作成します。このタスクは、集約または分析する必要がある重要なデータを保持するオブジェクトを操作するときに発生することがあり...
    プログラミング 2024 年 11 月 7 日に公開
  • PHP 連想配列内で検索する方法 – 簡単なヒント
    PHP 連想配列内で検索する方法 – 簡単なヒント
    連想配列は PHP の基本的なデータ構造であり、開発者はキーと値のペアを保存できます。これらは多用途であり、構造化データを表すためによく使用されます。 PHP 連想配列内の特定の要素を検索するのは一般的なタスクです。ただし、PHP で使用できるほとんどのネイティブ関数は、単純な配列でもうまく機能しま...
    プログラミング 2024 年 11 月 7 日に公開
  • Web 開発の未来: すべての開発者が知っておくべき新たなトレンドとテクノロジー
    Web 開発の未来: すべての開発者が知っておくべき新たなトレンドとテクノロジー
    導入 Web 開発は、初期の静的な HTML ページとシンプルな CSS デザインから大きく進歩しました。技術の進歩と、よりダイナミックでインタラクティブで応答性の高い Web サイトに対するユーザーの需要の高まりにより、この分野は長年にわたって急速に進化してきました。インターネッ...
    プログラミング 2024 年 11 月 7 日に公開
  • ays 初心者の Python コード者は ChatGPT を使用できます
    ays 初心者の Python コード者は ChatGPT を使用できます
    初心者の Python 開発者は、きれいなコードの作成からエラーのトラブルシューティングまで、数え切れないほどの課題に直面します。 ChatGPT は、生産性を向上させ、コーディング作業を合理化するための秘密兵器となります。際限なくドキュメントやフォーラムを調べる代わりに、ChatGPT に直接質...
    プログラミング 2024 年 11 月 7 日に公開

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3