diff --git a/src/ClaudeDo.Localization/CultureResolver.cs b/src/ClaudeDo.Localization/CultureResolver.cs new file mode 100644 index 0000000..95aa6f5 --- /dev/null +++ b/src/ClaudeDo.Localization/CultureResolver.cs @@ -0,0 +1,16 @@ +namespace ClaudeDo.Localization; + +public static class CultureResolver +{ + public static string Resolve(string cultureName, IReadOnlyCollection available, string fallback = "en") + { + if (string.IsNullOrWhiteSpace(cultureName)) return fallback; + + var exact = available.FirstOrDefault(c => string.Equals(c, cultureName, StringComparison.OrdinalIgnoreCase)); + if (exact is not null) return exact; + + var primary = cultureName.Split('-')[0]; + var byPrimary = available.FirstOrDefault(c => string.Equals(c, primary, StringComparison.OrdinalIgnoreCase)); + return byPrimary ?? fallback; + } +} diff --git a/tests/ClaudeDo.Localization.Tests/CultureResolverTests.cs b/tests/ClaudeDo.Localization.Tests/CultureResolverTests.cs new file mode 100644 index 0000000..496de3e --- /dev/null +++ b/tests/ClaudeDo.Localization.Tests/CultureResolverTests.cs @@ -0,0 +1,19 @@ +using ClaudeDo.Localization; + +namespace ClaudeDo.Localization.Tests; + +public class CultureResolverTests +{ + private static readonly string[] Codes = { "en", "de" }; + + [Theory] + [InlineData("de-DE", "de")] + [InlineData("de", "de")] + [InlineData("en-US", "en")] + [InlineData("fr-FR", "en")] + [InlineData("", "en")] + public void Resolve_maps_culture_to_available_code(string culture, string expected) + { + Assert.Equal(expected, CultureResolver.Resolve(culture, Codes, fallback: "en")); + } +}