В первой части я показал пример простого создания шаблона и его генерация в файл. Теперь, расскажу о дополнительных, интересных свойствах StringTemplate.
Скиннинг или наследование шаблонов
В StringTemplate предусмотрено наследование шаблонов. Предположим, вы создаете сайт с разным дизайном, или на разных языках. В таком случае, можно создать осную папку шаблонов (в моем примере — это super), и папку «скин»-а (в примере, это default). Шаблонизатор, в таком случае, будет искать все файлы сначала в папке default, а при их отсутствии — в super. Задать наследование можно с помощью свойства StringTemplateGroup.SuperGroup, примерно так:
superGroup = new StringTemplateGroup("super", TEMPLATES_URL + @"\super"); skinGroup = new StringTemplateGroup(skin, TEMPLATES_URL + @"\" + skin); skinGroup.SuperGroup = superGroup;
Локализация
В дополнение к наследованию, локализацию можно сделать приближенной к обычному ASP.NET — с помощью ресурс файлов. Несмотря на то, что на сайте StringTemplate есть много примеров локализации на разных языках. На прямую с ResourceManager он работать не стал (это просто не предусмотрено — подробней об этом в !третей части!), из за этого я использую вот такой класс:
public class ResourceManagerWrapper { public static ResourceManagerWrapper Create(string resourceName, CultureInfo culture = null) { var fullResourceName = Assembly.GetExecutingAssembly().GetName().Name + "." + resourceName; return new ResourceManagerWrapper( new ResourceManager(fullResourceName, Assembly.GetExecutingAssembly()), culture); //берем ресурс по названию из текущей сборки } public CultureInfo Culture; public ResourceManager Manager; public StringIndexer Strings; public ObjectIndexer Objects; public StreamIndexer Streams; public ResourceManagerWrapper(ResourceManager manager, CultureInfo culture = null) { this.Manager = manager; if (culture == null) culture = new CultureInfo("EN"); this.Culture = culture; //вот тут добавляем индексацию Strings = new StringIndexer(Manager); Objects = new ObjectIndexer(Manager); Streams = new StreamIndexer(Manager); } public ResourceSet TranslationsSet { get { return Manager.GetResourceSet(Culture, false, true); } } public class ObjectIndexer : StringTemplateDictionary<object> { ResourceManager manager; public ObjectIndexer(ResourceManager manager) { this.manager = manager; } public override object Get(string key) { return manager.GetObject(key); } } public class StreamIndexer : StringTemplateDictionary<Stream> { ResourceManager manager; public StreamIndexer(ResourceManager manager) { this.manager = manager; } public override Stream Get(string key) { return manager.GetStream(key); } } public class StringIndexer : StringTemplateDictionary<string> { ResourceManager manager; public StringIndexer(ResourceManager manager) { this.manager = manager; } public override string Get(string key) { return manager.GetString(key); } } }
StringTemplateDictionary это своего рода класс-заглушка с интерфейсом IDictionary, выглядит который вот так:
public abstract class StringTemplateDictionary<V> : IDictionary { public abstract V Get(string key); public object this[object key] { get { return Get(key.ToString()); } set { throw new NotImplementedException(); } } public void Add(object key, object value) { throw new NotImplementedException(); } public void Clear() { throw new NotImplementedException(); } public bool Contains(object key) { return this[key] != null; } public IDictionaryEnumerator GetEnumerator() { throw new NotImplementedException(); } public bool IsFixedSize { get { throw new NotImplementedException(); } } public bool IsReadOnly { get { return true; } } public ICollection Keys { get { throw new NotImplementedException(); } } public void Remove(object key) { throw new NotImplementedException(); } public ICollection Values { get { throw new NotImplementedException(); } } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } public int Count { get { throw new NotImplementedException(); } } public bool IsSynchronized { get { throw new NotImplementedException(); } } public object SyncRoot { get { throw new NotImplementedException(); } } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } }
Таким образом, появляется возможность передать ресурс как словарь:
var translations = ResourceManagerWrapper.Create("Translations", culture); page.SetAttribute("strings", translations.Strings);
И теперь использовать, как список — $strings.resourceName$
Инициализация
В итоге, собрав все вместе, мы получаем класс для инициализации и сохранения, который делает следующее:
- Создает экземпляр шаблона по имени.
- Инициализирует группы для поддержки скина.
- На основе культуры, добавляет ресурсы.
- Сохраняет результат работы в файл.
- Настройка финальной обработки (поговорим о ней в третей части).
Метки:C#, OpenSource, Template
Похожие статьи
- 23 сентября 2011 -- Конфигурационные секции. Web.config и App.config для «C# продолжающих». (0)
- 31 августа 2009 -- CRUD на SQLite (5)
- 27 ноября 2009 -- ASP.NET пейджинг. (Paging in ASP.NET) (3)
- 4 февраля 2009 -- LINQ Insert or Update еще одно решение. (2)
- 22 августа 2008 -- Собственная страница для обработки ошибок на ASP.NET (0)