Created
February 22, 2022 09:36
-
-
Save Doc1faux/410a80db6fc17d45b4e109b4849424c9 to your computer and use it in GitHub Desktop.
A one-shot function to get a default country for a locale. I was needed this method in order to display a country flag from a language code only (ISO 639-2 & 639-3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.annotation.NonNull; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
public final class LocaleUtils | |
{ | |
private static Map<String, String> sCountryForLocale; | |
/** | |
* @return a Map listing for each locale (ISO 639-2 & 639-3) | |
* the corresponding default country (ISO 3166-1) | |
*/ | |
@NonNull | |
public static final Map<String, String> countryForLocale() | |
{ | |
if (sCountryForLocale == null) | |
{ | |
sCountryForLocale = new HashMap<String, String>() {{ | |
// Add country for locale which could not be determined by logic | |
// i.e. more than 1 possible country and country code != locale code. | |
// Based on ISO 639-2 & 639-3 wikipedia articles: | |
// https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes | |
// https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Languages/List_of_ISO_639-3_language_codes_(2019) | |
// Selection has been done in this order: | |
// - Official language in only 1 country | |
// - Official language in more than 1 country but spoken widely only in 1 (e.g. Bengali) | |
// - Official language in more than 1 country ordered by speakers (e.g. Hausa) | |
// - Recognised regional/minority language in only 1 country | |
// - Recognised regional/minority language in more than 1 country ordered by speakers (e.g. Low German) | |
// - Native country ordered by population (e.g. Alemannic) | |
// - Flag likeness (e.g. Arabic spoken by countries of the Arab League) | |
put("af", "za"); put("ar", "sa"); put("bn", "bd"); put("bo", "cn"); put("ca", "ad"); | |
put("ccp", "bd"); put("ckb", "iq"); put("da", "dk"); put("ee", "gh"); put("el", "gr"); | |
put("en", "gb"); put("fa", "ir"); put("ff", "cm"); put("gsw", "ch"); put("ha", "ng"); | |
put("ko", "kr"); put("ln", "cd"); put("lrc", "ir"); put("mas", "ke"); put("ms", "my"); | |
put("nb", "no"); put("nds", "de"); put("ne", "np"); put("nmg", "cm"); put("om", "et"); | |
put("os", "ru"); put("pa", "in"); put("qu", "bo"); put("se", "no"); put("sq", "al"); | |
put("sr", "rs"); put("sv", "se"); put("sw", "tz"); put("ta", "lk"); put("teo", "ug"); | |
put("ti", "er"); put("ur", "pk"); put("ji", "ru"); put("yo", "ng"); put("yue", "hk"); | |
put("zh", "cn"); | |
}}; | |
// For others, do it by logic ;) | |
Locale[] availableLocales = Locale.getAvailableLocales(); | |
String previousLanguage = availableLocales[0].getLanguage(); | |
List<String> previousCountries = new ArrayList<>(); | |
// Firstly, we create a clean map of countries by locale | |
HashMap<String, List<String>> countriesForLocales = new HashMap<>(availableLocales.length); | |
for (Locale locale : availableLocales) | |
{ | |
String language = locale.getLanguage(); | |
// We ignore already added locales | |
if (sCountryForLocale.containsKey(language)) | |
{ | |
continue; | |
} | |
String country = locale.getCountry(); | |
if (! language.equals(previousLanguage)) | |
{ | |
// This happens for Esperanto | |
if (! previousCountries.isEmpty()) | |
{ | |
countriesForLocales.put(previousLanguage, previousCountries); | |
} | |
previousLanguage = language; | |
previousCountries = country.isEmpty() ? new ArrayList<>() | |
: new ArrayList<>(Collections.singleton(country)); | |
} | |
// This happens for base locale (without specified country) | |
// or locale with several alphabets (e.g. Serbian) | |
else if (! country.isEmpty() && ! previousCountries.contains(country)) | |
{ | |
previousCountries.add(country); | |
} | |
} | |
if (! sCountryForLocale.containsKey(previousLanguage) | |
&& ! countriesForLocales.containsKey(previousLanguage) | |
&& ! previousCountries.isEmpty()) | |
{ | |
countriesForLocales.put(previousLanguage, previousCountries); | |
} | |
// Now we populate our prefilled map with our locale-country tuples | |
for (Map.Entry<String, List<String>> countriesForLocale : countriesForLocales.entrySet()) | |
{ | |
String locale = countriesForLocale.getKey(); | |
List<String> countries = countriesForLocale.getValue(); | |
// If only one, we take it | |
if (countries.size() == 1) | |
{ | |
sCountryForLocale.put(locale, countries.get(0).toLowerCase()); | |
} | |
// Else we search for country code == locale code | |
else | |
{ | |
int index = countries.indexOf(locale.toUpperCase()); | |
if (index > -1) | |
{ | |
sCountryForLocale.put(locale, countries.get(index).toLowerCase()); | |
} | |
} | |
} | |
} | |
return sCountryForLocale; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment