使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
版本历史
- "初始历史"v9.1.32025/8/6
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.
GitHub link to the documentationCopy doc Markdown to clipboard
使用 Intlayer 翻译你的 SolidStart 网站 | 国际化 (i18n)
目录
本指南涵盖了一个服务端渲染的 SolidStart 应用程序:语言检测在请求时发生,页面在服务端以正确的语言渲染,并且搜索引擎所需的 <html lang>、hreflang 和 sitemap 信号都是在服务端生成的。
为什么选择 Intlayer 而不是其他替代方案?
与 @solid-primitives/i18n 或 i18next 等主流解决方案相比,Intlayer 是一个带有集成优化的解决方案,例如:
Intlayer 经过优化,可与 Solid 完美配合,提供组件级内容划分、响应式翻译以及扩展国际化 (i18n) 所需的所有功能。
无需将庞大的 JSON 文件加载到页面中,只需加载必要的内容。Intlayer 有助于将打包文件和页面体积减少高达 50%。
对应用程序的内容进行局部作用域划分有助于大型应用程序的维护。你可以复制或删除单个功能文件夹,而无需心理负担去审查整个内容代码库。此外,Intlayer 是完全类型化的,以确保内容的准确性。
将内容协同定位减少了大语言模型 (LLM) 所需的上下文。Intlayer 还附带了一套工具,例如用于测试缺失翻译的 CLI、LSP、MCP 和 agent skills,使 AI 代理的开发人员体验 (DX) 更加顺畅。
在 CI/CD 流水线中使用你选择的 LLM 按照 AI 提供商的成本自动进行翻译。Intlayer 还提供了一个编译器来自动提取内容,以及一个 Web 平台 来帮助在后台进行翻译。
将庞大的 JSON 文件连接到组件可能会导致性能和响应性问题。Intlayer 在构建时优化了内容加载。
在 SolidStart 应用程序中设置 Intlayer 的分步指南
安装依赖项
使用 npm 安装必要的软件包:
bash复制代码复制代码到剪贴板
npx intlayer init --interactive--interactive标志是可选的。如果你是 AI 代理,请使用intlayer-cli init。此命令将检测你的环境并安装所需的软件包。例如:
bash复制代码复制代码到剪贴板
npm install intlayer solid-intlayer vite-intlayerintlayer
solid-intlayer
将 Intlayer 与 Solid 应用程序集成的软件包。它为 Solid 国际化提供上下文提供程序 (context providers) 和钩子 (hooks)。
vite-intlayer
包含用于将 Intlayer 与 Vite 打包器 集成的 Vite 插件,以及检测用户偏好语言、管理 cookie 和处理 URL 重定向的语言路由句柄。
这里
vite-intlayer是一个服务端关注点,不仅是构建时的关注点:它提供了 SolidStart 的 Nitro 服务器运行的请求句柄。将其保留在dependencies中是安全的默认设置 —— 仅当你要部署包含 Nitro 内联句柄的构建后的.output目录时,才可以将其移动到devDependencies。配置你的项目
创建一个配置文件来配置应用程序的语言:
intlayer.config.ts复制代码复制代码到剪贴板
import { type IntlayerConfig, Locales } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // 你的其他语言 ], defaultLocale: Locales.ENGLISH, }, routing: { mode: "prefix-no-default", }, }; export default config;使用
prefix-no-default,默认语言从无前缀的 URL 提供:plaintext复制代码复制代码到剪贴板
/ /about → 英语 (默认语言)/fr /fr/about → 法语/es /es/about → 西班牙语通过此配置文件,你可以设置本地化 URL、中间件重定向、cookie 名称、内容声明的位置和扩展名、禁用控制台中的 Intlayer 日志等。有关可用参数的完整列表,请参阅配置文档。
在 Vite 配置中集成 Intlayer
将 Intlayer 插件添加到你的配置中:
vite.config.ts复制代码复制代码到剪贴板
import { solidStart } from "@solidjs/start/config"; import { nitro } from "nitro/vite"; import { defineConfig } from "vite"; import { intlayer } from "vite-intlayer"; export default defineConfig({ plugins: [solidStart(), nitro(), intlayer()], });intlayer()Vite 插件构建你的内容声明文件,在开发模式下监视它们,并在应用程序内部定义 Intlayer 环境变量。它还提供可优化性能的别名。语言路由随插件一起提供
SolidStart 运行在 Nitro 上,并且
intlayer()将其语言路由句柄直接注册到 Nitro 的服务器管道中(通过routing.enableProxy选项,默认为true)。无需配置其他内容:在构建好的服务器上,每个请求在到达路由器之前都会经过检查,并且- 语言从 URL 前缀读取,其次是
INTLAYER_LOCALEcookie,然后是Accept-Language请求头; - 当解析出的语言不是默认语言时,无前缀的 URL 会重定向到对应的本地化页面(
/→/fr); - 冗余前缀的 URL 会重定向回其规范形式(
/en/about→/about); - 语言 cookie 会在响应中写回。
- 语言从 URL 前缀读取,其次是
声明你的内容
创建并管理你的内容声明以存储翻译:
src/contents/home.content.ts复制代码复制代码到剪贴板
import { type Dictionary, t } from "intlayer"; const homeContent = { key: "home-page", content: { title: t({ en: "Hello world!", fr: "Bonjour le monde !", es: "¡Hola mundo!", }), metaTitle: "SolidStart + Intlayer", metaDescription: t({ en: "A SolidStart application internationalized with Intlayer.", fr: "Une application SolidStart internationalisée avec Intlayer.", es: "Una aplicación SolidStart internacionalizada con Intlayer.", }), documentation: t({ en: "Visit start.solidjs.com to learn how to build SolidStart apps.", fr: "Visitez start.solidjs.com pour apprendre à créer des applications SolidStart.", es: "Visita start.solidjs.com para aprender a crear aplicaciones SolidStart.", }), }, } satisfies Dictionary; export default homeContent;⚠️ SolidStart 特别注意点:
src/routes下的每个.ts/.tsx文件都会成为一个路由,而.content.ts文件具有默认导出,因此它会被误识别为一个页面。请将页面的内容声明保留在 routes 目录之外(src/contents/效果很好)。组件的内容可以保持协同定位,因为文件系统路由器不会扫描src/components。只要你的内容声明包含在
contentDir目录(默认为./src)中,并匹配内容声明文件扩展名(默认为.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}),就可以在应用程序的任何位置定义它们。有关更多详细信息,请参阅内容声明文档。
添加本地化路由
本步骤的目标是赋予每种语言自己的 URL,这也是搜索引擎进行索引的内容。
将你的页面移动到可选动态段下。在 SolidStart 的文件系统路由器中,
[[locale]]编译为:locale?路径模式:plaintext复制代码复制代码到剪贴板
src/routes/ [[locale]].tsx ← 验证动态段的 layout [[locale]]/ index.tsx → / 以及 /fr 以及 /es about.tsx → /about 以及 /fr/about 以及 /es/about [...404].tsx → 捕获其他任何内容的 catch-all布局文件的唯一工作是将该动态段约束为已配置的语言:
src/routes/[[locale]].tsx复制代码复制代码到剪贴板
import type { RouteSectionProps } from "@solidjs/router";import { locales } from "intlayer";export const route = { matchFilters: { locale: locales, },};export default function LocaleLayout(props: RouteSectionProps) { return <>{props.children}</>;}@solidjs/router将:locale?扩展为两种模式 —— 一种带有段,一种不带段 —— 并按特异性递减进行匹配。matchFilters是区分正常设置与令人困惑的设置的关键所在:显示表格的所有内容在弹窗中打开表格以清晰地查看所有数据
URL 没有 matchFilters带有 matchFilters/fr/about法语关于页面 法语关于页面 /about关于页面 (静态段胜出) 关于页面 /unknown主页,静默处理,且 locale=unknown不匹配 → 回退到 catch-all 404 如果你使用
'prefix-all'路由模式,请首选[locale](必需),如果是'no-prefix'或'search-params',则完全放弃该段。为你的应用程序提供语言 locale
URL 是语言 locale 的唯一真理来源:中间件已经将请求重定向到其本地化路径,因此在根布局中读取路径可使服务端渲染与客户端水化(hydration)保持一致,并使每次客户端导航都自动更新语言 locale。
src/app.tsx复制代码复制代码到剪贴板
import { MetaProvider } from "@solidjs/meta";import { Router, useLocation } from "@solidjs/router";import { FileRoutes } from "@solidjs/start/router";import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";import { IntlayerProvider } from "solid-intlayer";import { createEffect, type ParentProps, Suspense } from "solid-js";import { isServer } from "solid-js/web";import { Nav } from "~/components/Nav";import "./app.css";const RootLayout = (props: ParentProps) => { const location = useLocation(); const locale = () => getLocaleFromPath(location.pathname) ?? defaultLocale; // 服务端在 entry-server.tsx 中渲染 <html>; // 语言之间的客户端导航必须自行更新这些属性。 createEffect(() => { if (isServer) return; document.documentElement.lang = locale(); document.documentElement.dir = getHTMLTextDir(locale()); }); return ( <MetaProvider> <IntlayerProvider locale={locale()}> <Nav /> <Suspense>{props.children}</Suspense> </IntlayerProvider> </MetaProvider> );};export default function App() { return ( <Router root={RootLayout}> <FileRoutes /> </Router> );}IntlayerProvider会对其localeprop 作出响应,因此在 JSX 中传递访问器调用locale()就足够了 —— Solid 会将其编译为一个 getter,当 URL 改变时整个树都会以新语言重新渲染。在服务端设置 HTML 的 lang 和 dir 属性
<html>元素由entry-server.tsx在Router之外渲染。改为从请求 URL 读取语言 locale:src/entry-server.tsx复制代码复制代码到剪贴板
// @refresh reloadimport { createHandler, StartServer } from "@solidjs/start/server";import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";import { getRequestEvent } from "solid-js/web";export default createHandler(() => ( <StartServer document={({ assets, children, scripts }) => { const url = getRequestEvent()?.request.url ?? "/"; const locale = getLocaleFromPath(url) ?? defaultLocale; return ( <html dir={getHTMLTextDir(locale)} lang={locale}> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> {assets} </head> <body> <div id="app">{children}</div> {scripts} </body> </html> ); }} />));网络爬虫现在可以在首个字节接收到正确的语言:
html复制代码复制代码到剪贴板
<html dir="ltr" lang="fr"></html>在页面中使用 Intlayer
在整个应用程序中访问你的内容字典:
src/routes/[[locale]]/index.tsx复制代码复制代码到剪贴板
import { Meta, Title } from "@solidjs/meta";import { useIntlayer } from "solid-intlayer";import Counter from "~/components/Counter";export default function Home() { const content = useIntlayer("home-page"); return ( <main> <Title>{content.metaTitle.value}</Title> <Meta content={content.metaDescription.value} name="description" /> <h1>{content.title}</h1> <Counter /> <p>{content.documentation}</p> </main> );}在 Solid 中,
useIntlayer返回响应式内容(例如content)。你可以直接访问其属性。如果你想在
string属性中使用内容,例如alt、title、href、aria-label等,可以使用该函数的值,如下所示:html复制代码复制代码到剪贴板
<img src="{content.image.src.value}" alt="{content.image.value}" /><img src="{content.image.src.toString()}" alt="{content.image.toString()}" /><img src="{String(content.image.src)}" alt="{String(content.image)}" />要了解有关
useIntlayer钩子的更多信息,请参阅文档。内容节点不仅限于纯文本翻译。例如复数形式的计数器:
src/components/Counter.content.ts复制代码复制代码到剪贴板
import { type Dictionary, plural, t } from "intlayer";const counterContent = { key: "counter", content: { clicks: plural({ one: t({ en: "{{count}} click", fr: "{{count}} clic", es: "{{count}} clic", }), other: t({ en: "{{count}} clicks", fr: "{{count}} clics", es: "{{count}} clics", }), }), },} satisfies Dictionary;export default counterContent;src/components/Counter.tsx复制代码复制代码到剪贴板
import { useIntlayer } from "solid-intlayer";import { createSignal } from "solid-js";export default function Counter() { const [count, setCount] = createSignal(0); const content = useIntlayer("counter"); return ( <button onClick={() => setCount(count() + 1)} type="button"> {content.clicks(count())} </button> );}plural()通过针对当前语言的Intl.PluralRules选择类别,因此拥有两种以上复数形式的语言无需任何额外代码即可工作。创建本地化链接组件
创建自定义
Link组件,它会自动向内部 URL 添加当前语言的前缀:src/components/LocalizedLink.tsx复制代码复制代码到剪贴板
import { A, type AnchorProps } from "@solidjs/router";import { getLocalizedUrl } from "intlayer";import { useLocale } from "solid-intlayer";import type { ParentComponent } from "solid-js";export const LocalizedLink: ParentComponent<AnchorProps> = (props) => { const { locale } = useLocale(); const isExternal = () => /^[a-z][a-z0-9+.-]*:/i.test(props.href); const localizedHref = () => isExternal() ? props.href : getLocalizedUrl(props.href, locale()); return <A {...props} href={localizedHref()} />;};src/components/Nav.tsx复制代码复制代码到剪贴板
import { useIntlayer } from "solid-intlayer";import type { Component } from "solid-js";import { LocaleSwitcher } from "./LocaleSwitcher";import { LocalizedLink } from "./LocalizedLink";export const Nav: Component = () => { const content = useIntlayer("nav"); return ( <nav> <LocalizedLink href="/">{content.home}</LocalizedLink> <LocalizedLink href="/about">{content.about}</LocalizedLink> <LocaleSwitcher /> </nav> );};现在只需编写一次
href="/about",即可根据活动语言生成/about、/fr/about或/es/about—— 页面中的任何位置都无需手动添加前缀。创建语言切换器组件
将切换器渲染为**真实的 锚点**而非
<select>:当前页面的每种语言都会变为可爬取的链接,并且可以在新标签页中打开,这是仅依靠 JavaScript 的控件无法提供的。getPathWithoutLocale会从当前路径中剥离语言段,而getLocalizedUrl会为目标语言重新构建它,因此这些链接会遵循你的路由模式,无需硬编码任何内容。导航是改变渲染语言的原因 ——[[locale]]路由从 URL 中推导语言 —— 而setLocale会将选择保存在INTLAYER_LOCALEcookie 中,以便以后访问无语言前缀的 URL 时能解析为相同的语言。src/components/LocaleSwitcher.tsx复制代码复制代码到剪贴板
import { A, useLocation } from "@solidjs/router"; import { getHTMLTextDir, getLocaleName, getLocalizedUrl, getPathWithoutLocale, } from "intlayer"; import { useIntlayer, useLocale } from "solid-intlayer"; import { type Component, For } from "solid-js"; export const LocaleSwitcher: Component = () => { const content = useIntlayer("locale-switcher"); const location = useLocation(); const { locale, setLocale, availableLocales } = useLocale(); // 当前显示页面的规范(无语言段)路径 const pathWithoutLocale = () => getPathWithoutLocale(location.pathname); return ( <div> <button aria-label={content.label.value} popoverTarget="localePopover" type="button" > {getLocaleName(locale())} </button> <div id="localePopover" popover="auto"> <For each={availableLocales}> {(localeItem) => ( <A dir={getHTMLTextDir(localeItem)} // 仅精确定位,使默认语言链接不会在每个页面上都被标记为 active end href={getLocalizedUrl(pathWithoutLocale(), localeItem)} hreflang={localeItem} lang={localeItem} onClick={() => setLocale(localeItem)} // 确保浏览器的“后退”按钮返回到上一页 replace > {/* 各自语言下的语言名称 - 例如 Français */} {getLocaleName(localeItem)} </A> )} </For> </div> </div> ); };在 Solid 中,来自
useLocale的locale是一个 signal 访问器。使用带有括号的locale()响应式地读取其当前值。getLocaleName(localeItem)会以各自的语言渲染每种语言名称 ——English / Français / Español。传递第二个参数可以将其翻译为当前显示语言:例如getLocaleName(localeItem, locale())在英语中为English / French / Spanish,在法语中为anglais / français / espagnol。<A>已经在匹配当前 URL 的链接上设置了aria-current="page",因此无需额外添加处理。replace由路由器从渲染的属性中读取:它会替换历史记录条目而不是推入新条目,因此浏览器的“后退”按钮会返回切换前访问的页面,而不是返回前一种语言的同一页面。每个链接上的
dir和hreflang属性可使从右到左的语言名称保持正确的方向,并告知辅助技术和网络爬虫每个链接指向哪种语言。要了解有关
useLocale钩子的更多信息,请参阅文档。生成规范 canonical 和 hreflang 链接
可选hreflang注释告知搜索引擎/about、/fr/about和/es/about是不同语言下的同一个页面。getMultilingualUrls根据你的路由模式从规范(无语言段)路径中导出它们,因此无需硬编码任何内容:src/components/AlternateLinks.tsx复制代码复制代码到剪贴板
import { defaultLocale, getMultilingualUrls, getPathWithoutLocale,} from "intlayer";import { type Component, For } from "solid-js";export type AlternateLinksProps = { /** 正在渲染的页面的绝对 URL。 */ url: string;};export const AlternateLinks: Component<AlternateLinksProps> = (props) => { const multilingualUrls = () => { const { origin, pathname } = new URL(props.url); return Object.entries( getMultilingualUrls(`${origin}${getPathWithoutLocale(pathname)}`) ); }; const canonicalUrl = () => new URL(props.url).origin + new URL(props.url).pathname; return ( <> <link href={canonicalUrl()} rel="canonical" /> <For each={multilingualUrls()}> {([locale, localizedUrl]) => ( <link href={localizedUrl} hreflang={locale} rel="alternate" /> )} </For> <link href={ multilingualUrls().find(([locale]) => locale === defaultLocale)?.[1] } hreflang="x-default" rel="alternate" /> </> );};在可获取请求 URL 的文档 head 中渲染它:
src/entry-server.tsx复制代码复制代码到剪贴板
import { AlternateLinks } from "~/components/AlternateLinks";// … 在 <head> 内部,在其他 meta 标签旁边:<AlternateLinks url={url} />;随后
GET /fr/about将响应:html复制代码复制代码到剪贴板
<link href="https://example.com/fr/about" rel="canonical" /><link href="https://example.com/about" hreflang="en" rel="alternate" /><link href="https://example.com/fr/about" hreflang="fr" rel="alternate" /><link href="https://example.com/es/about" hreflang="es" rel="alternate" /><link href="https://example.com/about" hreflang="x-default" rel="alternate" />关于
@solidjs/meta的注意事项:在撰写本文时,@solidjs/meta中的<Title>和<Meta>在客户端水化后应用,但不会发散到 SolidStart v2 的服务端渲染<head>中。在 upstream 修复此问题之前,请直接在entry-server.tsx中渲染爬虫无需 JavaScript 即可看到的标签 ——canonical、hreflang以及需要的title/description,如上所示。处理未找到 (404) 页面
可选处于
src/routes根目录的通配符路由(splat route)可以捕获语言段未匹配到的所有路径 —— 包括被matchFilters拒绝的无效语言前缀。由于语言仍通过根布局来自 URL,因此 404 页面将以访问者的语言显示:src/routes/[...404].tsx复制代码复制代码到剪贴板
import { Title } from "@solidjs/meta";import { HttpStatusCode } from "@solidjs/start";import { useIntlayer } from "solid-intlayer";import { LocalizedLink } from "~/components/LocalizedLink";export default function NotFound() { const content = useIntlayer("not-found-page"); return ( <main> <Title>{content.metaTitle.value}</Title> <HttpStatusCode code={404} /> <h1>{content.title}</h1> <LocalizedLink href="/">{content.backHome}</LocalizedLink> </main> );}显示表格的所有内容在弹窗中打开表格以清晰地查看所有数据
请求 预期响应 /xx404—xx不是已配置的语言/nonexistent默认语言下的 404/fr/nonexistent法语下的 404(Page introuvable)生成多语言 sitemap 站点地图
可选Intlayer 的 sitemap 生成器将每个路径扩展为每个语言对应一个条目,并在它们之间连接
xhtml:link备用链接,因此路由只需列出规范的、无语言前缀的路径。与仅生成平铺 URL 的基础生成器不同,Intlayer 在每个页面的每个本地化变体之间建立双向链接,这有助于搜索引擎关联本地化 URL 并将正确的页面提供给正确的受众。
SolidStart 将导出 HTTP 方法的文件转换为 API 路由,并从路径中剥离
.ts扩展名 —— 因此src/routes/sitemap.xml.ts在/sitemap.xml处提供服务:src/routes/sitemap.xml.ts复制代码复制代码到剪贴板
import type { APIEvent } from "@solidjs/start/server"; import { generateSitemap } from "intlayer"; const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000"; export const GET = (_event: APIEvent) => { const sitemap = generateSitemap( [ { path: "/", changefreq: "daily", priority: 1.0 }, { path: "/about", changefreq: "monthly", priority: 0.8 }, ], { siteUrl: SITE_URL } ); return new Response(sitemap, { headers: { "Content-Type": "application/xml" }, }); };output of GET /sitemap.xml复制代码复制代码到剪贴板
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <url> <loc>https://example.com/about</loc> <changefreq>monthly</changefreq> <priority>0.8</priority> <xhtml:link rel="alternate" hreflang="en" href="https://example.com/about"/> <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/about"/> <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/about"/> <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/about"/> </url></urlset>API 路由不支持可选参数,因此请将此文件保留在
src/routes的根目录下,置于[[locale]]段之外。sitemap 已经包含了每种语言。你可以使用
getMultilingualUrls以相同方式构建robots.txt,以便Disallow条目涵盖敏感路径的每个本地化拼写:src/routes/robots.txt.ts复制代码复制代码到剪贴板
import { getMultilingualUrls } from "intlayer"; const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000"; const disallowedPaths = ["/admin", "/private"].flatMap((path) => Object.values(getMultilingualUrls(path)) ); export const GET = () => new Response( [ "User-agent: *", "Allow: /", ...disallowedPaths.map((path) => `Disallow: ${path}`), "", `Sitemap: ${SITE_URL}/sitemap.xml`, ].join("\n"), { headers: { "Content-Type": "text/plain" } } );在服务端函数中检索语言 locale
可选你可能希望在服务端函数或 API 路由内部访问当前语言 locale。
在像这样基于前缀的设置中,URL 具有权威性:
getLocaleFromPath从请求 URL 中读取前缀。getLocale是不带语言前缀的请求的回退机制 —— 它会检查INTLAYER_LOCALEcookie,然后检查x-intlayer-locale请求头,接着协商Accept-Language。src/routes/[[locale]]/index.tsx复制代码复制代码到剪贴板
import { createAsync } from "@solidjs/router";import { getCookie, getIntlayer, getLocale, getLocaleFromPath } from "intlayer";import { getRequestEvent } from "solid-js/web";const loadLocalizedData = async () => { "use server"; const request = getRequestEvent()?.request; const locale = getLocaleFromPath(request?.url) ?? (await getLocale({ // 从请求中获取 cookie (默认为 'INTLAYER_LOCALE') getCookie: (name) => getCookie(name, request?.headers.get("cookie") ?? ""), // 从请求中获取 header (默认为 'x-intlayer-locale'), // 回退到 Accept-Language 协商 getHeader: (name) => request?.headers.get(name) ?? undefined, })); // 使用 getIntlayer() 在组件外部检索部分内容 const content = getIntlayer("home-page", locale); return { locale, title: String(content.title) };};export default function Page() { const data = createAsync(() => loadLocalizedData()); return <p>{data()?.title}</p>;}此处不要仅依赖
getLocale:仅当访问者主动切换语言时才会写入语言 cookie,因此首次访问/fr/...将会被解析为默认语言。提取组件的内容
可选如果你有一个现有的代码库,转换数千个文件可能会非常耗时。
为了简化此过程,Intlayer 提议使用 编译器 (compiler) / 提取器 (extractor) 来转换组件并提取内容。
要进行设置,你可以在
intlayer.config.ts文件中添加一个compiler部分:intlayer.config.ts复制代码复制代码到剪贴板
import { type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { // ... 其他配置 compiler: { /** * 指示是否启用编译器。 */ enabled: true, /** * 定义输出文件路径 */ output: ({ fileName, extension }) => `./${fileName}${extension}`, /** * 指示在转换组件后是否应保存组件。 * * - 如果为 `true`,编译器将在磁盘中重写组件文件。因此转换将是永久性的,编译器在下一次进程中将跳过该转换。通过这种方式,编译器可以转换应用,然后将其移除。 * * - 如果为 `false`,编译器将仅在构建输出的代码中注入 `useIntlayer()` 函数调用,并保持基础代码库完好。转换将仅在内存中完成。 */ saveComponents: false, /** * 字典键前缀 */ dictionaryKeyPrefix: "", }, }; export default config;运行提取器以转换组件并提取内容
bash复制代码复制代码到剪贴板
npx intlayer extract之后,将生成的页面内容文件移出
src/routes,原因如步骤 5 所述。配置 TypeScript
Intlayer 使用模块增强 (module augmentation) 来获得 TypeScript 的优势并增强你的代码库。
确保你的 TypeScript 配置包含自动生成的类型:
tsconfig.json复制代码复制代码到剪贴板
{ compilerOptions: { // ... 你现有的配置 }, include: [ "src", "*.ts", ".intlayer/**/*.ts", // 包含自动生成的类型 ],}字典键和内容路径现在会在编译时进行检查:
tsx复制代码复制代码到剪贴板
useIntlayer("home-page"); // ✅useIntlayer("hom-page"); // ❌ Argument of type '"hom-page"' is not assignable to parameter of type 'keyof __DictionaryRegistry'
验证你的设置
构建并启动服务器,然后检查这些请求是否按预期运行:
复制代码到剪贴板
npm run buildnode .output/server/index.mjs在弹窗中打开表格以清晰地查看所有数据
| 请求 | 预期响应 |
|---|---|
GET / | 200 — 英语 |
GET / 带有 Accept-Language: fr | 302 → /fr |
GET / 带有 cookie INTLAYER_LOCALE=es | 302 → /es |
GET /fr | 200 — 法语, <html lang="fr"> |
GET /fr/about | 200 — 法语关于页面 |
GET /en/about | 302 → /about (规范重定向) |
GET /xx | 404 |
GET /fr/nonexistent | 404 法语 |
GET /sitemap.xml | 200 — 多语言 XML sitemap |
在 vite dev 下渲染页面的行行为相同。除非你自己将句柄注册为中间件,否则三个重定向行仅适用于构建后的服务器 —— 参见步骤 3。
请在 Node (vite dev) 上运行开发服务器,而不是在 Bun (bun --bun vite dev) 上:SolidStart 的 SSR 目前在 Bun 运行时下会失败并显示Expected a Response object, but received 'NodeResponse'。这与 Intlayer 无关 —— 它在纯模板上也会复现 —— 并且只影响开发服务器,不影响vite build。
Git 配置
建议忽略由 Intlayer 生成的文件。这可以让你避免将它们提交到 Git 仓库。
为此,你可以将以下指令添加到你的 .gitignore 文件中:
复制代码到剪贴板
# 忽略 Intlayer 生成的文件.intlayerVS Code 插件
为了提升你使用 Intlayer 的开发体验,你可以安装官方的 Intlayer VS Code 插件。
此插件提供:
- 翻译键的自动补全。
- 缺失翻译的实时错误检测。
- 翻译内容的行内预览。
- 轻松创建和更新翻译的快速操作。
深入了解
要进一步了解,你可以实现可视化编辑器或使用 CMS 外包你的内容。