Двуязычный интерфейс казахский и русский: без дублей
Как спроектировать двуязычный интерфейс казахский и русский в корпоративной системе: справочники, поиск и печать без дублирования логики.

Зачем вообще избегать дублей логики
Когда двуязычность делают "в лоб", часто появляются два набора экранов, два справочника и два сценария работы: русский вариант и казахский. На старте кажется, что так быстрее. На практике это почти всегда заканчивается расхождениями: в одном языке поле добавили, в другом забыли, бизнес-правило обновили только в одном месте, и пользователи начинают получать разные результаты.
Проблема дублей в том, что вы поддерживаете две системы внутри одной. Любое изменение в процессе (новый статус заявки, дополнительный реквизит, новый формат печати) приходится повторять и перепроверять дважды. Тестирование тоже удваивается, а ошибок становится заметно больше, потому что появляются комбинации: RU-экран + KZ-справочник, KZ-печать + RU-данные, разные роли доступа в разных ветках логики.
Обычно первыми ломаются сквозные и "невидимые" части:
- поиск (в одном языке ищет, в другом нет, или результаты отличаются)
- печать и отчеты (часть подписей переведена, часть осталась, реквизиты перепутаны)
- права доступа (в одном языке кнопку скрыли, в другом забыли)
- интеграции и выгрузки (одни и те же поля уходят с разными кодами или названиями)
В Казахстане у пользователей часто два разных ожидания: язык интерфейса и язык данных. Человек может выбрать интерфейс на казахском, но работать с документами, где контрагенты, должности или адреса заведены по-русски (или наоборот). Если система жестко "привязывает" данные к языковой версии экрана, начинается путаница: один и тот же объект выглядит как два разных, появляются дубли в справочниках и расхождения в отчетах.
Практический пример: в корпоративной системе для закупок один отдел печатает договоры на русском, другой на казахском, но согласование и статусы должны быть одинаковыми. Если логика разведена по языкам, то при изменении регламента (например, добавили обязательное поле для ИИН/БИН или новый этап согласования) правки придется делать в двух местах. Риск пропустить что-то в печатных формах и доступах становится максимальным.
Надежнее, когда логика одна, а язык меняется только в отображении: подписи, названия, формулировки, варианты поиска и печати. Такой подход проще сопровождать, легче тестировать и проще масштабировать, например при внедрениях у крупных организаций в РК, где важны качество и предсказуемость процессов (как в проектах системной интеграции уровня GSE.kz).
Что именно должно быть двуязычным
Главная ошибка при внедрении двуязычности - смешать два слоя: язык интерфейса и язык данных.
В двуязычный интерфейс обычно попадают кнопки, подписи полей, подсказки, сообщения об ошибках и названия разделов. Это UI-текст, и его удобнее хранить отдельно от бизнес-логики.
Язык данных - это то, что пользователи вводят и потом ищут, печатают и выгружают: названия организаций, должностей, товаров, услуг, статусов, подразделений. Эти значения живут в справочниках и документах. Именно здесь чаще всего появляется соблазн сделать два справочника или два набора экранов. Лучше сразу принять правило: объект один, а отображаемых названий может быть два.
Есть данные, которым перевод не нужен. Коды, ИИН/БИН, серийные номера, артикулы, номера договоров и счетов должны быть одинаковыми на любом языке. Их смысл не меняется, а попытка "переводить" такие поля только добавит расхождения и лишние проверки.
Заранее договоритесь о fallback-правиле, чтобы интерфейс был предсказуемым, даже если перевод не заполнен:
- если выбран KZ и есть перевод - показываем KZ
- если выбран KZ, но перевода нет - показываем RU (и наоборот)
- если нет ни RU, ни KZ - показываем код или технический ключ и помечаем как незаполненное
Чтобы не плодить версии одного и того же объекта, нужен единый ключ. Для справочников это обычно внутренний ID (или GUID), который не зависит от языка. Языковые названия - отдельные поля (например, name_ru и name_kz) или отдельная таблица переводов, но всегда привязанные к одному и тому же ключу. Тогда поиск, права доступа, связи документов и печатные формы работают по одной логике, а меняется только отображение текста.
Справочники: модель данных для RU и KZ
Справочники чаще всего ломают двуязычность: их много, они используются повсюду, и любая ошибка превращается в сотни мелких багов. Хорошая модель данных помогает сделать двуязычность без копирования сущностей и правил.
Самый простой вариант - отдельные поля name_ru и name_kk. Он оправдан, когда языков строго два, значения короткие, а структура справочника стабильна (например, типы документов, статусы, отделы). Плюс - легко читать и быстро фильтровать. Минус - при добавлении третьего языка начинаются миграции и правки во многих местах.
Более гибкий вариант - таблица переводов: entity_id, lang, value (и, при необходимости, тип значения). Это удобно, если справочники разные, языков может стать больше, или нужны дополнительные виды текста (полное название, краткое, для печати). Важно сразу зафиксировать: перевод - часть данных справочника, а не отдельная копия записи.
С уникальностью лучше не гадать. Обычно уникальным считается не перевод, а стабильный код записи (например, code или external_id). А вот name_ru и name_kk могут совпадать, меняться, иметь разные правила написания. Если бизнес все же требует уникальности названия, фиксируйте это отдельно: уникально в рамках языка и в рамках одного справочника.
Отдельно продумайте варианты названий. Часто нужно хранить официальное название (для договоров и печати), короткое (для таблиц и карточек), сокращение (как принято в компании), а также альтернативные варианты для поиска и старых данных.
Пакетные обновления справочников делайте по коду, а не по тексту. Тогда вы сможете обновить русские названия, не затирая казахские, и наоборот. Практичное правило: импорт сначала обновляет базовую запись (код, активность), затем отдельным шагом обновляет переводы по lang, не удаляя отсутствующие значения без явного флага "удалить".
Отображение справочников в интерфейсе без копирования экранов
Идея простая: один экран, одна логика, а язык - это настройка отображения. Тогда двуязычность не превращается в два параллельных набора форм, фильтров и проверок.
В списках справочников обычно достаточно показывать один язык как основной, а второй - как подсказку. Например, в колонке "Наименование" отображаете выбранный язык, а рядом (или в tooltip, или серым текстом) - альтернативный. Это помогает быстрее узнавать термин и снижает ошибки, когда в документах встречаются оба варианта.
Сортировка - место, где чаще всего "падает" ощущение качества. Для казахского и русского алфавитов порядок букв разный, и если сортировать "как попало", люди перестают находить нужное. Практика простая: сортируйте по полю текущего языка и используйте корректную коллацию для него. Если в базе или в поисковом движке это настраивается отдельно, выбирайте коллацию под KZ и RU, а не одну общую.
Чтобы не плодить два набора правил в фильтрах и выпадающих списках, держите логику на ключах, а не на тексте. Фильтр должен сравнивать идентификаторы (id, code), а текстовые подписи подставлять в последний момент, уже на UI.
Несколько правил, которые обычно решают 80% проблем:
- храните единый код элемента (
code) и два отображаемых значения (RU и KZ), а экран всегда работает сcode - в выпадающих списках показывайте текущий язык, а вторую подпись добавляйте там, где термины похожи или их часто путают
- для пустых переводов используйте понятный fallback: основной язык плюс отметка, что перевода нет
- не дублируйте подписи полей: на экране один ключ (например,
label.customerType), а тексты берутся из словаря переводов
Так UI остается одним и тем же, а переключение языка становится настройкой, а не отдельной веткой разработки.
Поиск по двум языкам: как сделать предсказуемо
Поиск в корпоративной системе - это не только строка в справочнике. Обычно пользователи ожидают, что одинаково работают: поиск по справочникам (контрагенты, должности), по спискам документов (заявки, счета) и быстрый поиск по полям на форме (например, "Найти сотрудника").
Главное правило: пользователь вводит как привык, а система находит одно и то же, независимо от того, на каком языке заполнены данные.
Нормализация ввода: убираем случайные различия
Сначала приведите запрос и данные к единому виду. Тогда "Алматы", "алматы" и " Алматы " будут одинаковыми. Обычно достаточно привести к одному регистру, убрать лишние пробелы и повторяющиеся разделители, нормализовать диакритику и варианты букв (если у вас встречаются разные способы ввода). Отдельно учтите раскладки: частая проблема, когда вводят в RU, а клавиатура стоит в KZ (и наоборот).
После этого у вас появится предсказуемая база для индексации и ранжирования.
Индексация и запрос: один понятный подход
Чаще всего удобно держать один индекс, но с отдельными полями для RU и KZ (например, name_ru и name_kz), плюс общее поле для "поисковой версии" (search_text), куда складываются обе формы. Тогда запрос всегда идет в одно место, а язык интерфейса влияет только на отображение.
Чтобы искать, когда введено на RU, а заполнено на KZ (или наоборот), делайте запрос одновременно по двум языковым полям. Если у вас есть транслитерация или словарь соответствий, подключайте их как дополнительный слой, но не как единственную опору.
Ранжирование держите простым и одинаковым везде: точное совпадение - выше всего; совпадение с начала слова - выше, чем "где-то внутри"; совпадение по активному языку интерфейса - чуть выше, чем по второму языку; транслитерация (если нужна) - ниже прямых совпадений.
Пример: пользователь в отделе закупок вводит "Aстана", а контрагент заведён как "Астана" или "Astana" в другой языковой форме. Если ввод нормализован и поиск идет по обоим полям, результат будет один и понятный, без ощущения, что "поиск сегодня сломался".
Печатные формы: один шаблон, два языка
Печатные формы часто ломают двуязычность, потому что текст в них быстро становится "жестко вшитым" в шаблон. Чтобы не плодить два набора документов, разделите ответственность: шаблон отвечает за структуру (таблицы, блоки, порядок полей), а язык - за словарь подписей и формулировок. Так вы сохраняете один документ и меняете язык без копирования логики.
Фиксированный текст (заголовки, подписи, статусы, стандартные фразы) храните в языковых ресурсах. В шаблоне оставьте ключи, например "doc.title", "sign.customer", "status.paid". Данные (номер, дата, суммы, ФИО, должность, реквизиты) должны приходить одинаково, без ветвления "если RU, то поле A".
Выбор языка печати стоит сделать явным правилом, а не случайностью. Язык интерфейса и язык документа не обязаны совпадать.
Как выбирать язык печати
Обычно работает один из вариантов: по получателю (язык хранится в карточке организации), по регламенту (для части документов всегда нужен RU или всегда KZ), по языку пользователя (как настройка по умолчанию, но с возможностью переключить перед печатью).
Самая сложная зона - падежи и склонения в фразах типа "выдано", "принято", "к кому", "от кого". Чтобы не править вручную каждый документ, избегайте фраз, где имя или должность надо склонять, и используйте нейтральные конструкции: "Подписант: {name}", "Должность: {role}". Если без падежей не обойтись, закрепите минимальный набор стандартных формулировок.
Перед релизом обязательно проверьте верстку на обоих языках. Казахские строки часто длиннее, а символы (Ә, Ө, Ү, Қ, Ң, І, Һ) требуют корректного шрифта. Проверьте переносы строк в заголовках и таблицах, обрезание длинных названий и адресов, единые форматы дат и чисел, встраивание шрифтов (чтобы буквы не превращались в квадраты), печать на разных принтерах и в PDF (чтобы поля не "уезжали").
Пошаговый план внедрения двуязычности
Начинайте не с перевода экранов, а с карты данных и правил. Двуязычность обычно ломается там, где один и тот же смысл хранится и обрабатывается по-разному для RU и KZ.
План, который удобно делать итерациями:
-
Составьте список сущностей и полей, которые должны быть на двух языках. Обычно это справочники (должности, подразделения, статусы, причины), подписи в печатных формах и системные сообщения. Сразу отметьте, что не переводится (коды, ИИН/БИН, номера договоров).
-
Выберите модель хранения переводов и правило fallback. Решите заранее: если KZ-значение пустое, показываем RU или показываем пусто и подсвечиваем? Для госдокументов чаще нужен строгий режим, для внутренних экранов допустим fallback.
-
Внедрите единый слой получения текстов. Для интерфейса это ресурсы (ключ - строка), для справочников - единый метод выбора displayName по языку. Экран не должен сам решать, что показывать: логика должна жить в одном месте.
-
Настройте поиск и индексацию так, чтобы результат был предсказуемым. Пользователь может ввести русскую транслитерацию или казахское написание, а запись должна находиться одинаково. Часто достаточно хранить нормализованное поле для поиска (без лишних пробелов, в одном регистре) для RU и KZ.
-
Стандартизируйте печатные формы: один шаблон, параметр языка, общий набор ключей и полей. Удобно иметь единый словарь подписей и единый способ подстановки значений, чтобы не плодить два почти одинаковых документа.
Отдельным шагом добавьте тестовые наборы данных и автопроверки. Например: запись со всеми переводами, запись без KZ (проверяем fallback), запись с казахскими символами в названии и поиск по обеим версиям.
Такой порядок хорошо работает и в больших внедрениях, когда часть пользователей работает на русском, а часть - на казахском, но процессы и печатные формы должны оставаться едиными.
Частые ошибки и ловушки
Проблемы двуязычности чаще всего не в переводе кнопок. Ошибки появляются там, где данные живут годами: справочники, поиск, печать и выгрузки. Один неверный выбор в модели данных потом тянет за собой постоянные доработки.
Самая дорогая ошибка - дублировать справочники под каждый язык. В итоге у вас два "одинаковых" контрагента, две должности, два склада. Отчеты расходятся, интеграции ломаются, а пользователи спорят, "какая запись правильная". Правильнее держать одну запись и отдельные поля или таблицу переводов.
Вторая ловушка - смешивать языки в одном поле без правил. Когда в названии то русский, то казахский, то оба сразу, качество данных быстро падает. Нужны четкие правила заполнения и простая проверка: что обязательно на RU, что обязательно на KZ, и где допускается пустое значение.
Часто перевод делают только в интерфейсе, а печатные формы и выгрузки забывают. Это особенно больно в документах для госорганов и закупок: пользователь видит на экране казахский, а в PDF или Excel уезжает русский. Проверяйте не только экраны, но и все выходные каналы.
Отдельный класс проблем - поиск. Если индекс или полнотекстовый поиск хранит только одну языковую версию, запросы на втором языке будут "как будто ничего нет". Типичный сценарий: бухгалтер ищет должность по-казахски, система молчит, хотя запись есть.
Признаки, что вы на скользкой дорожке:
- две версии одного справочника вместо переводов
- нет единых правил, что писать в RU и KZ полях
- печать и выгрузки отстают от UI
- поиск индексирует только один язык
- у справочников нет владельца, и переводы не обновляются
Помогает простой управленческий шаг: назначить ответственного за каждый ключевой справочник и ввести короткий цикл контроля. Например, раз в месяц сверять новые записи и переводы, чтобы они не расходились между подразделениями.
Короткий чеклист перед релизом
Перед релизом двуязычности важно проверить не только видимые подписи, но и поведение системы.
Пройдитесь по ключевым сценариям на тестовом стенде и на типовых ролях (оператор, руководитель, бухгалтер). Проверяйте на реальных записях: с заполненными RU и KZ, только с одним языком, и с длинными названиями.
- Переключение языка меняет подписи, подсказки и сообщения об ошибках, но не сбрасывает введенные данные и не "перезагружает" карточку так, что пользователь теряет контекст.
- В карточке объекта понятно, где RU и где KZ, а если перевод не заполнен, используется предсказуемый fallback (и это одинаково во всех экранах).
- Поиск работает в обе стороны: запрос на русском находит записи, где заполнено только казахское наименование, и наоборот.
- Сортировка и фильтры не выглядят случайными: порядок ожидаемый в обоих языках (особенно в длинных справочниках).
- Печатные формы и выгрузки корректно показывают казахские символы, переносы строк и не ломают верстку на длинных значениях.
Отдельно проверьте качество переводов. Без этого двуязычность быстро превращается в ситуацию, когда "половина интерфейса на одном языке".
- Есть отчет или простой список незаполненных переводов, а также понятное поле "кто отвечает" и срок, чтобы это реально закрывали, а не откладывали бесконечно.
Пример из практики: одна система для разных ролей и языков
Представьте кадровую систему в большой организации. Есть справочник должностей и подразделений, карточки сотрудников, приказы и отчеты. В Астане HR-специалист работает в интерфейсе на казахском, а бухгалтерия в Алматы открывает те же данные на русском. Важно, что это одна система, а не две разные версии.
Справочник должностей устроен так: у каждой записи один идентификатор и два текстовых поля (KZ и RU). Логика одна: правила доступа, проверки, маршруты согласования, расчеты. Меняются только подписи и отображаемые тексты.
Типичная ситуация с поиском: бухгалтер ищет сотрудника по должности и вводит запрос на русском, например "бухгалтер". Но в карточке должность заполнена только на казахском. Если поиск сделан правильно, система ищет сразу по двум полям и находит нужного человека. Пользователь видит результат на своем языке, но не теряет данные из другого.
Чтобы это работало стабильно, достаточно зафиксировать несколько правил:
- в справочнике всегда один код записи, независимо от языка
- для текста есть два поля, а не две записи
- поиск идет по обоим языкам, а сортировка и отображение - по языку интерфейса
- валидации и бизнес-правила не зависят от языка
Отдельный момент - печать приказа. Язык документа задается регламентом (например, для внешнего аудита нужен русский), а не тем, на каком языке открыт интерфейс. Тогда HR может работать на казахском, но распечатать приказ на русском по одной и той же форме.
Когда логика единая, обновления проходят проще: добавили новое поле в приказ - сделали это один раз, а не в двух параллельных шаблонах. Это резко снижает риск "тихих" ошибок, когда в одном языке все уже исправили, а во втором забыли.
Как организовать поддержку и что делать дальше
Двуязычность не заканчивается релизом. Через неделю появятся новые отделы, новые услуги, новые должности - и вместе с ними новые значения в справочниках и тексты в печатных формах. Если не договориться о правилах заранее, двуязычность быстро превратится в набор разрозненных переводов.
Назначьте владельцев контента. Это не разработчики: за справочники обычно отвечает бизнес (кадры, бухгалтерия, закупки), а за общие термины - редактор или методолог. Нужен простой процесс согласования: кто предлагает формулировку, кто проверяет, кто утверждает.
Чтобы не спорить каждый раз, задайте стандарт языка. Достаточно короткого документа на 1-2 страницы: как писать должности, как оформлять сокращения, какие официальные формулировки использовать в договорных и отчетных текстах. Помогает небольшой глоссарий ключевых терминов (10-30 слов), которые часто встречаются в системе.
Для поддержки в работе полезен простой ритм:
- единая очередь на запросы переводов (вместо переписок по чатам)
- правило: новое значение в справочнике появляется только вместе с переводом
- ответственные за проверку: носитель языка или сотрудник, который работает с документами каждый день
- фиксация источника формулировки (приказ, регламент, шаблон документа)
- регулярный короткий обзор: что добавили, где возникли спорные термины
Параллельно нужен план тестирования именно двуязычности. Проверяйте не только видимость текста, но и поведение: поиск должен находить записи по RU и KZ, а печатные формы - собираться корректно в обоих вариантах на одних и тех же данных.
Следующие шаги обычно такие: быстрый аудит (где тексты зашиты в код, где уже есть справочники, где есть дубли экранов), план миграции (перенос справочников на модель с переводами и замена жестких строк на ресурсы), поэтапный запуск без простоев (сначала справочники и интерфейс, затем поиск, затем печать), метрики качества (процент заполненных переводов и список пустых полей, которые блокируют релиз).
Если не хватает опыта в проектировании, тестировании и внедрении, GSE.kz может подключиться как системный интегратор. При необходимости команда также помогает с инфраструктурой для корпоративных решений (серверы и рабочие места) и сопровождением.
FAQ
Почему плохо делать два отдельных набора экранов под русский и казахский?
Лучше держать одну бизнес-логику и один набор экранов, а язык менять только в отображении текстов. Две параллельные ветки (RU и KZ) почти всегда расходятся со временем: в одном месте добавили поле или проверку, во втором забыли, и пользователи получают разные результаты.
В чем разница между языком интерфейса и языком данных?
Интерфейс — это кнопки, подписи полей, подсказки и ошибки; эти тексты живут в словаре переводов и не должны влиять на правила работы. Данные — это то, что вводят пользователи (названия, должности, подразделения), и они должны быть едиными объектами с несколькими языковыми отображениями, а не двумя разными сущностями.
Как правильно хранить двуязычные справочники, чтобы не появлялись дубли?
Один объект в справочнике должен иметь один стабильный идентификатор (id/GUID) и, при необходимости, код, а переводы хранить как отдельные поля (`name_ru`, `name_kk`) или в таблице переводов. Так связи, права доступа, отчеты и интеграции работают по ключам, а язык влияет только на то, какой текст показан пользователю.
Что выбрать: два поля name_ru/name_kk или отдельную таблицу переводов?
Если языков ровно два и справочник простой, обычно достаточно двух полей с названиями — это легче читать и быстрее фильтровать. Если возможны дополнительные языки, разные варианты текста (кратко/полностью/для печати) или много типов сущностей, удобнее таблица переводов с полями вроде `entity_id`, `lang`, `value`, чтобы не переделывать структуру при расширении.
Что показывать пользователю, если перевод на выбранном языке не заполнен?
Задайте единое правило заранее и применяйте его везде. Практичный вариант: показывать текст на выбранном языке, а если он пустой — показывать второй язык; если пусто в обоих, показывать код или техническое имя и явно отмечать, что перевод не заполнен, чтобы это можно было исправить.
Как сделать нормальную сортировку в списках для RU и KZ?
Сортируйте по полю текущего языка и используйте корректную коллацию для него, иначе порядок будет выглядеть случайным и люди перестанут находить нужное. Если технически невозможно настроить коллации, хотя бы сортируйте по заранее нормализованному полю (единый регистр, без лишних пробелов), чтобы результат был стабильным.
Как настроить поиск, чтобы находило и по-русски, и по-казахски?
Поиск должен искать одновременно по обоим языковым полям, а не только по языку интерфейса. Перед поиском нормализуйте ввод и данные: приведите к одному регистру, уберите лишние пробелы, унифицируйте похожие варианты букв, чтобы «Алматы» и « алматы » находились одинаково.
Нужно делать две печатные формы (RU и KZ) или одну?
Держите один шаблон документа и подставляйте язык через словарь формулировок и подписей, а не через копирование шаблона. Язык печати лучше выбирать явным правилом (по регламенту, получателю или настройке пользователя), потому что язык интерфейса и язык документа часто не совпадают.
Какие поля и значения не нужно переводить вообще?
Чаще всего не переводятся коды, ИИН/БИН, серийные номера, артикулы, номера договоров и счетов — их смысл не меняется от языка. Попытка «переводить» такие поля обычно приводит к расхождениям, лишним проверкам и ошибкам в интеграциях и отчетности.
Что обязательно проверить перед релизом двуязычности и как с этим помогает интегратор?
Минимум — тесты на переключение языка без потери введенных данных, проверка fallback для пустых переводов, поиск в обе стороны (RU-запрос на KZ-данных и наоборот) и контроль печати/PDF на казахских символах и длинных строках. Для крупных внедрений полезно, когда системный интегратор берет это как отдельный контур качества: единые правила, тестовые наборы данных и проверка сквозных сценариев до релиза.