Creation:2026-04-02Last update:2026-04-02

    自定义域名

    Intlayer 支持基于域名的语言路由,允许您从专用主机名提供特定语言。例如,可以将中国访问者引导至 intlayer.zh 而不是 intlayer.org/zh

    工作原理

    routing 中的 domains 映射将每种语言与一个主机名关联。Intlayer 在两个地方使用此映射:

    1. URL 生成 (getLocalizedUrl):当目标语言位于与当前页面 不同 的域名上时,返回绝对 URL(例如 https://intlayer.zh/about)。当两个域名匹配时,返回相对 URL(例如 /fr/about)。
    2. 服务器代理 (Next.js & Vite):进入的请求根据到达到达的域名进行重定向或重写。

    专用域名 vs 共享域名

    关键区别在于 专用性

    • 专用域名 - 只有一种语言映射到该主机名(例如 zh → intlayer.zh)。域名本身标识了语言,因此路径中不添加语言前缀。https://intlayer.zh/about 提供中文内容。
    • 共享域名 - 多种语言映射到同一个主机名(例如 enfr 都映射到 intlayer.org)。应用正规的基于前缀的路由。intlayer.org/fr/about 提供法语内容。

    配置

    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [
          Locales.ENGLISH,
          Locales.FRENCH,
          Locales.SPANISH,
          Locales.CHINESE,
        ],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-no-default",
        domains: {
          // 共享域名 - en 和 fr 在 intlayer.org 上使用前缀路由
          en: "intlayer.org",
          // 专用域名 - zh 有其自己的主机名,不需要 /zh/ 前缀
          zh: "intlayer.zh",
        },
      },
    };
    
    export default config;

    末在 domains 中列出的语言将继续使用标准前缀路由,没有任何域名覆盖。

    URL 生成

    getLocalizedUrl 根据调用上下文自动产生正确的 URL 类型。

    同域名语言(相对 URL)

    // 当前页面: intlayer.org/about
    getLocalizedUrl("/about", "fr", { currentDomain: "intlayer.org" });
    // → "/fr/about"
    
    getLocalizedUrl("/about", "en", { currentDomain: "intlayer.org" });
    // → "/about"  (默认语言,无前缀)

    跨域名语言(绝对 URL)

    // 当前页面: intlayer.org/about
    getLocalizedUrl("/about", "zh", { currentDomain: "intlayer.org" });
    // → "https://intlayer.zh/about"  (专用域名,无 /zh/ 前缀)

    从语言自己的域名提供服务

    // 当前页面: intlayer.zh/about
    getLocalizedUrl("/about", "zh", { currentDomain: "intlayer.zh" });
    // → "/about"  (已在正确的域名上 - 相对 URL)
    
    getLocalizedUrl("/about", "fr", { currentDomain: "intlayer.zh" });
    // → "https://intlayer.org/fr/about"  (跨域名链接回到 intlayer.org)

    当前域名自动检测

    currentDomain 是可选的。省略时,getLocalizedUrl 按此顺序解析:

    1. 绝对输入 URL 的主机名(例如 https://intlayer.org/aboutintlayer.org)。
    2. 浏览器环境中的 window.location.hostname
    3. 如果两者均不可用(不带显式选项的 SSR),则为同域名语言返回相对 URL,并且不生成绝对 URL - 这是安全的回退方案。
    // 浏览器 - window.location.hostname === 'intlayer.org'
    getLocalizedUrl("/about", "zh");
    // → "https://intlayer.zh/about"  (从 window 自动检测)
    
    // 从绝对 URL - 自动检测域名
    getLocalizedUrl("https://intlayer.org/about", "zh");
    // → "https://intlayer.zh/about"

    带有域名的 getMultilingualUrls

    getMultilingualUrls 为每种语言调用 getLocalizedUrl,因此它根据调用者的域名产生相对和绝对 URL 的混合:

    // currentDomain: 'intlayer.org'
    getMultilingualUrls("/about", { currentDomain: "intlayer.org" });
    // {
    //   en: "/about",
    //   fr: "/fr/about",
    //   es: "/es/about",
    //   zh: "https://intlayer.zh/about",
    // }

    这些绝对 URL 已准备好用于 SEO 的 <link rel="alternate" hreflang="..."> 标签。

    代理行为

    Next.js

    intlayerProxy 中间件自动处理域名路由。将其添加到您的 middleware.ts 中:

    export { intlayerProxy as default } from "next-intlayer/proxy";
    
    export const config = {
      matcher: "/((?!api|static|assets|robots|sitemap|.*\\..*|_next).*)",
    };

    重定向 - 请求到达了给定语言前缀的错误域名:

    GET intlayer.org/zh/about
    → 301 https://intlayer.zh/about

    重写 - 请求到达了语言的专用域名且没有前缀:

    GET intlayer.zh/about
    → 重写至 /zh/about  (仅 Next.js 内部路由,URL 保持简洁)

    Vite

    intlayerProxy Vite 插件在开发期间应用相同的逻辑:

    import { defineConfig } from "vite";
    import { intlayerProxy } from "vite-intlayer";
    
    export default defineConfig({
      plugins: [intlayerProxy()],
    });
    注意: 在本地开发中,您通常位于 localhost,因此跨域名重定向将指向实时域名,而不是另一个本地端口。如果需要在本地测试多域名路由,请使用 hosts 文件覆盖(例如 127.0.0.1 intlayer.zh)或反向代理。

    语言切换器

    来自 next-intlayeruseLocale hook 自动处理域名感知的导航。当用户切换到不同域名上的语言时,该 hook 会执行全页面导航 (window.location.href) 而不是客户端路由推送,因为 Next.js 路由无法跨越源 (origins)。

    "use client";
    
    import { useLocale } from "next-intlayer";
    
    export const LocaleSwitcher = () => {
      const { availableLocales, locale, setLocale } = useLocale();
    
      return (
        <ul>
          {availableLocales.map((localeEl) => (
            <li key={localeEl}>
              <button
                onClick={() => setLocale(localeEl)}
                aria-current={localeEl === locale ? "true" : undefined}
              >
                {l.toUpperCase()}
              </button>
            </li>
          ))}
        </ul>
      );
    };

    无需额外配置 - useLocale 内部检测 window.location.hostname 并决定是进行 router.replace(同域名)还是 window.location.href(跨域名)。

    SEO: hreflang 备用链接

    基于域名的路由通​​常与 hreflang 一起使用,以告诉搜索引擎为每种语言索引哪个 URL。使用 getMultilingualUrls 生成全套备用 URL:

    import { getMultilingualUrls } from "intlayer";
    import type { Metadata } from "next";
    
    export const generateMetadata = (): Metadata => {
      const alternates = getMultilingualUrls("/", {
        currentDomain: process.env.NEXT_PUBLIC_DOMAIN, // 例如 "intlayer.org"
      });
    
      return {
        alternates: {
          languages: alternates,
        },
      };
    };

    这会产生:

    <link rel="alternate" hreflang="en" href="https://intlayer.org/" />
    <link rel="alternate" hreflang="fr" href="https://intlayer.org/fr/" />
    <link rel="alternate" hreflang="es" href="https://intlayer.org/es/" />
    <link rel="alternate" hreflang="zh" href="https://intlayer.zh/" />

    核心实用程序

    实用程序 描述
    getLocalizedUrl(url, locale, { currentDomain }) 返回相对或绝对 URL,取决于目标语言是否在当前域名上。
    getMultilingualUrls(url, { currentDomain }) 返回语言键控的本地化 URL 映射,根据需要混合相对和绝对 URL。
    getPrefix(locale, { domains }) 为专用域名语言返回空前缀,否则返回普通前缀。