Использование языковых настроек для определения того, как использовать имперские единицы
Я работаю над приложением, которое хочет отображать длины либо в сантиметрах (см), либо в дюймах ("). Есть ли способ выбрать правильное устройство из локали? В любом случае я тоже собираюсь поставьте опцию, чтобы пользователь мог переопределить настройку локали.
США, Либерия и Бирма должны использовать имперские юниты и остальную часть мира. Один из способов - включить эту логику в свои классы, но я бы предпочел использовать любую встроенную логику, если она доступна. Любые указатели?
Ответы
Ответ 1
В конце концов я выбрал следующее решение.
public class UnitLocale {
public static UnitLocale Imperial = new UnitLocale();
public static UnitLocale Metric = new UnitLocale();
public static UnitLocale getDefault() {
return getFrom(Locale.getDefault());
}
public static UnitLocale getFrom(Locale locale) {
String countryCode = locale.getCountry();
if ("US".equals(countryCode)) return Imperial; // USA
if ("LR".equals(countryCode)) return Imperial; // Liberia
if ("MM".equals(countryCode)) return Imperial; // Myanmar
return Metric;
}
}
Например, используйте это так.
if (UnitLocale.getDefault() == UnitLocale.Imperial) convertToimperial();
Если также необходимы методы преобразования, их предпочтительно можно добавить в подклассы UnitLocale. Мне нужно было только обнаружить, использовать ли имперские юниты и отправить их на сервер.
Использование int
поверх java-объектов приводит к чрезвычайно низкому приросту производительности и усложняет чтение кода. Сравнение двух ссылок в Java сопоставимо по скорости со сравнением двух ints
. Кроме того, используя объекты позволяют добавлять методы к UnitLocale
класса или подкласса, таких как, convertToMetric и т.д.
Вы также можете использовать перечисление, если вы предпочитаете это.
Ответ 2
Небольшое улучшение в решении от @vidstige
Я бы использовал getCountry(). toUpperCase(), чтобы быть безопасным и изменить проверки на коммутатор для более чистого кода. Что-то вроде этого:
public static UnitLocale getFrom(Locale locale) {
String countryCode = locale.getCountry().toUpperCase();
switch (countryCode) {
case "US":
case "LR":
case "MM":
return Imperial;
default:
return Metric;
}
}
- Из ресурсов
Другим решением может быть создание папок ресурсов для каждой страны, например: [values_US] [values_LR] [values_MM] с логическим ресурсом, измененным на true. Затем прочитайте этот логический ресурс из кода.
Ответ 3
Просто дайте пользователю возможность выбрать предпочтительный блок в меню настроек. Если это путешествующий пользователь, вы не хотите, чтобы приложение было географически известно, IMO.
Ответ 4
Основываясь на других хороших решениях здесь, вы также можете реализовать это как функцию расширения Kotlin для объекта Locale:
fun Locale.isMetric(): Boolean {
return when (country.toUpperCase()) {
"US", "LR", "MM" -> false
else -> true
}
}
Таким образом, все, что вам нужно сделать, это позвонить:
val metric = Locale.getDefault().isMetric()
Ответ 5
Более или менее полный способ сделать это заключается в следующем.
Котлин:
private fun Locale.toUnitSystem() =
when (country.toUpperCase()) {
// https://en.wikipedia.org/wiki/United_States_customary_units
// https://en.wikipedia.org/wiki/Imperial_units
"US" -> UnitSystem.IMPERIAL_US
// UK, Myanmar, Liberia,
"GB", "MM", "LR" -> UnitSystem.IMPERIAL
else -> UnitSystem.METRIC
}
Обратите внимание, что существует разница между британскими и американскими имперскими системами, подробности см. В вики-статьях.