Локализация приложения
82WPF --- Элементы управления WPF --- Локализация приложения
Ресурсы сборки также оказываются очень кстати когда требуется локализовать окно. Используя ресурсы, вы позволяете элементам управления изменяться в соответствии с текущими параметрами культуры в Windows, что особенно удобно в случае таких элементов управления, как текстовые метки и изображения, которые чаще всего требуется переводить на различные языки.
На некоторых платформах локализация осуществляется путем предоставления множества копий таких элементов пользовательского интерфейса, как таблицы строк и изображения. В WPF локализация не является столь же детальной. Здесь единицей локализации является XAML-файл (формально это скомпилированный BAML-pecypc, который встраивается в приложение). При желании поддерживать три различных языка, потребуется включить три BAML-pecypca. WPF будет выбирать из них подходящий на основании текущих настроек культуры на компьютере, на котором выполняется приложение. (Точнее — WPF будет использовать для принятия решения значение свойства CurrentUICulture в обслуживающем пользовательский интерфейс потоке.)
Разумеется, в таком процессе не было бы особого смысла, если бы нужно было создавать (и развертывать) универсальную сборку со всеми локализованными ресурсами. Это было бы не лучше создания отдельных версий приложения для каждого языка, поскольку приложение приходилось бы полностью компоновать заново при каждой необходимости добавить поддержку для новой культуры (или необходимости настроить текст в одном из существующих ресурсов). К счастью, в .NET эта проблема решается с помощью подчиненных сборок (satellite assemblies), которые работают с приложением, но хранятся в отдельных подпапках.
При создании локализованного WPF-приложения каждый локализованный BAML-pecypc помещается в отдельную подчиненную сборку. Для того чтобы приложение могло использовать эту сборку, она размещается в подпапке под основной папкой приложения вроде подпапки fr-FR, предназначенной для французского языка. После этого приложение может связываться с этой подчиненной сборкой автоматически путем использования технологии зондирования (probing), которая является частью .NET Framework, начиная с версии 1.0.
Самая большая трудность в локализации приложения заключается в рабочем процессе — другими словами в том, как извлечь XAML-файлы из проекта, сделать их локализованными, скомпилировать в подчиненные сборки и затем вернуть обратно в приложение. Это самая запутанная часть "истории" локализации в WPF, поскольку никаких средств (включая Visual Studio), обладающих поддержкой локализации на этапе проектирования, пока не существует. Вероятнее всего такие средства появятся в будущем, а пока WPF все равно позволяет выполнять все, что необходимо для локализации приложения, просто с применением чуть большего количества усилий.
Создание локализуемых пользовательских интерфейсов
Прежде чем начинать что-либо переводить, сначала нужно разобраться с тем, как приложение будет реагировать на изменение содержимого. Например, если удвоить длину всего текста в пользовательском интерфейсе, как изменится общая компоновка окна? В случае если была разработана действительно гибкая компоновка, никаких проблем возникнуть не должно. Интерфейс должен быть способен подстроиться в соответствии с динамическим содержимым. Ниже описаны некоторые рекомендуемые приемы, гарантирующие следование правильному пути.
Не применяйте жестко закодированные значения ширины или высоты (или, по крайней мере, не используйте их с элементами, которые содержат непрокручиваемое текстовое содержимое).
Устанавливайте для свойства Window.SizeToContent значение Width, Height или WidthAndHeight, так чтобы размер окна мог увеличиваться по мере необходимости. (Опять-таки, это является обязательным не всегда; все зависит от структуры окна, но в некоторых случаях это очень полезно.)
Используйте для просмотра текста большого объема элемент ScrollViewer.
При желании локализовать приложение на язык, имеющий значительно отличающийся набор символов, понадобится использовать другой шрифт. Сделать это можно путем локализации в пользовательском интерфейсе свойства FontFamily или применения сложного шрифта вроде Global User Interface, Global Sans Serif или Global Serif, каждый из которых поддерживает все языки.
Может также потребоваться обдумать, каким образом компоновка будет работать при раскладке "справа налево" (вместо стандартной английской раскладки "слева направо"). Например, в арабском и иврите используется раскладка "справа налево". Этим поведением можно управлять посредством установки на каждой странице или в каждом окне приложения свойства FlowDirection. Более подробную информацию о раскладках "справа налево" можно найти в справке Visual Studio, в разделе Bidirectional Features (Средства двунаправленности).
Локализация — сложная тема. WPF предлагает работоспособное, но еще недостаточно зрелое решение. После того, как вы познакомитесь с основами, стоит заглянуть в документ Microsoft, посвященный локализации WPF, который доступен по адресу http://wpflocalization.codeplex.com вместе с кодом примеров. Можно ожидать, что в будущем поддержку локализации будет улучшена в инструментах проектирования, таких как Visual Studio и Expression Blend.
Подготовка приложения для локализации
Следующий шаг связан с включением поддержки локализации для проекта. Для этого потребуется внести только одно изменение, а именно — добавить в файл .csproj проекта где-нибудь в первом разделе <PropertyGroup> следующий элемент:
<UICulture>en-US</UICulture>
Это укажет компилятору, что языком (культурой) по умолчанию для приложения должен быть английский (США) (очевидно, что при необходимости можно выбрать другой язык). После внесения этой корректировки процесс компоновки изменится. При следующей компиляции приложения будет создана подпапка по имени en-US. Внутри этой папки будет находиться подчиненная сборка с таким же именем, как и у приложения, и расширением .resources.dll (например, LocalizableApplication.resources.dll).
В этой сборке будут содержаться все скомпилированные BAML-ресурсы для приложения, которые раньше хранились в основной сборке приложения.
Формально приложение локализуется не для какого-то конкретного языка, а для культуры, в которой учитываются региональные отличия. Культуры обозначаются с помощью двух разделенных дефисом идентификаторов. Первый указывает язык, а второй — страну. Следовательно, fr-CA означает французский язык, на котором разговаривают в Канаде, a fr-FR — французский, на котором общаются во Франции. Полный список имен культур и их идентификаторов можно найти в справке Visual Studio, в разделе, посвященном классу System.Globalization.Culturelnfo.
Это предполагает детальную локализацию, что может оказаться чрезмерным. К счастью, WPF позволяет локализовать приложение и на основе только языка. Например, при желании определить параметры так, чтобы они применялись для любого франкоговорящего региона, для культуры можно указать только идентификатор fr. Такой подход будет работать, если только не окажется доступной более специфическая культура, в точности соответствующая текущему компьютеру.
Теперь при запуске данного приложения среда CLR будет автоматически искать подчиненные сборки в соответствующем каталоге на основании региональных параметров компьютера, и загружать подходящий локализованный ресурс. Например, при запуске приложения на компьютере с культурой fr-FR среда CLR будет искать подпапку fr-FR и использовать подчиненные сборки, которые обнаружит там. Это означает, что для добавления в локализованное приложение поддержки дополнительных культур, потребуется просто добавить соответствующие дополнительные подпапки и подчиненные сборки, не беспокоясь об исходном исполняемом файле приложения.
Когда среда CLR начинает зондировать папки на предмет наличия подчиненной сборки, она следует нескольким простым правилам очередности:
Сначала она проверяет самый специфический из всех доступных каталог. Это означает, что CLR ищет подчиненную сборку, предназначенную для текущего языка и региона (вроде fr-FR).
Если CLR не удается обнаружить такой каталог, она начинает искать подчиненную сборку, предназначенную для текущего языка (такого как fr).
Если ей не удается найти и такой каталог, тогда генерируется исключение IOException.