Add language-aware article sorting
This commit is contained in:
@@ -29,6 +29,9 @@ public static class ItemsProxySorting
|
||||
}
|
||||
|
||||
public static void Apply(JsonNode root, ItemsProxyControls controls, CultureInfo culture, string[] titleArticles)
|
||||
=> Apply(root, controls, culture, _ => titleArticles);
|
||||
|
||||
public static void Apply(JsonNode root, ItemsProxyControls controls, CultureInfo culture, Func<JsonObject, string[]> titleArticlesForItem)
|
||||
{
|
||||
if (!TryGetItemsArray(root, out var itemsArray))
|
||||
return;
|
||||
@@ -36,9 +39,9 @@ public static class ItemsProxySorting
|
||||
var items = itemsArray.OfType<JsonObject>().ToList();
|
||||
var specs = BuildSortSpecs(controls.SortBy);
|
||||
if (specs.Length > 0 && items.Count > 1)
|
||||
items = Sort(items, specs, controls.SortOrder, culture, titleArticles);
|
||||
items = Sort(items, specs, controls.SortOrder, culture, titleArticlesForItem);
|
||||
|
||||
items = FilterByNameStartsWith(items, controls.NameStartsWith, culture, titleArticles);
|
||||
items = FilterByNameStartsWith(items, controls.NameStartsWith, culture, titleArticlesForItem);
|
||||
var filteredCount = items.Count;
|
||||
items = Slice(items, controls.StartIndex, controls.Limit);
|
||||
|
||||
@@ -77,24 +80,45 @@ public static class ItemsProxySorting
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] GetSortArticles(SortArticleCatalog articleCatalog, IEnumerable<SortArticleEntry> configuredArticles, string? sortLocale)
|
||||
public static string[] GetSortArticles(
|
||||
SortArticleCatalog articleCatalog,
|
||||
IEnumerable<SortArticleEntry> configuredArticles,
|
||||
string? titleLanguage,
|
||||
bool ignoreArticles = true)
|
||||
{
|
||||
var locale = (sortLocale ?? string.Empty).Trim();
|
||||
if (locale.Length == 0)
|
||||
locale = "en";
|
||||
if (!ignoreArticles)
|
||||
return [];
|
||||
|
||||
var configured = configuredArticles.ToArray();
|
||||
var custom = configured.FirstOrDefault(e => e.Language.Equals(locale, StringComparison.OrdinalIgnoreCase))
|
||||
?? configured.FirstOrDefault(e => locale.StartsWith(e.Language + "-", StringComparison.OrdinalIgnoreCase));
|
||||
var always = configured
|
||||
.Where(e => e.AlwaysApply == true)
|
||||
.SelectMany(e => SplitArticles(e.Articles));
|
||||
return always
|
||||
.Concat(GetLanguageArticles(articleCatalog, configured, titleLanguage))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static string[] GetLanguageArticles(
|
||||
SortArticleCatalog articleCatalog,
|
||||
SortArticleEntry[] configured,
|
||||
string? titleLanguage)
|
||||
{
|
||||
var language = (titleLanguage ?? string.Empty).Trim();
|
||||
if (language.Length == 0)
|
||||
return [];
|
||||
|
||||
var custom = configured.FirstOrDefault(e => e.Language.Equals(language, StringComparison.OrdinalIgnoreCase))
|
||||
?? configured.FirstOrDefault(e => language.StartsWith(e.Language + "-", StringComparison.OrdinalIgnoreCase));
|
||||
if (custom is not null)
|
||||
return SplitArticles(custom.Articles);
|
||||
|
||||
var builtIns = articleCatalog.GetBuiltIns();
|
||||
if (builtIns.TryGetValue(locale, out var exact))
|
||||
if (builtIns.TryGetValue(language, out var exact))
|
||||
return exact;
|
||||
|
||||
var dash = locale.IndexOf('-', StringComparison.Ordinal);
|
||||
return dash > 0 && builtIns.TryGetValue(locale[..dash], out var languageOnly)
|
||||
var dash = language.IndexOf('-', StringComparison.Ordinal);
|
||||
return dash > 0 && builtIns.TryGetValue(language[..dash], out var languageOnly)
|
||||
? languageOnly
|
||||
: [];
|
||||
}
|
||||
@@ -149,12 +173,12 @@ public static class ItemsProxySorting
|
||||
_ => SortKind.Text
|
||||
};
|
||||
|
||||
private static List<JsonObject> Sort(List<JsonObject> items, SortSpec[] specs, string sortOrder, CultureInfo culture, string[] titleArticles)
|
||||
private static List<JsonObject> Sort(List<JsonObject> items, SortSpec[] specs, string sortOrder, CultureInfo culture, Func<JsonObject, string[]> titleArticlesForItem)
|
||||
{
|
||||
var descending = sortOrder.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.FirstOrDefault()?.Equals("Descending", StringComparison.OrdinalIgnoreCase) == true;
|
||||
var comparer = StringComparer.Create(culture, true);
|
||||
var values = items.Select(item => new { Item = item, Values = specs.Select(spec => ValueFor(item, spec, culture, titleArticles)).ToArray() }).ToList();
|
||||
var values = items.Select(item => new { Item = item, Values = specs.Select(spec => ValueFor(item, spec, culture, titleArticlesForItem(item))).ToArray() }).ToList();
|
||||
|
||||
values.Sort((left, right) =>
|
||||
{
|
||||
@@ -197,14 +221,14 @@ public static class ItemsProxySorting
|
||||
|
||||
private readonly record struct SortValue(bool HasValue, string Text, double Number);
|
||||
|
||||
private static List<JsonObject> FilterByNameStartsWith(List<JsonObject> items, string prefix, CultureInfo culture, string[] titleArticles)
|
||||
private static List<JsonObject> FilterByNameStartsWith(List<JsonObject> items, string prefix, CultureInfo culture, Func<JsonObject, string[]> titleArticlesForItem)
|
||||
{
|
||||
prefix = (prefix ?? string.Empty).Trim();
|
||||
if (prefix.Length == 0)
|
||||
return items;
|
||||
|
||||
return items
|
||||
.Where(i => culture.CompareInfo.IsPrefix(StripArticle(GetString(i, "Name"), titleArticles), prefix, CompareOptions.IgnoreCase))
|
||||
.Where(i => culture.CompareInfo.IsPrefix(StripArticle(GetString(i, "Name"), titleArticlesForItem(i)), prefix, CompareOptions.IgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@@ -227,8 +251,9 @@ public static class ItemsProxySorting
|
||||
var word = article.Trim();
|
||||
if (word.Length == 0 || text.Length <= word.Length)
|
||||
continue;
|
||||
if (text.StartsWith(word + " ", StringComparison.OrdinalIgnoreCase))
|
||||
return text[(word.Length + 1)..].TrimStart();
|
||||
var attachedArticle = word.EndsWith("'", StringComparison.Ordinal);
|
||||
if (text.StartsWith(word + (attachedArticle ? string.Empty : " "), StringComparison.OrdinalIgnoreCase))
|
||||
return text[word.Length..].TrimStart();
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
Reference in New Issue
Block a user