
Континуирана локализација без TMS система
Ваш кôд се поставља континуирано. Тако треба и преводи. Ево како да аутоматизујете локализацију у развојном току.
Шта је континуирана локализација?
Континуирана локализација је пракса аутоматског превођења нових текстова као дела развојног тока, уместо груписања превода у повремена издања. Када програмер дода нову функцију са UI текстовима, они се преводе пре објављивања функције.
Традиционални приступ
Већина тимова групише преводе: прикупи нове текстове, извезе их у TMS, сачека преводиоце, увезе резултате и објави. Тако настаје уско грло локализације које одлаже међународна издања данима или недељама.
Програмер додаје нове текстове у датотеку изворног локала
Текстови се извозе и отпремају на TMS платформу
Преводиоци добијају обавештење и почињу рад
Преводи се прегледају и одобравају
Преведене датотеке се преузимају и поново спајају
Функционалност се испоручује са преводима (неколико дана или недеља касније)
Приступ изворно интегрисан у IDE
Уз превођење изворно за IDE, програмер преводи текстове као део уобичајеног тока програмирања. Без извоза, отпремања и чекања — преводи настају у истој сесији као и развој.
Програмер додаје нове текстове у датотеку изворног локала
Програмер тражи од свог AI помоћника да преведе датотеку
Преведене датотеке уписују се директно у пројекат
Функционалност се испоручује са преводима у истом commit кораку
Традиционални приступ
6 steps
Multiple tools and platforms
Days to weeks per cycle
Приступ изворно интегрисан у IDE
4 steps
Inside your editor
Same commit
Подесите pipeline превођења
Тимови који желе аутоматско превођење ван IDE окружења могу да додају CI/CD корак који преводи нове или измењене текстове при сваком слању на main. Ради са GitHub Actions, GitLab CI и сваким CI/CD системом.
Мали тимови нека почну превођењем у IDE окружењу. Додајте CI/CD аутоматизацију када тим прерасте три до четири програмера или када преводи морају бити загарантовани при сваком спајању у 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Додајте QA превода у CI
Аутоматске провере у CI pipeline процесу откривају недостајуће преводе, неисправна места за променљиве и неважеће 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", али немачки и даље приказује стари текст. Откривање пореди временске ознаке или hash вредности изворних и преведених датотека.
#!/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"Изаберите приступ превођењу
Није сваком садржају потребан исти приступ. UI текстови и ознаке одлично раде са AI превођењем. Маркетиншком тексту користи AI уз људски преглед. Правни текст и текст усклађености увек треба да преводе професионални људи преводиоци.
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 | PremiumGit ток рада за преводе
Преведите на грани функције пре спајања, не после. Тако свако спајање у 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
или кликните за избор
Циљни језици