From 2ef34078058ddff29cd9231ec34bb39bd723eea4 Mon Sep 17 00:00:00 2001 From: Dominique Louis Date: Sun, 17 Jan 2021 04:15:56 +0000 Subject: [PATCH] Use NSSpeechSynthesizer.AttributesForVoice to correctly populate the X.E Locale on Mac. (#1623) * Use Attributes to correctly populate the X.E Locale on Mac. Fix Locale Name on iOS. * Add ? check just in case the atrribute look-up fails and ToString() is called on a null object. * Improve the contents of the picker for Android Co-authored-by: Matthew Leibowitz --- .../ViewModel/TextToSpeechViewModel.cs | 27 ++++++++++++++----- .../TextToSpeech.ios.tvos.watchos.cs | 2 +- .../TextToSpeech/TextToSpeech.macos.cs | 5 ++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Samples/Samples/ViewModel/TextToSpeechViewModel.cs b/Samples/Samples/ViewModel/TextToSpeechViewModel.cs index aa33e972a..0be4fa795 100644 --- a/Samples/Samples/ViewModel/TextToSpeechViewModel.cs +++ b/Samples/Samples/ViewModel/TextToSpeechViewModel.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; @@ -87,13 +88,27 @@ void OnCancel() async Task OnPickLocale() { - var locales = await TextToSpeech.GetLocalesAsync(); - var names = locales.Select(i => i.Name).ToArray(); + var allLocales = await TextToSpeech.GetLocalesAsync(); + var locales = allLocales + .OrderBy(i => i.Language.ToLowerInvariant()) + .ToArray(); - var result = await Application.Current.MainPage.DisplayActionSheet("Pick", "OK", null, names); + var languages = locales + .Select(i => string.IsNullOrEmpty(i.Country) ? i.Language : $"{i.Language} ({i.Country})") + .ToArray(); - selectedLocale = locales.FirstOrDefault(i => i.Name == result); - Locale = (result == "OK" || string.IsNullOrEmpty(result)) ? "Default" : result; + var result = await Application.Current.MainPage.DisplayActionSheet("Pick", "OK", null, languages); + + if (!string.IsNullOrEmpty(result) && Array.IndexOf(languages, result) is int idx && idx != -1) + { + selectedLocale = locales[idx]; + Locale = result; + } + else + { + selectedLocale = null; + Locale = "Default"; + } } public ICommand CancelCommand { get; } diff --git a/Xamarin.Essentials/TextToSpeech/TextToSpeech.ios.tvos.watchos.cs b/Xamarin.Essentials/TextToSpeech/TextToSpeech.ios.tvos.watchos.cs index f7f555eb6..bf6eca930 100644 --- a/Xamarin.Essentials/TextToSpeech/TextToSpeech.ios.tvos.watchos.cs +++ b/Xamarin.Essentials/TextToSpeech/TextToSpeech.ios.tvos.watchos.cs @@ -13,7 +13,7 @@ public static partial class TextToSpeech internal static Task> PlatformGetLocalesAsync() => Task.FromResult(AVSpeechSynthesisVoice.GetSpeechVoices() - .Select(v => new Locale(v.Language, null, v.Language, v.Identifier))); + .Select(v => new Locale(v.Language, null, v.Name, v.Identifier))); internal static async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationToken cancelToken = default) { diff --git a/Xamarin.Essentials/TextToSpeech/TextToSpeech.macos.cs b/Xamarin.Essentials/TextToSpeech/TextToSpeech.macos.cs index 626aecde0..f8977801d 100644 --- a/Xamarin.Essentials/TextToSpeech/TextToSpeech.macos.cs +++ b/Xamarin.Essentials/TextToSpeech/TextToSpeech.macos.cs @@ -14,7 +14,8 @@ public static partial class TextToSpeech internal static Task> PlatformGetLocalesAsync() => Task.FromResult(NSSpeechSynthesizer.AvailableVoices - .Select(v => new Locale(v, null, null, null))); + .Select(voice => NSSpeechSynthesizer.AttributesForVoice(voice)) + .Select(attribute => new Locale(attribute["VoiceLanguage"]?.ToString(), null, attribute["VoiceName"]?.ToString(), attribute["VoiceIdentifier"]?.ToString()))); internal static async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationToken cancelToken = default) { @@ -30,7 +31,7 @@ internal static async Task PlatformSpeakAsync(string text, SpeechOptions options ss.Volume = NormalizeVolume(options.Volume); if (options.Locale != null) - ss.Voice = options.Locale.Language; + ss.Voice = options.Locale.Id; } ssd.FinishedSpeaking += OnFinishedSpeaking;