From f750f37a32406cc4790d81438d998e4e3e03107d Mon Sep 17 00:00:00 2001 From: yv01p Date: Fri, 12 Dec 2025 23:31:53 +0000 Subject: [PATCH] feat(strings): add IUtf8ToAsciiConverter and ICharacterMappingLoader interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Strings/ICharacterMappingLoader.cs | 16 +++++++++++ .../Strings/IUtf8ToAsciiConverter.cs | 25 +++++++++++++++++ .../Utf8ToAsciiConverterInterfaceTests.cs | 27 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/Umbraco.Core/Strings/ICharacterMappingLoader.cs create mode 100644 src/Umbraco.Core/Strings/IUtf8ToAsciiConverter.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Core/Strings/Utf8ToAsciiConverterInterfaceTests.cs diff --git a/src/Umbraco.Core/Strings/ICharacterMappingLoader.cs b/src/Umbraco.Core/Strings/ICharacterMappingLoader.cs new file mode 100644 index 0000000000..b82408f55e --- /dev/null +++ b/src/Umbraco.Core/Strings/ICharacterMappingLoader.cs @@ -0,0 +1,16 @@ +using System.Collections.Frozen; + +namespace Umbraco.Cms.Core.Strings; + +/// +/// Loads character mappings from JSON files. +/// +public interface ICharacterMappingLoader +{ + /// + /// Loads all mapping files and returns combined FrozenDictionary. + /// Higher priority mappings override lower priority. + /// + /// Frozen dictionary of character to string mappings. + FrozenDictionary LoadMappings(); +} diff --git a/src/Umbraco.Core/Strings/IUtf8ToAsciiConverter.cs b/src/Umbraco.Core/Strings/IUtf8ToAsciiConverter.cs new file mode 100644 index 0000000000..b3e538ae90 --- /dev/null +++ b/src/Umbraco.Core/Strings/IUtf8ToAsciiConverter.cs @@ -0,0 +1,25 @@ +namespace Umbraco.Cms.Core.Strings; + +/// +/// Converts UTF-8 text to ASCII, handling accented characters and transliteration. +/// +public interface IUtf8ToAsciiConverter +{ + /// + /// Converts text to ASCII, returning a new string. + /// + /// The text to convert. + /// Character to use for unmappable characters. Default '?'. + /// The ASCII-converted string. + string Convert(string? text, char fallback = '?'); + + /// + /// Converts text to ASCII, writing to output span. + /// Zero-allocation for callers who provide buffer. + /// + /// The input text span. + /// The output buffer. Must be at least input.Length * 4. + /// Character to use for unmappable characters. Default '?'. + /// Number of characters written to output. + int Convert(ReadOnlySpan input, Span output, char fallback = '?'); +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Strings/Utf8ToAsciiConverterInterfaceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Strings/Utf8ToAsciiConverterInterfaceTests.cs new file mode 100644 index 0000000000..fd5d0f15ce --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Strings/Utf8ToAsciiConverterInterfaceTests.cs @@ -0,0 +1,27 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Strings; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Strings; + +[TestFixture] +public class Utf8ToAsciiConverterInterfaceTests +{ + [Test] + public void IUtf8ToAsciiConverter_HasConvertStringMethod() + { + var type = typeof(IUtf8ToAsciiConverter); + var method = type.GetMethod("Convert", new[] { typeof(string), typeof(char) }); + + Assert.IsNotNull(method); + Assert.AreEqual(typeof(string), method.ReturnType); + } + + [Test] + public void IUtf8ToAsciiConverter_HasConvertSpanMethod() + { + var type = typeof(IUtf8ToAsciiConverter); + var methods = type.GetMethods().Where(m => m.Name == "Convert").ToList(); + + Assert.That(methods.Count, Is.GreaterThanOrEqualTo(2), "Should have at least 2 Convert overloads"); + } +}