Picking the Right Voice for Windows Phone

Recently, I had an interesting problem come up when testing localization (in French and Spanish in my case) in conjunction with letting the user choose a female or male voice in one of my Windows Phone apps (http://www.windowsphone.com/en-us/store/app/fn8/dd72d13d-1a7b-42c4-81d3-adbc98d4b002). The main part of the problem is basically financial, i.e. given the economics of app development it isn’t feasible to localize for many languages, let alone variants (cultures), e.g. whatever dialect of French is spoken in lower, mid-western Upper Volta. Additionally, given the inefficient workings of the Windows Phone store, it takes forever to submit (or even update) an app for each supported language. In my case, I have asked my translators to use a international a flavor as possible to cover as many markets as I can. Localizing into a language will still allow you to reach all the cultures that support the base language, e.g. localizing into Spanish will work for users in Spain (es-es) as well as Mexico (es-mx).

Part of the problem is technical. If you go this route, then when the user selects a gender for an installed voice, the app has to be able to match the appropriate voices from among those installed. With my first approach what I found when testing was that no voices were being selected at all in a device set to Mexican Spanish. The reason became immediately apparent when debugging:

The app was working fine in English because I was looking for a culture name and because en-us was the default culture for the app, it was finding that. But since the Spanish-speaking user is only getting a generic Spanish translation, the app was looking for a culture name of es-mx and blithely skipping over plain ol’ es.

So then I switched to grabbing the two-letter ISO language name instead. That made the app feliz in Español, but now on my device set to American English I was getting a male voice with a British accent when the radio button was set to female.

Another quick debug session and I could see that American voices Mike and Zira had some friends in the house I didn’t know about, including George and Susan from Great Britain and their friends Raul from Mexico and Stefan from Germany. All obviously there to enjoy Cortana’s predictions on the World Cup.

So here’s what can only be described as an amateurish hack to deal with this issue. Well, as my co-workers and I used to tell our boss in a previous job, all our code is “QDC – quick, dirty, or cheap. Pick any two.”

var twoLetterIsoLanguageName = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

var currentCultureName = CultureInfo.CurrentCulture.Name;

IEnumerable<VoiceInformation> voiceInfos = from voice in InstalledVoices.All select voice;

var localVoices = new List<VoiceInformation>();

// See if any voices match the current culture specifically
foreach (var voiceInfo in voiceInfos)
{
 if (voiceInfo.Language == currentCultureName)
 {
 localVoices.Add(voiceInfo);
 }

 localVoices =
 localVoices.OrderByDescending(v => v.Language).ThenByDescending(v => v.Gender).ToList();
}

// No matches? Go for the generic language instead
if (localVoices.Count < 1)
{
 foreach (var voiceInfo in voiceInfos)
 {
 var primaryLangStr = voiceInfo.Language.Split('-')[0];

 if (primaryLangStr == twoLetterIsoLanguageName)
 {
 localVoices.Add(voiceInfo);
 }

 localVoices =
 localVoices.OrderByDescending(v => v.Language).ThenByDescending(v => v.Gender).ToList();
 }
}

App.StorageSettings.TryGetValue("VoiceGender", out _voiceGender);

_speechSynthesizer.SetVoice(localVoices.ElementAt(_voiceGender));