[backend/federation] Add LDLocalizedString
This commit is contained in:
parent
3bfb133661
commit
9e713419ce
1 changed files with 155 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
|||
using System.Globalization;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -6,10 +7,113 @@ using J = Newtonsoft.Json.JsonPropertyAttribute;
|
|||
|
||||
namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
||||
|
||||
public class LDLocalizedString
|
||||
{
|
||||
/// <summary>
|
||||
/// key: BCP 47 language code, with empty string meaning "unknown"
|
||||
/// value: content, in that language
|
||||
/// </summary>
|
||||
public Dictionary<string, string?> Values { get; set; }
|
||||
|
||||
public LDLocalizedString()
|
||||
{
|
||||
Values = [];
|
||||
}
|
||||
|
||||
public LDLocalizedString(string? language, string? value)
|
||||
{
|
||||
Values = [];
|
||||
|
||||
// this is required to create a non-Map field for non-JsonLD remotes.
|
||||
Values.Add("", value);
|
||||
|
||||
if (language != null)
|
||||
{
|
||||
language = NormalizeLanguageCode(language);
|
||||
|
||||
if (language != null && language != "")
|
||||
Values.Add(language, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the remote sends different content to multiple languages, try and guess which one they prefer "by default".
|
||||
///
|
||||
/// This idea was taken from Sharkey's implementation.
|
||||
/// https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/401#note_1174
|
||||
/// </summary>
|
||||
/// <param name="language">The guessed language</param>
|
||||
/// <returns>The value, in the guessed language</returns>
|
||||
public string? GuessPreferredValue(out string? language)
|
||||
{
|
||||
if (Values.Count > 1)
|
||||
{
|
||||
var unknownValue = GetUnknownValue();
|
||||
if (unknownValue != null)
|
||||
{
|
||||
var preferred = Values.FirstOrDefault(i => !IsUnknownLanguage(i.Key) && i.Value == unknownValue);
|
||||
if (preferred.Value != null)
|
||||
{
|
||||
language = NormalizeLanguageCode(preferred.Key);
|
||||
return preferred.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Values.Count == 0)
|
||||
{
|
||||
language = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
var first = Values.FirstOrDefault(i => !IsUnknownLanguage(i.Key));
|
||||
if (first.Value == null)
|
||||
{
|
||||
first = Values.FirstOrDefault();
|
||||
if (first.Value == null)
|
||||
{
|
||||
language = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
language = IsUnknownLanguage(first.Key) ? null : NormalizeLanguageCode(first.Key);
|
||||
return first.Value;
|
||||
}
|
||||
|
||||
public static string? NormalizeLanguageCode(string lang)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CultureInfo.GetCultureInfo(lang).ToString();
|
||||
}
|
||||
catch (CultureNotFoundException)
|
||||
{
|
||||
// invalid language code
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Akkoma forces all non-localized text to be in the "und" language by adding { "@language":"und" } to it's context
|
||||
public static bool IsUnknownLanguage(string? lang) => lang == null || lang == "" || lang == "und";
|
||||
public string? GetUnknownValue()
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (Values.TryGetValue("", out value))
|
||||
return value;
|
||||
|
||||
if (Values.TryGetValue("und", out value))
|
||||
return value;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class LDValueObject<T>
|
||||
{
|
||||
[J("@type")] public string? Type { get; set; }
|
||||
[J("@value")] public required T Value { get; set; }
|
||||
[J("@type")] public string? Type { get; set; }
|
||||
[J("@value")] public required T Value { get; set; }
|
||||
[J("@language")] public string? Language { get; set; }
|
||||
}
|
||||
|
||||
public class ValueObjectConverter : JsonConverter
|
||||
|
@ -158,3 +262,52 @@ public sealed class XsdString(string? str)
|
|||
|
||||
public override string? ToString() => str;
|
||||
}
|
||||
|
||||
public class LocalizedValueObjectConverter : JsonConverter<LDLocalizedString>
|
||||
{
|
||||
public override LDLocalizedString? ReadJson(JsonReader reader, Type objectType, LDLocalizedString? existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var obj = JArray.Load(reader);
|
||||
var list = obj.ToObject<List<LDValueObject<string?>>>();
|
||||
if (list == null || list.Count == 0)
|
||||
return null;
|
||||
|
||||
var localized = new LDLocalizedString();
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
localized.Values.Add(item.Language ?? "", item.Value);
|
||||
}
|
||||
|
||||
return localized;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, LDLocalizedString? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
foreach (var item in value.Values)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
if (!LDLocalizedString.IsUnknownLanguage(item.Key))
|
||||
{
|
||||
writer.WritePropertyName("@language");
|
||||
writer.WriteValue(item.Key);
|
||||
}
|
||||
|
||||
writer.WritePropertyName("@value");
|
||||
writer.WriteValue(item.Value);
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue