Как стать автором
Обновить

Локализация и глобализация

Время на прочтение 5 мин
Количество просмотров 27K
В статье автор пытается очертить некоторые необходимые для понимания аспекты интернационализации в .NET, особенности китайской и не только локализаций, и несколько забавных моментов.

Терминология


Приведу несколько вольно переведенных и отредактированных определений из MSDN:
Локализация (Localization) — это процесс перевода ресурсов приложения в локализованные версии для каждого языка и региональных параметров, которую поддерживает приложение. Переход локализации должен происходить только после того, как выполнена условие Локализуемости (Localizability), т.е. исполняемый код отделен от любых элементов пользовательского интерфейса.

Глобализация (Globalization) — это процесс проектирования и разработки приложения, которое поддерживает локализованный пользовательский интерфейс и региональные данные для пользователей из разных культур. Cведения о конкретных языковых и региональных параметрах могут включать в себя: систему письма, используемые календари, соглашения о формате даты и времени, чисел, денежных и физических величин, правила сортировки и даже форматы адреса, телефона, размера бумаги по умолчанию.

Так что то, чем занимаются команды, приводящие к потребному виду изначально нелокализуемые продукты, называется громким словом — глобализацией, но никак не локализацией.


Язык и региональные стандарты


Итак, в .NET есть главный класс, представляющий информацию о языковых и региональных стандартах (для неуправляемого кода по-английски называемых ''locale'') — System.Globalization.CultureInfo. Рядом с ним есть еще Calendar, RegionInfo, NumberFormatInfo, DateTimeFormatInfo и мн. др.

У культуры есть имя (по сути — код), в этих терминах удобно общаться. У инвариантной культуры имя пустое, поэтому мы будем обозначать её как ivl.

Две культуры потока

У любого потока — экземпляра Thread есть два свойства: public CultureInfo CurrentCulture {get; set;} и public CultureInfo CurrentUICulture {get; set;}
Первая культура используется для форматирования чисел, дат и пр. региональных настроек, а вторая используется в алгоритме поиска подходящих локализованных ресурсов.

Так зачем же нужно две культуры? В этом есть резон: для потомка англосаксов, родившегося и живущего в Индии, родной язык — английский. На нем он и хочет видеть интерфейсы программ на своем ноутбуке. Однако, при работе в Excel'е он скорее всего будет оперировать рупиями (буква रु на хинди), и при этом знает, что площадь родной страны составляет 32,87,590.01 км2.



Структура дерева культур

Культуры образуют дерево. Т.е. у каждой культуры есть родительская.

В корне дерева расположена «никакая» культура — инвариантная. Она не содержит в себе информацию о регионе, представляет несуществующий инвариантный язык, правила форматирования в котором странным образом похожи на американские. Родителем инвариантной культуры является другая инвариантная культура, и так до stack overflow.

Противоположностью являются определенные (специфичные, specific) культуры. Они содержат в себе информацию и о языке/письме, и о регионе, и о форматировании чисел и дат. Примеры: ru-RU, en-US, en-IN.

Родителями специфичных культур культур являются нейтральные культуры. Назначение таких культур — нести информацию о языке и письме. До .NET 4.0 нейтральные культуры и не могли содержать информацию о форматировании и регионе, теперь эта информация берется из доминирующей специфичной культуры. Примеры: ru, en, mn-Cyrl (монгольский, кириллица), mn-Mong (старомонгольское письмо).

Вопрос на засыпку внимательному читателю: кто может быть родителем нейтральной культуры?

Распространенные заблуждения

Итак, мы с легкостью представляем веточку дерева культур на примере ivl <— ru <— ru-RU. Но неверно утверждать, что иерархия всегда состоит из трех культур. Так, например, думали авторы книги Язык программирования C# 2005 для профессионалов в примере к 17-й главе, и тогда это было почти верно.

Но языки с несколькими видами письма ломают стереотип.



До .NET 4.0 все было совсем запутанно: существовали специфичные культуры, родителем которых была инвариантная. См. тулу.

Китайский куст



На китайском говорят свыше 1,3 млрд человек, официальным является в Китайской Народной Республике, Китайской Республике (aka Тайвань) и Сингапуре. И не забудьте о специальных административных районах — Гонконге и Макао.

Существует два вида китайского письма: упрощенное (с 1956 г.) и традиционное. Традиционно китайцы писали сверху вниз, а столбцы шли справа налево. Совсем недавно, с 2004 г., на Тайване перестали официально использовать вертикальное письмо. Сейчас используется «европейский» способ письма — горизонтально слева направо.

Вернемся к .NET'у. Культуры zh-CHS и zh-CHT в .NET 2.0 были объявлены устаревшими и заменены на zh-Hans и zh-Hant. В дереве культур zh-Hans является родителем zh-CHS для корректной работы fallback process. В дальнейшем с любым патчем устаревшие культуры могут пропасть.

Отдельно подчеркну, что на территории КНР используются оба вида письма: в Гонконге и Макао — традиционное, на остальной бoльшей территории — упрощенное.

Fallback process

Для поиска подходящих ресурсов (текста, координат и размеров контролов, иконок и мн. др.) экземпляр ResourceManager смотрит на Thread.CurrentThread.CurrentUICulture. UI-культура может быть как специфичной, так и нейтральной. А вот Thread.CurrentThread.CurrentCulture м.б. только специфичной культурой.

Сначала менеджер ресурсов пытается найти ресурсы, чья культура совпадает с UI-культурой. Если не находит, то берет родительскую культуру и повторяет поиск. Если таким образом мы дойдем до инвариантной культуры, то придется использовать ресурсы по умолчанию (нейтральные) (часто они расположены в основной сборке, но не обязательно).

Правда, ресурсы по умолчанию тоже могут быть помечены культурой. См. подробности в MSDN.

Косяки от MS

№1

Вашему вниманию представлен еще один кустик культур — узбекский:



Понятно, что произошло: после 1991 г. когда-то переведенные на кириллицу языки стали усиленно от кириллицы избавлять.

У класса CultureInfo есть свойство string NativeName, т.е. название культуры на описываемом языке. Для культуры uz-Latn-UZ значение NativeName равно U'zbek (U'zbekiston Respublikasi), хотя на самом деле должно быть O'zbek (O'zbekiston Respublikasi).

Багу уже много версий .NET.

№2

Поговорим про бывшую союзную республику Молдавию, самоназвание ''Молдова''. Говорят молдаване на молдавском языке. Хотя ученые-филологи спорят, что это не самостоятельный язык, а диалект румынского.

По факту, существует три румынских языка:
  • румынский в Румынии (латиница);
  • румынский в Приднестровье (кириллица), оставшийся в том виде, в каком был на момент распада Союза;
  • румынский в Молдавии (латиница), со своим вариантом латинизации, не совпадающем с принятым в Румынии.

Казалось бы, в .NET мы можем ожидать увидеть три специфичные румынские культуры, ну, или две — по политическим причинам (Приднестровье). Но нет, Молдавии в Windows NLS API нет. Есть только культура ro-RO, Румынский (Румыния). Именно такой локалью молдавские пользователи и пользуются. Зато Microsoft в Молдавии есть.

Ну и конечно же, .NET позволяет создавать собственные культуры.

Интересно, что когда-то давно, в первых .NET'ах и старых операционках были замечены культуры ru-MO и ro-MO. Да, код региона был MO, а не MD как сейчас. Стандарт ISO поменялся?

Табу для локализуемых приложений


Список не может быть полным, зато примеры из личного опыта отлавливания багов локализованных приложений.

№1

Очевидно, что никогда нельзя зашиваться на имена системных папок. Хотя, казалось бы, куда могут подеваться Program Files? По какой-то нелепости в локализованной на русский Windows эту папку не стали переименовывать. Но так не во всех локализациях!

В испанской локализации папка гордо именуется Archivos de programa. Рекомендую: перевод Гугла с испанского на русский.

№2

Настоящим бичом глобализуемого-локализуемого приложения являются строки. Конкатенирующиеся. Но даже если строки с подстановками, то переводчикам содержимое подстановок без комментариев неочевидно: "{0}" вызвало ошибку "{1}".{2}Обратитесь к {3}. А под {2} имеется в виду банальный Environment.NewLine.

Ссылки


MSDN


Статьи


Инструменты


Теги:
Хабы:
+36
Комментарии 16
Комментарии Комментарии 16

Публикации

Истории

Работа

.NET разработчик
66 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн