
Mở rộng văn bản trong i18n: Ngăn bố cục bị vỡ do độ dài bản dịch
Giao diện tiếng Anh của bạn vừa khít hoàn hảo. Rồi bản dịch tiếng Đức xuất hiện — dài hơn 30%. Tiếng Phần Lan dài hơn 40%. Nút bị tràn, bảng bị vỡ và bố cục bạn dày công thiết kế tan tành. Kiểm thử mở rộng văn bản giúp ngăn điều này.
Tại sao văn bản mở rộng làm vỡ bố cục
Nhà phát triển thiết kế giao diện bằng văn bản tiếng Anh, một trong những ngôn ngữ cô đọng nhất. Khi có bản dịch, các ngôn ngữ dài hơn làm tràn vùng chứa, phá vỡ bố cục lưới, cắt ngắn nhãn nút và đẩy nội dung khỏi màn hình. Những lỗi này chỉ xuất hiện ở một số ngôn ngữ nên không thể thấy khi chỉ phát triển và kiểm thử bằng tiếng Anh.
// English is one of the most compact languages.
// Translations are almost always LONGER.
// English (source):
"Save" // 4 chars
// Translations:
"Speichern" // German: 10 chars (+150%)
"Enregistrer" // French: 12 chars (+200%)
"Guardar" // Spanish: 7 chars (+75%)
"Сохранить" // Russian: 9 chars (+125%)
"Tallenna" // Finnish: 8 chars (+100%)
// Buttons, labels, and table headers designed for
// English text WILL break in other languages.Tỷ lệ mở rộng văn bản theo ngôn ngữ
Tỷ lệ mở rộng trung bình so với văn bản nguồn tiếng Anh. Chuỗi ngắn (dưới 20 ký tự) mở rộng nhiều hơn chuỗi dài vì mỗi lựa chọn từ ngữ ảnh hưởng lớn hơn đến tổng độ dài.
// Average text expansion relative to English:
// European languages:
// German: +30-35% (compound words)
// Finnish: +30-40% (agglutinative)
// French: +15-25% (articles, prepositions)
// Spanish: +15-25%
// Italian: +15-25%
// Portuguese: +15-25%
// Russian: +20-30% (case endings)
// Polish: +20-30%
// Greek: +20-30%
// Asian languages (CJK):
// Chinese: -30-50% (shorter in characters, but wider per char)
// Japanese: -20-40% (kanji compress meaning)
// Korean: -10-20%
// Right-to-left:
// Arabic: +20-30%
// Hebrew: +10-20%
// Rule of thumb by source string length:
// 1-10 chars: expect +200% expansion
// 11-20 chars: expect +80% expansion
// 21-70 chars: expect +40% expansion
// 71+ chars: expect +30% expansionKiểm thử bằng i18n-pseudo
Chiến lược mở rộng của i18n-pseudo thêm phần đệm vào chuỗi nguồn để mô phỏng độ dài bản dịch. Hãy đặt tỷ lệ mở rộng phù hợp với ngôn ngữ đích và kiểm thử bố cục trước khi có bản dịch thực tế.
# Method 1: Pseudo-localization with expansion
npx i18n-pseudo generate \
--source locales/en.json \
--output locales/pseudo-expanded.json \
--expansion 1.4 \
--preset expanded
# Method 2: Longest-translation analysis
npx i18n-validate expansion \
--source locales/en.json \
--targets 'locales/*.json' \
--report expansion-report.json
# Output:
# Key | EN | Longest | Lang | Ratio
# ---------------------|-----|---------|------|-------
# nav.settings | 8 | 14 | de | 175%
# buttons.save | 4 | 12 | fr | 300%
# errors.networkFailed | 14 | 28 | fi | 200%
# Method 3: Visual regression with expanded text
npx playwright test \
--project=expansion-test \
--update-snapshots// playwright.config.ts
export default defineConfig({
projects: [
{
name: 'expansion-test',
use: {
locale: 'pseudo-expanded',
},
},
],
});
// tests/expansion.spec.ts
test('buttons do not overflow with expanded text', async ({ page }) => {
await page.goto('/');
// Check no horizontal overflow
const buttons = await page.locator('button').all();
for (const button of buttons) {
const box = await button.boundingBox();
const parent = await button.locator('..').boundingBox();
expect(box!.x + box!.width).toBeLessThanOrEqual(
parent!.x + parent!.width
);
}
// Visual snapshot comparison
await expect(page).toHaveScreenshot('homepage-expanded.png', {
maxDiffPixels: 100,
});
});Phương pháp thiết kế tốt nhất cho i18n
Để xây dựng bố cục xử lý được văn bản mở rộng, bạn cần đưa ra các quyết định thiết kế trước khi bắt đầu dịch. Những phương pháp này giúp ngăn các lỗi phổ biến nhất do văn bản mở rộng.
/* 1. Use flexible containers, not fixed widths */
/* WRONG */
.button { width: 120px; }
/* RIGHT */
.button { min-width: 80px; padding: 8px 16px; }
/* 2. Allow text wrapping in labels */
/* WRONG */
.label { white-space: nowrap; overflow: hidden; }
/* RIGHT */
.label { overflow-wrap: break-word; }
/* 3. Use CSS Grid/Flexbox for adaptive layouts */
.nav {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
/* 4. Reserve space for the longest expected translation */
/* Use min-width based on ~1.4x English length */
.table-header {
min-width: max-content;
padding-right: 16px;
}
/* 5. Test with the longest language first */
/* German and Finnish are good stress-test languages */
/* 6. For CJK: account for wider characters */
/* CJK characters are typically 2x the width of Latin chars */
/* Even though text is shorter, it may be wider visually */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