Для кого эта статья
Пример задачи, используемой для демонстрации
Решение от Microsoft
ResxWrap - как средство устранения подобных недостатков
Как сгенерировать обертку
Заглянем внутрь
Резюме
Исходники
Для кого эта статья
В первую очередь, эта статья предназначена разработчикам программных
компонентов для платформы .NET, поддерживающих интернационализацию.
Статья будет полезна для всех, кто работает с .NET, используя файлы
ресурсов и функции типа String.Format.
Пример задачи, используемой для демонстрации
Мы имеем программу Windows Forms, которая должна поддерживать 3
языка: английский, итальянский и русский. В частности, в строке
состояния программы должна выводиться строчка: "Дата: {текущее число}"
на языке текущей локали пользователя.
Решение от Microsoft
Microsoft в таком случае рекомендует сделать следующее:
- Создать по одному .resx файлу для каждого из поддерживаемых
языков для хранения строковых ресурсов.
- Добавить в каждый из этих файлов строчку с общим идентификатором
ресурса, например "IDS_DATE", с текстом, соответствующим языку.
Например, для английской версии, тект будет "Date: {0}".
- Написать примерно следующий код:
string messageTemplate = resourceManager.GetString( "IDS_DATE" );
string finalMessage = string.Format( messageTemplate, new DateTime() );
// Обновление текста в строке состояния
ПРИМЕЧАНИЕ
Казалось бы, все хорошо, но взглянем на этот код повнимательнее:
- Если изменить имя идентификатора в ресурсах или ошибиться в
написании этого имени в коде, то компилятор не выдаст ошибки, т.к. в
коде это имя записывается в виде строки.
- Зачастую строковые ресурсы - это шаблоны сообщений, содержащие
несколько параметров, а т.к. сами шаблоны объявлены в другом файле,
это создает дополнительный риск того, что количество или
последовательность параметров при дальнейшем форматировании шаблона
будут рассогласованны.
ResxWrap - как средство устранения подобных недостатков
Именно для решения этих проблем была создана утилита ResxWrap -
генератор классов-оберток для текстовых ресурсов из .resx файлов.
Классы-обертки предоставляют пользователю возможность работать с
ресурсами в гораздо более удобной манере. Для вышеописанного примера
достаточно написать:
string finalMassage = generatedWrapper.IDS_DATE( new DateTime() );
// Обновление текста в строке состояния
Что же изменилось?
- Вместо двух строчек кода мы имеем одну. Не так плохо сократить
количество рутинного кода в два раза.
- Если название идентификатора изменится, теперь мы в
безопасности, т.к. компилятор тут же выдаст ошибку, поскольку у
класса-обертки больше не будет метода IDS_DATE.
- Если мы изменим количество аргументов в текстовом шаблоне
"IDS_DATE", то тоже никаких проблем. Компилятор опять сообщит нам об
ошибке - ведь сигнатура соответствующего метода класса-обертки
изменится тоже.
- Редактируя вызов этого метода можно посмотреть справку по
каждому параметру для уверенности, что порядок их следования
правильный.
Как сгенерировать обертку
ResxWrap - утилита, управляемая параметрами командной строки.
Возвращаясь к нашему примеру, допустим, что наш проект имеет
пространство имен по умолчанию "SampleApp", файлы проекта находятся в
директории "C:\My Projects\SampleApp", а файл ресурсов называется
"StringTable.resx". Тогда, чтобы сгенерировать класс-обертку достаточно
запустить генератор со следующими параметрами:
ResxWrap SampleApp "C:\My Projects\SampleApp\" StringTable
При завершении генерации в директории проекта появится новый файл с
именем "__StringTable.cs", который будет содержать определение
одноименнного класса описанного в том же пространстве имен.
Конечно можно создать .bat файл и каждый раз при изменении в
"StringTable.resx" запускать генератор вновь, но для надежности лучше
добавить одну строчку в Pre-build Event Command Line в настройках
проекта. Для этого достаточно написать в случае нашего примера
следующее:
ResxWrap SampleApp $(ProjectDir) StringTable
Заглянем внутрь
Сгенерированный класс содержит:
- конструктор, в котором происходит инициализация экземпляра
защищенного поля типа System.Resources.ResourceManager;
- доступные только для чтения статические поля, с именема для
каждого идентификатора ресурса, объявленного в .resx файле;
- методы и доступное только для чтения свойства, возвращающие
текстовое значение для каждого ресурса.
Если текстовая строка содержит параметры, то сигнатура метода будет
содержать соответствующее количество параметров, сопровожденных
комментариями, а тело метода, помимо загрузки шаблона текстового
сообщения, будет также содержать вызов String.Format, готовящий
финальную версию сообщения.
Резюме
Итак, если вы решили использовать утилиту ResxWrap при разработке
проекта, вам нужно:
- добавить вызов утилиты ResxWrap в файл проекта;
- перекомпилировать проект;
- добавить сгенеренный файл класса-обертки в список файлов
проекта;
- создать экземляр класса-оберки;
- вызвать соответствующий метод или свойство для извлечения нужных
текстовых ресурсов.
Исходники
Проект CRL Resource
Wrapper разрабатывается в рамках движения Open Source. Утилита
ResxWrap доступна для свободного скачивания по следующему адресу:
http://sourceforge.net/project/showfiles.php?group_id=98011&package_id=104991.