تكامل Vite + React

يتكامل @lingo.dev/compiler مع Vite من خلال إضافة تعمل مع إعدادات SPA وSSR.

الإعداد

1. تثبيت الحزمة

pnpm install @lingo.dev/compiler

2. تكوين Vite

أضف lingoCompilerPlugin إلى ملف تكوين Vite الخاص بك:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingoCompilerPlugin } from "@lingo.dev/compiler/vite";

export default defineConfig({
  plugins: [
    lingoCompilerPlugin({
      sourceRoot: "src",
      sourceLocale: "en",
      targetLocales: ["es", "de", "fr"],
      models: "lingo.dev",
      dev: {
        usePseudotranslator: true,
      },
    }),
    react(),
  ],
});

ترتيب الإضافات: ضع lingoCompilerPlugin قبل إضافة react(). هذا يضمن أن المترجم يحول JSX الخاص بك قبل أن تعالجه React.

3. إضافة المزود

قم بتغليف تطبيقك بـ LingoProvider في نقطة الدخول الخاصة بك:

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { LingoProvider } from "@lingo.dev/compiler/react";
import App from "./App";
import "./index.css";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <LingoProvider>
      <App />
    </LingoProvider>
  </StrictMode>
);

مهم: ضع LingoProvider في أعلى مستوى ممكن في شجرة المكونات الخاصة بك. إذا كنت تستخدم TanStack Router أو React Router، ضع LingoProvider فوق مزود الموجه.

إعداد SPA

بالنسبة لتطبيقات الصفحة الواحدة، الإعداد أعلاه كافٍ. تتم إدارة اللغة من جانب العميل.

مبدل اللغة

"use client";

import { useLingoContext } from "@lingo.dev/compiler/react";

export function LanguageSwitcher() {
  const { locale, setLocale } = useLingoContext();

  return (
    <div>
      <label>Language:</label>
      <select value={locale} onChange={(e) => setLocale(e.target.value)}>
        <option value="en">English</option>
        <option value="es">Español</option>
        <option value="de">Deutsch</option>
        <option value="fr">Français</option>
      </select>
    </div>
  );
}

إعداد SSR (React Router، Remix، TanStack Start)

بالنسبة لأطر عمل SSR، قد تحتاج إلى التعامل مع اكتشاف اللغة على الخادم.

اكتشاف اللغة المخصص

أنشئ .lingo/locale-resolver.server.ts لمنطق جانب الخادم:

// .lingo/locale-resolver.server.ts
export async function getServerLocale(): Promise<string> {
  // Access request context (framework-specific)
  // Example: parse cookies, headers, or database
  return "en"; // Return detected locale
}

و .lingo/locale-resolver.client.ts لجانب العميل:

// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
  return localStorage.getItem("locale") || "en";
}

export function persistLocale(locale: string): void {
  localStorage.setItem("locale", locale);
}

راجع محللات اللغة المخصصة للحصول على أمثلة خاصة بأطر العمل.

التكامل مع TanStack Router

بالنسبة لـ TanStack Router، ضع LingoProvider فوق RouterProvider:

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { LingoProvider } from "@lingo.dev/compiler/react";
import { routeTree } from "./routeTree.gen";

const router = createRouter({ routeTree });

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <LingoProvider>
      <RouterProvider router={router} />
    </LingoProvider>
  </StrictMode>
);

يضمن هذا توفر الترجمات في جميع مكونات التوجيه الخاصة بك وعدم كسر السياق بواسطة تقسيم الكود.

التكامل مع React Router

بالنسبة لـ React Router v6/v7:

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { LingoProvider } from "@lingo.dev/compiler/react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <LingoProvider>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </LingoProvider>
  </StrictMode>
);

HMR والتطوير

يدعم المترجم بشكل كامل الاستبدال الفوري للوحدات (HMR) في Vite. عند تحديث نص قابل للترجمة:

  1. يكتشف المترجم التغيير
  2. يُنشئ خادم الترجمة ترجمات جديدة (أو ترجمات زائفة)
  3. يُحدّث HMR المكون الخاص بك دون إعادة تحميل كاملة
  4. يتم الحفاظ على حالة المكون

يعمل Fast Refresh بشكل طبيعي—لا يتداخل المترجم مع HMR الخاص بـ Vite.

إعدادات البناء

بناء التطوير

{
  dev: {
    usePseudotranslator: true, // Fast fake translations
  }
}

قم بتشغيل npm run dev للحصول على ملاحظات فورية مع الترجمات الزائفة.

بناء الإنتاج

{
  buildMode: "cache-only", // Use pre-generated translations
}

قم بتشغيل npm run build. تأتي الترجمات من .lingo/metadata.json—لا حاجة لاستدعاءات API.

أفضل ممارسة: قم بإنشاء ترجمات حقيقية في CI قبل بناء الإنتاج. راجع أوضاع البناء.

تقسيم الكود

يحترم المترجم تقسيم الكود في Vite. تتضمن كل قطعة محملة بشكل كسول الترجمات التي تحتاجها فقط.

// Lazy-loaded route
const Dashboard = lazy(() => import("./pages/Dashboard"));

// Dashboard component's translations are bundled with the Dashboard chunk

يتم إزالة الترجمات غير المستخدمة تلقائيًا—يتم تضمين الترجمات المستخدمة فقط في كل قطعة.

TypeScript

المترجم مكتوب بالكامل:

import type { LingoConfig } from "@lingo.dev/compiler";

const config: LingoConfig = {
  sourceRoot: "src",
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  models: "lingo.dev",
};

متغيرات البيئة

استخدم نظام متغيرات البيئة في Vite لمفاتيح API:

# .env
VITE_LINGO_API_KEY=your_key_here

الوصول في الإعدادات:

{
  models: "lingo.dev",
  // API key is automatically read from LINGODOTDEV_API_KEY env variable
}

لا تقم أبدًا بإرسال مفاتيح API. أضف .env إلى .gitignore.

المشاكل الشائعة

"Cannot find module '@lingo.dev/compiler/react'" تأكد من تثبيت الحزمة: pnpm install @lingo.dev/compiler

HMR يتعطل بعد إضافة LingoProvider تحقق من أن lingoCompilerPlugin موضوع قبل إضافة react() في إعدادات Vite الخاصة بك.

الترجمات لا تظهر في الإنتاج تحقق من buildMode: "cache-only" وأن .lingo/metadata.json يحتوي على ترجمات لجميع اللغات.

السياق معطل مع تقسيم الكود تأكد من وضع LingoProvider فوق موفر التوجيه الخاص بك (TanStack Router، React Router، إلخ). وإلا، قد تفقد المسارات المقسمة السياق.

المنفذ 60000 قيد الاستخدام بالفعل يعثر خادم الترجمة تلقائيًا على المنافذ المتاحة (60000-60099). إذا كانت جميعها قيد الاستخدام، قم بالتكوين يدويًا:

{
  dev: {
    translationServerStartPort: 61000, // Use different port range
  }
}

الخطوات التالية