Text to speech returns a different non-existant Lo

2019-02-27 11:18发布

问题:

original question

I have a standard texttospeech, android.speech.tts.TextToSpeech

I initialize it and set a language by using tts.setLanguage(Locale.getDefault())

That default Locale is de_DE (for germany, correct). Right after setting it, i ask the tts to give me its language tts.getLanguage()

now it tells me that its set to "deu_DEU"

There is no Locale with that setting. So i cant even check if its set to the right language because i cant find the Locale object that has the matching values.

Issue might be related to Android 4.3, but i didnt find any info.

Background is, that i need to show values with the same decimal symbol, but tts needs the correct symbol or it says "dot" in german which makes NO sense at all.

Conclusion:

A Locale is a container that contains a string that is composed of a language, a country and an optional string. Every text-to-speech engine can return a custom Locale like "eng_USA_texas".

Furthermore the Locale that is returned by the tts engine can only be a "close match" to the wanted Locale. So "en_US" instead of "en_UK".

However, Locale has a method called getLanguage() and it returns the first part of above mentioned string. "en" or "eng". Those Language codes are regulated by ISO and one can hope that everyone sticks to it. (see link in the accepted answer)

So checking for tts.getLanguage().getLanguage().startsWith("en") should always be true if its some form of english language setting and the ISO standards are fulfilled.

It is important to mention that Locales should not be compared by locale_a == locale_b as both can be different objects yet have the same content, they are containers of sort.
Always compare with locale_a.equals(locale_b)

I hope this helps people sort out some problems with tts and language

回答1:

You're right, it's frustrating how the locale codes the TTS object uses are different to those of the device locale. I don't understand why this decision was made.

To add further complication, the TTS Engine can supply all kinds of different locales, such as eng_US_sarah or en-US-female etc. It's down to the TTS Engine how these are stored and displayed.

I've had to write additional code to iterate through the returned locales and attempt to match them to the locale the system can use, or vica-versa.

To start with, take a look at how the engines you have installed are returning their locale information. You can then start to collate in your code a list to associate 'deu_DEU' to 'de_De'.

This is often simplistic by using split("_") & startsWith(String), but unfortunately not for all locales.

Here's some base code I've used to analyse the installed TTS Engines' locale structure.

private void getEngines() {

    final Intent ttsIntent = new Intent();
    ttsIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);

    final PackageManager pm = getActivity().getPackageManager();

    final List<ResolveInfo> list = pm.queryIntentActivities(ttsIntent, PackageManager.GET_META_DATA);

    final ArrayList<Intent> intentArray = new ArrayList<Intent>(list.size());

    for (int i = 0; i < list.size(); i++) {

        final Intent getIntent = new Intent();
        getIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);

        getIntent.setPackage(list.get(i).activityInfo.applicationInfo.packageName);
        getIntent.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);

        intentArray.add(getIntent);

    }

    for (int i = 0; i < intentArray.size(); i++) {
        startActivityForResult(intentArray.get(i), i);
    }
}

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {

    try {

        if (data != null) {             
            System.out.print(data.getStringArrayListExtra("availableVoices").toString());
        }

    } catch (NullPointerException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

From the above ISO-3 codes and the device locale format, you should be able to come up with something for the locales you are concerned with.

I've been intending to submit an enhancement request to AOSP for a while, as all TTS Engines need to use constant values and extras such as gender etc need to be added to use the TTS Engines to their full capabilities.

EDIT: Further to your edit, note the wording regarding setLanguage(). The individual TTS Engine will try and match as close as possible to the requested locale, but that applied locale may be completely wrong, depending on how lenient the Engine provider is in their code and their response.