Using locale settings to detect wheter to use imperial units

六眼飞鱼酱① 提交于 2019-12-03 03:39:37

问题


I'm working on an app that wants to display lengths either in centimeters (cm) or in inches("). Is there a way to select the right unit from the locale? In any event I'm also going to put in an option so that the user can to override the locale setting.

USA, Liberia, and Burma should use imperial units and the rest of the world normal units. One way is to put in this logic in my own classes, but I would prefer using any built in logic if available. Any pointers?


回答1:


In the end I went for the following solution.

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;
    }
}

Use it like this for example.

if (UnitLocale.getDefault() == UnitLocale.Imperial) convertToimperial();

If convert methods are also need they can preferably be added to subclasses of UnitLocale. I only needed to detect wheter to use imperial units and send it to the server.

Using ints over java objects have extremely slim performance gains and makes the code harder to read. Comparing two references in java is comparable in speed to comparing two ints. Also using objects allow us to add methods to the UnitLocale class or subclasses such as, convertToMetric, etc.

You could also use an enum instead if you prefer that.




回答2:


A more or less complete way to do this is this way.

Kotlin:

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
    }

Note that there is a difference between UK and US imperial systems, see the wiki articles for more details.




回答3:


  1. Programmatically

Making a small improvement in the solution from @vidstige

I would use getCountry().toUpperCase() to be safe and change the checks to a switch for a cleaner code. Something like this:

public static UnitLocale getFrom(Locale locale) {
    String countryCode = locale.getCountry().toUpperCase();
    switch (countryCode) {
        case "US":
        case "LR":
        case "MM":
            return Imperial;
        default:
            return Metric;
    }
}
  1. From Resources

Another solution could be creating resources folders for each country like: [values_US] [values_LR] [values_MM] with a boolean resource changed to true. Then read that boolean resource from the code.




回答4:


Just give the user the option to choose a preferred unit in a settings menu. If it is a traveling user you don't want the app to be geographically aware, IMO.




回答5:


Building on the other nice solutions here, you can also implement this as a Kotlin extension function to the Locale object:

fun Locale.isMetric(): Boolean {
    return when (country.toUpperCase()) {
        "US", "LR", "MM" -> false
        else -> true
    }
}

This way, all you need to do is call:

val metric = Locale.getDefault().isMetric()


来源:https://stackoverflow.com/questions/4898237/using-locale-settings-to-detect-wheter-to-use-imperial-units

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!