不同的“翻译” JsonProperty名称

时间:2019-09-19 14:35:07

标签: c# json.net

我想将JSON中使用的密钥转换为不同的语言。

从设计的角度来看,我知道在设计接口,API等时这似乎是胡说八道。为什么不首先使用英语?好吧,我没有写这个要求;)

/// <summary>serialization language</summary>
public enum Language
{
   /// <summary>English</summary>
   EN,
   /// <summary>German</summary>
   DE
   // some more ...
}

最简单的方法可能是属性:

/// <summary>An Attribute to add different "translations"</summary>
public class TranslatedFieldName : Attribute
{
   public string Name { get; }
   public Language Lang{ get; }
   // actually there might be a dictionary with lang-name pairs later on; but let's keep it simple
   public TranslatedFieldName(string translatedName, Language lang)
   {
       this.Lang = lang;
       this.Name = translatedName;
    }
}

然后将这个属性添加到我要序列化的类中:

/// <summary>I want to serialize classes of this kind to json in different languages </summary>
public class TranslatableObject
{
    [TranslatedFieldName("deutscher_schluessel", Language.DE)]
    public string english_key;
}

并致电JsonConvert.SerializeObject(...)

public void SerializationMethod()
{
    TranslatableObject to = new TranslatableObject()
    {
        english_key = "foo bar"
    };
    string englishJson = JsonConvert.SerializeObject(to); // == { "english_key": "foo bar" }
    string germanJson = JsonConvert.SerializeObject(to, new MultiLangConverter(Language.DE); // == { "deutscher_schluessel": "foo bar" }
}

我不知道用过的MultiLangConverter的实际外观如何:

public class MultiLangConverter : JsonConverter
{
    private readonly Language _lang,

    public MultiLangConverter() : this(Language.EN) { }

    public MultiLangConverter(Language lang)
    {
        _lang = lang;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Out of scope for now");
    }

    public override bool CanRead
    {
        get { return false; } // out of scope for now
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // what goes here?
    }
}

我尝试过的所有尝试似乎都过于复杂。我真的需要一个JsonConverter吗?还是更适合使用ContractResolver?

1 个答案:

答案 0 :(得分:5)

我认为您可以使用属性来表示已翻译的字段名称,这是正确的选择,但我认为您最终将希望使用自定义ContractResolver来处理翻译,而不是使用JsonConverter,尤其是如果您需要对多个模型类进行翻译(可能会发生)。

这是解析器的外观:

public class MultiLangResolver : DefaultContractResolver
{
    public Language Language { get; set; }

    public MultiLangResolver(Language lang)
    {
        Language = lang;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        // See if there is a [TranslatedFieldName] attribute applied to the property 
        // for the requested language
        var att = prop.AttributeProvider.GetAttributes(true)
                                        .OfType<TranslatedFieldNameAttribute>()
                                        .FirstOrDefault(a => a.Lang == Language);

        // if so, change the property name to the one from the attribute
        if (att != null)
        {
            prop.PropertyName = att.Name;
        }
        return prop;
    }
}

这是使用解析器进行序列化的方式:

public static string Serialize(object obj, Language lang)
{
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new MultiLangResolver(lang),
        Formatting = Formatting.Indented
    };
    var json = JsonConvert.SerializeObject(obj, settings);
    return json;
}

另一个注意事项:您将要用TranslatedFieldNameAttribute属性标记您的[AttributeUsage]类,该属性表示该类可以在属性上使用并且可以多次应用(一次针对每种所需的语言)支持):

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class TranslatedFieldNameAttribute : Attribute
{
    ...
}

正在运行的演示:https://dotnetfiddle.net/lIQaJc