
Bản địa hóa liên tục không cần TMS
Mã của bạn được triển khai liên tục. Bản dịch cũng nên như vậy. Sau đây là cách tự động bản địa hóa trong quy trình phát triển.
Bản địa hóa liên tục là gì?
Bản địa hóa liên tục là cách tự động dịch chuỗi mới ngay trong quy trình phát triển thay vì gom bản dịch thành từng đợt phát hành định kỳ. Khi lập trình viên thêm tính năng mới có chuỗi UI, hệ thống sẽ dịch các chuỗi đó trước khi phát hành tính năng.
Phương pháp truyền thống
Phần lớn nhóm xử lý bản dịch theo đợt: thu thập chuỗi mới, xuất sang TMS, chờ biên dịch viên, nhập kết quả rồi phát hành. Cách này tạo nút thắt bản địa hóa, khiến bản phát hành quốc tế chậm vài ngày hoặc vài tuần.
Lập trình viên thêm chuỗi mới vào tệp locale nguồn
Chuỗi được xuất và tải lên nền tảng TMS
Biên dịch viên nhận thông báo và bắt đầu làm việc
Bản dịch được duyệt và phê duyệt
Tệp đã dịch được tải xuống và hợp nhất trở lại
Tính năng được phát hành kèm bản dịch (sau vài ngày đến vài tuần)
Phương pháp tích hợp trong IDE
Với tính năng dịch tích hợp trong IDE, lập trình viên dịch chuỗi ngay trong quy trình viết mã thường ngày. Không cần xuất, tải lên hay chờ đợi — bản dịch được tạo trong cùng phiên phát triển.
Lập trình viên thêm chuỗi mới vào tệp locale nguồn
Lập trình viên yêu cầu trợ lý AI dịch tệp
Tệp đã dịch được ghi thẳng vào dự án
Tính năng và bản dịch được phát hành trong cùng một commit
Phương pháp truyền thống
6 steps
Multiple tools and platforms
Days to weeks per cycle
Phương pháp tích hợp trong IDE
4 steps
Inside your editor
Same commit
Thiết lập quy trình dịch
Với nhóm muốn tự động dịch ngoài IDE, hãy thêm một bước CI/CD để dịch chuỗi mới hoặc đã thay đổi mỗi khi đẩy lên main. Cách này hoạt động với GitHub Actions, GitLab CI hoặc mọi hệ thống CI/CD.
Nhóm nhỏ nên bắt đầu bằng tính năng dịch tích hợp trong IDE. Hãy thêm tự động hóa CI/CD khi nhóm có hơn 3-4 lập trình viên hoặc khi bạn cần bảo đảm mọi lần hợp nhất vào main đều có bản dịch.
# .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 pushThêm bước đảm bảo chất lượng bản dịch vào CI
Các bước kiểm tra tự động trong quy trình CI phát hiện bản dịch thiếu, placeholder hỏng và định dạng thông báo ICU không hợp lệ trước khi đưa lên production. Đây là các tập lệnh đơn giản dùng để so sánh tệp locale nguồn với mọi locale đích.
#!/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
doneXác thực bản dịch trong CI
Phát hiện và xử lý độ lệch bản dịch
Độ lệch bản dịch xảy ra khi chuỗi nguồn thay đổi nhưng bản dịch không được cập nhật. Tiếng Anh ghi "Save changes" nhưng tiếng Đức vẫn giữ nội dung cũ. Cơ chế phát hiện độ lệch so sánh dấu thời gian hoặc hàm băm nội dung của tệp nguồn và tệp dịch.
#!/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"Chọn phương pháp dịch
Không phải mọi nội dung đều cần cùng một phương pháp dịch. AI xử lý tốt chuỗi và nhãn UI. Nội dung tiếp thị nên kết hợp AI với người duyệt. Văn bản pháp lý và tuân thủ luôn cần biên dịch viên chuyên nghiệp.
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 | PremiumQuy trình Git cho bản dịch
Hãy dịch trên nhánh tính năng trước khi hợp nhất. Cách này bảo đảm mọi lần hợp nhất vào main đều có bản dịch đầy đủ. Thêm bước kiểm tra trước khi hợp nhất để xác minh độ đầy đủ của bản dịch cho mọi locale được hỗ trợ.
Tệp locale JSON lớn thường gây xung đột hợp nhất khi nhiều nhánh cùng sửa. Hãy sắp xếp khóa theo bảng chữ cái và đặt mỗi khóa trên một dòng để giảm kích thước diff, giúp giải quyết xung đột dễ hơn.
# .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');
\""Lỗi thường gặp
Chỉ bản địa hóa sau khi phát triển
Không xác thực bản dịch ở cấp CI
Phức tạp hóa quá mức bằng TMS
Không theo dõi độ mới của bản dịch
Dùng thử i18n Agent ngay
Thả tệp bản dịch của bạn vào đây
JSON, YAML, PO, XML, CSV, Markdown, Properties
hoặc nhấp để duyệt
Ngôn ngữ đích