поиск более чистого кода при встраивании вызовов razor в текст

#asp.net-mvc-3 #internationalization #razor

#asp.net-mvc-3 #интернационализация #razor

Вопрос:

Раньше у меня было что-то вроде этого:

 We suggest you read our @Html.ActionLink("help page", "Help", "Home") before
proceeding.
  

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

 We suggest you read our [HelpPage] before proceeding.
  

и затем в представлении, которое я должен выполнить:

 @MvcHtmlString.Create(this.Resource("Help").ToString()
   .Replace("[HelpPage]",
       @Html.ActionLink("help page", "Help", "Home").ToString()
   )
)
  

Какие еще стратегии вы можете использовать для интернационализации с помощью Razor?

this.Resource() это расширение страницы, которое вызывает .GetLocalResourceObject() и возвращает MvcHtmlString

Ответ №1:

Вы должны создать отдельный кодовый метод, который заменяет любые [placeholder] s фактическими ссылками, затем вызвать этот помощник в представлениях Razor.

Это даст вам единственное место для изменения кода, который заполняет ссылки.

Комментарии:

1. звучит разумно, но я не могу до конца это продумать… так что бы я сделал @Html.MyFn("Help", @Html.ActionLink()) ? это действительно похоже на создание шаблонов… вышесказанное было бы хорошо для замены одного «тега», но если бы у меня было 2, это усложнялось … мысли?

2. @ekkis: Вы должны выполнить замену тега в функции.

3. да, но проблема в том, что нет хорошего способа сделать это универсальным … если только я не должен был передать словарь, где термин является токеном для замены, а определение некоторым фрагментом кода для запуска, например, Dictionary<string, code> tags = new Dictionary<string, string>() { "Help", "@Html.ActionLink(...)" }; @Html.MyFn(tags) где myFn прочитал бы вторую строку и eval() ее (каким-то образом — я еще не настолько хорошо разбираюсь в C #, чтобы знать как)

4. @ekkis: Именно. ЭТО должно быть a Dictionary<string, Func<string, IHtmlString>> ; значениями должны быть делегаты, которые вы можете вызывать с помощью [contents] . Это дает вам единое место для размещения всех тегов.

Ответ №2:

У меня была такая же проблема. Вместо использования заполнителей я использую то же форматирование в своих строках ресурсов, как если бы я использовал String.Format() . Пример использования этого; мои строки ресурсов

 LogOnText1 | Please enter your user name and password. {0} if you don't have an account.
LogOnText1Register | Register
  

и мой взгляд (razor):

 @MvcHtmlString.Create(String.Format(ViewRes.AccountStrings.LogOnText1,
                      Html.ActionLink(ViewRes.AccountStrings.LogOnText1Register, "Register")))
  

Я думаю, что это немного чище

Комментарии:

1. это достойный подход, но мне никогда не нравилась его позиционность. Обсуждение SLaks на самом деле закончилось тем, что привело к хорошему решению. Я отвечу на это здесь, чтобы закрыть проблему

Ответ №3:

итак, вот что я в итоге написал:

 public static class PageExtensions
{
    public static MvcHtmlString Resource(
        this WebViewPage page, string key, 
        Dictionary<string, MvcHtmlString> tokenMap
    ) {
        HttpContextBase http = page.ViewContext.HttpContext;
        string text = (string) http.GetLocalResourceObject(page.VirtualPath, key);
        return new TagReplacer(text, tokenMap).ToMvcHtmlString();
    }
  

где замены тегов выполняются следующим образом:

 public class TagReplacer
{
    Dictionary<string, MvcHtmlString> tokenmap;
    public string Value { get; set; } 

    public TagReplacer(string text, Dictionary<string, MvcHtmlString> tokenMap)
    {
        tokenmap = tokenMap;

        Regex re = new Regex(@"[.*?]", RegexOptions.IgnoreCase);
        Value = re.Replace(text, new MatchEvaluator(this.Replacer));
    }

    public string Replacer(Match m)
    {
        return tokenmap[m.Value.RemoveSet("[]")].ToString();
    }

    public MvcHtmlString ToMvcHtmlString()
    {
        return MvcHtmlString.Create(Value);
    }
}
  

итак, в моем коде я теперь могу называть это следующим образом:

 @{
   Dictionary<string, MvcHtmlString> tagmap = new Dictionary<string, MvcHtmlString>() {
                { "HelpPage", Html.ActionLink("help page", "Help", "Home") }
            };
}
  

и в других местах:

 @this.Resource("Help", tagmap)
  

любые предложения по улучшению приветствуются