diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 7f55d890992..d5a4e4129a5 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -14,13 +14,25 @@ namespace Flow.Launcher.Infrastructure { public class PinyinAlphabet : IAlphabet { + private static readonly IReadOnlyDictionary PolyphonicPhraseOverrides = new Dictionary + { + ["重启"] = ["Chong", "Qi"], + }; + private readonly ConcurrentDictionary _pinyinCache = new(); private readonly Settings _settings; private ReadOnlyDictionary currentDoublePinyinTable; public PinyinAlphabet() + : this(Ioc.Default.GetRequiredService()) + { + } + + public PinyinAlphabet(Settings settings) { - _settings = Ioc.Default.GetRequiredService(); + ArgumentNullException.ThrowIfNull(settings); + + _settings = settings; LoadDoublePinyinTable(); _settings.PropertyChanged += (sender, e) => @@ -118,6 +130,8 @@ public bool ShouldTranslate(string stringToTranslate) private (string translation, TranslationMapping map) BuildCacheFromContent(string content) { var resultList = WordsHelper.GetPinyinList(content); + ApplyPolyphonicPhraseOverrides(content, resultList); + var resultBuilder = new StringBuilder(_settings.UseDoublePinyin ? 3 : 4); // Pre-allocate with estimated capacity var map = new TranslationMapping(); @@ -163,6 +177,29 @@ public bool ShouldTranslate(string stringToTranslate) return _pinyinCache[content] = result; } + private static void ApplyPolyphonicPhraseOverrides(string content, string[] resultList) + { + foreach (var (phrase, pinyin) in PolyphonicPhraseOverrides) + { + var index = content.IndexOf(phrase, StringComparison.Ordinal); + while (index >= 0) + { + if (pinyin.Length != phrase.Length || index + pinyin.Length > resultList.Length) + { + index = content.IndexOf(phrase, index + phrase.Length, StringComparison.Ordinal); + continue; + } + + for (var i = 0; i < pinyin.Length; i++) + { + resultList[index + i] = pinyin[i]; + } + + index = content.IndexOf(phrase, index + phrase.Length, StringComparison.Ordinal); + } + } + } + /// /// Optimized Chinese character detection using the comprehensive CJK Unicode ranges /// diff --git a/Flow.Launcher.Test/PinyinAlphabetTest.cs b/Flow.Launcher.Test/PinyinAlphabetTest.cs new file mode 100644 index 00000000000..40a2392d77f --- /dev/null +++ b/Flow.Launcher.Test/PinyinAlphabetTest.cs @@ -0,0 +1,40 @@ +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.UserSettings; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Flow.Launcher.Test +{ + [TestFixture] + public class PinyinAlphabetTest + { + [TestCase("重启", "Chong Qi")] + [TestCase("重启 Flow Launcher", "Chong Qi Flow Launcher")] + [TestCase("重庆", "Chong Qing")] + public void Translate_ShouldUseExpectedPinyinForPolyphonicPhrases(string content, string expected) + { + var alphabet = new PinyinAlphabet(new Settings + { + ShouldUsePinyin = true + }); + + var result = alphabet.Translate(content); + + ClassicAssert.AreEqual(expected, result.translation); + } + + [Test] + public void FuzzyMatch_ShouldMatchRestartByCorrectPinyin() + { + var settings = new Settings + { + ShouldUsePinyin = true + }; + var matcher = new StringMatcher(new PinyinAlphabet(settings), settings); + + var result = matcher.FuzzyMatch("chongqi", "重启"); + + ClassicAssert.True(result.Success); + } + } +}