
Розширення тексту в i18n: як запобігти порушенню макета через довжину перекладу
Ваш англомовний інтерфейс має бездоганний вигляд. Аж ось надходить німецький переклад — на 30% довший. Фінський — на 40%. Текст виходить за межі кнопок, таблиці деформуються, а ретельно спроєктований макет руйнується. Тестування розширення тексту допомагає цьому запобігти.
Чому розширення тексту порушує макети
Розробники проєктують інтерфейси з англійським текстом, а англійська — одна з найкомпактніших мов. Коли надходять переклади, довший текст виходить за межі контейнерів, порушує сіткові макети, обрізає підписи кнопок і виштовхує вміст за межі екрана. Такі помилки виникають лише в окремих локалях, тому залишаються непомітними під час розробки й тестування тільки англійською мовою.
// 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.Коефіцієнти розширення тексту за мовами
Середні коефіцієнти розширення порівняно з англійським вихідним текстом. Короткі рядки (до 20 символів) розширюються більше за довгі, оскільки вибір окремих слів сильніше впливає на загальну довжину.
// 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Тестування за допомогою i18n-pseudo
Стратегія розширення i18n-pseudo додає заповнення до вихідних рядків, щоб імітувати довжину перекладу. Установіть коефіцієнт розширення відповідно до цільових мов і протестуйте макети ще до надходження справжніх перекладів.
# 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,
});
});Найкращі практики проєктування для i18n
Щоб створити макети, здатні вмістити розширений текст, проєктні рішення потрібно ухвалити ще до початку перекладу. Ці практики запобігають найпоширенішим помилкам, пов’язаним із розширенням.
/* 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
або натисніть, щоб вибрати
Цільові мови