
欢迎来到 utities.online 技术教程系列!今天,我们将剖析我们开源的 video-splitter 工具的多语言预渲染实现——这是一个基于浏览器的视频分割工具。本指南将带您了解实现全球用户无缝多语言支持的架构、工作流程和优化方案。
多语言预渲染是一种在构建时为每种语言生成静态 HTML 文件的技术,结合了服务器端渲染 (SSR) 和静态站点生成 (SSG) 的优点:
这种方法非常适合像 video-splitter 这样对性能要求高的多语言 Web 应用,其中速度和可访问性至关重要。
| 技术 | 用途 | 选择原因 |
|---|---|---|
| React 18 | 前端 UI | 基于组件的架构,通过 ReactDOMServer 提供内置的 SSR 支持。 |
| i18next + react-i18next | 国际化 (i18n) | 强大、灵活,支持命名空间和插值等高级功能。 |
| Vite | 构建工具 | 极速构建和 HMR,支持原生 ESM。 |
| Node.js | 运行时环境 | 为预渲染脚本和服务器端逻辑提供支持。 |
| ReactDOMServer | 服务器端渲染 | 官方 React SSR 解决方案,用于在服务器上生成 HTML。 |
video-splitter 项目采用模块化结构,以提高清晰度和可维护性:
├── src/
│ ├── i18n/
│ │ ├── index.ts # i18n 配置和初始化
│ │ └── locales/ # 翻译文件(例如 `en/`、`zh/`、`es/`)
│ ├── entry-server.tsx # 带有 `render` 函数的 SSR 入口点
│ └── constants.ts # 全局常量(例如 `DOMAIN_NAME`)
├── prerender.js # 用于生成静态 HTML 的预渲染脚本
└── package.json # 构建和预渲染脚本
关键设计原则:
/i18n 中。prerender.js 脚本设置环境并准备为每种语言生成静态页面:
javascriptimport fs from 'node:fs'; import path from 'node:path'; import url from 'node:url'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); const templateHtml = fs.readFileSync('./dist/static/index.html', 'utf-8');
脚本扫描 locales/ 目录,而不是硬编码语言:
javascriptconst localesDir = path.resolve(__dirname, 'src/i18n/locales'); const languages = fs.readdirSync(localesDir).filter(name => fs.statSync(path.join(localesDir, name)).isDirectory() );
路由是动态生成的:
//{lang}/(例如 /zh/、/es/)javascriptconst routes = ['/'].concat( languages.filter(lang => lang !== 'en').map(lang => `/${lang}`) );
entry-server.tsx 中的 render 函数处理每种语言的 SSR:
javascriptexport async function render(url: string, languages: string[]) { const seoContent = await getSeoContent(url); const i18nInstance = await initI18n(seoContent.language); i18nInstance.changeLanguage(seoContent.language); const html = renderToString(); // 生成 hreflang 标签和其他 SEO 元数据... }
对于每个路由,脚本:
dist/static/{lang}/index.html。javascriptfor (const route of routes) { const lang = route === '/' ? 'en' : route.split('/')[1]; const rendered = await render(route, languages); const html = template .replace(``, rendered.head) .replace(``, rendered.html) .replace(/]*)>/, ``); fs.writeFileSync(`dist/static${route}/index.html`, html); }
src/i18n/index.ts 文件集中管理 i18n 逻辑:
javascriptexport const languages = [ 'en', 'zh', 'es', 'fr', 'de', 'ja', 'ko', /* ... 共 28 种 */ ]; export const initI18n = async (language?: string) => { try { const translations = await preloadCommonTranslations(); return await sharedInitI18n(translations, language); } catch (error) { return await sharedInitI18n({}); // 回退到空配置 } };
主要功能:
翻译组织在带有命名空间的JSON 文件中:
json{ "videoSplitter": { "title": "VideoSplitter - 快速视频分割工具", "uploadVideo": "上传视频", "dragAndDrop": "将视频文件拖放到此处" }, "common": { "processing": "处理中", "success": "成功", "error": "错误" } }
优点:
videoSplitter) 和共享 (common) 翻译。package.json 脚本自动化流程:
json"scripts": { "build": "vite build", "build:server": "vite build --config vite.config.server.ts", "generate": "pnpm run build && pnpm run build:server && node prerender" }
步骤:
prerender.js 为所有语言生成静态 HTML。动态语言检测
locales/ 自动发现支持的语言。自动路由生成
/{lang}/ 目录和 HTML 文件。SEO 优化
lang 属性和 hreflang 标签。强大的回退机制
性能优化
javascript// 设置全局标签以解析资源路径 const head = renderToString( );
video-splitter 项目展示了如何结合 React SSR、i18next 和 Vite 创建一个可扩展的多语言静态站点。这种方法平衡了性能、SEO 和可维护性——非常适合全球工具。
探索更多:
向您提问: 您是否正在项目中实现多语言支持?您遇到了哪些挑战,又是如何解决的?让我们一起讨论!