Как стать автором
Обновить

Локализация .NET приложения, а в частности ASP.NET WebForms

Время на прочтение 4 мин
Количество просмотров 2.4K
Привет Хабрадруг!
Я, конечно, понимаю, что тема это уже заезжена до дыр, но попытаюсь описать мое видение локализации приложения и ее реализацию. И так, что мы хотим получить в итоге: Систему быстрой локализации .NET приложения, а в частности WebForms, на стадии пост разработки. По пунктам:

1. Разработка приложения: минимум внимания локализации.
2. Завершение разработки: минимум времени на локализацию.
И ещё надо, что бы это все было максимально удобно и просто.

Если коротко, то все будет выглядеть так:

У нас будет метод, что то на подобии gettext, в который мы будем передавать какой-то текст, или ключ + текст, а метод в свою очередь нам вернет локализованную строку или же то, что было в него передано. А также будет утилита, которая пропарсит *.cs, *.aspx, *.ascx файлы в поисках этого самого метода, получит оттуда ключи и текст, посмотрит или данные тексты и ключи уже имеются в ресурсах приложения. Потом мы воспользуемся google translate, что бы хоть худо бедно, да перевести новые тексты. И напоследок отредактируем переводы и сохраним это все назад в ресурсы. Готово.
Явно, что похожий, или может даже лучший механизм уже разработан, но полазив в интернете, увидел только мега тяжёлые и к тому-же платные решения.



Итак, приступим к реализации. Начнем со вспомогательного класса, a для server-side контролов c ExpressionBuilder-a:

public static class L
{
  private static readonly Regex KeyRepairRegex = new Regex("[^\\w\\d]", RegexOptions.Compiled);
  
  public static string Run(string value)
  {
    var key = GenerateKey(value);
    var localized = Resources.ResourceManager.GetString(key);
    return string.IsNullOrEmpty(localized) ? value : localized;
  }

  public static string Run(string key, string value)
  {
    var localized = Resources.ResourceManager.GetString(key);
    return string.IsNullOrEmpty(localized) ? value : localized;
  }

  public static string Run(string key, string value, params object[] format)
  {
    var localized = Run(key, value);

    if (format != null && format.Length > 0)
    {
      try
      {
        localized = string.Format(localized, format);
      }
      catch
      {
        
      }
    }
    return localized;
  }

  private static string GenerateKey(string value)
  {
    if (string.IsNullOrEmpty(value)) return value;

    value = value.Length > 23 ? value.Substring(0, 23) + "__" : value;    
    value = KeyRepairRegex.Replace(value, "_");
    if (char.IsUpper(value[0])) value = "_" + value;
    value = value.ToLowerInvariant();

    return value;
  }
}


Теперь, во время разработки, в местах, где нам понадобится локализация пишем:

<%= L.Run("Hello, Mr.Everybody") %>


Класс L специально не находиться ни в каком namespace, что бы не приходилось в *.ascx файлах делать его импорт.

<%@ Import Namespace ="Example.Namespace" %>


Здесь есть, как видно из кода, не мало важный метод GenerateKey. Если мы передаем только текст, без ключа, то этот метод сгенерирует ключ и именно этот ключ мы будем искать в ресурсах. Ключ в ресурсах может содержать только символы [a-z0-9_]. И наша утилита будет использовать этот же метод для генерации ключей. Сейчас еще рассмотрим ExpressionBuilder и приведу более конкретный пример всей схемы. Для чего же нам нужен этот самый Builder?

Конструкция <%=%> в серверных контролах приведет к ошибке, а для <%# %> надо дополнительно вызывать DataBind метод, что не очень удобно. Нам нужен класс унаследованный от ExpressionBuilder.

public class LExpressionBuilder: ExpressionBuilder
  {
    public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
      var thisType = new CodeTypeReferenceExpression(GetType());      
      var expression = new CodePrimitiveExpression(entry.Expression.Trim());
      const string evaluationMethod = "Localize";
      return new CodeMethodInvokeExpression(thisType, evaluationMethod, new CodeExpression[] { expression });
    }

    public static string Localize(string expression)
    {
      return L.Run(expression);
    }

    public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
      return Localize(entry.Expression);
    }

    public override bool SupportsEvaluate
    {
      get { return true; }
    }
  }


В результате пишем:

<input typ='submit' id='btnSubmit' runat='server' value="<%$ L:A people free to choose will always choose peace %>"/>


Первая часть готова. Переходим к утилите. Это обыкновенное WinForms приложение.

Диаграмма Классов

Как видно из диаграммы, код довольно прямолинейный. Но главное — простой. Мы загружаем нужный нам Solution или проект, указываем в классе Settings путь к нашему файлу ресурсов. И ...«поехали»! Solution класс загрузит все файлы. CodeParser загрузит все строки и ключи в класс Translation, который в свою очередь, загрузит все переводы с ресурсов и покажет все это в GridView. Теперь можно переводить вручную или через google, можна сохранить оригинальные строки в текстовый файл или что то еще реализовать, к примеру, сохранение в xml.

Assembla Subversion(Регистрация не обязательна)

Утилита эта написана для себя нa скорую руку, по принципу: «лишь бы работало», поэтому попрошу гуру не судить строго. Если будет у кого то интерес, могу довести это дело до, хотя бы, альфа версии.

Что ещё хочется сделать:

CodeParser выдирая строки из файлов запоминает их позиции. А так как большинство локализированных строк идут у меня изначально без ключей, то на их генерацию уходит несколько лишних наносекунд, поэтому утилита должна после вставлять в файлы ключи к строкам.

Но и без этого все работает очень шустро, хотя буду рад выслушать любую критику или пожелания.

Спасибо за внимание.

* Source code was highlighted with Source Code Highlighter.
Теги:
Хабы:
+2
Комментарии 2
Комментарии Комментарии 2

Публикации

Истории

Работа

.NET разработчик
69 вакансий

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн