Як перекладати повідомлення, використовуючи ICU MessageFormat
Дата оновлення перекладу 2024-05-29
Як перекладати повідомлення, використовуючи ICU MessageFormat
Повідомлення (тобто, рядки) у додатках практично ніколи не бувають абсолютно статичними. Вони містять змінні або іншу складну логіку на кшталт плюралізації. Для того, щоб обробити це, компонент Translator підтримує синтаксис ICU MessageFormat.
Tip
Ви можете простестувати приклади ICU MessageFormatter у цьому онлайн-редакторі.
Використання формату повідомлень ICU
Для того, щоб використати формат повідомлень ICU, домен повідмлення повинен
мати суфікс +intl-icu
:
???????? ???? ????? | ???? ????? ??????? ??????????? ICU |
---|---|
messages.en.yaml |
messages+intl-icu.en.yaml |
messages.fr_FR.xlf |
messages+intl-icu.fr_FR.xlf |
admin.en.yaml |
admin+intl-icu.en.yaml |
Всі повідомлення у цьому файлі тепер будуть оброблені MessageFormatter під час перекладу.
Заповнювачі повідомлень
Базове використання MessageFormat дозволяє вам використовувати заповнювачі (які називаються аргументами в ICU MessageFormat) у ваших повідомленнях:
1 2
# translations/messages+intl-icu.en.yaml
say_hello: 'Hello {name}!'
Caution
У попередньому форматі перекладу, заповнювачі часто були обгорнуті в %
(наприклад, %name%
). Цей символ %
більше не є валідним з синтаксисом
ICU MessageFormat, тому вам потрібно переіменувати ваші параметри, якщо ви
оновлюєтесь з попереднього формату.
Все, розміщене у фігурних дужках ({...}
) обробляється форматувальником та
замінюється заповнювачем:
1 2 3 4 5
// виводить "Hello Fabien!"
echo $translator->trans('say_hello', ['name' => 'Fabien']);
// виводить "Hello Symfony!"
echo $translator->trans('say_hello', ['name' => 'Symfony']);
Вибір різних повідомлень, в залежності від стану
Синтаксис фігурних дужок дозволяє "змінювати" виведення змінної. Однією з таких
функцій є функція select
. Вона діє як PHP-функція switch statement, і дозволяє
використовувати різні рядки, в залежності від значення змінної. Типове використання
цього гендру:
1 2 3 4 5 6 7 8 9
# translations/messages+intl-icu.en.yaml
# вимагається ключ 'other', який обирається, якщо не підходить більше жодний випадок
invitation_title: >-
{organizer_gender, select,
female {{organizer_name} has invited you for her party!}
male {{organizer_name} has invited you for his party!}
other {{organizer_name} have invited you for their party!}
}
Це може виглядати дуже складно. Базовий синтаксис для всіх функцій -
{variable_name, function_name, function_statement}
(де, як ви побачите пізніше,
function_statement
є необовʼязковим для деяких функцій). У даному випадку, імʼя
функції - select
, а її ствердження містить "випадок" цього вибору. Ця функція
застосовується поверх змінної organizer_gender
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// виводить "Ryan has invited you for his party!"
echo $translator->trans('invitation_title', [
'organizer_name' => 'Ryan',
'organizer_gender' => 'male',
]);
// виводить "John & Jane have invited you for their party!"
echo $translator->trans('invitation_title', [
'organizer_name' => 'John & Jane',
'organizer_gender' => 'not_applicable',
]);
// виводить "ACME Company has invited you to their party!"
echo $translator->trans('invitation_title', [
'organizer_name' => 'ACME Company',
'organizer_gender' => 'not_applicable',
]);
Синтаксис {...}
варіюється між режимами "literal" (буквально) і "code" (код).
Це дозволяє вам використовувати буквальний текст в обраних ствердженнях:
- Перший блок
{organizer_gender, select, ...}
запускає режим "code", що означає, щоorganizer_gender
обробляється як змінна. - Внутрішній блок
{... has invited you for her party!}
повертає вас у режим "literal", що означає, що текст не обробляється. - Всередині цього блоку,
{organizer_name}
знову запускає режим "code", дозволяючиorganizer_name
бути обробленим як змінна.
Tip
Хоча може здатися логічнішим розташовувати лише her
, his
або their
у
змінному ствердженні, краще використовувати "складні аргументи" зкраю структури
повідомлення. Рядки таким чином читаніші для перекладачів, і як ви можете побачити
у випадку other
, інші частини речення можуть підпадати під вплив змінних.
Tip
Можливо перекладати повідомлення ICU MessageFormat прямо у коді, не визначаючи їх в жодному файлі:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$invitation = '{organizer_gender, select,
female {{organizer_name} has invited you to her party!}
male {{organizer_name} has invited you to his party!}
multiple {{organizer_name} have invited you to their party!}
other {{organizer_name} has invited you to their party!}
}';
// prints "Ryan has invited you to his party!"
echo $translator->trans(
$invitation,
[
'organizer_name' => 'Ryan',
'organizer_gender' => 'male',
],
// if you prefer, the required "+intl-icu" suffix is also defined as a constant:
// Symfony\Component\Translation\MessageCatalogueInterface::INTL_DOMAIN_SUFFIX
'messages+intl-icu'
);
Плюралізація
Інша цікава функція - plural
. Вона дозволяє вам працювати з плюралізацією
у ваших повідомленнях (наприклад, There are 3 apples
і There is one apple
).
Функція виглядає дуже схожою на функцію select
:
1 2 3 4 5 6 7
# translations/messages+intl-icu.en.yaml
num_of_apples: >-
{apples, plural,
=0 {There are no apples}
=1 {There is one apple...}
other {There are # apples!}
}
Правила плюралізації насправді достатньо складні та відрізнаються у кожній мові. Наприклад, російська використовує різні множинні закінчення для чисел, що закінчуються на 1; чисел, що закінчуються на 2, 3 або 4; чисел, що закінчуються на 5, 6, 7, 8 або 9; і крім цього є ще виключення!
Для того, щоб правильно перекласти це, можливі випадки у функції plural
також
відрізнятимуться для кожної мови. Наприклад, російська мова матиме one
, few
,
many
і other
, в той час як англійська - лише one
та other
. Повний
список можливих випадків можна знайти у документі Unicode
Правила множинних чисел у різних мовах. Додавши префікс =
, ви можете відповідати
точним значенням (як 0
у прикладі вище).
Використання цього рядку таке ж, як зі змінними та вибором:
1 2 3 4 5
// виводить "There is one apple..."
echo $translator->trans('num_of_apples', ['apples' => 1]);
// виводить "There are 23 apples!"
echo $translator->trans('num_of_apples', ['apples' => 23]);
Note
Ви також можете встановити змінну offset
, щоб визначити, чи має плюралізація бути
відносною (наприклад, у реченнях на кшталт You and # other people
/ You and # other person
).
Tip
При поєднанні функцій select
і plural
, постарайтеся, щоб функція
select
все одно була крайньою:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
{gender_of_host, select,
female {{num_guests, plural, offset:1
=0 {{host} does not give a party.}
=1 {{host} invites {guest} to her party.}
=2 {{host} invites {guest} and one other person to her party.}
other {{host} invites {guest} and # other people to her party.}
}}
male {{num_guests, plural, offset:1
=0 {{host} does not give a party.}
=1 {{host} invites {guest} to his party.}
=2 {{host} invites {guest} and one other person to his party.}
other {{host} invites {guest} and # other people to his party.}
}}
other {{num_guests, plural, offset:1
=0 {{host} does not give a party.}
=1 {{host} invites {guest} to their party.}
=2 {{host} invites {guest} and one other person to their party.}
other {{host} invites {guest} and # other people to their party.}
}}
}
Додаткові функції заповнювача
Крім цього, ICU MessageFormat має декілька інших цікавих функцій.
Ordinal
Схоже на plural
, selectordinal
дозволяє вам використовувати числа як порядкову шкалу:
1 2 3 4 5 6 7 8 9 10 11 12
# translations/messages+intl-icu.en.yaml
finish_place: >-
You finished {place, selectordinal,
one {#st}
two {#nd}
few {#rd}
other {#th}
}!
# при форматуванні числа лише як порядкового (як вище), ви також можете
# використати функцію `ordinal`:
finish_place: You finished {place, ordinal}!
1 2 3 4 5 6 7 8
// виводить "You finished 1st!"
echo $translator->trans('finish_place', ['place' => 1]);
// виводить "You finished 9th!"
echo $translator->trans('finish_place', ['place' => 9]);
// виводить "You finished 23rd!"
echo $translator->trans('finish_place', ['place' => 23]);
Можливі випадки цього також продемонстровані у документі Unicode Правила множинних чисел у різних мовах.
Дата і час
Функція дата та час дозволяє вам форматувати дати у цільовій локалі, використовуючи IntlDateFormatter:
1 2
# translations/messages+intl-icu.en.yaml
published_at: 'Published at {publication_date, date} - {publication_date, time, short}'
"Ствердження функції" для функцій time
та date
може бути short
,
medium
, long
або full
, що відповідає
константам, визначеним класом IntlDateFormatter:
1 2
// виводить "Published at Jan 25, 2019 - 11:30 AM"
echo $translator->trans('published_at', ['publication_date' => new \DateTime('2019-01-25 11:30:00')]);
Numbers
Форматувальник number
дозволяє вам форматувати числа, використовуючи
NumberFormatter Intl:
1 2 3
# translations/messages+intl-icu.en.yaml
progress: '{progress, number, percent} of the work is done'
value_of_object: 'This artifact is worth {value, number, currency}'
1 2 3 4 5 6 7 8 9
// виводить "82% of the work is done"
echo $translator->trans('progress', ['progress' => 0.82]);
// виводить "100% of the work is done"
echo $translator->trans('progress', ['progress' => 1]);
// виводить "This artifact is worth $9,988,776.65"
// якщо б ми переклали це, наприклад, французькою, значення відображувалося б як
// "9 988 776,65 €"
echo $translator->trans('value_of_object', ['value' => 9988776.65]);