| The Java `Locale` API is broken in a few ways that should be avoided, with some |
| examples of error prone issues below: |
| |
| #### Constructors |
| |
| The constructors don't validate the parameters at all, they just "trust" it |
| 100%. |
| |
| For example: |
| |
| ``` |
| Locale locale = new Locale("en_AU"); |
| toString() : "en_au" |
| getLanguage() : "en_au" |
| locale.getCountry : "" |
| |
| locale = new Locale("somethingBad#!34, too long, and clearly not a locale ID"); |
| toString() : "somethingbad#!34, too long, and clearly not a locale id" |
| getLanguage() : "somethingbad#!34, too long, and clearly not a locale id" |
| getCountry() : "" |
| ``` |
| |
| As you can see, the full string is interpreted as language, and the country is |
| empty. |
| |
| For `new Locale("zh", "tw", "#Hant")` you get: |
| |
| ``` |
| toString() : zh_TW_#Hant |
| getLanguage() : zh |
| getCountry() : TW |
| getScript() : |
| getVariant() : #Hant |
| ``` |
| |
| And for `Locale.forLanguageTag("zh-hant-tw")` you get a different result: |
| |
| ``` |
| toString() : zh_TW_#Hant |
| getLanguage() : zh |
| getCountry() : TW |
| getScript() : Hant |
| getVariant() : |
| ``` |
| |
| We can see that while the `toString()` value for both locales are equivalent, |
| the individual parts are different. More specifically, the first locale is |
| incorrect since `#Hant` is supposed to be the script for the locale rather than |
| the variant. \ |
| There's no reliable way of getting a correct result through a `Locale` |
| constructor, so we should prefer using `Locale.forLanguageTag()` (and the IETF |
| BCP 47 format) for correctness. |
| |
| **Note:** You might see a `.replace("_", "-")` appended to a suggested fix for |
| the error prone checker for this bug pattern. This is sanitization measure to |
| handle the fact that `Locale.forLanguageTag()` accepts the "minus form" of a tag |
| (`en-US`) but not the "underscore form" (`en_US`). It will silently default to |
| `Locale.ROOT` if the latter form is passed in. |
| |
| #### toString() |
| |
| This poses the inverse of the constructor problem |
| |
| ``` |
| Locale myLocale = Locale.forLanguageTag("zh-hant-tw") |
| String myLocaleStr = myLocale.toString() // zh_TW_#Hant |
| Locale derivedLocale = ??? // Not clean way to get a correct locale from this string |
| ``` |
| |
| The `toString()` implementation for `Locale` isn't necessarily incorrect in |
| itself. \ |
| It is intended to be _"concise but informative representation that is easy for a |
| person to read"_ (see documentation at |
| [Object.toString()](https://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#toString\(\))). |
| |
| So it is not intended to produce a value that can be turned back into a |
| `Locale`. It is not a serialization format. \ |
| It often produces a value that _looks_ like a locale identifier, but it is not. |