العودة إلى المدونة
Terminal output showing a translation script writing de.json and fr.json, alongside a folder tree and a browser rendering the German locale route.

كيفية ترجمة تطبيق Next.js باستخدام PolyLingo في أقل من 30 دقيقة

By Robert

كيفية ترجمة تطبيق Next.js باستخدام PolyLingo في أقل من 30 دقيقة

بحلول نهاية هذا الدرس، سيكون لديك مشروع Next.js App Router متعدد اللغات يعمل: تم استخراج السلاسل النصية إلى messages/en.json، وملفات اللغة المترجمة لكل لغة تحتاجها، وnext-intl يقدم الملف الصحيح لكل مسار، ونص Node واحد يمكنك إعادة تشغيله كلما تغير المحتوى الخاص بك.

لا حاجة للتسجيل في منصة ترجمة. لا رسوم ثابتة لكل لغة. مكالمة API واحدة تتعامل مع جميع لغات الهدف دفعة واحدة.

ما ستحتاجه:

  • مشروع Next.js يستخدم App Router (Next.js 14 أو 15)
  • Node.js 18 أو أحدث
  • حساب PolyLingo مجاني ومفتاح API

الخطوة 1: احصل على مفتاح API الخاص بـ PolyLingo (5 دقائق)

أنشئ حسابًا مجانيًا على usepolylingo.com. تشمل الخطة المجانية 100,000 رمز شهريًا، وهو ما يكفي لترجمة ملف لغة متوسط الحجم إلى أكثر من 10 لغات عدة مرات.

بمجرد الدخول، اذهب إلى مفاتيح API في لوحة التحكم وأنشئ مفتاحًا. سترى القيمة الكاملة مرة واحدة فقط، لذا انسخها فورًا.

أضفها إلى مشروعك كمتغير بيئي. لا تقم أبداً بإضافته إلى نظام التحكم في الإصدارات ولا تكشف عنه في كود العميل:

# .env.local
POLYLINGO_API_KEY="pl_your_key_here"

تحقق من إمكانية الوصول إلى API قبل المتابعة:

curl -sS "https://api.usepolylingo.com/v1/health"

يجب أن تتلقى حمولة JSON صغيرة مع "status": "ok".


الخطوة 2: تثبيت next-intl وإعداد التوجيه (10 دقائق)

ثبت المكتبة:

npm install next-intl

أنشئ ملف i18n.ts في جذر مشروعك. هذا يخبر next-intl باللغات التي تدعمها وكيفية تحميل ملف الرسائل الصحيح لكل طلب:

// i18n.ts
import { getRequestConfig } from 'next-intl/server'

export const locales = ['en', 'de', 'fr'] as const
export type Locale = (typeof locales)[number]
export const defaultLocale: Locale = 'en'

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale
  if (!locale || !locales.includes(locale as Locale)) {
    locale = defaultLocale
  }
  return {
    locale,
    messages: (await import(`./messages/${locale}.json`)).default,
  }
})

أضف وسيطًا (middleware) لإضافة بادئة اللغة إلى المسارات:

// middleware.ts
import createMiddleware from 'next-intl/middleware'
import { locales, defaultLocale } from './i18n'

export default createMiddleware({
  locales: [...locales],
  defaultLocale,
  localePrefix: 'as-needed',
})

export const config = {
  matcher: ['/((?!api|_next|.*\..*).*)'],
}

انقل ملفات الصفحات إلى app/[locale]/. حدّث التخطيط الجذري ليستقبل معامل اللغة ويغلف الأطفال بـ NextIntlClientProvider:

// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl'
import { getMessages } from 'next-intl/server'

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode
  params: Promise<{ locale: string }>
}) {
  const { locale } = await params
  const messages = await getMessages()
  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  )
}

الخطوة 3: استخراج السلاسل النصية إلى ملف رسائل JSON (10 دقائق)

أنشئ مجلد messages/ في جذر مشروعك. أضف ملف en.json مع سلاسل المصدر الخاصة بك. يستخدم next-intl هيكل مفتاح متداخل:

{
  "Home": {
    "title": "Welcome",
    "cta": "Get started"
  }
}

حدّث صفحاتك لاستخدام useTranslations بدلاً من السلاسل النصية الثابتة:

// app/[locale]/page.tsx
import { useTranslations } from 'next-intl'

export default function HomePage() {
  const t = useTranslations('Home')
  return (
    <main>
      <h1>{t('title')}</h1>
      <button type="button">{t('cta')}</button>
    </main>
  )
}

الآن اكتب نص الترجمة. هذا يقرأ messages/en.json، يرسله إلى API الخاص بـ PolyLingo مع format: "json"، ويكتب ملف إخراج واحد لكل لغة هدف. علامة format: "json" تخبر API بالحفاظ على هيكل المفاتيح وترجمة القيم النصية فقط — المفاتيح المتداخلة، والمصفوفات، والأنواع غير النصية تعود دون تغيير.

// scripts/translate-messages.mjs
// Run with: node scripts/translate-messages.mjs

import fs from 'node:fs'
import path from 'node:path'

const API_KEY = process.env.POLYLINGO_API_KEY
const API_URL = (process.env.POLYLINGO_API_URL || 'https://api.usepolylingo.com/v1').replace(/\/$/, '')
const TARGETS = ['de', 'fr'] // extend this array to add more locales

const enPath = path.join('messages', 'en.json')
const en = JSON.parse(fs.readFileSync(enPath, 'utf8'))

const res = await fetch(`${API_URL}/translate`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    content: JSON.stringify(en),
    format: 'json',
    targets: TARGETS,
    model: 'standard',
  }),
})

if (!res.ok) {
  const err = await res.text()
  throw new Error(`PolyLingo ${res.status}: ${err}`)
}

const { translations } = await res.json()

for (const locale of TARGETS) {
  const out = path.join('messages', `${locale}.json`)
  fs.writeFileSync(out, JSON.stringify(JSON.parse(translations[locale]), null, 2) + '\n')
  console.log('Wrote', out)
}

شغّله:

node scripts/translate-messages.mjs

يجب أن ترى مخرجات مثل:

Wrote messages/de.json
Wrote messages/fr.json

افتح تلك الملفات وتحقق منها. ستكون مفاتيحك مطابقة لـ en.json. فقط القيم النصية هي التي تغيرت.


الخطوة 4: اختبار سريع للمسارات (5 دقائق)

ابدأ خادم التطوير الخاص بك:

npm run dev

زر http://localhost:3000 و http://localhost:3000/de. يجب أن تظهر العناوين والأزرار بالإنجليزية والألمانية على التوالي. أضف المزيد من اللغات بتمديد مصفوفة TARGETS في النص ومصفوفة locales في i18n.ts، ثم أعد تشغيل النص.

تحقق من استخدام الرموز في لوحة تحكم PolyLingo تحت Usage. لملف لغة صغير مترجم إلى لغتين، ستستخدم بضع مئات من الرموز من حصتك الشهرية.


إلى أين تذهب من هنا

أضف المزيد من اللغات. يرسل النص طلبًا واحدًا بغض النظر عن عدد الإدخالات في TARGETS. إضافة اليابانية، الإسبانية، والعربية تكلف مكالمة API واحدة، وليس ثلاث.

اربطه بـ CI. أضف POLYLINGO_API_KEY كسري مستودع في GitHub Actions وشغّل النص كجزء من خط أنابيب البناء الخاص بك. تبقى ملفات اللغة متزامنة تلقائيًا كلما تغير en.json.

ترجم صيغ أخرى. نفس نمط النص يعمل لصفحات توثيق Markdown (format: "markdown") وقوالب البريد الإلكتروني HTML (format: "html"). يحافظ API على الهيكل في جميع الحالات.

استخدم نقطة النهاية الدُفعية للمشاريع الأكبر. إذا كان لديك ملفات JSON منفصلة متعددة (واحدة لكل منطقة ميزة، على سبيل المثال)، يقبل POST /translate/batch حتى 100 عنصر في طلب واحد، كل منها مع id و format خاص به.


جربه مجانًا

تشمل الخطة المجانية لـ PolyLingo 100,000 رمز شهريًا. لا حاجة لبطاقة ائتمان.

curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
  -H "Authorization: Bearer $POLYLINGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "{\"Home\":{\"title\":\"Welcome\",\"cta\":\"Get started\"}}",
    "format": "json",
    "targets": ["de", "fr", "es", "ja"]
  }'

احصل على مفتاح API الخاص بك