自动处理中的多语言属性.NET类

本文关键字:语言 属性 NET 处理 | 更新日期: 2023-09-27 18:01:06

我正在尝试在ASP中处理多种语言。NET Webforms(.NET 4.5,C#(的应用程序。

基本上,我的SQL Server 2012数据库中的一些实体具有类似NameDescription的属性,它们以三种语言存在——德语、法语和意大利语。

这些存储为列Name_De(德语(、Name_Fr(法语(和Name_It(意大利语(。

当我创建。NET对象,当然,我也在实体类中获得这三个属性。但对于在屏幕上显示,例如在网格中,如果我能以某种方式"神奇地"始终显示"正确"的语言,那就太好了。这应该基于Thread.Current.CurrentUICulture.TwoLetterISOLanguageName(根据浏览器的语言偏好,返回defrit(。

因此,我希望能够以某种方式创建例如。NET属性,可以让我做这样的事情:

基本"模块"实体-从现有SQL Server数据库生成:

public partial class Module
{
    public string ModuleCode { get; set; }
    public string Name_De { get; set; }
    public string Name_Fr { get; set; }
    public string Name_It { get; set; }
    ... // other properties
}

单独文件中的部分扩展名

public partial class Module
{
    [Multilingual]
    public string Name { get; set; }
}

基本思想是:我可以访问Module.Name属性,根据CurrentUICulture的当前设置,当我访问Name属性的getter时,会获取Name_DeName_FrName_It的值。

像这样的事情可以在C#中完成吗?我看过很多自定义属性的实现,但似乎从来没有做过这样的事情。。。

自动处理中的多语言属性.NET类

假设您使用两个独立的实体(一个由SQL实体生成,另一个仅包含Name属性的"业务实体"(,您是否愿意使用类似AutoMapper的东西?

如果是,则可以根据当前线程区域性调整解析函数以映射实体。

   switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
   {
       case "DE":
           return dto.Name_De;
       case "FR":
           return dto.Name_Fr;
       // ...
       default :
           return String.Empty;
    }   

这将适用于您的场景。

如果这是一个可以为你工作的解决方案,我认为这个问题非常接近你所寻找的:多语言网站中本地化解析程序的自动映射器映射

如果你真的走自定义属性的路线,恐怕你将不得不处理反射和字符串解析。AFAIK,提供的本地化功能无法实现这一点。NET。AutoMapper会对你隐藏它。

在这种情况下,自定义属性的问题是您仍在尝试访问Name属性。您试图通过使属性访问其他属性来"隐藏"属性的默认行为。如果我理解正确,您希望Multilingual自定义属性将您的属性转换为:

public String Name
{
    get
    {  switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
       {
           case "DE":
               return dto.Name_De;
           case "FR":
               return dto.Name_Fr;
           // ...
           default :
               return String.Empty;
        } 
    }
}

如果这是正确的,那么您将无法在属性上轻松做到这一点,因为属性永远不会知道Name_De属性的存在。

其他仍然不是您想要的选项:

void Main()
{
    Module mod = new Module();
    mod.Name_De = "name";
    mod.Name_Fr = "nom";
    // This is the unfortunate nasty bit. I address the property using its name 
    // in a String which is just bad. I don't think there is a way
    // you will be able to address the ".Name" property directly and have
    // it return the localized value through your custom attribute though
    String localizedValue = mod.GetLocalizedProperty("Name");
}

[AttributeUsage(AttributeTargets.Property)]
public sealed class MultilingualAttribute : Attribute
{
   public MultilingualAttribute()
   {
   }
}
public static class ModuleExtensions
{
   public static String GetLocalizedProperty(this Module module, String propName)
   {
        var type = typeof(Module);
        var propInfo = type.GetProperty(propName);
        // Make sure the prop really is "Multilingual"
        if(Attribute.IsDefined(propInfo, typeof(MultilingualAttribute)))
        {
            String localizedPropName = propInfo.Name;
            switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
            {
                case "DE":
                    localizedPropName += "_De";
                    return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
                case "FR":
                    localizedPropName += "_Fr";
                    return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
            }
        }
        return String.Empty;
   }
}
public class Module
{
    public String Name_De {get; set;}
    public String Name_Fr {get; set;}
    [Multilingual]
    public String Name {get; set;}
    public Module()
    {
    }
}

不幸的是,我不知道有什么比这更强大的方法可以使用自定义属性来满足您的需求。坦率地说,我不认为这是一个好的解决方案,只是因为我想看看我能用自定义属性做些什么。在一个更"正常"的属性上使用这段代码并没有什么实际意义,因为它会以更清晰的方式(没有属性(做同样的事情。正如您在最初的问题中所说,您的目标是拦截对Name属性的调用,但这并没有实现。