В русскоязычных интерфейсах имена пользователей требуют грамматической адаптации: одно и то же имя изменяется в зависимости от падежа, а также синтаксической роли в предложении. В отличие от английского языка, где имя чаще всего остаётся неизменным, в русском языке корректная форма имени зависит от контекста сообщения.
Типичные сценарии:
При интернационализации через FormatJS базовые механизмы ICU MessageFormat не предоставляют встроенного склонения имён, поскольку ICU ориентирован на правила чисел, множественности и выбора (plural/sel ect), но не на морфологию имён.
FormatJS использует ICU MessageFormat как основу для шаблонов:
import { IntlMessageFormat } fr om 'intl-messageformat';
const msg = new IntlMessageFormat(
'Письмо отправлено {name}',
'ru'
);
msg.format({ name: 'Иван' });
Результат всегда будет одинаковым вне зависимости от падежа:
Письмо отправлено Иван
ICU поддерживает конструкции:
Однако отсутствует механизм:
Самый прямолинейный способ — хранить все падежные формы имени заранее:
const user = {
name: {
nominative: 'Иван',
genitive: 'Ивана',
dative: 'Ивану',
accusative: 'Ивана',
instrumental: 'Иваном',
prepositional: 'Иване'
}
};
Использование в сообщениях:
const msg = new IntlMessageFormat(
'Профиль {nameGenitive} обновлён',
'ru'
);
msg.format({
nameGenitive: user.name.genitive
});
Особенности подхода:
FormatJS поддерживает передачу функций через values, что
позволяет внедрять пользовательскую логику форматирования.
const cases = {
genitive: (name) => inflect(name, 'genitive')
};
const msg = new IntlMessageFormat(
'Профиль {name}',
'ru'
);
msg.format({
name: cases.genitive('Иван')
});
Здесь inflect — внешняя функция морфологического
анализа.
Этот подход часто комбинируется с библиотеками:
В крупных системах склонение имён выносится на уровень сервиса:
async function getInflectedName(name, caseForm) {
const response = await fetch('/api/inflect', {
method: 'POST',
body: JSON.stringify({ name, case: caseForm })
});
const data = await response.json();
return data.result;
}
Использование:
const msg = new IntlMessageFormat(
'Письмо отправлено {name}',
'ru'
);
const formatted = await msg.formatAsync({
name: await getInflectedName('Иван', 'dative')
});
Преимущества:
Недостатки:
Имя пользователя может быть:
Поэтому система склонения должна учитывать классификацию:
const nameMeta = {
value: 'Jean-Luc',
type: 'foreign', // native | foreign | nickname | brand
language: 'fr'
};
Правила применения:
ICU MessageFormat позволяет выбирать шаблон:
const msg = new IntlMessageFormat(
`{gender, select,
male {Профиль обновлён пользователем {name}}
female {Профиль обновлён пользователем {name}}
other {Профиль обновлён пользователем {name}}
}`,
'ru'
);
Склонение имени остаётся внешним:
msg.format({
gender: 'male',
name: inflect('Иван', 'instrumental')
});
Таким образом разделяются задачи:
FormatJS поддерживает rich-text значения:
const msg = new IntlMessageFormat(
'Добро пожаловать, <b>{name}</b>',
'ru',
null,
{ formatters: {} }
);
Подстановка:
msg.format({
name: (chunks) => `<span class="name">${chunks}</span>`
});
Это не решает склонение, но позволяет:
При использовании динамической морфологии важно учитывать производительность.
Стратегия:
const cache = new Map();
function inflectCached(name, form) {
const key = `${name}:${form}`;
if (cache.has(key)) {
return cache.get(key);
}
const result = inflect(name, form);
cache.set(key, result);
return result;
}
Особенно важно при массовых списках пользователей:
При неизвестном языке или отсутствии поддержки склонения:
function safeInflect(user, form) {
if (user.locale !== 'ru') {
return user.name;
}
if (!isInflectable(user.name)) {
return user.name;
}
return inflect(user.name, form);
}
Это предотвращает:
В типичной архитектуре FormatJS слой сообщений отделён:
const messages = {
profileUpdated: 'Профиль {name} обновлён',
messageSent: 'Сообщение отправлено {name}'
};
Обёртка:
function formatMessage(id, values) {
const msg = new IntlMessageFormat(messages[id], 'ru');
return msg.format(values);
}
Интеграция с морфологией:
formatMessage('messageSent', {
name: inflect('Иван', 'dative')
});
В больших i18n-системах обычно применяется комбинация:
Архитектурная схема:
Даже при использовании FormatJS остаются фундаментальные ограничения:
В результате система интернационализации перестаёт быть только задачей шаблонов и превращается в гибрид лингвистики и программной архитектуры.