From 4671e5ed5c00879c9bc18ee58e7a3ba6968157a1 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 15 Apr 2026 23:32:23 +0300 Subject: [PATCH 1/9] Transliteration Refactoring --- .../Filters/SlugifyFilter.cs | 1 + .../OrchardCore.Liquid.csproj | 1 + .../OrchardCore.Liquid/Startup.cs | 1 - .../Liquid}/TransliterateFilter.cs | 5 ++-- .../OrchardCore.Localization/Startup.cs | 4 +++ .../OrchardCore.Media.csproj | 1 + .../SlugifyMediaNameNormalizerService.cs | 1 + .../Extensions/StringExtensions.cs | 12 +++++++++ .../TransliterationSlugServiceExtensions.cs | 25 +++++++++++++++++++ .../Modules/Services/ISlugService.cs | 9 ------- .../OrchardCore.Abstractions.csproj | 1 + .../Modules/Services/SlugService.cs | 11 -------- .../OrchardCore/OrchardCore.csproj | 3 +-- .../Tokens.Content/SlugServiceTests.cs | 1 + 14 files changed, 51 insertions(+), 25 deletions(-) rename src/OrchardCore.Modules/{OrchardCore.Liquid/Filters => OrchardCore.Localization/Liquid}/TransliterateFilter.cs (80%) create mode 100644 src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/StringExtensions.cs create mode 100644 src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs index 7453c9e1f4b..c6dfa8ea12a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs @@ -1,5 +1,6 @@ using Fluid; using Fluid.Values; +using OrchardCore.Localization; using OrchardCore.Modules.Services; namespace OrchardCore.Liquid.Filters; diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/OrchardCore.Liquid.csproj b/src/OrchardCore.Modules/OrchardCore.Liquid/OrchardCore.Liquid.csproj index 3a013f28474..d527e334252 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/OrchardCore.Liquid.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/OrchardCore.Liquid.csproj @@ -24,6 +24,7 @@ + diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Liquid/Startup.cs index 5aaa43ebdf5..7043b3991c2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/Startup.cs @@ -72,7 +72,6 @@ public override void ConfigureServices(IServiceCollection services) .AddLiquidFilter("local") .AddLiquidFilter("utc") .AddLiquidFilter("slugify") - .AddLiquidFilter("transliterate") .AddLiquidFilter("liquid") .AddLiquidFilter("href") .AddLiquidFilter("absolute_url") diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/TransliterateFilter.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs similarity index 80% rename from src/OrchardCore.Modules/OrchardCore.Liquid/Filters/TransliterateFilter.cs rename to src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs index 1e480bbd892..ac33133a0e0 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/TransliterateFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs @@ -1,8 +1,9 @@ -using AnyAscii; using Fluid; using Fluid.Values; +using OrchardCore.Liquid; +using OrchardCore.Localization; -namespace OrchardCore.Liquid.Filters; +namespace OrchardCore.localization.Liquid.Filters; public class TransliterateFilter : ILiquidFilter { diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs index f9d2ea3639a..acd820ce306 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.Options; using OrchardCore.Admin.Models; using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.Liquid; +using OrchardCore.localization.Liquid.Filters; using OrchardCore.Localization.Drivers; using OrchardCore.Localization.Models; using OrchardCore.Localization.Services; @@ -34,6 +36,8 @@ public override void ConfigureServices(IServiceCollection services) AddDataAnnotationsPortableObjectLocalization(); services.Replace(ServiceDescriptor.Singleton()); + + services.AddLiquidFilter("transliterate"); } /// diff --git a/src/OrchardCore.Modules/OrchardCore.Media/OrchardCore.Media.csproj b/src/OrchardCore.Modules/OrchardCore.Media/OrchardCore.Media.csproj index a06d986a8ed..a55f8840861 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/OrchardCore.Media.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Media/OrchardCore.Media.csproj @@ -39,6 +39,7 @@ + diff --git a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs index 8a74ca14712..b83bdca7c34 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Options; +using OrchardCore.Localization; using OrchardCore.Modules.Services; namespace OrchardCore.Media.Services; diff --git a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/StringExtensions.cs b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/StringExtensions.cs new file mode 100644 index 00000000000..140d505b7d1 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/StringExtensions.cs @@ -0,0 +1,12 @@ +namespace OrchardCore.Localization; + +/// +/// +/// +public static class StringExtensions +{ + /// + /// Converts the non-Latin characters to their ASCII equivalents. + /// + public static string Transliterate(this string text) => AnyAscii.Transliteration.Transliterate(text); +} diff --git a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs new file mode 100644 index 00000000000..67395c3f6ae --- /dev/null +++ b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs @@ -0,0 +1,25 @@ +using OrchardCore.Modules.Services; + +namespace OrchardCore.Localization; + +public static class TransliterationSlugServiceExtensions +{ + /// + /// Transforms specified text to the form suitable for URL slugs, + /// optionally transliterating non-Latin characters to their ASCII equivalents first. + /// + /// The text to transform. + /// Whether to transliterate non-Latin characters before slugifying. + /// The slug created from the input text. + public static string Slugify(this ISlugService slugService, string text, bool transliterate) + { + ArgumentException.ThrowIfNullOrEmpty(text); + + if (transliterate) + { + text = text.Transliterate(); + } + + return slugService.Slugify(text); + } +} diff --git a/src/OrchardCore/OrchardCore.Abstractions/Modules/Services/ISlugService.cs b/src/OrchardCore/OrchardCore.Abstractions/Modules/Services/ISlugService.cs index be70f8064fa..21b9c8f0b56 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Modules/Services/ISlugService.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Modules/Services/ISlugService.cs @@ -9,15 +9,6 @@ public interface ISlugService /// The slug created from the input text. string Slugify(string text); - /// - /// Transforms specified text to the form suitable for URL slugs, - /// optionally transliterating non-Latin characters to their ASCII equivalents first. - /// - /// The text to transform. - /// Whether to transliterate non-Latin characters before slugifying. - /// The slug created from the input text. - string Slugify(string text, bool transliterate); - /// /// Transforms specified text to a custom form generally not suitable for URL slugs. /// Allows you to use a specified separator char. diff --git a/src/OrchardCore/OrchardCore.Abstractions/OrchardCore.Abstractions.csproj b/src/OrchardCore/OrchardCore.Abstractions/OrchardCore.Abstractions.csproj index 025ed9c0599..df33cb1778e 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/OrchardCore.Abstractions.csproj +++ b/src/OrchardCore/OrchardCore.Abstractions/OrchardCore.Abstractions.csproj @@ -16,6 +16,7 @@ + diff --git a/src/OrchardCore/OrchardCore/Modules/Services/SlugService.cs b/src/OrchardCore/OrchardCore/Modules/Services/SlugService.cs index d6c40aa2f9e..5f02de22b27 100644 --- a/src/OrchardCore/OrchardCore/Modules/Services/SlugService.cs +++ b/src/OrchardCore/OrchardCore/Modules/Services/SlugService.cs @@ -1,6 +1,5 @@ using System.Globalization; using System.Text; -using AnyAscii; using Cysharp.Text; namespace OrchardCore.Modules.Services; @@ -10,16 +9,6 @@ public class SlugService : ISlugService private const char Hyphen = '-'; private const int MaxLength = 1000; - public string Slugify(string text, bool transliterate) - { - if (transliterate && !string.IsNullOrEmpty(text)) - { - text = text.Transliterate(); - } - - return Slugify(text); - } - public string Slugify(string text, char separator) { throw new NotImplementedException(); diff --git a/src/OrchardCore/OrchardCore/OrchardCore.csproj b/src/OrchardCore/OrchardCore/OrchardCore.csproj index 03fd9517016..94c5acc04df 100644 --- a/src/OrchardCore/OrchardCore/OrchardCore.csproj +++ b/src/OrchardCore/OrchardCore/OrchardCore.csproj @@ -1,4 +1,4 @@ - + @@ -14,7 +14,6 @@ - diff --git a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs index c293f3e2069..3fef3f9c456 100644 --- a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs +++ b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs @@ -1,3 +1,4 @@ +using OrchardCore.Localization; using OrchardCore.Modules.Services; namespace OrchardCore.Tests.Tokens.Content; From 22738882fd3690615673e0c5881f348b27724bad Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 16 Apr 2026 00:06:21 +0300 Subject: [PATCH 2/9] Remove transliterate param --- .../OrchardCore.Liquid/Filters/SlugifyFilter.cs | 5 ++++- .../Services/SlugifyMediaNameNormalizerService.cs | 8 ++++++-- .../Extensions/TransliterationSlugServiceExtensions.cs | 10 ++-------- .../Tokens.Content/SlugServiceTests.cs | 9 +-------- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs index c6dfa8ea12a..5b1264fcdb4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs @@ -17,7 +17,10 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu { var transliterateArg = arguments["transliterate"]; var transliterate = transliterateArg.IsNil() || transliterateArg.ToBooleanValue(); + var slug = transliterate + ? _slugService.SlugifyWithTransliteration(input.ToStringValue()) + : _slugService.Slugify(input.ToStringValue()); - return new StringValue(_slugService.Slugify(input.ToStringValue(), transliterate)); + return new StringValue(slug); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs index b83bdca7c34..15df19614ac 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs @@ -19,11 +19,15 @@ public SlugifyMediaNameNormalizerService( public string NormalizeFolderName(string folderName) { - return _slugService.Slugify(folderName, _options.Transliterate); + return _options.Transliterate + ? _slugService.SlugifyWithTransliteration(folderName) + : _slugService.Slugify(folderName); } public string NormalizeFileName(string fileName) { - return _slugService.Slugify(Path.GetFileNameWithoutExtension(fileName), _options.Transliterate) + Path.GetExtension(fileName); + return _options.Transliterate + ? _slugService.SlugifyWithTransliteration(Path.GetFileNameWithoutExtension(fileName)) + : _slugService.Slugify(Path.GetFileNameWithoutExtension(fileName)) + Path.GetExtension(fileName); } } diff --git a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs index 67395c3f6ae..611355e8f80 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs @@ -9,17 +9,11 @@ public static class TransliterationSlugServiceExtensions /// optionally transliterating non-Latin characters to their ASCII equivalents first. /// /// The text to transform. - /// Whether to transliterate non-Latin characters before slugifying. /// The slug created from the input text. - public static string Slugify(this ISlugService slugService, string text, bool transliterate) + public static string SlugifyWithTransliteration(this ISlugService slugService, string text) { ArgumentException.ThrowIfNullOrEmpty(text); - if (transliterate) - { - text = text.Transliterate(); - } - - return slugService.Slugify(text); + return slugService.Slugify(text.Transliterate()); } } diff --git a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs index 3fef3f9c456..6340fa3fef6 100644 --- a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs +++ b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs @@ -82,14 +82,7 @@ public void ShouldPreserveNonLatinCharacters(string input, string expected) [Fact] public void ShouldTransliterateWhenRequested() { - var slug = _slugService.Slugify("Æneid", transliterate: true); + var slug = _slugService.SlugifyWithTransliteration("Æneid"); Assert.Equal("aeneid", slug); } - - [Fact] - public void ShouldNotTransliterateWhenDisabled() - { - var slug = _slugService.Slugify("Æneid", transliterate: false); - Assert.Equal("æneid", slug); - } } From e9f382615d993fe44b0612f7c7bc20307e9f46fd Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 16 Apr 2026 00:24:35 +0300 Subject: [PATCH 3/9] transliterate -> translit --- src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs index acd820ce306..9aa6f7471b3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs @@ -37,7 +37,7 @@ public override void ConfigureServices(IServiceCollection services) services.Replace(ServiceDescriptor.Singleton()); - services.AddLiquidFilter("transliterate"); + services.AddLiquidFilter("translit"); } /// From c53f525af2f5e42b7db12293d4cf435105b8e750 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 16 Apr 2026 21:14:52 +0300 Subject: [PATCH 4/9] Revert "transliterate -> translit" This reverts commit e9f382615d993fe44b0612f7c7bc20307e9f46fd. --- src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs index 9aa6f7471b3..acd820ce306 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs @@ -37,7 +37,7 @@ public override void ConfigureServices(IServiceCollection services) services.Replace(ServiceDescriptor.Singleton()); - services.AddLiquidFilter("translit"); + services.AddLiquidFilter("transliterate"); } /// From bdb68d30919d17c8142f1696e0091cc488e82141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Thu, 23 Apr 2026 10:56:59 -0700 Subject: [PATCH 5/9] Apply suggestion from @sebastienros --- .../OrchardCore.Localization/Liquid/TransliterateFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs index ac33133a0e0..5ae0908b4a3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs @@ -3,7 +3,7 @@ using OrchardCore.Liquid; using OrchardCore.Localization; -namespace OrchardCore.localization.Liquid.Filters; +namespace OrchardCore.Localization.Liquid.Filters; public class TransliterateFilter : ILiquidFilter { From 4b9d5d0a9b1da996d63f884c4a50644800106ef4 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 24 Apr 2026 03:04:36 +0300 Subject: [PATCH 6/9] SlugifyWithTransliteration -> SlugifyAndTransliterate --- .../OrchardCore.Liquid/Filters/SlugifyFilter.cs | 2 +- .../Services/SlugifyMediaNameNormalizerService.cs | 4 ++-- .../Extensions/TransliterationSlugServiceExtensions.cs | 10 +++++----- .../Tokens.Content/SlugServiceTests.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs index 5b1264fcdb4..fdc82ec7163 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs @@ -18,7 +18,7 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu var transliterateArg = arguments["transliterate"]; var transliterate = transliterateArg.IsNil() || transliterateArg.ToBooleanValue(); var slug = transliterate - ? _slugService.SlugifyWithTransliteration(input.ToStringValue()) + ? _slugService.SlugifyAndTransliterate(input.ToStringValue()) : _slugService.Slugify(input.ToStringValue()); return new StringValue(slug); diff --git a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs index 15df19614ac..7a4bcbf7a41 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/Services/SlugifyMediaNameNormalizerService.cs @@ -20,14 +20,14 @@ public SlugifyMediaNameNormalizerService( public string NormalizeFolderName(string folderName) { return _options.Transliterate - ? _slugService.SlugifyWithTransliteration(folderName) + ? _slugService.SlugifyAndTransliterate(folderName) : _slugService.Slugify(folderName); } public string NormalizeFileName(string fileName) { return _options.Transliterate - ? _slugService.SlugifyWithTransliteration(Path.GetFileNameWithoutExtension(fileName)) + ? _slugService.SlugifyAndTransliterate(Path.GetFileNameWithoutExtension(fileName)) : _slugService.Slugify(Path.GetFileNameWithoutExtension(fileName)) + Path.GetExtension(fileName); } } diff --git a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs index 611355e8f80..e18c01ba9f9 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Localization/Extensions/TransliterationSlugServiceExtensions.cs @@ -5,12 +5,12 @@ namespace OrchardCore.Localization; public static class TransliterationSlugServiceExtensions { /// - /// Transforms specified text to the form suitable for URL slugs, - /// optionally transliterating non-Latin characters to their ASCII equivalents first. + /// Converts the specified text to a URL-friendly slug after applying transliteration. /// - /// The text to transform. - /// The slug created from the input text. - public static string SlugifyWithTransliteration(this ISlugService slugService, string text) + /// The slug service used to generate the slug from the transliterated text. + /// The input text to transliterate and convert to a slug. Cannot be null or empty. + /// A slugified string representing the transliterated input text. + public static string SlugifyAndTransliterate(this ISlugService slugService, string text) { ArgumentException.ThrowIfNullOrEmpty(text); diff --git a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs index 6340fa3fef6..7218569b0d9 100644 --- a/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs +++ b/test/OrchardCore.Tests/Tokens.Content/SlugServiceTests.cs @@ -82,7 +82,7 @@ public void ShouldPreserveNonLatinCharacters(string input, string expected) [Fact] public void ShouldTransliterateWhenRequested() { - var slug = _slugService.SlugifyWithTransliteration("Æneid"); + var slug = _slugService.SlugifyAndTransliterate("Æneid"); Assert.Equal("aeneid", slug); } } From 4822d19299d1574942f174a0bc6cb1ad6d8c0ad2 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 24 Apr 2026 03:10:15 +0300 Subject: [PATCH 7/9] Fix the build --- .../OrchardCore.Localization/Liquid/TransliterateFilter.cs | 1 - src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs index 5ae0908b4a3..e87a4a13c5d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Liquid/TransliterateFilter.cs @@ -1,7 +1,6 @@ using Fluid; using Fluid.Values; using OrchardCore.Liquid; -using OrchardCore.Localization; namespace OrchardCore.Localization.Liquid.Filters; diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs index acd820ce306..150142de423 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs @@ -6,8 +6,8 @@ using OrchardCore.Admin.Models; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.Liquid; -using OrchardCore.localization.Liquid.Filters; using OrchardCore.Localization.Drivers; +using OrchardCore.Localization.Liquid.Filters; using OrchardCore.Localization.Models; using OrchardCore.Localization.Services; using OrchardCore.Modules; From 50fcf788024e3c45e3213d70b644ada4e4933010 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 29 Apr 2026 04:26:44 +0300 Subject: [PATCH 8/9] Split the filters --- .../OrchardCore.Liquid/Filters/SlugifyFilter.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs index fdc82ec7163..73ff824dfd4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs +++ b/src/OrchardCore.Modules/OrchardCore.Liquid/Filters/SlugifyFilter.cs @@ -1,6 +1,5 @@ using Fluid; using Fluid.Values; -using OrchardCore.Localization; using OrchardCore.Modules.Services; namespace OrchardCore.Liquid.Filters; @@ -15,11 +14,7 @@ public SlugifyFilter(ISlugService slugService) } public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext ctx) { - var transliterateArg = arguments["transliterate"]; - var transliterate = transliterateArg.IsNil() || transliterateArg.ToBooleanValue(); - var slug = transliterate - ? _slugService.SlugifyAndTransliterate(input.ToStringValue()) - : _slugService.Slugify(input.ToStringValue()); + var slug = _slugService.Slugify(input.ToStringValue()); return new StringValue(slug); } From 90248669ed3c61097979faaceb460c70065938fb Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 29 Apr 2026 22:46:19 +0300 Subject: [PATCH 9/9] Add more unit tests --- .../Apis/Context/SiteStartup.cs | 1 + .../OrchardCore.Liquid/SlugifyFilterTests.cs | 54 +++++++++++++++++++ .../TransliterateFilterTests.cs | 36 +++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 test/OrchardCore.Tests/Modules/OrchardCore.Liquid/SlugifyFilterTests.cs create mode 100644 test/OrchardCore.Tests/Modules/OrchardCore.Liquid/TransliterateFilterTests.cs diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 78c0dc5f03d..0b4224e4472 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -23,6 +23,7 @@ public void ConfigureServices(IServiceCollection services) "OrchardCore.Tenants" ) .AddTenantFeatures( + "OrchardCore.Localization", "OrchardCore.Apis.GraphQL" ) .ConfigureServices(collection => diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/SlugifyFilterTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/SlugifyFilterTests.cs new file mode 100644 index 00000000000..711be569f4b --- /dev/null +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/SlugifyFilterTests.cs @@ -0,0 +1,54 @@ +using Fluid; +using OrchardCore.Liquid; +using OrchardCore.Tests.Apis.Context; + +namespace OrchardCore.Tests.Modules.OrchardCore.Liquid; + +public class SlugifyFilterTests +{ + [Theory] + [InlineData("Æneid Æneid", "æneid-æneid")] + [InlineData("Aeneid Aeneid", "aeneid-aeneid")] + public async Task SlugifyFilterShouldReturnSlugifiedString(string text, string expected) + { + // Arrange + var context = new SiteContext(); + + await context.InitializeAsync(); + + // Act & Assert + await context.UsingTenantScopeAsync(async scope => + { + var template = $$$"""{{ "{{{text}}}" | slugify }}"""; + + var liquidTemplateManager = scope.ServiceProvider.GetRequiredService(); + + var result = await liquidTemplateManager.RenderStringAsync(template, NullEncoder.Default, null); + + Assert.NotEmpty(result); + Assert.Equal(expected, result); + }); + } + + [Fact] + public async Task SlugifyThenTransliterateFilterShouldReturnSlugifiedTransliteratedString() + { + // Arrange + var context = new SiteContext(); + + await context.InitializeAsync(); + + // Act & Assert + await context.UsingTenantScopeAsync(async scope => + { + var template = """{{ "Æneid Æneid" | transliterate | slugify }}"""; + + var liquidTemplateManager = scope.ServiceProvider.GetRequiredService(); + + var result = await liquidTemplateManager.RenderStringAsync(template, NullEncoder.Default, null); + + Assert.NotEmpty(result); + Assert.Equal("aeneid-aeneid", result); + }); + } +} diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/TransliterateFilterTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/TransliterateFilterTests.cs new file mode 100644 index 00000000000..2de87d92e21 --- /dev/null +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Liquid/TransliterateFilterTests.cs @@ -0,0 +1,36 @@ +using Fluid; +using OrchardCore.Liquid; +using OrchardCore.Tests.Apis.Context; + +namespace OrchardCore.Tests.Modules.OrchardCore.Liquid; + +public class TransliterateFilterTests +{ + [Theory] + [InlineData("Æneid", "Aeneid")] + [InlineData("æneid", "aeneid")] + [InlineData("Aeneid", "Aeneid")] + [InlineData("aeneid", "aeneid")] + [InlineData("Ελληνικά", "Ellinika")] + [InlineData("джинсы_клеш", "dzhinsy_klesh")] + public async Task TransliterateFilterShouldReturnTransliteratedString(string text, string expected) + { + // Arrange + var context = new SiteContext(); + + await context.InitializeAsync(); + + // Act & Assert + await context.UsingTenantScopeAsync(async scope => + { + var template = $$$"""{{ "{{{text}}}" | transliterate }}"""; + + var liquidTemplateManager = scope.ServiceProvider.GetRequiredService(); + + var result = await liquidTemplateManager.RenderStringAsync(template, NullEncoder.Default, null); + + Assert.NotEmpty(result); + Assert.Equal(expected, result); + }); + } +}