Skip to main content

การขยายข้อความใน i18n : ป้องกันเลย์เอาต์เสียหายจากความยาวคำแปล

UI ภาษาอังกฤษของคุณพอดีอย่างสมบูรณ์แบบ แต่เมื่อคำแปลภาษาเยอรมันมาถึงกลับยาวขึ้น 30% ส่วนภาษาฟินแลนด์ยาวขึ้น 40% ปุ่มล้น ตารางเสีย และเลย์เอาต์ที่ออกแบบอย่างประณีตพังลง การทดสอบการขยายข้อความป้องกันปัญหานี้ได้

1

เหตุใดการขยายข้อความจึงทำให้เลย์เอาต์เสียหาย

นักพัฒนาออกแบบ UI ด้วยข้อความภาษาอังกฤษซึ่งเป็นหนึ่งในภาษาที่กระชับที่สุด เมื่อคำแปลมาถึง ภาษาที่ใช้ข้อความยาวกว่าจะล้นคอนเทนเนอร์ ทำเลย์เอาต์กริดเสีย ตัดป้ายปุ่ม และดันเนื้อหาออกนอกหน้าจอ บั๊กเหล่านี้ปรากฏเฉพาะในบางภาษา จึงมองไม่เห็นระหว่างการพัฒนาและทดสอบด้วยภาษาอังกฤษเพียงภาษาเดียว

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.
การขยายข้อความไม่ใช่กรณีพิเศษ UI ทุกชุดที่รองรับหลายภาษาจะพบปัญหานี้ ภาษาเยอรมันยาวกว่าภาษาอังกฤษ 30% ภาษาฟินแลนด์ยาวกว่า 40% และบางภาษาอาจยาวกว่า 100% สำหรับข้อความสั้น การทดสอบการขยายก่อนมีคำแปลจริงช่วยป้องกันการออกแบบใหม่ที่มีค่าใช้จ่ายสูง
2

อัตราการขยายข้อความตามภาษา

อัตราการขยายเฉลี่ยเมื่อเทียบกับข้อความต้นฉบับภาษาอังกฤษ ข้อความสั้น (ไม่เกิน 20 อักขระ) ขยายมากกว่าข้อความยาว เพราะการเลือกแต่ละคำส่งผลต่อความยาวรวมมากกว่า

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
ตัวเลขเหล่านี้เป็นค่าเฉลี่ย ข้อความบางรายการอาจขยายมากกว่านี้อย่างมาก เช่น ป้ายปุ่มภาษาอังกฤษ 2 คำอาจกลายเป็น 4 คำในภาษาเยอรมัน ทดสอบองค์ประกอบ UI สำคัญอย่างปุ่ม เมนูนำทาง และส่วนหัวตารางด้วยอัตราที่สูงกว่า (50% ขึ้นไป)
3

การทดสอบด้วย i18n-pseudo

กลยุทธ์การขยายของ i18n-pseudo เติมข้อความต้นฉบับให้ยาวขึ้นเพื่อจำลองความยาวคำแปล ตั้งอัตราการขยายให้ตรงกับภาษาเป้าหมาย แล้วทดสอบเลย์เอาต์ก่อนมีคำแปลจริง

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,
  });
});
ทดสอบด้วยการขยาย 40% สำหรับภาษายุโรป และ 50% สำหรับกรณีเลวร้ายที่สุด หากเลย์เอาต์รองรับการขยาย 50% ได้ ก็จะรองรับแทบทุกภาษา
4

แนวทางปฏิบัติด้านการออกแบบสำหรับ i18n

การสร้างเลย์เอาต์ให้รองรับการขยายข้อความต้องตัดสินใจด้านการออกแบบก่อนเริ่มงานแปล แนวทางเหล่านี้ช่วยป้องกันบั๊กที่เกี่ยวข้องกับการขยายซึ่งพบบ่อยที่สุด

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 */

ลองใช้ i18n Agent ตอนนี้

ลากและวางไฟล์แปลของคุณที่นี่

JSON, YAML, PO, XML, CSV, Markdown, Properties

หรือคลิกเพื่อเลือกไฟล์

ภาษาเป้าหมาย

ไม่ต้องลงทะเบียนประเมินราคาได้ทันที

คำถามที่พบบ่อยเกี่ยวกับการขยายข้อความ