i18n-inlang-localization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesei18n / Inlang / Localization
i18n / Inlang / 应用本地化
| Concern | Section |
|---|---|
| Inlang framework — projects, plugins, validation, ICU message format | Inlang |
| Translate workflow |
| 关注点 | 章节 |
|---|---|
| Inlang框架 — 项目、插件、校验、ICU消息格式 | Inlang |
| Translate workflow |
Inlang
Inlang
inlang CLI
inlang 命令行工具
Automate localization tasks with . Machine translate missing messages, validate configs, and build plugins.
@inlang/clibash
npx @inlang/cli [command]Minimum Node: v18.0.0. Use to ensure current version: .
@latestnpx @inlang/cli@latest [command]使用自动化本地化任务,包括机器翻译缺失的消息、校验配置以及构建插件。
@inlang/clibash
npx @inlang/cli [command]最低Node版本要求:v18.0.0。使用确保获取最新版本:。
@latestnpx @inlang/cli@latest [command]Project Setup
项目配置
An inlang project requires a folder with :
project.inlang/settings.jsonmy-app/
├── project.inlang/
│ └── settings.json
├── messages/
│ ├── en.json # Source language
│ └── de.json # Translations
└── src/一个inlang项目需要包含文件的目录:
settings.jsonproject.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
快速参考
| Task | Command |
|---|---|
| Machine translate all | |
| Translate specific locales | |
| Translate (CI, no prompt) | |
| Validate project | |
| Build a plugin | |
| Build plugin (watch) | |
| Lint translations | |
| Open inlang ecosystem | |
| 任务 | 命令 |
|---|---|
| 机器翻译所有缺失内容 | |
| 翻译指定语言 | |
| 翻译(CI环境,无交互提示) | |
| 校验项目配置 | |
| 构建插件 | |
| 构建插件(监听模式) | |
| 检查翻译文件 | |
| 打开inlang生态系统 | |
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]| Option | Description |
|---|---|
| Skip confirmation prompt (for CI/CD) |
| Path to project root (default: cwd) |
| Base locale override |
| Comma-separated target locales (e.g. |
翻译所有缺失的消息内容。默认使用inlang免费翻译服务,也支持Google Cloud Translation以获得更高可靠性。
bash
npx @inlang/cli machine translate [options]| 选项 | 说明 |
|---|---|
| 跳过确认提示(适用于CI/CD流水线) |
| 项目根路径(默认:当前工作目录) |
| 覆盖基准语言设置 |
| 逗号分隔的目标语言(例如: |
validate
validate
Checks project config is correct.
bash
npx @inlang/cli validate --project ./path/to/project.inlang| Option | Description |
|---|---|
| Path to project root (default: cwd) |
检查项目配置是否正确。
bash
npx @inlang/cli validate --project ./path/to/project.inlang| 选项 | 说明 |
|---|---|
| 项目根路径(默认:当前工作目录) |
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| Option | Description |
|---|---|
| Entry point (e.g. |
| Output directory (default: |
| Watch mode for development |
构建inlang模块(插件开发场景)。
bash
npx @inlang/cli plugin build --entry ./src/index.ts --outdir ./dist| 选项 | 说明 |
|---|---|
| 入口文件(例如: |
| 输出目录(默认: |
| 开发监听模式 |
CI/CD Integration
CI/CD集成
Always use () in pipelines to skip interactive prompts:
--force-fbash
npx @inlang/cli machine translate -f --project ./project.inlang
npx @inlang/cli validate --project ./project.inlang在流水线中请务必使用()参数跳过交互提示:
--force-fbash
npx @inlang/cli machine translate -f --project ./project.inlang
npx @inlang/cli validate --project ./project.inlangCommon Mistakes
常见问题
| Mistake | Fix |
|---|---|
| "Command not found" | Use |
| Missing translations after translate | Check |
| Validation fails | Ensure |
| Wrong locales translated | Use |
| Node version error | Requires Node v18.0.0+ |
| Nested JSON keys require bracket notation: |
| Otomi not supported by Google Translate — translate manually or skip |
| 问题 | 解决方法 |
|---|---|
| "Command not found" | 使用 |
| 翻译后仍存在缺失内容 | 检查settings.json中的 |
| 校验失败 | 确保 |
| 翻译了错误的语言 | 使用 |
| Node版本错误 | 需要Node v18.0.0及以上版本 |
| 嵌套JSON键需要使用括号语法: |
| 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-jsonWhen reads nested JSON:
plugin-jsonjson
{ "navbar": { "moreOptions": "More options" } }It flattens to key . Paraglide then generates:
"navbar.moreOptions"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 exportedAlternative — use with flat keys:
If you want style (dot-accessible), use flat underscore keys in your JSON
with instead of :
plugin-message-formatm.navbar_share()plugin-message-formatplugin-jsonjson
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"navbar_share": "Share",
"common_back": "Back"
}This generates directly — no bracket notation needed.
m.navbar_share()Rule of thumb:
- Nested JSON + →
plugin-jsonm["section.key"]() - Flat JSON + →
plugin-message-formatm.flat_key()
这是从i18next迁移到使用的Paraglide时最常见的错误来源。
plugin-json当读取嵌套JSON时:
plugin-jsonjson
{ "navbar": { "moreOptions": "More options" } }它会将其扁平化为键。Paraglide随后会生成:
"navbar.moreOptions"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() // 内部名称,未公开导出替代方案 — 使用和平坦键:
如果您希望使用样式(点访问),请在JSON中使用扁平下划线键,并搭配而非:
plugin-message-formatm.navbar_share()plugin-message-formatplugin-jsonjson
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"navbar_share": "Share",
"common_back": "Back"
}这会直接生成 — 无需使用括号语法。
m.navbar_share()经验法则:
- 嵌套JSON + →
plugin-jsonm["section.key"]() - 扁平JSON + →
plugin-message-formatm.flat_key()
Paraglide JS Integration (Vite + React)
Paraglide JS集成(Vite + React)
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.
@inlang/paraglide-jsParaglide JS () 将inlang消息编译为可摇树优化、类型安全的函数。支持客户端渲染(CSR)、服务端渲染(SSR)和静态站点生成(SSG),已在TanStack的CI/CD流水线中测试验证。
@inlang/paraglide-jsQuick Start
快速开始
bash
npx @inlang/paraglide-js@latest initThis creates the folder and configures your project. Then add the Vite plugin:
project.inlang/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此命令会创建目录并配置您的项目。然后添加Vite插件:
project.inlang/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 instead of :
plugin-message-formatplugin-jsonjson
{
"$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 schema:
inlang-message-formatjson
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"example_message": "Hello world {username}",
"home_page": "Home page",
"about_page": "About page"
}使用而非:
plugin-message-formatplugin-jsonjson
{
"$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"
}
}消息文件使用 schema:
inlang-message-formatjson
{
"$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 API to de-localize URLs for route matching and re-localize for display:
rewritetsx
// 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 />
</>
),
})使用 API移除URL中的语言前缀以匹配路由,并在显示时重新添加语言前缀:
rewritetsx
// 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 :
paraglideMiddlewarets
// 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>
)
}对于服务端渲染,使用拦截请求:
paraglideMiddlewarets
// 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 from the generated route tree:
urlPatternsts
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 into in the Paraglide Vite plugin config.
translatedPathnamesurlPatterns通过从生成的路由树中推导,确保每个路由都有对应的翻译:
urlPatternsts
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' },
})将导入到Paraglide Vite插件配置的中。
translatedPathnamesurlPatternsPrerendering Localized Routes
预渲染本地化路由
Use to generate localized versions for static prerendering. Compile Paraglide before build with the CLI:
localizeHrefts
import { localizeHref } from './paraglide/runtime'
export const prerenderRoutes = ['/', '/about'].map((path) => ({
path: localizeHref(path),
prerender: { enabled: true },
}))使用生成本地化版本以用于静态预渲染。在构建前使用CLI编译Paraglide:
localizeHrefts
import { localizeHref } from './paraglide/runtime'
export const prerenderRoutes = ['/', '/about'].map((path) => ({
path: localizeHref(path),
prerender: { enabled: true },
}))Key Paraglide APIs
核心Paraglide API
| Import | Purpose |
|---|---|
| Access translated message (type-safe) |
| Message with interpolation |
| Get current locale |
| Switch locale |
| Array of available locales |
| Check if URL needs locale redirect |
| Strip locale prefix for route matching |
| Add locale prefix for display |
| Localize a path for prerendering |
| SSR middleware (from |
| 导入内容 | 用途 |
|---|---|
| 访问翻译后的消息(类型安全) |
| 带插值的消息 |
| 获取当前语言 |
| 切换语言 |
| 可用语言数组 |
| 检查URL是否需要语言重定向 |
| 移除语言前缀以匹配路由 |
| 添加语言前缀用于显示 |
| 本地化路径以用于预渲染 |
| SSR中间件(来自 |
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.tsmy-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.tsVS Code Extension
VS Code扩展
Add :
.vscode/extensions.jsonjson
{
"recommendations": ["inlang.vs-code-extension"]
}添加:
.vscode/extensions.jsonjson
{
"recommendations": ["inlang.vs-code-extension"]
}Installation (optional)
安装(可选)
bash
npm install -D @inlang/cli # project-scoped (recommended)
yarn add --dev @inlang/cli # yarn alternativeUsing without installing is preferred — scopes version to project and works for all team members automatically.
npxbash
npm install -D @inlang/cli # 项目级安装(推荐)
yarn add --dev @inlang/cli # yarn替代方案推荐使用而不进行全局安装 — 这样可以将版本限定在项目范围内,且所有团队成员都能自动使用正确版本。
npxTranslate 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
重要说明
- Only translate/sync the DIFF - Compare English source with existing Chinese translation, only update changed parts. DO NOT re-translate the entire file.
- DO NOT remove any content.
- 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>;After translate:
<APIItem name="extendApi" type="function">
xxxx 内容
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;- 仅翻译/同步差异内容 - 对比英文源文件与现有中文翻译,仅更新变更部分,请勿重新翻译整个文件。
- 请勿删除任何内容。
- 您可以翻译标题Markdown内容,例如## Plugin Context。
示例:
<APIItem name="extendApi" type="function">
xxxx content
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;翻译后:
<APIItem name="extendApi" type="function">
xxxx 内容
ts
(api: (ctx: PlatePluginContext<AnyPluginConfig>) => any) => PlatePlugin<C>;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 153Last 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(完成翻译后,请自动将此日期更新为当前日期。)