Локализация адресных полей по культуре и культуре пользовательского интерфейса в Asp.Net MVC 3 - PullRequest
2 голосов
/ 07 июля 2011

У меня есть тип модели адреса, который включает следующие поля:

public string CountyState { get; set; }
public string PostZip { get; set; }

Я использую настроенную версию DisplayNameAttribute (написанную до того, как .Net 4 DisplayAttribute дала нам локализацию), котораяпозволяет локализовать отображаемое имя этих двух полей.

Поэтому, естественно, локальные en-GB переводы это "County" и "Post Code ", тогда как для en-US они, конечно, "State" и"Zip Code".

Однако на моем веб-сайте MVC отображаются платежные страницы для различных предприятий в разных местах, которые также должны быть в состоянии переводить на другие языки. Таким образом, культура пользовательского интерфейса может быть en-GB, но адресв полях по-прежнему должны отображаться "State" и "Zip Code", если платеж принимается за американский бизнес (внутренняя культура en-US).

Таким образом, может показаться, что один тип / ключ ресурсалокализованного поиска для этих полей отображения недостаточно. Я не хочу использовать разные типы моделей в зависимости от страны, а я не хочу писать разные Html - оба решения станут неуправляемыми по мере роста моего сайта, так как предприятия и т. д. будут добавляться через базу данных.

Мой сайт уже использует CurrentCulture для указания культуры бизнеса по умолчанию (конечно, используется для форматирования валюты),и я использую CurrentUICulture для обозначения культуры пользователя;поэтому я посчитал то, что мне кажется немного странным решением:

Используйте строку, локализованную на CurrentCulture, для поиска ключа ресурса для поля - например, ResourceName_Display_Address_PostZip.Когда en-GB это вернет DisplayName_GB_PostCode, но когда en-US вернет DisplayName_US_ZipCode.

Теперь используйте CurrentUICulture для поиска локализованной версии этого.

Я бызатем нужно написать атрибут, который может обернуть эту логику так, чтобы она была совместима с MVC.

Хорошее решение?Или я пропустил что-то ослепительно очевидное!?

Ответы [ 3 ]

1 голос
/ 07 июля 2011

Это просто псевдокод.Я сейчас не в том месте, чтобы тестировать и отлаживать.Но если ваша настроенная версия DisplayNameAttribute имеет связанный CurrentCulture, вы сможете написать и метод расширения, подобный этому:

    public static string GetLocalizedDisplayName<TProperty>(Expression<Func<TProperty>> e)
    {
        var modelType = ((MemberExpression)e.Body).Member.ReflectedType.GetType();
        var classProperties = TypeDescriptor.GetProperties(modelType).OfType<CustomAttribute>;
        var prop = from property in classProperties
                   where property.CultureInfo == CultureInfo.CurrentCulture
                   select property;

        return prop != null && !string.IsNullOrEmpty(prop.DisplayName) ? prop.DisplayName : member.Member.Name;
    }
0 голосов
/ 11 июля 2011

Итак, это то, что я сделал.

Мне пришлось сделать этот код более локальным для моего конкретного проекта, потому что он опирается на класс ресурса, передаваемый в виде открытого статического свойства ResourceManagerтипа System.Resources.ResourceManager.Это верно для класса, сгенерированного собственными строго типизированными классами доступа к ресурсам VS (сгенерированными из файлов .resx), и поэтому я думаю, что он, вероятно, квалифицируется как повторно используемый.Он использует это, так что он может указать культуру, которая будет использоваться при поиске строк.

Сначала выполняется поиск ресурса (с использованием CurrentCulture) для имени ресурса, которое будет использоваться для свойства модели.текст;затем он перекачивает эту строку обратно в другой поиск ресурсов (используя CurrentUICulture), чтобы получить фактическое отображаемое имя, которое будет использоваться.

Я заменил всю проверку ошибок на TODO, чтобы сохранить ее краткой.

В конце концов, я получил непосредственно из DisplayNameAttribute, потому что этот новый шаблон не очень хорошо сочетался с кодом, который я использовал (оторванный от RequiredAttribute), чтобы получить строки ресурсов на основе UICulture для моего собственного существующего настраиваемого атрибута.Мне не нравится имя класса, но я не могу придумать ничего лучшего прямо сейчас.

public class CultureDrivenDisplayNameAttribute : DisplayNameAttribute
{
  private readonly string _displayName = null;
  public CultureDrivenDisplayNameAttribute(Type resourceType,
    string resourceNameLookup)
  {
    //TODO: check for null args

    //get the ResourceManager member
    var prop = resourceType.GetProperty(
      "ResourceManager", 
      System.Reflection.BindingFlags.Public 
        | System.Reflection.BindingFlags.Static);

    //TODO: check for null or unexpected property type.

    System.Resources.ResourceManager resourceManager = 
      prop.GetValue(null, null) as System.Resources.ResourceManager;

    //TODO: check for null

    //ResourceManager is used as it lets us specify the culture - we need this
    //to be able to lookup first on Culture, then by UICulture.
    string finalResourceName = 
      resourceManager.GetString(resourceNameLookup, 
        Thread.CurrentThread.CurrentCulture);

    //TODO: check for null/whitespace resource value

    _displayName = resourceManager.GetString(finalResourceName, 
      Thread.CurrentThread.CurrentUICulture);
    //TODO: check for null display name
  }

  public override string DisplayName
  {
    get
    {
      return _displayName;
    }
  }
}

Итак, теперь я украшаю свойства PostZip / CountyState моей адресной модели следующим образом:

[CultureDrivenDisplayName(typeof(StringResources), 
  "ResourceName_AddressDetails_CountyState")]
public string CountyState { get; set; }

[CultureDrivenDisplayName(typeof(StringResources), 
  "ResourceName_AddressDetails_PostZip")]
public string PostZip { get; set; }

И затем, в моем нейтральном файле ресурсов:

ResourceName_AddressDetails_CountyState: "DisplayName_AddressDetails_CountyState"
ResourceName_AddressDetails_PostZip: "DisplayName_AddressDetails_PostZip"
DisplayName_AddressDetails_CountyState: "County/State"
DisplayName_AddressDetails_PostZip: "Post/Zip Code"

Так что, если я не настроил файлы ресурсов для данной культуры, адрес отобразит разумный текст.

Но в моем файле ресурсов en-GB:

ResourceName_AddressDetails_CountyState: "DisplayName_AddressDetails_CountyState_GB"
ResourceName_AddressDetails_PostZip: "DisplayName_AddressDetails_PostZip_GB"
DisplayName_AddressDetails_CountyState_GB: "County"
DisplayName_AddressDetails_PostZip_GB: "Post Code"

Так что теперь, независимо от культуры пользовательского интерфейса, на английском сайте всегда будет отображаться 'County' или 'Post Code';но культура пользовательского интерфейса может обеспечить собственный локальный перевод обеих фраз, если пожелает, просто определяя локализованные версии _GB суффиксированных строк ресурсов.

Я также понял, что мне может потребоваться выполнитьто же самое для целых страниц, поэтому я собираюсь расширить движки представлений Razor и Aspx для автоматической поддержки версий на основе культуры и пользовательского интерфейса, использующих подпапки.единственная проблема заключается в том, как интерпретировать папку /en-GB/ - это относится к фоновой или внешней культуре!

0 голосов
/ 08 июля 2011
[Required(ErrorMessageResourceType=typeof(Languages.Resource),ErrorMessageResourceName="PostZip")]
[Display(ResourceType=typeof(Languages.Resource),Name="PostZip")]
public string PostZip { get; set; }

Теперь создайте разные файлы .resx для разных местных жителей, например

Name = PostZip |Значение = почтовый индекс [для en-US]

Имя = почтовый индекс |Значение = почтовый индекс [для en-GB]

--- внутри контроллера -----

 //whatever logic you are looking for, now  set culture manually

CultureInfo ci = new CultureInfo("hi");
System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);

---------- вид изнутри --------------

 @Html.LabelFor(model => model.PostZip)

см. http://haacked.com/archive/2009/12/12/localizing-aspnetmvc-validation.aspx эту ссылку тоже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...