Search K
دليل الترجمة
يأتي SnapOtter مزوّدًا بـ 21 لغة جاهزة للاستخدام. يستخدم نظام i18n وقت تشغيل مخصصًا خفيف الوزن مع اكتمال اللغات المفروض عبر TypeScript وتقسيم الشيفرة الديناميكي.
اللغات المدعومة
| الرمز | اللغة | Native Name | Direction |
|---|---|---|---|
en | الإنجليزية | English | LTR |
zh-CN | الصينية (المبسطة) | 简体中文 | LTR |
zh-TW | الصينية (التقليدية) | 繁體中文 | LTR |
ja | اليابانية | 日本語 | LTR |
ko | الكورية | 한국어 | LTR |
es | الإسبانية | Español | LTR |
fr | الفرنسية | Français | LTR |
it | الإيطالية | Italiano | LTR |
pt-BR | البرتغالية (البرازيل) | Português (Brasil) | LTR |
de | الألمانية | Deutsch | LTR |
nl | الهولندية | Nederlands | LTR |
sv | السويدية | Svenska | LTR |
ru | الروسية | Русский | LTR |
pl | البولندية | Polski | LTR |
uk | الأوكرانية | Українська | LTR |
ar | العربية | العربية | RTL |
tr | التركية | Türkçe | LTR |
hi | الهندية | हिन्दी | LTR |
vi | الفيتنامية | Tiếng Việt | LTR |
id | الإندونيسية | Bahasa Indonesia | LTR |
th | التايلاندية | ไทย | LTR |
كيف يعمل اكتشاف اللغة
يستخدم SnapOtter ترتيب حلٍّ من ثلاث طبقات:
- تفضيل المستخدم - مخزَّن في
localStorage("snapotter-locale")ومتزامن مع إعدادات المستخدم عند تسجيل الدخول - الاكتشاف التلقائي للمتصفح - يمرّ عبر مصفوفة
navigator.languagesمع مطابقة بادئة BCP 47 - الافتراضي للنسخة - متغيّر البيئة
DEFAULT_LOCALEالخاص بالمشرف (يُجلَب منGET /api/v1/config/locale) - الرجوع إلى الإنجليزية - متاح دائمًا
يمكن للمستخدمين تغيير اللغة من:
- محدِّد الكرة الأرضية في التذييل (سطح المكتب، ظاهر دائمًا)
- محدِّد اللغة في صفحة تسجيل الدخول (قبل المصادقة)
- قسم الإعدادات > عام (تفضيل لكل مستخدم)
- قائمة اللغة المنسدلة في الشريط الجانبي للجوال
- قسم الإعدادات > النظام يحدّد الافتراضي على مستوى النسخة (للمشرف فقط)
كيف تعمل الترجمات
توجد جميع سلاسل واجهة المستخدم في packages/shared/src/i18n/. الملف المرجعي هو en.ts، الذي يصدّر كائنًا مُنمَّطًا يحتوي على كل سلسلة يستخدمها التطبيق (نحو 1500 مفتاح). اللغات الأخرى هي ملفات منفصلة (مثل de.ts و fr.ts) تصدّر البنية نفسها.
يستخدم النوع TranslationKeys الأداة DeepStringRecord لقبول أي قيمة سلسلة مع فرض بنية المفاتيح. يلتقط TypeScript المفاتيح المفقودة في أي ملف ترجمة في وقت التصريف.
يُحمَّل فقط الإعداد اللغوي النشط في وقت التشغيل عبر import() الديناميكي، مما يُبقي الحزمة الرئيسية صغيرة.
استخدام الترجمات في المكوّنات
tsx
import { useTranslation } from "@/contexts/i18n-context";
import { format, plural } from "@/lib/format";
function MyComponent() {
const { t, locale, setLocale } = useTranslation();
return (
<div>
<h1>{t.common.settings}</h1>
<p>{format(t.settings.people.deleteConfirm, { username: "admin" })}</p>
<p>{plural(count, t.automate.fileCount, t.automate.fileCountPlural)}</p>
</div>
);
}المساهمة بترجمة
نرحّب بطلبات سحب الترجمة مباشرة. يمكنك تحسين إعداد لغوي موجود أو إضافة إعداد جديد.
للإبلاغ عن ترجمة خاطئة دون تقديم شيفرة، افتح مشكلة على GitHub مع ذكر اللغة والسلسلة غير الصحيحة والإصلاح المقترح.
TIP
لا تتطلب طلبات سحب الترجمة موافقة مسبقة. انسخ المستودع (fork)، وأجرِ تغييراتك، وافتح طلب سحب. راجع دليل المساهمة لمعرفة عملية طلب السحب الكاملة ومتطلب CLA.
كيفية إنشاء ترجمة أو تحديثها
1. انسخ المستودع (fork) واستنسخه
bash
git clone https://github.com/<your-username>/snapotter.git
cd snapotter
pnpm install2. انسخ الملف المرجعي (للغة جديدة فقط)
تخطَّ هذه الخطوة إذا كنت تحسّن ترجمة موجودة.
bash
cp packages/shared/src/i18n/en.ts packages/shared/src/i18n/XX.ts3. ترجم السلاسل
افتح ملفك الجديد وترجم كل قيمة سلسلة. أبقِ بنية الكائن والمفاتيح كما هي تمامًا.
ts
import type { TranslationKeys } from "./en.js";
export const xx: TranslationKeys = {
common: {
upload: "Your translation here",
// ... translate all entries
},
// ... translate all sections
} as const;القواعد:
- لا تترجم مفاتيح الكائن، بل القيم النصية فقط
- أبقِ
as constفي النهاية - استورد
TranslationKeysمن./en.jsونمّط تصديرك - أبقِ العناصر النائبة
{variable}كما هي تمامًا - يجب أن تحتوي المصفوفات (
rotatingPhrasesوprogressMessages) على العدد نفسه من المدخلات - لا تترجم: SnapOtter و JPEG و PNG و WebP و EXIF و API وغيرها من المصطلحات التقنية
4. سجّل الإعداد اللغوي (للغة جديدة فقط)
أضف إعدادك اللغوي إلى SUPPORTED_LOCALES في packages/shared/src/i18n/index.ts:
ts
{ code: "xx", name: "Language Name", nativeName: "Native Name", dir: "ltr" },5. تحقّق
bash
pnpm typecheck # catches missing or mistyped keys
pnpm lint # formatting check
pnpm dev # manually verify strings appear correctly6. أرسل
افتح طلب سحب على main بعنوان مثل feat(i18n): add Swedish translation أو fix(i18n): correct German typos. سيطلب منك روبوت CLA التوقيع عند مساهمتك الأولى.
إضافة مفاتيح ترجمة جديدة
عند إضافة ميزة جديدة تحتاج إلى سلاسل واجهة مستخدم جديدة:
- أضف المفاتيح الجديدة إلى
en.tsأولًا (الملف المرجعي) - شغّل
pnpm typecheck- سيفشل كل ملف إعداد لغوي إذا كان يفتقد المفتاح الجديد - أضف المفتاح الجديد إلى جميع ملفات الإعداد اللغوي (استخدم الإنجليزية كخيار رجوع مؤقت)
الإعداد
حدّد لغة النسخة الافتراضية عبر متغيّر البيئة:
yaml
DEFAULT_LOCALE: "de" # German as the default for all new usersمرجع الملفات
| الملف | الغرض |
|---|---|
packages/shared/src/i18n/en.ts | سلاسل الإنجليزية (الإعداد اللغوي المرجعي، نحو 1500 مفتاح) |
packages/shared/src/i18n/index.ts | SUPPORTED_LOCALES و loadTranslations() وتصديرات الأنواع |
packages/shared/src/i18n/<locale>.ts | ملفات الترجمة لكل لغة |
apps/web/src/contexts/i18n-context.tsx | خطاف I18nProvider و useTranslation() |
apps/web/src/lib/format.ts | مساعدات format() و plural() و formatFileSize() |
apps/api/src/routes/config.ts | نقطة النهاية العامة GET /api/v1/config/locale |
ترجمة الموقع الإلكتروني والوثائق ومرجع API
يغطي دعم الـ 21 لغة أعلاه التطبيق. الموقع العام (snapotter.com)، وموقع الوثائق هذا، ومرجع REST API مترجمة أيضًا إلى جميع الـ 21 لغة، بواسطة مسار منفصل مقيَّد بالتجزئة يعيد استخدام أسماء الأدوات وأوصافها نفسها من packages/shared/src/i18n، لذا تبقى المصطلحات متسقة في كل مكان.
مترجمة آليًا افتراضيًا
كل صفحة غير إنجليزية على الموقع والوثائق مترجمة آليًا في التمريرة الأولى (بواسطة جلسة Claude Code، وليس خدمة طرف ثالث) وتحمل شعارًا صغيرًا قابلًا للإغلاق يوضّح ذلك، مع رابط للعودة إلى هنا. هذا متعمَّد: فهو يشحن جميع الـ 21 لغة بسرعة وبصدق، ثم يدعو المجتمع إلى تحسين الصفحات الأهم. الترجمة الآلية توصّل المعنى؛ والمراجعة البشرية تجعله يُقرأ بشكل طبيعي.
كيف يقرّر المسار ما يترجمه
تُجزَّأ كل وحدة قابلة للترجمة من المصدر الإنجليزي، وتُخزَّن التجزئة بجوار ترجمتها. في كل تشغيل، يقوم المسار بما يلي:
- يترجم أي وحدة ليس لها ترجمة بعد،
- يتخطى أي وحدة لا يزال تجزئتها المخزَّنة يطابق المصدر الإنجليزي،
- يعيد ترجمة وحدة آلية عندما يتغير مصدرها الإنجليزي،
- ويضع علامة على وحدة بشرية مُنقَّحة بوسم
stale(تحتاج مراجعة) عندما يتغير مصدرها الإنجليزي، بدلًا من الكتابة فوق عملك.
تنقيح ترجمة ويب عبر طلب سحب
تحسّن ترجمة موقع أو وثائق أو مرجع API بالطريقة نفسها التي تحسّن بها إعدادًا لغويًا للتطبيق: بتحرير الملف المُولَّد وفتح طلب سحب.
- اعثر على الترجمة المُولَّدة للغتك:
- سلاسل واجهة الموقع:
apps/landing/src/i18n/<locale>.json - صفحة وثائق:
apps/docs/<locale>/**.md - مرجع API:
apps/api/src/openapi.<locale>.yaml
- سلاسل واجهة الموقع:
- حرّر النص. أبقِ الشيفرة والروابط و
{placeholders}وأي علامات⸤I18N…⸥كما هي تمامًا؛ فمُدقّق المسار يرفض أي ترجمة تُسقط هذه العناصر أو تعيد ترتيبها. - افتح طلب سحب. يقلب تحرير الوحدة مصدرها من
machineإلىhuman، لذا لن يكتب المسار فوقها أبدًا في تشغيل لاحق. إذا تغير المصدر الإنجليزي بعد ذلك، توضَع علامة على وحدتك بوسمstaleللمراجعة بدلًا من استبدالها بصمت.
للإبلاغ عن ترجمة خاطئة دون تقديم شيفرة، افتح مشكلة على GitHub مع ذكر عنوان URL للصفحة واللغة والنص غير الصحيح وإصلاحك المقترح.
TIP
يشغّل المشرفون مسار الترجمة؛ لست بحاجة إلى مفتاح API للمساهمة. فقط حرّر الملف المُولَّد وافتح طلب سحب. راجع scripts/i18n/README.md لمعرفة كيفية تشغيل المسار.
