A bug that spoke Russian and crashed my app
imzaldih.com
A bug that spoke Russian and crashed my app
1–10 of 22 posts
Re: A bug that spoke Russian and crashed my app
#2> I did more tests, and it seems that out of the over 100 languages Android supports, only Russian encoding broke SQLite. Not even Chinese, which we typically think of as the most complicated (and also I tested changing to this language much earlier before trying the other).
Is this an issue?
Re: A bug that spoke Russian and crashed my app
#3> If the device is in Russian, Locale.getDefault() returns “русский”, and it seems that SQLite doesn’t like this for some reason. > I did more tests, and it seems that out of the over 100 languages Android supports, only Russian encoding broke SQLite. Not even Chinese, which we typically think of as the most complicated (and also I tested changing to this language much earlier before trying the other). Is this an iss…
[0] https://stackoverflow.com/questions/46916210/cannot-get-writ...
[1] https://github.com/google/ExoPlayer/issues/8251
[2] https://docs.oracle.com/javase/8/docs/api/java/util/Locale.h...
Re: A bug that spoke Russian and crashed my app
#4> If the device is in Russian, Locale.getDefault() returns “русский”, and it seems that SQLite doesn’t like this for some reason. > I did more tests, and it seems that out of the over 100 languages Android supports, only Russian encoding broke SQLite. Not even Chinese, which we typically think of as the most complicated (and also I tested changing to this language much earlier before trying the other). Is this an iss…
According to some people on the Internet [0][1], it is. Apparently, Java's (Android's?) Locale.getLanguage() is broken for Russian locale and instead of returning "ru" as the docs promise [2], it returns "русский". [0] https://stackoverflow.com/questions/46916210/cannot-get-writ... [1] https://github.com/google/ExoPlayer/issues/8251 [2] https://docs.oracle.com/javase/8/docs/api/java/util/Locale.h...
public void updateAppLanguage(Context context) {
String languageCode = Locale.getDefault().getDisplayLanguage();
Locale locale = new Locale(languageCode);
Locale.setDefault(locale);
... which the JDK docs say:>Returns a name for the locale's language that is appropriate for display to the user.
So maybe `getLanguage` is broken or maybe it isn't, but it seems wrong to use `getDisplayLanguage` for this purpose regardless.
(What even is the point of doing `Locale.setDefault()` with the same Locale that `Locale.getDefault()` returned? I don't know anything about Android.)
Re: A bug that spoke Russian and crashed my app
#5The linked code is:
String languageCode = Locale.getDefault().getDisplayLanguage();
Locale locale = new Locale(languageCode);
Locale.setDefault(locale);
But `getDisplayLanguage()` is defined as returning the display name, not the language code:> if the locale is en_US and the default DISPLAY locale is fr_FR, getDisplayLanguage() will return "anglais"
https://developer.android.com/reference/java/util/Locale#get...()
----
This then proceeds to create a locale with a corrupt language code. The language parameter of `Locale` is not validated (besides a null check), and using a corrupt Locale in `Locale.setDefault()` will cause a number of bugs
Re: A bug that spoke Russian and crashed my app
#6Earlier quoted context omitted.
According to some people on the Internet [0][1], it is. Apparently, Java's (Android's?) Locale.getLanguage() is broken for Russian locale and instead of returning "ru" as the docs promise [2], it returns "русский". [0] https://stackoverflow.com/questions/46916210/cannot-get-writ... [1] https://github.com/google/ExoPlayer/issues/8251 [2] https://docs.oracle.com/javase/8/docs/api/java/util/Locale.h...
Except that TFA is using `getDisplayLanguage` public void updateAppLanguage(Context context) { String languageCode = Locale.getDefault().getDisplayLanguage(); Locale locale = new Locale(languageCode); Locale.setDefault(locale); ... which the JDK docs say: >Returns a name for the locale's language that is appropriate for display to the user. So maybe `getLanguage` is broken or maybe it isn't, but it seems wrong to use…
The code intends to trim the country, variant and any extensions from the value returned from `Locale.getDefault()`
Example: "Chinese (Traditional) - Taiwan" to "Chinese"
Pseudocode:
`zh_Hant_TW` -> `zh`
It also normalizes to fix some Android internal mapping issues due to changes in ISO 639 (Hebrew can be `iw` or `he[b]`)
Re: A bug that spoke Russian and crashed my app
#7Earlier quoted context omitted.
According to some people on the Internet [0][1], it is. Apparently, Java's (Android's?) Locale.getLanguage() is broken for Russian locale and instead of returning "ru" as the docs promise [2], it returns "русский". [0] https://stackoverflow.com/questions/46916210/cannot-get-writ... [1] https://github.com/google/ExoPlayer/issues/8251 [2] https://docs.oracle.com/javase/8/docs/api/java/util/Locale.h...
Except that TFA is using `getDisplayLanguage` public void updateAppLanguage(Context context) { String languageCode = Locale.getDefault().getDisplayLanguage(); Locale locale = new Locale(languageCode); Locale.setDefault(locale); ... which the JDK docs say: >Returns a name for the locale's language that is appropriate for display to the user. So maybe `getLanguage` is broken or maybe it isn't, but it seems wrong to use…
1. `getLanguage` should return the 2-letter ISO 3166-1 language code, or an empty string if missing. -- e.g. en, ru, fr, etc.
2. `getISO3Language` should return the 3-letter ISO 3166-1 language code, or an empty string if missing. -- e.g. eng, rus, fra, etc.
1. `getDisplayLanguage` should return the language display name in the current locale, or an empty string if missing. -- e.g. English, Russian, French, etc.
Re: A bug that spoke Russian and crashed my app
#8Earlier quoted context omitted.
Except that TFA is using `getDisplayLanguage` public void updateAppLanguage(Context context) { String languageCode = Locale.getDefault().getDisplayLanguage(); Locale locale = new Locale(languageCode); Locale.setDefault(locale); ... which the JDK docs say: >Returns a name for the locale's language that is appropriate for display to the user. So maybe `getLanguage` is broken or maybe it isn't, but it seems wrong to use…
For language: 1. `getLanguage` should return the 2-letter ISO 3166-1 language code, or an empty string if missing. -- e.g. en, ru, fr, etc. 2. `getISO3Language` should return the 3-letter ISO 3166-1 language code, or an empty string if missing. -- e.g. eng, rus, fra, etc. 1. `getDisplayLanguage` should return the language display name in the current locale, or an empty string if missing. -- e.g. English, Russian, Fre…
Btw you have a formatting error. The third numbered point is listed as another '1.'.
Re: A bug that spoke Russian and crashed my app
#9This isn't fixed properly The linked code is: String languageCode = Locale.getDefault().getDisplayLanguage(); Locale locale = new Locale(languageCode); Locale.setDefault(locale); But `getDisplayLanguage()` is defined as returning the display name, not the language code: > if the locale is en_US and the default DISPLAY locale is fr_FR, getDisplayLanguage() will return "anglais" https://developer.android.com/reference/…
The specific Locale() constructor used in the code is documented as taking a parameter: "An ISO 639 alpha-2 or alpha-3 language code, or a language subtag up to 8 characters in length. See the Locale class description about valid language values."
I'd guess the app code lucked out on the string returned from getDisplayLanguage() getting mapped to the appropriate language in all the other cases that the app supports.
Now if getLanguage() had been renamed to getLanguageCode() then maybe a dev might have had the light bulb turn on, but random string returned from an API passed to another API passes the compile test and the app doesn't blow up, so we're good to go...
Searching for the offending incorrect code on the web doesn't return any matching "sample" code, so I'm not sure where the app got the bug from.
Re: A bug that spoke Russian and crashed my app
#10This isn't fixed properly The linked code is: String languageCode = Locale.getDefault().getDisplayLanguage(); Locale locale = new Locale(languageCode); Locale.setDefault(locale); But `getDisplayLanguage()` is defined as returning the display name, not the language code: > if the locale is en_US and the default DISPLAY locale is fr_FR, getDisplayLanguage() will return "anglais" https://developer.android.com/reference/…
I agree. Locale.getLanguage() returns the language code. The specific Locale() constructor used in the code is documented as taking a parameter: "An ISO 639 alpha-2 or alpha-3 language code, or a language subtag up to 8 characters in length. See the Locale class description about valid language values." I'd guess the app code lucked out on the string returned from getDisplayLanguage() getting mapped to the appropriat…