> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devinenterprise.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Adicionar suporte a japonês e espanhol em uma aplicação Next.js

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="Adicionar japonês e espanhol a um app Next.js" description="Devin instala o next-i18next, extrai strings hardcoded para arquivos JSON de locale, adiciona traduções em japonês e espanhol e verifica a troca de idioma no navegador." prompt="Adicione internacionalização ao nosso app Next.js usando next-i18next. Instale next-i18next, i18next e react-i18next. Configure o roteamento de locales com defaultLocale 'en' e locales ['en', 'es', 'ja']. Analise os diretórios components/ e pages/ em busca de todas as strings hardcoded em inglês (texto em JSX, placeholders, aria-labels, mensagens de erro, tooltips). Crie arquivos de locale estruturados em public/locales/{en,es,ja}/common.json com chaves com namespace. Substitua todas as strings hardcoded por chamadas a t(). Adicione serverSideTranslations a cada página. Adicione um seletor de idioma à navbar. Use traduções de placeholder para espanhol e japonês. Inicie o servidor de desenvolvimento e teste cada página nos três idiomas — verifique se há strings restantes em inglês, overflow de layout e problemas de roteamento. Continue iterando até que tudo funcione. Não abra um PR até que os três idiomas sejam renderizados corretamente em todas as páginas." category="Desenvolvimento de funcionalidades" features="" />

<div className="uc-detail-wrapper">
  <Tip>Não quer configurar isso manualmente? Cole um link para esta página em uma sessão do Devin e peça que ele configure tudo para você.</Tip>

  <Steps>
    <Step title="(Opcional) Defina o escopo da base de código com o Ask Devin">
      Se você não tem certeza de como seu app Next.js está estruturado ou quais componentes contêm strings fixas (hardcoded), use o [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) para investigar primeiro:

      <PromptBlock agent="ada">
        ```txt Definir o escopo do trabalho de i18n theme={null}
        Ajude-me a entender o escopo de adicionar i18n ao nosso app Next.js:
        1. Estamos usando o Pages Router ou o App Router?
        2. Quantos componentes e páginas têm strings fixas (hardcoded) em inglês?
        3. Já temos alguma configuração de i18n ou arquivos de localidade/idioma?
        4. Quais componentes compartilhados (botões, formulários, modais) contêm texto?
        5. Existem strings que devem permanecer em inglês (nomes de marca, códigos de API)?
        ```
      </PromptBlock>

      Você também pode iniciar uma sessão do Devin diretamente a partir do Ask Devin, e tudo o que ele já tiver aprendido será mantido como contexto.
    </Step>

    <Step title="Inicie a configuração de i18n">
      Adicionar internacionalização a um app Next.js significa conectar o roteamento por locale, configurar middleware, extrair todas as strings fixas e criar arquivos de tradução — tudo isso antes mesmo de testar uma única troca de idioma. Devin cuida de todo o pipeline: instala `next-i18next`, configura o roteamento de locale do Next.js, extrai strings de dezenas de componentes e verifica o resultado no navegador.

      <PromptBlock>
        ```txt Add Japanese and Spanish to our Next.js app theme={null}
        Adicione internacionalização ao nosso app Next.js usando next-i18next.

        - Instale next-i18next, i18next e react-i18next
        - Configure next-i18next.config.js com defaultLocale "en" e
          locales ["en", "es", "ja"]
        - Atualize next.config.js para incluir a configuração de i18n
        - Analise components/ e pages/ em busca de todas as strings fixas em inglês
          (texto em JSX, atributos placeholder, aria-labels, mensagens de erro, tooltips)
        - Crie arquivos de locale estruturados em public/locales/{en,es,ja}/common.json
          com chaves com namespace (por exemplo, common.save, auth.loginButton, errors.notFound)
        - Substitua cada string fixa por uma chamada t() usando useTranslation('common')
        - Adicione serverSideTranslations ao getStaticProps / getServerSideProps de cada página
        - Adicione um menu suspenso de troca de idioma em components/Navbar.tsx usando a alternância de locale do next/router
        - Use traduções provisórias para espanhol e japonês — vamos trocar
          por traduções profissionais depois
        - Rode o app e alterne entre os três idiomas para confirmar que nada quebra

        ## Testing & verification
        - Inicie o servidor de desenvolvimento e alterne entre as rotas /en, /es e /ja
        - Verifique cada página em busca de strings em inglês que ainda não foram traduzidas
        - Confirme que o seletor de idioma alterna corretamente
        - Teste se valores interpolados (nomes, contagens) são renderizados em cada locale
        - Verifique se os layouts não quebram com strings maiores em espanhol ou
          com caracteres japoneses mais largos
        - Se algo estiver quebrado — traduções ausentes, overflow de layout,
          erros de roteamento — corrija e teste novamente. Continue iterando até que
          os três idiomas sejam renderizados corretamente em todas as páginas.
        - Não abra um PR até que tudo funcione de ponta a ponta
        ```
      </PromptBlock>

      Use o comando de slash **`/plan`** no início da sessão para que Devin investigue primeiro sua base de código — ele vai descobrir se você está usando o Pages Router ou o App Router, identificar a biblioteca de i18n correta e descrever a abordagem antes de escrever qualquer código. Revise o plano e sugira mudanças antes que ele comece.
    </Step>

    <Step title="Como o Devin realiza a configuração">
      Devin trabalha de forma metódica na sua base de código Next.js — configurando o pipeline de i18n, extraindo strings e gerando arquivos de locale. Veja como isso funciona:

      1. **Instala dependências** — Executa `npm install next-i18next i18next react-i18next` e cria os arquivos de configuração:

      ```js theme={null}
      // next-i18next.config.js
      module.exports = {
        i18n: {
          defaultLocale: 'en',
          locales: ['en', 'es', 'ja'],
        },
      };
      ```

      ```js theme={null}
      // next.config.js
      const { i18n } = require('./next-i18next.config');

      module.exports = {
        i18n,
        // ...sua configuração existente
      };
      ```

      2. **Analisa cada componente** — Lê cada arquivo em `components/` e `pages/`, identificando texto hardcoded em JSX, atributos como `placeholder` e `aria-label`, template literals e mensagens de erro

      3. **Gera arquivos de locale** — Cria arquivos JSON estruturados em `public/locales/`:

      ```json theme={null}
      // public/locales/en/common.json
      {
        "common": {
          "save": "Save",
          "cancel": "Cancel",
          "loading": "Loading..."
        },
        "auth": {
          "login": "Log in",
          "signup": "Create account",
          "forgotPassword": "Forgot your password?"
        },
        "dashboard": {
          "welcome": "Welcome back, {{name}}",
          "items_one": "{{count}} item",
          "items_other": "{{count}} items"
        }
      }
      ```

      ```json theme={null}
      // public/locales/ja/common.json
      {
        "common": {
          "save": "保存",
          "cancel": "キャンセル",
          "loading": "読み込み中..."
        },
        "auth": {
          "login": "ログイン",
          "signup": "アカウント作成",
          "forgotPassword": "パスワードをお忘れですか？"
        },
        "dashboard": {
          "welcome": "おかえりなさい、{{name}}",
          "items_one": "{{count}} 件",
          "items_other": "{{count}} 件"
        }
      }
      ```

      ```json theme={null}
      // public/locales/es/common.json
      {
        "common": {
          "save": "Guardar",
          "cancel": "Cancelar",
          "loading": "Cargando..."
        },
        "auth": {
          "login": "Iniciar sesión",
          "signup": "Crear cuenta",
          "forgotPassword": "¿Olvidaste tu contraseña?"
        },
        "dashboard": {
          "welcome": "Bienvenido de nuevo, {{name}}",
          "items_one": "{{count}} elemento",
          "items_other": "{{count}} elementos"
        }
      }
      ```

      4. **Substitui strings in-place** — Envolve cada componente com `useTranslation('common')` e troca texto hardcoded por chamadas a `t()`, lidando com interpolação para valores dinâmicos como `t('dashboard.welcome', { name: user.name })`

      5. **Configura o carregamento no servidor** — Adiciona `serverSideTranslations` a cada página para que as traduções estejam disponíveis no momento da renderização:

      ```tsx theme={null}
      // pages/dashboard.tsx
      import { serverSideTranslations } from 'next-i18next/serverSideTranslations';

      export const getStaticProps = async ({ locale }) => ({
        props: {
          ...(await serverSideTranslations(locale, ['common'])),
        },
      });
      ```

      6. **Adiciona o seletor de idioma** — Cria um menu suspenso na barra de navegação que usa o recurso de alternância de locale do roteador do Next.js:

      ```tsx theme={null}
      // components/LanguageSwitcher.tsx
      import { useRouter } from 'next/router';

      export default function LanguageSwitcher() {
        const router = useRouter();

        const switchLocale = (locale: string) => {
          router.push(router.pathname, router.asPath, { locale });
        };

        return (
          <select
            value={router.locale}
            onChange={(e) => switchLocale(e.target.value)}
          >
            <option value="en">English</option>
            <option value="es">Español</option>
            <option value="ja">日本語</option>
          </select>
        );
      }
      ```
    </Step>

    <Step title="Testar e iterar">
      Devin executa `npm run dev`, abre o app em seu [navegador integrado](/pt-BR/work-with-devin/devin-session-tools) e navega entre as rotas `/en`, `/es` e `/ja` para verificar se tudo está funcionando. Se algo estiver quebrado — uma tradução faltando, um layout estourando, uma rota que retorna 404 — Devin corrige e testa novamente automaticamente.

      Use o comando de barra **`/test`** a qualquer momento para pedir ao Devin que execute todos os testes novamente e verifique tudo de novo no navegador. Use **`/review`** antes da PR final para que o Devin revise o próprio código em busca de strings faltando, nomes de chaves inconsistentes ou chamadas `serverSideTranslations` ausentes.

      Devin verifica:

      * Todo o texto visível está traduzido (sem strings em inglês sobrando no modo espanhol/japonês)
      * Os layouts não quebram com strings em espanhol mais longas ou caracteres japoneses mais largos
      * O seletor de idioma alterna entre os três locales
      * Valores interpolados (nomes de usuário, contagens) são renderizados corretamente em cada locale
      * As regras de pluralização funcionam (por exemplo, "1 item" → "1 件" em japonês, "1 elemento" em espanhol)
      * O roteamento de locale do Next.js funciona — `/ja/dashboard` mostra a versão em japonês
    </Step>

    <Step title="Itere a partir daqui">
      Depois que a configuração base de i18n estiver pronta, faça melhorias a partir dela.

      <PromptBlock>
        ```txt Substituir por traduções profissionais theme={null}
        Substitua as traduções provisórias em espanhol e japonês por estas
        traduções profissionais do nosso fornecedor. [Anexe os arquivos JSON traduzidos.]
        Garanta que todas as chaves em public/locales/en/common.json estejam cobertas e
        que não restem valores provisórios nos arquivos es e ja.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Adicionar coreano como quarto locale theme={null}
        Adicione coreano (ko) como um novo locale. Atualize next-i18next.config.js para incluir
        "ko" no array locales, crie public/locales/ko/common.json com
        traduções provisórias, adicione a opção ao LanguageSwitcher e
        verifique se as rotas /ko funcionam no navegador.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Dividir traduções por namespace de página theme={null}
        Nosso common.json está ficando grande. Divida-o em arquivos de namespace separados:
        public/locales/{en,es,ja}/auth.json, dashboard.json e settings.json.
        Atualize a chamada serverSideTranslations de cada página para carregar somente os
        namespaces de que ela precisa.
        ```
      </PromptBlock>
    </Step>

    <Step title="Atualize a configuração do seu repositório">
      Esta tarefa instala novas dependências (`next-i18next`, `i18next`, `react-i18next`). Depois que o PR for mesclado, atualize a [configuração do ambiente](/pt-BR/onboard-devin/environment) para que o snapshot do ambiente do Devin inclua esses pacotes em sessões futuras:

      1. Vá para [**Settings > Devin's Environment > Repositories**](https://app.devin.ai/settings/machine?utm_source=docs\&utm_medium=use-case-gallery)
      2. Selecione seu repositório e clique em **Configure**
      3. Em **Upkeep > Maintain dependencies**, confira se o comando de instalação (por exemplo, `npm ci`) está configurado
      4. Clique em **Save** para atualizar o snapshot

      Você também pode definir uma **Upkeep Frequency** para que o Devin volte a executar a instalação de dependências automaticamente, em uma programação definida — isso mantém o snapshot atualizado conforme seu `package.json` evolui, evitando que sessões futuras gastem tempo instalando pacotes na inicialização.
    </Step>

    <Step title="Analise o PR com o Devin Review">
      Depois que o Devin abrir um PR, use o [Devin Review](https://app.devin.ai/review?utm_source=docs\&utm_medium=use-case-gallery) para revisar as alterações de i18n. O Devin Review pode identificar strings com texto fixo que passaram batido, nomes inconsistentes de chaves de tradução e chamadas ausentes de `serverSideTranslations` em diferentes páginas.
    </Step>
  </Steps>
</div>
