i18n-inlang-localization

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

i18n / Inlang / Localization

i18n / Inlang / 应用本地化

ConcernSection
Inlang framework — projects, plugins, validation, ICU message formatInlang
/translate
slash command — quick translation workflow
Translate workflow

关注点章节
Inlang框架 — 项目、插件、校验、ICU消息格式Inlang
/translate
斜杠命令 — 快速翻译工作流
Translate workflow

Inlang

Inlang

inlang CLI

inlang 命令行工具

Automate localization tasks with
@inlang/cli
. Machine translate missing messages, validate configs, and build plugins.
bash
npx @inlang/cli [command]
Minimum Node: v18.0.0. Use
@latest
to ensure current version:
npx @inlang/cli@latest [command]
.
使用
@inlang/cli
自动化本地化任务,包括机器翻译缺失的消息、校验配置以及构建插件。
bash
npx @inlang/cli [command]
最低Node版本要求:v18.0.0。使用
@latest
确保获取最新版本:
npx @inlang/cli@latest [command]

Project Setup

项目配置

An inlang project requires a
project.inlang/
folder with
settings.json
:
my-app/
├── project.inlang/
│   └── settings.json
├── messages/
│   ├── en.json          # Source language
│   └── de.json          # Translations
└── src/
一个inlang项目需要包含
settings.json
文件的
project.inlang/
目录:
my-app/
├── project.inlang/
│   └── settings.json
├── messages/
│   ├── en.json          # 源语言
│   └── de.json          # 翻译文件
└── src/

settings.json

settings.json

json
{
  "$schema": "https://inlang.com/schema/project-settings",
  "baseLocale": "en",
  "locales": ["en", "de", "fr"],
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@latest/dist/index.js"
  ],
  "plugin.inlang.json": {
    "pathPattern": "./messages/{locale}.json"
  }
}
Supported plugins: JSON, i18next, next-intl, ICU message format.
json
{
  "$schema": "https://inlang.com/schema/project-settings",
  "baseLocale": "en",
  "locales": ["en", "de", "fr"],
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@latest/dist/index.js"
  ],
  "plugin.inlang.json": {
    "pathPattern": "./messages/{locale}.json"
  }
}
支持的插件:JSON、i18next、next-intl、ICU消息格式。

Base translation file (messages/en.json)

基准翻译文件(messages/en.json)

json
{
  "greeting": "Hello {name}!",
  "welcome": "Welcome to our app"
}
json
{
  "greeting": "Hello {name}!",
  "welcome": "Welcome to our app"
}

Quick Reference

快速参考

TaskCommand
Machine translate all
npx @inlang/cli machine translate --project ./project.inlang
Translate specific locales
npx @inlang/cli machine translate --targetLocales sk,zh,pt-BR
Translate (CI, no prompt)
npx @inlang/cli machine translate -f
Validate project
npx @inlang/cli validate --project ./project.inlang
Build a plugin
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist
Build plugin (watch)
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist --watch
Lint translations
npx @inlang/cli lint
Open inlang ecosystem
npx @inlang/cli open [command]
任务命令
机器翻译所有缺失内容
npx @inlang/cli machine translate --project ./project.inlang
翻译指定语言
npx @inlang/cli machine translate --targetLocales sk,zh,pt-BR
翻译(CI环境,无交互提示)
npx @inlang/cli machine translate -f
校验项目配置
npx @inlang/cli validate --project ./project.inlang
构建插件
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist
构建插件(监听模式)
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist --watch
检查翻译文件
npx @inlang/cli lint
打开inlang生态系统
npx @inlang/cli open [command]

Commands

命令详情

machine translate

machine translate

Translates all missing messages. Uses inlang's free translation service by default; supports Google Cloud Translation for higher reliability.
bash
npx @inlang/cli machine translate [options]
OptionDescription
-f, --force
Skip confirmation prompt (for CI/CD)
--project <path>
Path to project root (default: cwd)
--locale <source>
Base locale override
--targetLocales <targets...>
Comma-separated target locales (e.g.
sk,zh,pt-BR
)
翻译所有缺失的消息内容。默认使用inlang免费翻译服务,也支持Google Cloud Translation以获得更高可靠性。
bash
npx @inlang/cli machine translate [options]
选项说明
-f, --force
跳过确认提示(适用于CI/CD流水线)
--project <path>
项目根路径(默认:当前工作目录)
--locale <source>
覆盖基准语言设置
--targetLocales <targets...>
逗号分隔的目标语言(例如:
sk,zh,pt-BR

validate

validate

Checks project config is correct.
bash
npx @inlang/cli validate --project ./path/to/project.inlang
OptionDescription
--project <path>
Path to project root (default: cwd)
检查项目配置是否正确。
bash
npx @inlang/cli validate --project ./path/to/project.inlang
选项说明
--project <path>
项目根路径(默认:当前工作目录)

lint

lint

Lint translation files for issues.
bash
npx @inlang/cli lint [options]
检查翻译文件中的问题。
bash
npx @inlang/cli lint [options]

plugin build

plugin build

Build an inlang module (plugin development).
bash
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist
OptionDescription
--entry <path>
Entry point (e.g.
src/index.ts
)
--outdir <path>
Output directory (default:
./dist
)
--watch
Watch mode for development
构建inlang模块(插件开发场景)。
bash
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist
选项说明
--entry <path>
入口文件(例如:
src/index.ts
--outdir <path>
输出目录(默认:
./dist
--watch
开发监听模式

CI/CD Integration

CI/CD集成

Always use
--force
(
-f
) in pipelines to skip interactive prompts:
bash
npx @inlang/cli machine translate -f --project ./project.inlang
npx @inlang/cli validate --project ./project.inlang
在流水线中请务必使用
--force
-f
)参数跳过交互提示:
bash
npx @inlang/cli machine translate -f --project ./project.inlang
npx @inlang/cli validate --project ./project.inlang

Common Mistakes

常见问题

MistakeFix
"Command not found"Use
npx @inlang/cli@latest
to get latest version
Missing translations after translateCheck
pathPattern
in settings.json matches actual file paths
Validation failsEnsure
project.inlang/settings.json
exists and
modules
URLs are valid
Wrong locales translatedUse
--targetLocales
to specify exact targets
Node version errorRequires Node v18.0.0+
m.section_key()
doesn't exist (TS error)
Nested JSON keys require bracket notation:
m["section.key"]()
not
m.section_key()
. See Paraglide Naming Gotcha below
oto
locale fails machine translate
Otomi not supported by Google Translate — translate manually or skip
问题解决方法
"Command not found"使用
npx @inlang/cli@latest
获取最新版本
翻译后仍存在缺失内容检查settings.json中的
pathPattern
是否与实际文件路径匹配
校验失败确保
project.inlang/settings.json
存在且
modules
中的URL有效
翻译了错误的语言使用
--targetLocales
指定精确的目标语言
Node版本错误需要Node v18.0.0及以上版本
m.section_key()
不存在(TS错误)
嵌套JSON键需要使用括号语法
m["section.key"]()
而非
m.section_key()
。详见下方Paraglide命名陷阱
oto
语言机器翻译失败
Otomi语言不被Google Translate支持,请手动翻译或跳过

Paraglide Naming Gotcha: Nested JSON Keys

Paraglide命名陷阱:嵌套JSON键

This is the #1 source of errors when migrating from i18next to Paraglide with
plugin-json
.
When
plugin-json
reads nested JSON:
json
{ "navbar": { "moreOptions": "More options" } }
It flattens to key
"navbar.moreOptions"
. Paraglide then generates:
js
// Internal variable is lowercased + dedup suffix
const navbar_moreoptions1 = ...
// But the PUBLIC export preserves the original dot-separated key
export { navbar_moreoptions1 as "navbar.moreOptions" }
Correct usage — bracket notation required:
tsx
import * as m from "@/paraglide/messages";

// ✅ CORRECT — original key with dots, bracket notation
m["navbar.moreOptions"]()
m["common.back"]()
m["auth.page.emailLabel"]()

// ❌ WRONG — underscore style does NOT exist as an export
m.navbar_moreOptions()    // Property does not exist
m.navbar_moreoptions1()   // Internal name, not exported
Alternative — use
plugin-message-format
with flat keys:
If you want
m.navbar_share()
style (dot-accessible), use flat underscore keys in your JSON with
plugin-message-format
instead of
plugin-json
:
json
{
  "$schema": "https://inlang.com/schema/inlang-message-format",
  "navbar_share": "Share",
  "common_back": "Back"
}
This generates
m.navbar_share()
directly — no bracket notation needed.
Rule of thumb:
  • Nested JSON +
    plugin-json
    m["section.key"]()
  • Flat JSON +
    plugin-message-format
    m.flat_key()
这是从i18next迁移到使用
plugin-json
的Paraglide时最常见的错误来源。
plugin-json
读取嵌套JSON时:
json
{ "navbar": { "moreOptions": "More options" } }
它会将其扁平化为键
"navbar.moreOptions"
。Paraglide随后会生成:
js
// 内部变量为小写+去重后缀
const navbar_moreoptions1 = ...
// 但公开导出的内容保留原始点分隔键
export { navbar_moreoptions1 as "navbar.moreOptions" }
正确用法 — 必须使用括号语法:
tsx
import * as m from "@/paraglide/messages";

// ✅ 正确 — 使用原始带点的键和括号语法
m["navbar.moreOptions"]()
m["common.back"]()
m["auth.page.emailLabel"]()

// ❌ 错误 — 下划线样式的导出不存在
m.navbar_moreOptions()    // 属性不存在
m.navbar_moreoptions1()   // 内部名称,未公开导出
替代方案 — 使用
plugin-message-format
和平坦键:
如果您希望使用
m.navbar_share()
样式(点访问),请在JSON中使用扁平下划线键,并搭配
plugin-message-format
而非
plugin-json
json
{
  "$schema": "https://inlang.com/schema/inlang-message-format",
  "navbar_share": "Share",
  "common_back": "Back"
}
这会直接生成
m.navbar_share()
— 无需使用括号语法。
经验法则:
  • 嵌套JSON +
    plugin-json
    m["section.key"]()
  • 扁平JSON +
    plugin-message-format
    m.flat_key()

Paraglide JS Integration (Vite + React)

Paraglide JS集成(Vite + React)

Paraglide JS (
@inlang/paraglide-js
) compiles inlang messages into tree-shakeable, type-safe functions. Works with CSR, SSR, and SSG. Tested as part of TanStack's CI/CD pipeline.
Paraglide JS (
@inlang/paraglide-js
) 将inlang消息编译为可摇树优化、类型安全的函数。支持客户端渲染(CSR)、服务端渲染(SSR)和静态站点生成(SSG),已在TanStack的CI/CD流水线中测试验证。

Quick Start

快速开始

bash
npx @inlang/paraglide-js@latest init
This creates the
project.inlang/
folder and configures your project. Then add the Vite plugin:
ts
// vite.config.ts
import { paraglideVitePlugin } from '@inlang/paraglide-js'

export default defineConfig({
  plugins: [
    paraglideVitePlugin({
      project: './project.inlang',
      outdir: './src/paraglide',
    }),
    // ... other plugins (tanstackRouter, react, etc.)
  ],
})
bash
npx @inlang/paraglide-js@latest init
此命令会创建
project.inlang/
目录并配置您的项目。然后添加Vite插件:
ts
// vite.config.ts
import { paraglideVitePlugin } from '@inlang/paraglide-js'

export default defineConfig({
  plugins: [
    paraglideVitePlugin({
      project: './project.inlang',
      outdir: './src/paraglide',
    }),
    // ... 其他插件(tanstackRouter、react等)
  ],
})

Vite Plugin Config (Full)

Vite插件完整配置

For localized URLs with locale-prefixed paths:
ts
paraglideVitePlugin({
  project: './project.inlang',
  outdir: './src/paraglide',
  outputStructure: 'message-modules',
  cookieName: 'PARAGLIDE_LOCALE',
  strategy: ['url', 'cookie', 'preferredLanguage', 'baseLocale'],
  urlPatterns: [
    {
      pattern: '/',
      localized: [
        ['en', '/'],
        ['de', '/de'],
      ],
    },
    {
      pattern: '/about',
      localized: [
        ['en', '/about'],
        ['de', '/de/ueber'],
      ],
    },
    {
      pattern: '/:path(.*)?',
      localized: [
        ['en', '/:path(.*)?'],
        ['de', '/de/:path(.*)?'],
      ],
    },
  ],
})
对于带语言前缀路径的本地化URL:
ts
paraglideVitePlugin({
  project: './project.inlang',
  outdir: './src/paraglide',
  outputStructure: 'message-modules',
  cookieName: 'PARAGLIDE_LOCALE',
  strategy: ['url', 'cookie', 'preferredLanguage', 'baseLocale'],
  urlPatterns: [
    {
      pattern: '/',
      localized: [
        ['en', '/'],
        ['de', '/de'],
      ],
    },
    {
      pattern: '/about',
      localized: [
        ['en', '/about'],
        ['de', '/de/ueber'],
      ],
    },
    {
      pattern: '/:path(.*)?',
      localized: [
        ['en', '/:path(.*)?'],
        ['de', '/de/:path(.*)?'],
      ],
    },
  ],
})

settings.json for Paraglide

Paraglide对应的settings.json

Uses
plugin-message-format
instead of
plugin-json
:
json
{
  "$schema": "https://inlang.com/schema/project-settings",
  "baseLocale": "en",
  "locales": ["en", "de"],
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
  ],
  "plugin.inlang.messageFormat": {
    "pathPattern": "./messages/{locale}.json"
  }
}
Message files use
inlang-message-format
schema:
json
{
  "$schema": "https://inlang.com/schema/inlang-message-format",
  "example_message": "Hello world {username}",
  "home_page": "Home page",
  "about_page": "About page"
}
使用
plugin-message-format
而非
plugin-json
json
{
  "$schema": "https://inlang.com/schema/project-settings",
  "baseLocale": "en",
  "locales": ["en", "de"],
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
  ],
  "plugin.inlang.messageFormat": {
    "pathPattern": "./messages/{locale}.json"
  }
}
消息文件使用
inlang-message-format
schema:
json
{
  "$schema": "https://inlang.com/schema/inlang-message-format",
  "example_message": "Hello world {username}",
  "home_page": "Home page",
  "about_page": "About page"
}

TanStack Router i18n with URL Rewrites (CSR)

TanStack Router i18n与URL重写(客户端渲染)

Use the
rewrite
API to de-localize URLs for route matching and re-localize for display:
tsx
// src/main.tsx
import { createRouter } from '@tanstack/react-router'
import { deLocalizeUrl, localizeUrl } from './paraglide/runtime.js'

const router = createRouter({
  routeTree,
  rewrite: {
    input: ({ url }) => deLocalizeUrl(url),
    output: ({ url }) => localizeUrl(url),
  },
})
Handle redirects in root route to prevent infinite redirect loops (required for offline/CSR apps):
tsx
// src/routes/__root.tsx
import { redirect, createRootRoute } from '@tanstack/react-router'
import { getLocale, setLocale, locales, shouldRedirect } from '@/paraglide/runtime'
import { m } from '@/paraglide/messages'

export const Route = createRootRoute({
  beforeLoad: async () => {
    document.documentElement.setAttribute('lang', getLocale())
    const decision = await shouldRedirect({ url: window.location.href })
    if (decision.redirectUrl) {
      throw redirect({ href: decision.redirectUrl.href })
    }
  },
  component: () => (
    <>
      <Link to="/">{m.home_page()}</Link>
      <Link to="/about">{m.about_page()}</Link>
      {locales.map((locale) => (
        <button key={locale} onClick={() => setLocale(locale)}>
          {locale}
        </button>
      ))}
      <Outlet />
    </>
  ),
})
使用
rewrite
API移除URL中的语言前缀以匹配路由,并在显示时重新添加语言前缀:
tsx
// src/main.tsx
import { createRouter } from '@tanstack/react-router'
import { deLocalizeUrl, localizeUrl } from './paraglide/runtime.js'

const router = createRouter({
  routeTree,
  rewrite: {
    input: ({ url }) => deLocalizeUrl(url),
    output: ({ url }) => localizeUrl(url),
  },
})
在根路由中处理重定向以避免无限重定向循环(离线/客户端渲染应用必需):
tsx
// src/routes/__root.tsx
import { redirect, createRootRoute } from '@tanstack/react-router'
import { getLocale, setLocale, locales, shouldRedirect } from '@/paraglide/runtime'
import { m } from '@/paraglide/messages'

export const Route = createRootRoute({
  beforeLoad: async () => {
    document.documentElement.setAttribute('lang', getLocale())
    const decision = await shouldRedirect({ url: window.location.href })
    if (decision.redirectUrl) {
      throw redirect({ href: decision.redirectUrl.href })
    }
  },
  component: () => (
    <>
      <Link to="/">{m.home_page()}</Link>
      <Link to="/about">{m.about_page()}</Link>
      {locales.map((locale) => (
        <button key={locale} onClick={() => setLocale(locale)}>
          {locale}
        </button>
      ))}
      <Outlet />
    </>
  ),
})

TanStack Start SSR Integration

TanStack Start服务端渲染集成

For server-side rendering, intercept requests with
paraglideMiddleware
:
ts
// server.ts
import { paraglideMiddleware } from './paraglide/server.js'
import handler from '@tanstack/react-start/server-entry'

export default {
  fetch(req: Request): Promise<Response> {
    return paraglideMiddleware(req, ({ request }) => handler.fetch(request))
  },
}
Set HTML lang attribute in root document:
tsx
import { getLocale } from '../paraglide/runtime.js'

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html lang={getLocale()}>
      <head><HeadContent /></head>
      <body>
        {children}
        <Scripts />
      </body>
    </html>
  )
}
对于服务端渲染,使用
paraglideMiddleware
拦截请求:
ts
// server.ts
import { paraglideMiddleware } from './paraglide/server.js'
import handler from '@tanstack/react-start/server-entry'

export default {
  fetch(req: Request): Promise<Response> {
    return paraglideMiddleware(req, ({ request }) => handler.fetch(request))
  },
}
在根文档中设置HTML lang属性:
tsx
import { getLocale } from '../paraglide/runtime.js'

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html lang={getLocale()}>
      <head><HeadContent /></head>
      <body>
        {children}
        <Scripts />
      </body>
    </html>
  )
}

Typesafe Translated Pathnames

类型安全的翻译路径名

Ensure every route has translations by deriving
urlPatterns
from the generated route tree:
ts
import { Locale } from '@/paraglide/runtime'
import { FileRoutesByTo } from '../routeTree.gen'

type RoutePath = keyof FileRoutesByTo

function toUrlPattern(path: string) {
  return path
    .replace(/\/\$/, '/:path(.*)?')           // catch-all
    .replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?') // optional params
    .replace(/\$([a-zA-Z0-9_]+)/g, ':$1')       // named params
    .replace(/\/+$/, '')                          // trailing slash
}

function createTranslatedPathnames(
  input: Record<RoutePath, Record<Locale, string>>,
) {
  return Object.entries(input).map(([pattern, locales]) => ({
    pattern: toUrlPattern(pattern),
    localized: Object.entries(locales).map(
      ([locale, path]) => [locale as Locale, `/${locale}${toUrlPattern(path)}`],
    ),
  }))
}

export const translatedPathnames = createTranslatedPathnames({
  '/': { en: '/', de: '/' },
  '/about': { en: '/about', de: '/ueber' },
})
Import
translatedPathnames
into
urlPatterns
in the Paraglide Vite plugin config.
通过从生成的路由树中推导
urlPatterns
,确保每个路由都有对应的翻译:
ts
import { Locale } from '@/paraglide/runtime'
import { FileRoutesByTo } from '../routeTree.gen'

type RoutePath = keyof FileRoutesByTo

function toUrlPattern(path: string) {
  return path
    .replace(/\/\$/, '/:path(.*)?')           // 捕获所有
    .replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?') // 可选参数
    .replace(/\$([a-zA-Z0-9_]+)/g, ':$1')       // 命名参数
    .replace(/\/+$/, '')                          // 移除末尾斜杠
}

function createTranslatedPathnames(
  input: Record<RoutePath, Record<Locale, string>>,
) {
  return Object.entries(input).map(([pattern, locales]) => ({
    pattern: toUrlPattern(pattern),
    localized: Object.entries(locales).map(
      ([locale, path]) => [locale as Locale, `/${locale}${toUrlPattern(path)}`],
    ),
  }))
}

export const translatedPathnames = createTranslatedPathnames({
  '/': { en: '/', de: '/' },
  '/about': { en: '/about', de: '/ueber' },
})
translatedPathnames
导入到Paraglide Vite插件配置的
urlPatterns
中。

Prerendering Localized Routes

预渲染本地化路由

Use
localizeHref
to generate localized versions for static prerendering. Compile Paraglide before build with the CLI:
ts
import { localizeHref } from './paraglide/runtime'

export const prerenderRoutes = ['/', '/about'].map((path) => ({
  path: localizeHref(path),
  prerender: { enabled: true },
}))
使用
localizeHref
生成本地化版本以用于静态预渲染。在构建前使用CLI编译Paraglide:
ts
import { localizeHref } from './paraglide/runtime'

export const prerenderRoutes = ['/', '/about'].map((path) => ({
  path: localizeHref(path),
  prerender: { enabled: true },
}))

Key Paraglide APIs

核心Paraglide API

ImportPurpose
m.message_key()
Access translated message (type-safe)
m.message_key({ var })
Message with interpolation
getLocale()
Get current locale
setLocale(locale)
Switch locale
locales
Array of available locales
shouldRedirect({ url })
Check if URL needs locale redirect
deLocalizeUrl(url)
Strip locale prefix for route matching
localizeUrl(url)
Add locale prefix for display
localizeHref(path)
Localize a path for prerendering
paraglideMiddleware(req, handler)
SSR middleware (from
./paraglide/server.js
)
导入内容用途
m.message_key()
访问翻译后的消息(类型安全)
m.message_key({ var })
带插值的消息
getLocale()
获取当前语言
setLocale(locale)
切换语言
locales
可用语言数组
shouldRedirect({ url })
检查URL是否需要语言重定向
deLocalizeUrl(url)
移除语言前缀以匹配路由
localizeUrl(url)
添加语言前缀用于显示
localizeHref(path)
本地化路径以用于预渲染
paraglideMiddleware(req, handler)
SSR中间件(来自
./paraglide/server.js

Project Structure (Paraglide)

Paraglide项目结构

my-app/
├── project.inlang/
│   ├── settings.json
│   ├── project_id         # Auto-generated
│   └── .gitignore          # Contains: cache
├── messages/
│   ├── en.json
│   └── de.json
├── src/
│   ├── paraglide/          # Generated (gitignored)
│   │   ├── runtime.js
│   │   ├── messages.js
│   │   └── server.js       # SSR only
│   ├── routes/
│   │   ├── __root.tsx
│   │   ├── index.tsx
│   │   └── about.tsx
│   └── main.tsx
├── server.ts               # SSR only
└── vite.config.ts
my-app/
├── project.inlang/
│   ├── settings.json
│   ├── project_id         # 自动生成
│   └── .gitignore          # 包含:cache
├── messages/
│   ├── en.json
│   └── de.json
├── src/
│   ├── paraglide/          # 生成文件(已加入git忽略)
│   │   ├── runtime.js
│   │   ├── messages.js
│   │   └── server.js       # 仅SSR场景使用
│   ├── routes/
│   │   ├── __root.tsx
│   │   ├── index.tsx
│   │   └── about.tsx
│   └── main.tsx
├── server.ts               # 仅SSR场景使用
└── vite.config.ts

VS Code Extension

VS Code扩展

Add
.vscode/extensions.json
:
json
{
  "recommendations": ["inlang.vs-code-extension"]
}
添加
.vscode/extensions.json
json
{
  "recommendations": ["inlang.vs-code-extension"]
}

Installation (optional)

安装(可选)

bash
npm install -D @inlang/cli    # project-scoped (recommended)
yarn add --dev @inlang/cli     # yarn alternative
Using
npx
without installing is preferred — scopes version to project and works for all team members automatically.

bash
npm install -D @inlang/cli    # 项目级安装(推荐)
yarn add --dev @inlang/cli     # yarn替代方案
推荐使用
npx
而不进行全局安装 — 这样可以将版本限定在项目范围内,且所有团队成员都能自动使用正确版本。

Translate workflow

翻译工作流

You are a professional translator. Translate/Synchronize the following MDX content from English to cn. Preserve all Markdown formatting, code blocks, and component tags. Do not translate code inside code blocks or component names. Filename for <name>.mdx (English) = <name>.cn.mdx (Chinese) The content is in .mdx format, which combines Markdown with JSX components.
您是专业翻译人员,请将以下MDX内容从英文翻译/同步为中文。保留所有Markdown格式、代码块和组件标签,不要翻译代码块内的代码或组件名称。 英文文件<name>.mdx对应中文文件<name>.cn.mdx 内容采用MDX格式,融合了Markdown与JSX组件。

Important Notice

重要说明

  1. Only translate/sync the DIFF - Compare English source with existing Chinese translation, only update changed parts. DO NOT re-translate the entire file.
  2. DO NOT remove any content.
  3. You can translate the title markdown ## Plugin Context.
For Example: <APIItem name="extendApi" type="function"> xxxx content
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;
</APIItem>
After translate: <APIItem name="extendApi" type="function"> xxxx 内容
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;
</APIItem>
  1. 仅翻译/同步差异内容 - 对比英文源文件与现有中文翻译,仅更新变更部分,请勿重新翻译整个文件。
  2. 请勿删除任何内容。
  3. 您可以翻译标题Markdown内容,例如## Plugin Context。
示例: <APIItem name="extendApi" type="function"> xxxx content
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;
</APIItem>
翻译后: <APIItem name="extendApi" type="function"> xxxx 内容
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;
</APIItem>

How to Determine Which Files Need to Be Updated

如何确定需要更新的文件

Calculate: today's date - last document modification date = days
bash
./tooling/scripts/list-translate-files.sh [days]
Example: today is 2026-01-01, last date is 2025-08-01 → ~153 days
bash
./tooling/scripts/list-translate-files.sh 153
Last document modification date: 2026-01-18 (After completing the translation, automatically update this date to today's date.)
计算方式:当前日期 - 文档最后修改日期 = 天数
bash
./tooling/scripts/list-translate-files.sh [days]
示例:当前日期为2026-01-01,最后修改日期为2025-08-01 → 约153天
bash
./tooling/scripts/list-translate-files.sh 153
文档最后修改日期:2026-01-18(完成翻译后,请自动将此日期更新为当前日期。)