Картинка блога

В первой части я показал пример простого создания шаблона и его генерация в файл. Теперь, расскажу о дополнительных, интересных свойствах 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$

Инициализация

В итоге, собрав все вместе, мы получаем класс для инициализации и сохранения, который делает следующее:

  • Создает экземпляр шаблона по имени.
  • Инициализирует группы для поддержки скина.
  • На основе культуры, добавляет ресурсы.
  • Сохраняет результат работы в файл.
  • Настройка финальной обработки (поговорим о ней в третей части).

Метки:, ,