В статье автор пытается очертить некоторые необходимые для понимания аспекты интернационализации в .NET, особенности китайской и не только локализаций, и несколько забавных моментов.
Приведу несколько вольно переведенных и отредактированных определений из MSDN:
Так что то, чем занимаются команды, приводящие к потребному виду изначально нелокализуемые продукты, называется громким словом — глобализацией, но никак не локализацией.
Итак, в .NET есть главный класс, представляющий информацию о языковых и региональных стандартах (для неуправляемого кода по-английски называемых ''locale'') —
У культуры есть имя (по сути — код), в этих терминах удобно общаться. У инвариантной культуры имя пустое, поэтому мы будем обозначать её как
У любого потока — экземпляра
Первая культура используется для форматирования чисел, дат и пр. региональных настроек, а вторая используется в алгоритме поиска подходящих локализованных ресурсов.
Так зачем же нужно две культуры? В этом есть резон: для потомка англосаксов, родившегося и живущего в Индии, родной язык — английский. На нем он и хочет видеть интерфейсы программ на своем ноутбуке. Однако, при работе в Excel'е он скорее всего будет оперировать рупиями (буква रु на хинди), и при этом знает, что площадь родной страны составляет
Культуры образуют дерево. Т.е. у каждой культуры есть родительская.
В корне дерева расположена «никакая» культура — инвариантная. Она не содержит в себе информацию о регионе, представляет несуществующий инвариантный язык, правила форматирования в котором странным образом похожи на американские. Родителем инвариантной культуры является другая инвариантная культура, и так до stack overflow.
Противоположностью являются определенные (специфичные, specific) культуры. Они содержат в себе информацию и о языке/письме, и о регионе, и о форматировании чисел и дат. Примеры:
Родителями специфичных культур культур являются нейтральные культуры. Назначение таких культур — нести информацию о языке и письме. До
Вопрос на засыпку внимательному читателю: кто может быть родителем нейтральной культуры?
Итак, мы с легкостью представляем веточку дерева культур на примере
Но языки с несколькими видами письма ломают стереотип.
До .NET 4.0 все было совсем запутанно: существовали специфичные культуры, родителем которых была инвариантная. См. тулу.
На китайском говорят свыше 1,3 млрд человек, официальным является в Китайской Народной Республике, Китайской Республике (aka Тайвань) и Сингапуре. И не забудьте о специальных административных районах — Гонконге и Макао.
Существует два вида китайского письма: упрощенное (с 1956 г.) и традиционное. Традиционно китайцы писали сверху вниз, а столбцы шли справа налево. Совсем недавно, с 2004 г., на Тайване перестали официально использовать вертикальное письмо. Сейчас используется «европейский» способ письма — горизонтально слева направо.
Вернемся к .NET'у. Культуры
Отдельно подчеркну, что на территории КНР используются оба вида письма: в Гонконге и Макао — традиционное, на остальной бoльшей территории — упрощенное.
Для поиска подходящих ресурсов (текста, координат и размеров контролов, иконок и мн. др.) экземпляр
Сначала менеджер ресурсов пытается найти ресурсы, чья культура совпадает с UI-культурой. Если не находит, то берет родительскую культуру и повторяет поиск. Если таким образом мы дойдем до инвариантной культуры, то придется использовать ресурсы по умолчанию (нейтральные) (часто они расположены в основной сборке, но не обязательно).
Правда, ресурсы по умолчанию тоже могут быть помечены культурой. См. подробности в MSDN.
Вашему вниманию представлен еще один кустик культур — узбекский:
Понятно, что произошло: после 1991 г. когда-то переведенные на кириллицу языки стали усиленно от кириллицы избавлять.
У класса
Багу уже много версий .NET.
Поговорим про бывшую союзную республику Молдавию, самоназвание ''Молдова''. Говорят молдаване на молдавском языке. Хотя ученые-филологи спорят, что это не самостоятельный язык, а диалект румынского.
По факту, существует три румынских языка:
Казалось бы, в .NET мы можем ожидать увидеть три специфичные румынские культуры, ну, или две — по политическим причинам (Приднестровье). Но нет, Молдавии в Windows NLS API нет. Есть только культура
Ну и конечно же, .NET позволяет создавать собственные культуры.
Интересно, что когда-то давно, в первых .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
- .NET Framework 4: What's New in Globalization and Localization
- Globalizing and Localizing .NET Framework Applications (.NET Framework 4.5)
- National Language Support (NLS) API Reference
- WPF: Globalization and Localization
Статьи
- Глава из книги “ Язык программирования C# 2005 для профессионалов” с примерами
- zh-Hans, zh-Hant and the «old» zh-CHS, zh-CHT
- The 'Program Files' folder in different languages
Инструменты
- Исправленное дерево культур на основе примера