Skip to main content

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.

1

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.

The expansion problem
// 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.
Mở rộng văn bản không phải là trường hợp hiếm gặp. Mọi giao diện hỗ trợ nhiều ngôn ngữ đều sẽ gặp vấn đề này. Tiếng Đức dài hơn tiếng Anh 30%, tiếng Phần Lan dài hơn 40% và một số ngôn ngữ có thể dài hơn trên 100% đối với chuỗi ngắn. Kiểm thử độ mở rộng trước khi có bản dịch giúp tránh phải thiết kế lại tốn kém.
2

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.

Expansion ratios by language
// 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% expansion
Đây là các giá trị trung bình. Từng chuỗi có thể mở rộng nhiều hơn đáng kể — nhãn nút gồm 2 từ tiếng Anh có thể thành 4 từ trong tiếng Đức. Hãy kiểm thử với tỷ lệ cao hơn (trên 50%) cho các thành phần giao diện quan trọng như nút, thanh điều hướng và tiêu đề bảng.
3

Kiể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ế.

Terminal
# 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
Visual regression tests
// 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,
  });
});
Hãy kiểm thử với mức mở rộng 40% cho các ngôn ngữ châu Âu và 50% cho tình huống xấu nhất. Nếu bố cục vẫn ổn khi mở rộng 50%, bố cục đó sẽ xử lý được hầu như mọi ngôn ngữ.
4

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.

CSS best practices
/* 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

Không cần đăng kýBáo giá tức thì

Câu hỏi thường gặp về mở rộng văn bản