
التوطين المستمر دون نظام TMS
تنشر شيفرتك باستمرار؛ ويجب أن تُنشر ترجماتك باستمرار أيضاً. إليك كيفية أتمتة التوطين ضمن سير عمل التطوير.
ما هو التوطين المستمر؟
التوطين المستمر هو ممارسة ترجمة السلاسل الجديدة تلقائياً كجزء من سير عمل التطوير، بدلاً من تجميع الترجمات في إصدارات دورية. عندما يضيف المطوّر ميزة جديدة تتضمن سلاسل واجهة مستخدم، تُترجم هذه السلاسل قبل شحن الميزة.
النهج التقليدي
تجمع معظم الفرق الترجمات على دفعات: تجمع السلاسل الجديدة، وتُصدرها إلى نظام TMS، وتنتظر المترجمين، ثم تستورد النتائج، وبعد ذلك تشحن. يخلق هذا عنق زجاجة في التوطين يؤخر الإصدارات الدولية أياماً أو أسابيع.
يضيف المطوّر سلاسل جديدة إلى ملف الإعدادات المحلية المصدر
تُصدَّر السلاسل وتُرفع إلى منصة TMS
يُبلَّغ المترجمون ويبدؤون العمل
تُراجع الترجمات وتُعتمد
تُنزل الملفات المترجمة وتُدمج من جديد
تُشحن الميزة مع الترجمات (بعد أيام إلى أسابيع)
النهج الأصلي داخل IDE
مع الترجمة الأصلية داخل IDE، يترجم المطوّر السلاسل كجزء من سير عمل البرمجة المعتاد. لا تصدير، لا رفع، لا انتظار — تحدث الترجمات في الجلسة نفسها التي يتم فيها التطوير.
يضيف المطوّر سلاسل جديدة إلى ملف الإعدادات المحلية المصدر
يطلب المطوّر من مساعده بالذكاء الاصطناعي ترجمة الملف
تُكتب الملفات المترجمة مباشرةً إلى المشروع
تُشحن الميزة مع الترجمات في الالتزام نفسه
النهج التقليدي
6 steps
Multiple tools and platforms
Days to weeks per cycle
النهج الأصلي داخل IDE
4 steps
Inside your editor
Same commit
إعداد خط ترجمتك
بالنسبة إلى الفرق التي تريد ترجمة آلية تتجاوز IDE، أضف خطوة في CI/CD لترجمة السلاسل الجديدة أو المتغيرة مع كل push إلى main. يعمل ذلك مع GitHub Actions وGitLab CI أو أي نظام CI/CD.
ابدأ بالترجمة الأصلية داخل IDE للفرق الصغيرة. أضف أتمتة CI/CD عندما ينمو فريقك إلى أكثر من 3-4 مطورين أو عندما تحتاج إلى ضمان توفر الترجمات مع كل دمج إلى main.
# .github/workflows/translate.yml
name: Translate
on:
push:
branches: [main]
paths: ['locales/en/**']
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Translate changed strings
run: |
npx i18n-agent translate locales/en.json \
--to de,ja,es,fr,ko,zh-Hans \
--api-key ${{ secrets.I18N_AGENT_API_KEY }}
- name: Commit translations
run: |
git config user.name "github-actions"
git config user.email "[email protected]"
git add locales/
git diff --cached --quiet || git commit -m "chore: update translations"
git push# .gitlab-ci.yml
translate:
stage: deploy
only:
changes:
- locales/en/**
script:
- npx i18n-agent translate locales/en.json
--to de,ja,es,fr --api-key $I18N_AGENT_API_KEY
- git add locales/ && git commit -m "chore: translations" && git pushإضافة ضمان جودة الترجمة إلى CI
تلتقط الفحوص الآلية ضمن خط CI الترجمات المفقودة، وplaceholders المعطوبة، وصيغ رسائل ICU غير الصالحة قبل أن تصل إلى الإنتاج. هذه نصوص بسيطة تقارن ملف الإعدادات المحلية المصدر مع جميع الإعدادات المحلية المستهدفة.
#!/bin/bash
# check-translations.sh — Run in CI to catch missing translations
SOURCE="locales/en.json"
LANGS=("de" "ja" "es" "fr")
EXIT_CODE=0
# Extract all keys from source
SOURCE_KEYS=$(jq -r '[paths(scalars)] | map(join(".")) | .[]' "$SOURCE" | sort)
SOURCE_COUNT=$(echo "$SOURCE_KEYS" | wc -l)
for lang in "${LANGS[@]}"; do
TARGET="locales/$lang.json"
if [ ! -f "$TARGET" ]; then
echo "❌ Missing: $TARGET"
EXIT_CODE=1
continue
fi
TARGET_KEYS=$(jq -r '[paths(scalars)] | map(join(".")) | .[]' "$TARGET" | sort)
MISSING=$(comm -23 <(echo "$SOURCE_KEYS") <(echo "$TARGET_KEYS"))
if [ -n "$MISSING" ]; then
COUNT=$(echo "$MISSING" | wc -l)
echo "❌ $lang: $COUNT missing keys"
echo "$MISSING" | head -5
EXIT_CODE=1
else
echo "✅ $lang: all $SOURCE_COUNT keys present"
fi
done
exit $EXIT_CODE#!/bin/bash
# check-placeholders.sh — Validate placeholder consistency
SOURCE="locales/en.json"
LANGS=("de" "ja" "es")
for lang in "${LANGS[@]}"; do
TARGET="locales/$lang.json"
# Compare placeholders like {{name}}, {count}, %s, %d
jq -r 'paths(scalars) as $p | [($p | join(".")), (getpath($p))]
| @tsv' "$SOURCE" | while IFS=$'\t' read -r key value; do
SOURCE_PH=$(echo "$value" | grep -oE '\{\{[^}]+\}\}|%[sd@]' | sort)
TARGET_VAL=$(jq -r "getpath($(echo $key | jq -R 'split(".")'))" "$TARGET")
TARGET_PH=$(echo "$TARGET_VAL" | grep -oE '\{\{[^}]+\}\}|%[sd@]' | sort)
if [ "$SOURCE_PH" != "$TARGET_PH" ]; then
echo "❌ $lang/$key: placeholder mismatch"
echo " Source: $SOURCE_PH"
echo " Target: $TARGET_PH"
fi
done
doneتحقّق من الترجمات في CI
اكتشاف انجراف الترجمة والتعامل معه
يحدث انجراف الترجمة عندما تتغير السلاسل المصدرية ولا تُحدَّث الترجمات. تقول الإنجليزية "Save changes" بينما لا تزال الألمانية تعرض النص القديم. يقارن اكتشاف الانجراف الطوابع الزمنية للملفات أو تجزئات المحتوى.
#!/bin/bash
# detect-drift.sh — Find stale translations
SOURCE="locales/en.json"
SOURCE_HASH=$(md5sum "$SOURCE" | cut -d' ' -f1)
HASH_FILE=".translation-hashes"
# Compare current source hash with stored hash
if [ -f "$HASH_FILE" ]; then
STORED_HASH=$(grep "^en:" "$HASH_FILE" | cut -d: -f2)
if [ "$SOURCE_HASH" != "$STORED_HASH" ]; then
echo "⚠️ Source strings changed since last translation"
echo " Run translations to update all locales"
# Show which keys changed
git diff HEAD~1 "$SOURCE" | grep '^[+-]' | grep -v '^[+-][+-]'
fi
fi
# Update stored hash
echo "en:$SOURCE_HASH" > "$HASH_FILE"اختر نهج الترجمة المناسب لك
ليست كل أنواع المحتوى بحاجة إلى النهج نفسه في الترجمة. تعمل ترجمة الذكاء الاصطناعي بشكل ممتاز مع سلاسل واجهة المستخدم والتسميات. ويستفيد النص التسويقي من الذكاء الاصطناعي مع مراجعة بشرية. أما النصوص القانونية ونصوص الامتثال فيجب أن تتولاها دائماً ترجمة بشرية احترافية.
Translation Approach Comparison:
Content Type | Approach | Cost/word | Quality
─────────────────────┼───────────────────┼────────────┼──────────
UI strings, labels | AI/LLM | $0.001-01 | Production
Tooltips, help text | AI/LLM | $0.001-01 | Production
Marketing copy | AI + human review | $0.05-0.15 | High
Legal / compliance | Human translator | $0.15-0.40 | Certified
Brand voice content | Human translator | $0.20-0.50 | Premiumسير عمل Git للترجمات
ترجِم على فرع الميزة لديك قبل الدمج، لا بعده. يضمن ذلك أن كل عملية دمج إلى main تتضمن ترجمات كاملة. أضِف فحصًا قبل الدمج يتحقق من اكتمال الترجمات لكل اللغات المحلية المدعومة.
تتسبب ملفات JSON الكبيرة الخاصة باللغات المحلية في تعارضات دمج متكررة عندما تُعدّلها فروع متعددة في الوقت نفسه. رتّب المفاتيح أبجديًا واستخدم مفتاحًا واحدًا لكل سطر لتقليل حجم الفروقات وتسهيل حل التعارضات.
# .gitattributes — reduce merge conflicts in locale files
locales/*.json merge=union
# Sort keys alphabetically to minimize diffs:
# package.json script:
"sort-locales": "node -e \"
const fs = require('fs');
const f = process.argv[1];
const d = JSON.parse(fs.readFileSync(f));
const s = (o) => Object.keys(o).sort().reduce((r,k) =>
({...r, [k]: typeof o[k]==='object' ? s(o[k]) : o[k]}), {});
fs.writeFileSync(f, JSON.stringify(s(d), null, 2)+'\\n');
\""المزالق الشائعة
اعتبار التوطين خطوة لاحقة للتطوير
غياب التحقق من الترجمة على مستوى CI
الإفراط في التعقيد باستخدام TMS
عدم تتبع حداثة الترجمات
جرّب i18n Agent الآن
أفلت ملف الترجمة هنا
JSON, YAML, PO, XML, CSV, Markdown, Properties
أو انقر للاستعراض
اللغات المستهدفة