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

# Ajouter le japonais et l’espagnol à une app 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="Ajouter le japonais et l'espagnol à une application Next.js" description="Devin installe next-i18next, extrait les chaînes codées en dur vers des fichiers JSON de locale, ajoute les traductions en japonais et en espagnol, et vérifie le basculement de langue dans le navigateur." prompt="Ajoutez l'internationalisation à notre application Next.js avec next-i18next. Installez next-i18next, i18next et react-i18next. Configurez le routage des locales avec defaultLocale 'en' et locales ['en', 'es', 'ja']. Analysez components/ et pages/ pour trouver toutes les chaînes anglaises codées en dur (texte JSX, placeholders, aria-labels, messages d'erreur, info-bulles). Créez des fichiers de locales structurés sous public/locales/{en,es,ja}/common.json avec des clés utilisant des espaces de noms. Remplacez chaque chaîne codée en dur par un appel à t(). Ajoutez serverSideTranslations à chaque page. Ajoutez un sélecteur de langue dans la barre de navigation. Utilisez des traductions provisoires pour l'espagnol et le japonais. Démarrez le serveur de développement et testez chaque page dans les trois langues — vérifiez l'absence de chaînes anglaises restantes, les dépassements de mise en page et les problèmes de routage. Continuez à itérer jusqu'à ce que tout fonctionne. N'ouvrez pas de pull request (PR) tant que les trois langues ne s'affichent pas correctement sur chaque page." category="Développement de fonctionnalités" features="" />

<div className="uc-detail-wrapper">
  <Tip>Vous ne souhaitez pas effectuer cette configuration manuellement ? Collez un lien vers cette page dans une session Devin et demandez-lui de tout configurer pour vous.</Tip>

  <Steps>
    <Step title="(Facultatif) Définir la portée de la base de code avec Ask Devin">
      Si vous ne savez pas comment votre application Next.js est structurée ou quels composants contiennent des chaînes codées en dur, utilisez [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) pour commencer par analyser la situation :

      <PromptBlock agent="ada">
        ```txt Scope the i18n work theme={null}
        Help me understand the scope of adding i18n to our Next.js app:
        1. Are we using the Pages Router or App Router?
        2. How many components and pages have hardcoded English strings?
        3. Do we already have any i18n setup or locale files?
        4. Which shared components (buttons, forms, modals) contain text?
        5. Are there any strings that should stay in English (brand names, API codes)?
        ```
      </PromptBlock>

      Vous pouvez aussi démarrer une session Devin directement depuis Ask Devin, et tout ce qu'il aura appris sera conservé dans le contexte.
    </Step>

    <Step title="Démarrer la configuration de l’i18n">
      L’ajout de l’internationalisation à une app Next.js implique de configurer le routage par locale, de paramétrer le middleware, d’extraire chaque chaîne codée en dur et de créer des fichiers de traduction — tout cela avant même de pouvoir tester un simple changement de langue. Devin prend en charge l’ensemble du pipeline : installation de `next-i18next`, configuration du routage par locale dans Next.js, extraction des chaînes depuis des dizaines de composants et vérification du résultat dans le navigateur.

      <PromptBlock>
        ```txt Ajoute le japonais et l’espagnol à notre app Next.js theme={null}
        Ajoute l’internationalisation à notre app Next.js en utilisant next-i18next.

        - Installe next-i18next, i18next et react-i18next
        - Configure next-i18next.config.js avec defaultLocale "en" et
          locales ["en", "es", "ja"]
        - Mets à jour next.config.js pour inclure la configuration i18n
        - Analyse components/ et pages/ pour trouver toutes les chaînes anglaises codées en dur
          (texte JSX, attributs placeholder, aria-labels, messages d’erreur, info-bulles)
        - Crée des fichiers de locale structurés sous public/locales/{en,es,ja}/common.json
          avec des clés avec espaces de noms (par ex. common.save, auth.loginButton, errors.notFound)
        - Remplace chaque chaîne codée en dur par un appel t() en utilisant useTranslation('common')
        - Ajoute serverSideTranslations à getStaticProps / getServerSideProps de chaque page
        - Ajoute un menu déroulant de sélection de langue dans components/Navbar.tsx en utilisant le changement de locale de next/router
        - Utilise des traductions provisoires pour l’espagnol et le japonais — nous les remplacerons
          plus tard par des traductions professionnelles
        - Lance l’app et bascule entre les trois langues pour confirmer que rien ne casse

        ## Tests et vérification
        - Démarre le serveur de développement et bascule entre les routes /en, /es et /ja
        - Vérifie chaque page pour repérer les chaînes anglaises restantes non traduites
        - Vérifie que le sélecteur de langue bascule correctement
        - Teste que les valeurs interpolées (noms, nombres) s’affichent correctement dans chaque locale
        - Vérifie que les mises en page ne se cassent pas avec des chaînes espagnoles plus longues ou
          des caractères japonais plus larges
        - Si quelque chose est cassé — traductions manquantes, débordements de mise en page,
          erreurs de routage — corrige et teste de nouveau. Continue d’itérer jusqu’à ce que les
          trois langues s’affichent correctement sur chaque page.
        - N’ouvre pas de PR tant que tout ne fonctionne pas de bout en bout
        ```
      </PromptBlock>

      Utilise la commande slash **`/plan`** au début de la session pour que Devin analyse d’abord ta base de code — il déterminera si tu utilises le Pages Router ou l’App Router, identifiera la bonne bibliothèque i18n et décrira son approche avant d’écrire la moindre ligne de code. Passe le plan en revue et suggère des modifications avant qu’il ne commence.
    </Step>

    <Step title="Comment Devin gère la mise en place">
      Devin parcourt méthodiquement le code de votre projet Next.js : il configure le pipeline i18n, extrait les chaînes et crée les fichiers de langue. Voici à quoi cela ressemble :

      1. **Installe les dépendances** — Exécute `npm install next-i18next i18next react-i18next` et crée les fichiers de configuration :

      ```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,
        // ...votre configuration existante
      };
      ```

      2. **Analyse chaque composant** — Lit chaque fichier dans `components/` et `pages/`, en identifiant le texte en dur dans le JSX, les attributs comme `placeholder` et `aria-label`, les template literals et les messages d’erreur

      3. **Construit les fichiers de langue** — Crée des fichiers JSON structurés sous `public/locales/` :

      ```json theme={null}
      // public/locales/fr/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. **Remplace les chaînes directement dans le code** — Encapsule chaque composant avec `useTranslation('common')` et remplace le texte en dur par des appels à `t()`, en gérant l’interpolation pour les valeurs dynamiques comme `t('dashboard.welcome', { name: user.name })`

      5. **Met en place le chargement côté serveur** — Ajoute `serverSideTranslations` à chaque page pour que les traductions soient disponibles au moment du rendu :

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

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

      6. **Ajoute le sélecteur de langue** — Crée un menu déroulant dans la barre de navigation qui utilise la fonction de changement de langue (locale) du routeur 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="Testez et itérez">
      Devin exécute `npm run dev`, ouvre l’app dans son [navigateur intégré](/fr/work-with-devin/devin-session-tools) et navigue entre les routes `/en`, `/es` et `/ja` pour vérifier que tout fonctionne. Si quelque chose ne va pas — une traduction manquante, une mise en page qui déborde, une route qui renvoie une 404 — Devin le corrige et refait les tests automatiquement.

      Utilisez la commande slash **`/test`** à tout moment pour demander à Devin de relancer tous les tests et de revérifier dans le navigateur. Utilisez **`/review`** avant la PR finale pour demander à Devin de relire son propre code afin de repérer les chaînes manquantes, les noms de clés incohérents ou les appels `serverSideTranslations` manquants.

      Devin vérifie :

      * Tout le texte visible est traduit (aucune chaîne en anglais restante en mode espagnol/japonais)
      * Les mises en page ne se cassent pas avec des chaînes espagnoles plus longues ou des caractères japonais plus larges
      * Le sélecteur de langue bascule entre les trois locales
      * Les valeurs interpolées (noms d’utilisateur, nombres) s’affichent correctement dans chaque langue
      * Les règles de pluralisation fonctionnent (par ex. : "1 item" → "1 件" en japonais, "1 elemento" en espagnol)
      * Le routage Next.js par locale fonctionne — `/ja/dashboard` affiche la version japonaise
    </Step>

    <Step title="Continuer l’itération à partir d’ici">
      Une fois la configuration i18n de base en place, poursuivez pour l’étendre.

      <PromptBlock>
        ```txt Remplacer par des traductions professionnelles theme={null}
        Remplacez les traductions espagnoles et japonaises provisoires par ces
        traductions professionnelles fournies par notre prestataire. [Joignez les fichiers JSON traduits.]
        Assurez-vous que toutes les clés de public/locales/en/common.json sont couvertes et
        qu’aucune traduction provisoire ne reste dans les fichiers es et ja.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Ajouter le coréen comme quatrième langue theme={null}
        Ajoutez le coréen (ko) comme nouvelle langue. Mettez à jour next-i18next.config.js pour inclure
        "ko" dans le tableau locales, créez public/locales/ko/common.json avec
        des traductions provisoires, ajoutez l’option au LanguageSwitcher et
        vérifiez que les routes /ko fonctionnent dans le navigateur.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Scinder les traductions par espace de noms de page theme={null}
        Notre common.json devient volumineux. Scindez-le en fichiers d’espace de noms séparés :
        public/locales/{en,es,ja}/auth.json, dashboard.json et settings.json.
        Mettez à jour l’appel serverSideTranslations de chaque page pour ne charger que les
        espaces de noms dont elle a besoin.
        ```
      </PromptBlock>
    </Step>

    <Step title="Mettre à jour la configuration de votre dépôt">
      Cette tâche installe de nouvelles dépendances (`next-i18next`, `i18next`, `react-i18next`). Après la fusion de la pull request (PR), mettez à jour la [configuration de l’environnement](/fr/onboard-devin/environment) afin que l’instantané d’environnement de Devin contienne ces packages pour les futures sessions :

      1. Allez dans [**Settings > Devin's Environment > Repositories**](https://app.devin.ai/settings/machine?utm_source=docs\&utm_medium=use-case-gallery)
      2. Sélectionnez votre dépôt et cliquez sur **Configure**
      3. Sous **Upkeep > Maintain dependencies**, vérifiez que votre commande d’installation (par exemple, `npm ci`) est définie
      4. Cliquez sur **Save** pour mettre à jour l’instantané

      Vous pouvez également définir une **Upkeep Frequency** pour que Devin réexécute automatiquement l’installation des dépendances selon une programmation ; cela permet de garder l’instantané à jour au fur et à mesure que votre `package.json` évolue, afin que les futures sessions ne perdent pas de temps à installer les dépendances au démarrage.
    </Step>

    <Step title="Passez en revue la PR avec Devin Review">
      Une fois que Devin a ouvert la PR, utilisez [Devin Review](https://app.devin.ai/review?utm_source=docs\&utm_medium=use-case-gallery) pour examiner les modifications i18n. Devin Review peut détecter les chaînes codées en dur oubliées, les incohérences dans le nommage des clés de traduction et les appels `serverSideTranslations` manquants sur l’ensemble des pages.
    </Step>
  </Steps>
</div>
