> ## 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.

# 为 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="为 Next.js 应用添加日语和西班牙语" description="Devin 安装 next-i18next，将硬编码字符串提取到 locale JSON 文件中，添加日语和西班牙语翻译，并在浏览器中验证语言切换。" prompt="使用 next-i18next 为我们的 Next.js 应用添加国际化。安装 next-i18next、i18next 和 react-i18next。配置 locale 路由，将 defaultLocale 设为 'en'，locales 设为 ['en', 'es', 'ja']。扫描 components/ 和 pages/ 目录中所有硬编码的英文字符串（JSX 文本、占位符、aria-label、错误信息、工具提示）。在 public/locales/{en,es,ja}/common.json 下创建带命名空间键的结构化 locale 文件。将每一个硬编码字符串替换为 t() 调用。在每个页面中添加 serverSideTranslations。为导航栏添加语言切换器。为西班牙语和日语使用占位翻译。启动开发服务器，并在三种语言下测试每个页面——检查是否有遗留英文字符串、布局溢出，以及路由是否异常。在一切正常之前持续迭代。在所有页面的三种语言都能正确渲染之前不要打开 PR。" category="功能开发" features="" />

<div className="uc-detail-wrapper">
  <Tip>不想手动配置？将本页链接粘贴到 Devin 会话中，让它帮你完成所有设置。</Tip>

  <Steps>
    <Step title="（可选）通过 Ask Devin 界定代码库范围">
      如果你不确定你的 Next.js 应用是如何构建的，或者不清楚哪些组件包含硬编码字符串，可以先使用 [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) 进行排查：

      <PromptBlock agent="ada">
        ```txt Scope the i18n work theme={null}
        帮我了解在我们的 Next.js 应用中添加 i18n 的工作范围：
        1. 我们在使用 Pages Router 还是 App Router？
        2. 有多少组件和页面包含硬编码的英文字符串？
        3. 我们是否已经有任何 i18n 配置或 locale 文件？
        4. 哪些共享组件（buttons、forms、modals）包含文本？
        5. 是否有任何字符串需要保持英文（品牌名称、API 代码）？
        ```
      </PromptBlock>

      你也可以直接在 Ask Devin 中启动一个 Devin 会话，它会保留之前获取到的全部上下文。
    </Step>

    <Step title="开始进行 i18n 配置">
      为 Next.js 应用添加国际化，意味着要配置本地化路由、设置中间件、提取所有硬编码文案并创建翻译文件——这些都要在你能测试一次语言切换之前完成。Devin 会处理整个流程：安装 `next-i18next`，配置 Next.js 的 locale 路由，从数十个组件中提取字符串，并在浏览器中验证结果。

      <PromptBlock>
        ```txt Add Japanese and Spanish to our Next.js app theme={null}
        使用 next-i18next 为我们的 Next.js 应用添加国际化支持，增加日语和西班牙语。

        - 安装 next-i18next、i18next 和 react-i18next
        - 在 next-i18next.config.js 中配置 defaultLocale "en" 和
          locales ["en", "es", "ja"]
        - 更新 next.config.js 以包含 i18n 配置
        - 扫描 components/ 和 pages/ 中所有硬编码的英文字符串
          （JSX 文本、placeholder 属性、aria-label、错误信息、工具提示）
        - 在 public/locales/{en,es,ja}/common.json 下创建结构化的 locale 文件，
          使用带命名空间的 key（例如 common.save、auth.loginButton、errors.notFound）
        - 将每个硬编码字符串替换为使用 useTranslation('common') 的 t() 调用
        - 在每个页面的 getStaticProps / getServerSideProps 中添加 serverSideTranslations
        - 在 components/Navbar.tsx 中使用 next/router 的 locale 切换添加语言切换下拉菜单
        - 为西班牙语和日语使用占位翻译——之后我们会替换为
          专业翻译
        - 运行应用并在三种语言之间切换，以确认一切正常

        ## Testing & verification
        - 启动开发服务器并在 /en、/es 和 /ja 路由之间切换
        - 检查每个页面是否有遗留未翻译的英文字符串
        - 验证语言切换器能正确切换
        - 测试插值变量（名称、计数）在每个 locale 中是否正确渲染
        - 检查在更长的西班牙语字符串或
          更宽的日文字符下布局是否正常
        - 如果有任何问题——缺失翻译、布局溢出、
          路由错误——修复后重新测试。持续迭代直到
          三种语言在每个页面上都能在每个页面上正确渲染。
        - 在一切端到端工作正常之前不要打开 PR
        ```
      </PromptBlock>

      在会话开始时使用 **`/plan`** 斜杠命令，这样 Devin 会先检查你的代码库——它会判断你使用的是 Pages Router 还是 App Router，找出合适的 i18n 库，并在编写任何代码之前先列出整体方案。先审阅这个计划，并在它开始执行之前提出修改建议。
    </Step>

    <Step title="Devin 如何完成设置">
      Devin 会以有条不紊的方式处理你的 Next.js 代码库——配置 i18n 流程、提取字符串并构建本地化文件。如下所示：

      1. **安装依赖项** —— 运行 `npm install next-i18next i18next react-i18next` 并创建配置文件：

      ```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,
        // ...你现有的配置
      };
      ```

      2. **扫描每个组件** — 读取 `components/` 和 `pages/` 中的每个文件，识别 JSX 中的硬编码文本、`placeholder` 和 `aria-label` 等属性中的文本、模板字符串以及错误字符串

      3. **构建本地化文件** — 在 `public/locales/` 下创建结构化 JSON：

      ```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. **就地替换字符串** — 为每个组件包裹 `useTranslation('common')`，并将硬编码文本替换为 `t()` 调用，同时处理动态值的插值，例如 `t('dashboard.welcome', { name: user.name })`

      5. **配置服务端加载** — 在每个页面中添加 `serverSideTranslations`，以便在渲染时即可获取翻译内容：

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

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

      6. **添加语言切换器** —— 在导航栏中创建一个使用 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="测试与迭代">
      Devin 运行 `npm run dev`，在其[内置浏览器](/zh/work-with-devin/devin-session-tools)中打开应用，并在 `/en`、`/es` 和 `/ja` 路由之间来回访问，以验证一切正常工作。如果出现问题——缺少翻译、布局溢出、路由返回 404——Devin 会自动修复并重新测试。

      在任意时间都可以使用 **`/test`** 斜杠命令，让 Devin 重新运行所有测试并在浏览器中重新验证。最终提交 PR 之前使用 **`/review`**，让 Devin 自查代码中是否有遗漏的文案、键名不一致或缺少 `serverSideTranslations` 调用。

      Devin 会检查：

      * 所有可见文本都已翻译 (在西班牙语/日语模式下没有残留的英文字符串)
      * 使用更长的西班牙语字符串或更宽的日文字符时，布局不会出错
      * 语言切换器可以在三种语言环境之间正常切换
      * 插值的值 (用户名、计数) 在每种语言环境中都能正确渲染
      * 复数规则工作正常 (例如，"1 item" → "1 件" (日语) ，"1 elemento" (西班牙语) )
      * Next.js 语言环境路由正常工作——`/ja/dashboard` 会显示日文版本
    </Step>

    <Step title="从此处开始迭代">
      在完成基础的 i18n 设置后，继续扩展它。

      <PromptBlock>
        ```txt 使用专业翻译替换 theme={null}
        将占位用的西班牙语和日语翻译替换为我们供应商提供的
        专业翻译。[附上已翻译的 JSON 文件。]
        确保 public/locales/en/common.json 中的所有键都已覆盖，
        且 es 和 ja 文件中不再有占位内容。
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt 添加韩语作为第四种语言环境 theme={null}
        添加韩语（ko）作为新的语言环境。在 next-i18next.config.js 中
        将 "ko" 加入 locales 数组，创建带占位翻译的
        public/locales/ko/common.json，在 LanguageSwitcher 中添加该选项，
        并在浏览器中验证 /ko 路由是否正常工作。
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt 按页面命名空间拆分翻译 theme={null}
        我们的 common.json 变得很大了。将其拆分为独立的命名空间文件：
        public/locales/{en,es,ja}/auth.json、dashboard.json 和 settings.json。
        更新每个页面的 serverSideTranslations 调用，
        只加载该页面所需的命名空间。
        ```
      </PromptBlock>
    </Step>

    <Step title="更新你的仓库设置">
      此任务会安装新的依赖 (`next-i18next`、`i18next`、`react-i18next`) 。在 PR 合并后，更新你的[环境配置](/zh/onboard-devin/environment)，这样 Devin 的环境快照在后续会话中就会包含这些软件包：

      1. 前往 [**Settings > Devin's Environment > Repositories**](https://app.devin.ai/settings/machine?utm_source=docs\&utm_medium=use-case-gallery)
      2. 选择你的代码库并点击 **Configure**
      3. 在 **Upkeep > Maintain dependencies** 下，确认已设置安装命令 (例如 `npm ci`)
      4. 点击 **Save** 更新快照

      你也可以设置 **Upkeep Frequency**，让 Devin 按计划自动重新执行依赖安装——这样可以在你的 `package.json` 发生变更时保持快照为最新状态，从而避免后续会话在启动时浪费时间安装依赖包。
    </Step>

    <Step title="使用 Devin Review 审查此 PR">
      Devin 提交 PR 后，使用 [Devin Review](https://app.devin.ai/review?utm_source=docs\&utm_medium=use-case-gallery) 来审查这些 i18n 变更。Devin Review 可以帮助发现遗漏的硬编码字符串、不一致的翻译 key 命名，以及各页面中缺失的 `serverSideTranslations` 调用。
    </Step>
  </Steps>
</div>
