Setting up website localization for Ukrainian language
Ukrainian language (uk / uk-UA) uses Cyrillic with letters absent in Russian: Ї ї, І і, Є є, Ґ ґ. Rules for numeral declension differ from Russian. Ukrainian is the second most common language in CIS, mandatory for websites targeting Ukrainian audience.
Basic setup
// config/app.php
'locale' => 'uk',
'fallback_locale' => 'en',
// resources/lang/uk/messages.php
return [
'welcome' => 'Ласкаво просимо на наш сайт',
'catalog' => 'Каталог',
'cart' => 'Кошик',
'checkout' => 'Оформлення замовлення',
'search' => 'Пошук',
'add_to_cart' => 'Додати до кошика',
'price' => 'Ціна',
'in_stock' => 'Є в наявності',
'out_of_stock' => 'Немає в наявності',
'order_placed' => 'Замовлення оформлено',
'login' => 'Увійти',
'register' => 'Зареєструватися',
'logout' => 'Вийти',
];
Numeral declension in Ukrainian
Ukrainian has three forms, like Russian, but with different rules for some digits:
function pluralUk(int $n, string $one, string $few, string $many): string
{
$abs = abs($n);
$mod10 = $abs % 10;
$mod100 = $abs % 100;
if ($mod100 >= 11 && $mod100 <= 19) return "$n $many";
if ($mod10 === 1) return "$n $one";
if ($mod10 >= 2 && $mod10 <= 4) return "$n $few";
return "$n $many";
}
// "товар / товари / товарів"
echo pluralUk(1, 'товар', 'товари', 'товарів'); // 1 товар
echo pluralUk(3, 'товар', 'товари', 'товарів'); // 3 товари
echo pluralUk(11, 'товар', 'товари', 'товарів'); // 11 товарів
echo pluralUk(21, 'товар', 'товари', 'товарів'); // 21 товар
Key difference from Russian: in Ukrainian, "few" form applies for 2–4, not just "two" (form coincides, but named differently). In practice, code is identical.
const rules = new Intl.PluralRules('uk')
const forms: Record<string, string> = {
one: 'товар',
few: 'товари',
many: 'товарів',
other: 'товарів',
}
const pluralize = (n: number) => `${n} ${forms[rules.select(n)]}`
Date and currency formatting
const df = new Intl.DateTimeFormat('uk-UA', {
day: 'numeric',
month: 'long',
year: 'numeric',
})
df.format(new Date()) // "28 березня 2026 р."
// Hryvnia
new Intl.NumberFormat('uk-UA', {
style: 'currency',
currency: 'UAH',
maximumFractionDigits: 0,
}).format(1990) // "1 990 ₴"
// Numbers
new Intl.NumberFormat('uk-UA').format(1234567.89)
// "1 234 567,89"
const rtf = new Intl.RelativeTimeFormat('uk', { numeric: 'auto' })
rtf.format(-1, 'day') // "вчора"
rtf.format(-5, 'day') // "5 днів тому"
rtf.format(2, 'hour') // "через 2 години"
Ukrainian letter specifics
The letter «Ї» (U+0407 / U+0457) is unique to Ukrainian. «І» differs from Russian «И». «Є» ≠ «Е».
Not all fonts contain «Ґ» (U+0490 / U+0491). Check fonts:
body {
font-family: 'PT Sans', 'Roboto', 'Noto Sans', Arial, sans-serif;
}
All three fonts contain complete Ukrainian alphabet.
Laravel: validation messages
// resources/lang/uk/validation.php
return [
'required' => 'Поле «:attribute» є обов\'язковим.',
'email' => 'Поле «:attribute» повинно містити коректну email-адресу.',
'min' => [
'string' => 'Поле «:attribute» має містити не менше :min символів.',
],
'unique' => 'Таке значення поля «:attribute» вже існує.',
'attributes' => [
'email' => 'email',
'password' => 'пароль',
'name' => 'ім\'я',
'phone' => 'телефон',
],
];
Ukraine phone numbers
function formatUaPhone(value: string): string {
const digits = value.replace(/\D/g, '')
const normalized = digits.startsWith('0') ? '380' + digits.slice(1) : digits
if (normalized.length !== 12 || !normalized.startsWith('380')) return value
return `+380 (${normalized.slice(3, 5)}) ${normalized.slice(5, 8)}-${normalized.slice(8, 10)}-${normalized.slice(10)}`
}
formatUaPhone('0671234567') // "+380 (67) 123-45-67"
SEO
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta property="og:locale" content="uk_UA">
<link rel="alternate" hreflang="uk" href="https://example.ua/uk/" />
<link rel="alternate" hreflang="ru" href="https://example.ua/" />
<link rel="alternate" hreflang="x-default" href="https://example.ua/" />
</head>
Timeframe
Setting up locale, UI translations, date/currency/phone formatting — 1 working day.







