
Непрерывная локализация без 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 для перевода новых или изменённых строк при каждой отправке в 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 выявляют отсутствующие переводы, нарушенные заполнители и недопустимые форматы сообщений 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
Обнаруживать и устранять расхождение переводов
Расхождение возникает, когда исходные строки меняются, а переводы не обновляются. В английской версии уже написано «Сохранить изменения», а в немецкой остаётся старый текст. Для выявления расхождения сравниваются временные метки или хеши содержимого исходного файла и файлов перевода.
#!/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
или нажмите, чтобы выбрать
Целевые языки