Для
кого эта статья
Пример
задачи, используемой для демонстрации
Решение
от 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() );
// Обновление текста в строке состояния
ПРИМЕЧАНИЕ
Подробную информацию по вопросу
использования ресурсов в .NET можно найти, например, по
следующему адресу: http://samples.gotdotnet.com/quickstart/howto/doc/useresources.aspx
.
Казалось бы, все хорошо, но взглянем на этот код
повнимательнее:
- Если изменить имя идентификатора в ресурсах или
ошибиться в написании этого имени в коде, то компилятор не
выдаст ошибки, т.к. в коде это имя записывается в виде
строки.
- Зачастую строковые ресурсы - это шаблоны сообщений,
содержащие несколько параметров, а т.к. сами шаблоны
объявлены в другом файле, это создает дополнительный риск
того, что количество или последовательность параметров при
дальнейшем форматировании шаблона будут рассогласованны.
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.