ak1394 / react-native-tts

React Native Text-To-Speech library for Android and iOS
618 stars 156 forks source link

[Bug] Android language returns weird. #111

Open guhyeon opened 5 years ago

guhyeon commented 5 years ago

In Some Devices, voice.language returns wrong language for example 'en-x-Ivariant-001'.

device: galaxy note4 android version: 6.0.1 (Marshmallow)

guhyeon commented 5 years ago

to get iso2 format locale. (ex. en-US, en-GB, ko-KR...) 2 digit language- 2 digit countryCode

show this source.

TextToSpeechModule.java should be added bellow

`

   public TextToSpeechModule(ReactApplicationContext reactContext) {
        super(reactContext);

        //initialize ISO3, ISO2 languague country code mapping.
       //++++++++++++++++++++++++++
        initCountryLanguageCodeMapping();
        ...
    }

    //++++++++++++++++++++++++++ start
    private Map<String, Locale> localeCountryMap;
    private Map<String, Locale> localeLanguageMap;
    private void initCountryLanguageCodeMapping() {
        String[] countries = Locale.getISOCountries();
        localeCountryMap = new HashMap<String, Locale>(countries.length);
        for (String country : countries) {
            Locale locale = new Locale("", country);
            localeCountryMap.put(locale.getISO3Country().toUpperCase(), locale);
        }
        String[] languages = Locale.getISOLanguages();
        localeLanguageMap = new HashMap<String, Locale>(languages.length);
        for (String language : languages) {
            Locale locale = new Locale(language);
            localeLanguageMap.put(locale.getISO3Language(), locale);
        }
    }

    private String iso3CountryCodeToIso2CountryCode(String iso3CountryCode) {
        return localeCountryMap.get(iso3CountryCode).getCountry();
    }

    private String iso3LanguageCodeToIso2LanguageCode(String iso3LanguageCode) {
        return localeLanguageMap.get(iso3LanguageCode).getLanguage();
    }
    //++++++++++++++++++++++++++ end

    @ReactMethod
    public void voices(Promise promise) {
        if(notReady(promise)) return;

        WritableArray voiceArray = Arguments.createArray();

        if (Build.VERSION.SDK_INT >= 21) {
            try {
                for(Voice voice: tts.getVoices()) {
                    WritableMap voiceMap = Arguments.createMap();
                    voiceMap.putString("id", voice.getName());
                    voiceMap.putString("name", voice.getName());

                    //++++++++++++++++++++++++++ 
                    String language = voice.getLocale().getISO3Language();
                    String country = voice.getLocale().getISO3Country();
                    String language_Country = iso3LanguageCodeToIso2LanguageCode(language);
                    if(country!="")
                    {
                        language_Country+="-"+iso3CountryCodeToIso2CountryCode(country);
                    }
                    //++++++++++++++++++++++++++ 
                    //voiceMap.putString("language", voice.getLocale().toLanguageTag());
                    voiceMap.putString("language", language_Country);
                    voiceMap.putInt("quality", voice.getQuality());
                    voiceMap.putInt("latency", voice.getLatency());
                    voiceMap.putBoolean("networkConnectionRequired", voice.isNetworkConnectionRequired());
                    voiceMap.putBoolean("notInstalled", voice.getFeatures().contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED));
                    voiceArray.pushMap(voiceMap);
                }
            } catch (Exception e) {
              // Purposefully ignore exceptions here due to some buggy TTS engines.
              // See http://stackoverflow.com/questions/26730082/illegalargumentexception-invalid-int-os-with-samsung-tts
            }
        }

        promise.resolve(voiceArray);
    }
its4net commented 5 years ago

@guhyeon Please submit pull request with your solution.