Trang chủSandboxTrưng bàyỨng dụngTài liệuBlog
    • EnglishTiếng Anh
      EN
    • русскийTiếng Nga
      RU
    • 日本語Tiếng Nhật
      JA
    • françaisTiếng Pháp
      FR
    • 한국어Tiếng Hàn
      KO
    • 中文Tiếng Trung
      ZH
    • españolTiếng Tây Ban Nha
      ES
    • DeutschTiếng Đức
      DE
    • العربيةTiếng Ả Rập
      AR
    • italianoTiếng Italy
      IT
    • British EnglishTiếng Anh (Anh)
      EN-GB
    • portuguêsTiếng Bồ Đào Nha
      PT
    • हिन्दीTiếng Hindi
      HI
    • TürkçeTiếng Thổ Nhĩ Kỳ
      TR
    • polskiTiếng Ba Lan
      PL
    • IndonesiaTiếng Indonesia
      ID
    • Tiếng ViệtTiếng Việt
      VI
    • українськаTiếng Ukraina
      UK
    /
    Lọc tài liệu theo framework
    Alt+←
    Tại sao Intlayer?
    Bắt đầu
    Khái niệm
    • Intlayer làm việc như thế nào
    • Cấu hình
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Editor visual
    • CMS
    • Tích hợp CI/CD
    • DịchSố nhiềuLiệt kêĐiều kiệnGiới tínhChènTệpNestingMarkdownHTMLLấy hàm
    • File cho mỗi ngôn ngữ
    • Biên dịch
    • Tự động điền
    • Kiểm tra
    • Tối ưu hóa gói
    Môi trường
    • Next.js 14 và App Router
      Next.js 15
      Next.js không locale URL
      Next.js và Page Router
      Trình biên dịch
    • Tanstack Start Solid
    • Astro và React
      Astro và Svelte
      Astro và Vue
      Astro và Solid
      Astro và Preact
      Astro và Lit
      Astro và Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt và Vue
    • Vite và Solid
    • SvelteKit
    • Vite và Preact
    • Vite và Vanilla JS
    • Vite và Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native và Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx và React
    Plugins
    • JSON
    • gettext (.po)
    Mở rộng VS Code
    Tác nhân
    • MCP Server
    • Kỹ năng tác nhân
    Phiên bản
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Đặt câu hỏi
    1. Documentation
    2. Môi trường
    3. Vite và React
    4. Compiler
    Ngày tạo:2024-03-07Cập nhật lần cuối:2026-05-06
    Xem mẫu ứng dụng trên GitHub

    Trang này có một mẫu ứng dụng có sẵn.

    Xem ứng dụng trưng bày

    Trang này liên kết đến bản demo trực tiếp của mẫu.

    Xem video hướng dẫn

    Trang này có video hướng dẫn.

    Tham chiếu tài liệu này tới trợ lý AI yêu thích của bạn
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Đặt câu hỏi và nhận tóm tắt tài liệu bằng cách tham chiếu trang này và nhà cung cấp AI bạn chọn

    Lịch sử phiên bản

    1. "Cập nhật cách sử dụng API useIntlayer của Solid sang truy cập thuộc tính trực tiếp"
      v8.9.04/5/2026
    2. "Update compiler options, add FilePathPattern support"
      v8.2.09/3/2026
    3. "Phát hành lần đầu"
      v8.1.623/2/2026

    Nội dung của trang này đã được dịch bằng AI.

    Xem phiên bản mới nhất của nội dung gốc bằng tiếng Anh
    Chỉnh sửa tài liệu này

    Nếu bạn có ý tưởng để cải thiện tài liệu này, vui lòng đóng góp bằng cách gửi pull request trên GitHub.

    Liên kết GitHub tới tài liệu
    Sao chép

    Sao chép Markdown của tài liệu vào bộ nhớ tạm

    Cách làm cho ứng dụng Vite và React hiện có trở thành đa ngôn ngữ (i18n) sau đó (hướng dẫn i18n 2026)

    www.youtube.com
    ide.intlayer.org
    intlayer-vite-react-template.vercel.app

    Xem Mẫu ứng dụng trên GitHub.

    Mục lục

    Tại sao việc quốc tế hóa một ứng dụng hiện có lại khó khăn?

    Nếu bạn đã từng thử thêm nhiều ngôn ngữ vào một ứng dụng vốn chỉ được xây dựng cho một ngôn ngữ, bạn sẽ hiểu được nỗi vất vả đó. Nó không chỉ "khó" mà còn cực kỳ tẻ nhạt. Bạn phải rà soát qua từng tệp tin, săn lùng từng chuỗi văn bản và chuyển chúng vào các tệp từ điển riêng biệt.

    Sau đó là phần đầy rủi ro: thay thế toàn bộ văn bản đó bằng các hook mã nguồn mà không làm hỏng giao diện hoặc logic của bạn. Đó là loại công việc khiến việc phát triển tính năng mới bị đình trệ trong nhiều tuần và cảm giác như một quá trình cấu trúc lại mã (refactoring) không bao giờ kết thúc.

    Intlayer Compiler là gì?

    Intlayer Compiler được xây dựng để bỏ qua những công việc thủ công nặng nhọc đó. Thay vì bạn phải tự trích xuất các chuỗi ký tự, trình biên dịch sẽ làm việc đó cho bạn. Nó quét mã của bạn, tìm văn bản và sử dụng AI để tạo ra các từ điển ở chế độ nền. Sau đó, nó sửa đổi mã của bạn trong quá trình xây dựng (build) để chèn các hook i18n cần thiết. Về cơ bản, bạn vẫn viết ứng dụng như thể nó chỉ có một ngôn ngữ, và trình biên dịch sẽ tự động xử lý việc chuyển đổi đa ngôn ngữ.

    Tài liệu trình biên dịch: /vi/doc/compiler

    Hạn chế

    Vì trình biên dịch thực hiện phân tích và chuyển đổi mã (chèn hook và tạo từ điển) tại thời điểm biên dịch, nó có thể làm chậm quá trình xây dựng ứng dụng của bạn.

    Để giảm bớt tác động này trong quá trình phát triển, bạn có thể cấu hình trình biên dịch chạy ở chế độ 'build-only' hoặc tắt nó khi không cần thiết.


    Hướng dẫn từng bước để thiết lập Intlayer trong ứng dụng Vite và React

    Bước 1: Cài đặt các gói phụ thuộc

    Cài đặt các gói cần thiết bằng npm:

    bash
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    npm install intlayer react-intlayernpm install vite-intlayer --save-devnpx intlayer init
    • intlayer Gói cốt lõi cung cấp các công cụ quốc tế hóa để quản lý cấu hình, dịch thuật, khai báo nội dung, chuyển đổi mã và các lệnh CLI.

    • react-intlayer Gói tích hợp Intlayer với ứng dụng React. Nó cung cấp các trình cung cấp ngữ cảnh (context providers) và các hook cho việc quốc tế hóa React.

    • vite-intlayer Bao gồm plugin Vite để tích hợp Intlayer với Vite bundler, cũng như middleware để phát hiện ngôn ngữ ưa thích của người dùng, quản lý cookie và xử lý chuyển hướng URL.

    Bước 2: Cấu hình dự án của bạn

    Tạo một tệp cấu hình để thiết lập các ngôn ngữ cho ứng dụng của bạn:

    intlayer.config.ts
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.VIETNAMESE, Locales.FRENCH],    defaultLocale: Locales.ENGLISH,  },  compiler: {    /**     * Cho biết trình biên dịch có nên được bật hay không.     */    enabled: true,    /**     * Thư mục đầu ra cho các từ điển được tối ưu hóa.     */    output: ({ locale, key }) => `compiler/${locale}/${key}.json`,    /**     * Chỉ chèn nội dung vào tệp đã tạo, không có khóa.     */    noMetadata: false,    /**     * Tiền tố khóa từ điển     */    dictionaryKeyPrefix: "", // Remove base prefix    /**     * Cho biết liệu các thành phần có nên được lưu sau khi được chuyển đổi hay không.     * Bằng cách đó, trình biên dịch có thể được chạy một lần duy nhất để chuyển đổi ứng dụng, và sau đó nó có thể được gỡ bỏ.     */    saveComponents: false,  },  ai: {    provider: "openai",    model: "gpt-5-mini",    apiKey: process.env.OPEN_AI_API_KEY,    applicationContext: "Ứng dụng này là một ứng dụng bản đồ", // Lưu ý: bạn có thể tùy chỉnh mô tả ứng dụng này  },};export default config;
    Lưu ý: Đảm bảo bạn đã đặt OPEN_AI_API_KEY trong các biến môi trường của mình.
    Thông qua tệp cấu hình này, bạn có thể thiết lập các URL được bản địa hóa, chuyển hướng middleware, tên cookie, vị trí và phần mở rộng của các khai báo nội dung, tắt nhật ký Intlayer trong console, v.v. Để biết danh sách đầy đủ các tham số có sẵn, hãy tham khảo tài liệu cấu hình.

    Bước 3: Tích hợp Intlayer trong cấu hình Vite của bạn

    Thêm plugin intlayer vào cấu hình của bạn.

    vite.config.ts
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import { defineConfig } from "vite";import react from "@vitejs/plugin-react-swc";import { intlayer, intlayerCompiler } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [react(), intlayer(), intlayerCompiler()],});
    Plugin Vite intlayer() được sử dụng để tích hợp Intlayer với Vite. Nó đảm bảo việc xây dựng các tệp khai báo nội dung và theo dõi chúng trong chế độ phát triển. Nó định nghĩa các biến môi trường Intlayer trong ứng dụng Vite. Ngoài ra, nó cung cấp các bí danh (aliases) để tối ưu hóa hiệu suất.
    Plugin Vite intlayerCompiler() được sử dụng để trích xuất nội dung từ component và ghi các tệp .content.

    Bước 4: Biên dịch mã của bạn

    Chỉ cần viết các component của bạn với các chuỗi ký tự được mã hóa cứng (hardcoded) bằng ngôn ngữ mặc định của bạn. Trình biên dịch sẽ xử lý phần còn lại.

    Ví dụ về giao diện trang của bạn có thể trông như sau:

    src/App.tsx
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import { useState, type FC } from "react";import reactLogo from "./assets/react.svg";import viteLogo from "/vite.svg";import "./App.css";import { IntlayerProvider } from "react-intlayer";const AppContent: FC = () => { const [count, setCount] = useState(0); return (   <>     <div>       <a href="https://vitejs.dev" target="_blank">         <img src={viteLogo} className="logo" alt="Vite logo" />       </a>       <a href="https://react.dev" target="_blank">         <img src={reactLogo} className="logo react" alt="React logo" />       </a>     </div>     <h1>Vite + React</h1>     <div className="card">       <button onClick={() => setCount((count) => count + 1)}>         count is {count}       </button>       <p>         Edit <code>src/App.tsx</code> and save to test HMR       </p>     </div>     <p className="read-the-docs">       Click on the Vite and React logos to learn more     </p>   </> );};const App: FC = () => ( <IntlayerProvider>   <AppContent /> </IntlayerProvider>);export default App;
    i18n/app-content.content.json
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    { key: "app-content", content: {   nodeType: "translation",   translation: {     en: {       viteLogo: "Vite logo",       reactLogo: "React logo",       title: "Vite + React",       countButton: "count is",       editMessage: "Edit",       hmrMessage: "and save to test HMR",       readTheDocs: "Click on the Vite and React logos to learn more",     },     vi: {       viteLogo: "Logo Vite",       reactLogo: "Logo React",       title: "Vite + React",       countButton: "số đếm là",       editMessage: "Sửa",       hmrMessage: "và lưu để kiểm tra HMR",       readTheDocs: "Nhấp vào logo Vite và React để tìm hiểu thêm",     },   } }}
    src/App.tsx
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import { useState, type FC } from "react";import reactLogo from "./assets/react.svg";import viteLogo from "/vite.svg";import "./App.css";import { IntlayerProvider, useIntlayer } from "react-intlayer";const AppContent: FC = () => { const [count, setCount] = useState(0); const content = useIntlayer("app-content"); return (   <>     <div>       <a href="https://vitejs.dev" target="_blank">         <img src={viteLogo} className="logo" alt={content.viteLogo.value} />       </a>       <a href="https://react.dev" target="_blank">         <img           src={reactLogo}           className="logo react"           alt={content.reactLogo.value}         />       </a>     </div>     <h1>{content.title}</h1>     <div className="card">       <button onClick={() => setCount((count) => count + 1)}>         {content.countButton} {count}       </button>       <p>         {content.editMessage} <code>src/App.tsx</code> {content.hmrMessage}       </p>     </div>     <p className="read-the-docs">{content.readTheDocs}</p>   </> );};const App: FC = () => ( <IntlayerProvider>   <AppContent /> </IntlayerProvider>);export default App;
    • IntlayerProvider được sử dụng để cung cấp ngôn ngữ cho các component con.

    (Tùy chọn) Bước 6: Thay đổi ngôn ngữ của nội dung

    Để thay đổi ngôn ngữ của nội dung, bạn có thể sử dụng hàm setLocale được cung cấp bởi hook useLocale. Hàm này cho phép bạn thiết lập ngôn ngữ của ứng dụng và cập nhật nội dung tương ứng.

    src/components/LocaleSwitcher.tsx
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import type { FC } from "react";import { Locales } from "intlayer";import { useLocale } from "react-intlayer";const LocaleSwitcher: FC = () => {  const { setLocale } = useLocale();  return (    <button onClick={() => setLocale(Locales.English)}>      Thay đổi ngôn ngữ sang tiếng Anh    </button>  );};
    Để tìm hiểu thêm về hook useLocale, hãy tham khảo tài liệu.

    (Tùy chọn) Bước 7: Điền các bản dịch còn thiếu

    Intlayer cung cấp một công cụ CLI để giúp bạn điền các bản dịch còn thiếu. Bạn có thể sử dụng lệnh intlayer để kiểm tra và điền các bản dịch còn thiếu từ mã nguồn của bạn.

    bash
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    npx intlayer test         # Kiểm tra xem có bản dịch nào còn thiếu không
    bash
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    npx intlayer fill         # Điền các bản dịch còn thiếu
    Để biết thêm chi tiết, vui lòng tham khảo tài liệu CLI

    (Tuỳ chọn) Sitemap và robots.txt (sinh lúc build)

    Intlayer cung cấp generateSitemap và getMultilingualUrls để định dạng sitemap.xml đa ngôn ngữ và robots.txt cho crawler rồi tự ghi vào public/. Thường chạy một script Node nhỏ trước Vite (ví dụ hook npm predev / prebuild).

    Sitemap

    Trình tạo sitemap của Intlayer tôn trọng cấu hình locale và thêm metadata cho crawler.

    Sitemap hỗ trợ không gian tên xhtml:link (hreflang). Thay vì chỉ liệt kê URL phẳng, Intlayer nối hai chiều mọi bản địa phương của từng trang (ví dụ /about, /fr/about hoặc /about?lang=fr tùy chế độ routing).

    Robots.txt

    Dùng getMultilingualUrls để quy tắc Disallow áp dụng cho mọi biến thể URL của đường dẫn nhạy cảm.

    1. Thêm generate-seo.mjs ở thư mục gốc dự án

    generate-seo.mjs
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    import fs from "fs";import path from "path";import { fileURLToPath } from "url";import { generateSitemap, getMultilingualUrls } from "intlayer";const __dirname = path.dirname(fileURLToPath(import.meta.url));const SITE_URL = (process.env.SITE_URL || "http://localhost:5173").replace(  /\/$/,  "");const pathList = [  { path: "/", changefreq: "daily", priority: 1.0 },  { path: "/about", changefreq: "monthly", priority: 0.7 },];const sitemapXml = generateSitemap(pathList, { siteUrl: SITE_URL });fs.writeFileSync(path.join(__dirname, "public", "sitemap.xml"), sitemapXml);const getAllMultilingualUrls = (urls) =>  urls.flatMap((url) => Object.values(getMultilingualUrls(url)));const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);const robotsTxt = [  "User-agent: *",  "Allow: /",  ...disallowedPaths.map((path) => `Disallow: ${path}`),  "",  `Sitemap: ${SITE_URL}/sitemap.xml`,].join("\n");fs.writeFileSync(path.join(__dirname, "public", "robots.txt"), robotsTxt);console.log("SEO files generated successfully.");

    Cần cài intlayer để script import. Môi trường production đặt SITE_URL (ví dụ trong CI).

    Nên dùng generate-seo.mjs cho ESM của Node. Nếu dùng generate-seo.js, đặt "type": "module" trong package.json hoặc bật ESM tương đương.

    2. Chạy script trước Vite

    package.json
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    {  "scripts": {    "dev": "vite",    "prebuild": "node generate-seo.mjs",    "build": "vite build",    "preview": "vite preview"  }}

    Chỉnh lệnh nếu dùng pnpm hoặc yarn. Có thể gọi từ CI hoặc bước pipeline khác.

    Cấu hình Git

    Khuyên dùng bỏ qua các tệp do Intlayer tạo ra. Điều này giúp bạn tránh việc commit chúng vào kho lưu trữ Git của mình.

    Để làm điều này, bạn có thể thêm các hướng dẫn sau vào tệp .gitignore của mình:

    .gitignore
    Sao chép mã

    Sao chép đoạn mã vào khay nhớ tạm (clipboard)

    # Bỏ qua các tệp do Intlayer tạo ra.intlayer

    Tiện ích mở rộng VS Code

    Để cải thiện trải nghiệm phát triển của bạn với Intlayer, bạn có thể cài đặt Intlayer VS Code Extension chính thức.

    Cài đặt từ VS Code Marketplace

    Tiện ích này cung cấp:

    • Tự động hoàn thành cho các khóa dịch thuật.
    • Phát hiện lỗi thời gian thực cho các bản dịch còn thiếu.
    • Xem trước trực tiếp nội dung đã dịch.
    • Các hành động nhanh để dễ dàng tạo và cập nhật bản dịch.

    Để biết thêm chi tiết về cách sử dụng tiện ích, hãy tham khảo tài liệu Intlayer VS Code Extension.

    Đi xa hơn

    Để tìm hiểu sâu hơn, bạn có thể triển khai visual editor hoặc bên thứ ba hóa nội dung của bạn bằng CMS.

    React Router v7 (fs-routes)
    Vite và Vue
    Alt+→

    Trong trang này

      Các cuộc thảo luận là ẩn danh và được xem xét thường xuyên để giải quyết các vấn đề phổ biến. Hãy thoải mái chia sẻ ý tưởng tính năng, phản hồi về tài liệu hoặc bất cứ điều gì liên quan đến Intlayer, chúng tôi sử dụng thông tin này để định hình lộ trình và cải thiện sản phẩm.

      npm install intlayer react-intlayernpm install vite-intlayer --save-devnpx intlayer init
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.VIETNAMESE, Locales.FRENCH],    defaultLocale: Locales.ENGLISH,  },  compiler: {    /**     * Cho biết trình biên dịch có nên được bật hay không.     */    enabled: true,    /**     * Thư mục đầu ra cho các từ điển được tối ưu hóa.     */    output: ({ locale, key }) => `compiler/${locale}/${key}.json`,    /**     * Chỉ chèn nội dung vào tệp đã tạo, không có khóa.     */    noMetadata: false,    /**     * Tiền tố khóa từ điển     */    dictionaryKeyPrefix: "", // Remove base prefix    /**     * Cho biết liệu các thành phần có nên được lưu sau khi được chuyển đổi hay không.     * Bằng cách đó, trình biên dịch có thể được chạy một lần duy nhất để chuyển đổi ứng dụng, và sau đó nó có thể được gỡ bỏ.     */    saveComponents: false,  },  ai: {    provider: "openai",    model: "gpt-5-mini",    apiKey: process.env.OPEN_AI_API_KEY,    applicationContext: "Ứng dụng này là một ứng dụng bản đồ", // Lưu ý: bạn có thể tùy chỉnh mô tả ứng dụng này  },};export default config;
      import { defineConfig } from "vite";import react from "@vitejs/plugin-react-swc";import { intlayer, intlayerCompiler } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [react(), intlayer(), intlayerCompiler()],});
      import { useState, type FC } from "react";import reactLogo from "./assets/react.svg";import viteLogo from "/vite.svg";import "./App.css";import { IntlayerProvider } from "react-intlayer";const AppContent: FC = () => { const [count, setCount] = useState(0); return (   <>     <div>       <a href="https://vitejs.dev" target="_blank">         <img src={viteLogo} className="logo" alt="Vite logo" />       </a>       <a href="https://react.dev" target="_blank">         <img src={reactLogo} className="logo react" alt="React logo" />       </a>     </div>     <h1>Vite + React</h1>     <div className="card">       <button onClick={() => setCount((count) => count + 1)}>         count is {count}       </button>       <p>         Edit <code>src/App.tsx</code> and save to test HMR       </p>     </div>     <p className="read-the-docs">       Click on the Vite and React logos to learn more     </p>   </> );};const App: FC = () => ( <IntlayerProvider>   <AppContent /> </IntlayerProvider>);export default App;
      { key: "app-content", content: {   nodeType: "translation",   translation: {     en: {       viteLogo: "Vite logo",       reactLogo: "React logo",       title: "Vite + React",       countButton: "count is",       editMessage: "Edit",       hmrMessage: "and save to test HMR",       readTheDocs: "Click on the Vite and React logos to learn more",     },     vi: {       viteLogo: "Logo Vite",       reactLogo: "Logo React",       title: "Vite + React",       countButton: "số đếm là",       editMessage: "Sửa",       hmrMessage: "và lưu để kiểm tra HMR",       readTheDocs: "Nhấp vào logo Vite và React để tìm hiểu thêm",     },   } }}
      import { useState, type FC } from "react";import reactLogo from "./assets/react.svg";import viteLogo from "/vite.svg";import "./App.css";import { IntlayerProvider, useIntlayer } from "react-intlayer";const AppContent: FC = () => { const [count, setCount] = useState(0); const content = useIntlayer("app-content"); return (   <>     <div>       <a href="https://vitejs.dev" target="_blank">         <img src={viteLogo} className="logo" alt={content.viteLogo.value} />       </a>       <a href="https://react.dev" target="_blank">         <img           src={reactLogo}           className="logo react"           alt={content.reactLogo.value}         />       </a>     </div>     <h1>{content.title}</h1>     <div className="card">       <button onClick={() => setCount((count) => count + 1)}>         {content.countButton} {count}       </button>       <p>         {content.editMessage} <code>src/App.tsx</code> {content.hmrMessage}       </p>     </div>     <p className="read-the-docs">{content.readTheDocs}</p>   </> );};const App: FC = () => ( <IntlayerProvider>   <AppContent /> </IntlayerProvider>);export default App;
      import type { FC } from "react";import { Locales } from "intlayer";import { useLocale } from "react-intlayer";const LocaleSwitcher: FC = () => {  const { setLocale } = useLocale();  return (    <button onClick={() => setLocale(Locales.English)}>      Thay đổi ngôn ngữ sang tiếng Anh    </button>  );};
      npx intlayer test         # Kiểm tra xem có bản dịch nào còn thiếu không
      npx intlayer fill         # Điền các bản dịch còn thiếu
      import fs from "fs";import path from "path";import { fileURLToPath } from "url";import { generateSitemap, getMultilingualUrls } from "intlayer";const __dirname = path.dirname(fileURLToPath(import.meta.url));const SITE_URL = (process.env.SITE_URL || "http://localhost:5173").replace(  /\/$/,  "");const pathList = [  { path: "/", changefreq: "daily", priority: 1.0 },  { path: "/about", changefreq: "monthly", priority: 0.7 },];const sitemapXml = generateSitemap(pathList, { siteUrl: SITE_URL });fs.writeFileSync(path.join(__dirname, "public", "sitemap.xml"), sitemapXml);const getAllMultilingualUrls = (urls) =>  urls.flatMap((url) => Object.values(getMultilingualUrls(url)));const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);const robotsTxt = [  "User-agent: *",  "Allow: /",  ...disallowedPaths.map((path) => `Disallow: ${path}`),  "",  `Sitemap: ${SITE_URL}/sitemap.xml`,].join("\n");fs.writeFileSync(path.join(__dirname, "public", "robots.txt"), robotsTxt);console.log("SEO files generated successfully.");
      {  "scripts": {    "dev": "vite",    "prebuild": "node generate-seo.mjs",    "build": "vite build",    "preview": "vite preview"  }}
      # Bỏ qua các tệp do Intlayer tạo ra.intlayer