我一直在尝试让Java根据语言环境转换数字。
遇到了this post,这对自从理解之前起了很大的帮助,我已经设计了自己的方法将数字转换为特定的语言环境(关于该主题的其他混乱讨论)

所以假设我有:

Locale arabicLocale = new Locale.Builder().setLanguage("ar").setRegion("SA")
 .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-arab").build();

Locale thaiLocale = new Locale.Builder().setLanguage("th").setRegion("TH")
 .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-thai").build();

Locale hinduLocale = new Locale.Builder().setLanguage("hi").setRegion("IN")
 .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-hindu").build();

DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(arabicLocale);
NumberFormat numberFormat = NumberFormat.getNumberInstance(arabicLocale);
println" Arabic ${numberFormat.format(123.22)}"

dfs = DecimalFormatSymbols.getInstance(thaiLocale);
numberFormat = NumberFormat.getNumberInstance(thaiLocale);
println" Thai ${numberFormat.format(123.22)}"

dfs = DecimalFormatSymbols.getInstance(hinduLocale);
numberFormat = NumberFormat.getNumberInstance(hinduLocale);
println" Hindu ${numberFormat.format(123.22)}"

这将产生以下输出
 Arabic ١٢٣٫٢٢
 Thai ๑๒๓.๒๒
 Hindu १२३.२२

这篇文章的目的是试图确定我如何查找或获取代码本身以指向正确的Locale.UNICODE_LOCALE_EXTENSION,因为这些和印度教徒的东西只是从我的角度进行猜测,而我在理解我该怎么做时遇到了麻烦希伯来中文日语也一样。尽管我认为中文和日文可能使用阿拉伯数字系统,但在这一点上可能是错误的。

无论如何,关于如何自动捕获这部分数据或标准的任何帮助/指针,如页面中具有我可以枚举的所有定义的页面,将大有帮助

我正在更深入地研究LocaleExtensions
static {
        CALENDAR_JAPANESE = new LocaleExtensions("u-ca-japanese", Character.valueOf('u'), UnicodeLocaleExtension.CA_JAPANESE);
        NUMBER_THAI = new LocaleExtensions("u-nu-thai", Character.valueOf('u'), UnicodeLocaleExtension.NU_THAI);
    }

所以现在这更有意义nu-language =数字ca-language =日历

但是在运行时:
Locale japLocale = new Locale.Builder().setLanguage("ja").setRegion("JP")
                    .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-japanese").build();

我得到英文数字。

根据原始问题,链接
https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry

希伯来语
Type: language
Subtag: he
Description: Hebrew
Added: 2005-10-16
Suppress-Script: Hebr

但是在尝试以下操作时:
Locale hebrewLocale = new Locale.Builder().setLanguage("he").setRegion("IL")
                    .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-hebr").build();

我得到123.22
要回答我自己的问题,您可以从这里建立一个枚举http://www.oracle.com/technetwork/java/javase/java8locales-2095355.html
Greek (el) Greece (GR) (Grek)  el-GR
Hebrew (iw) Israel (IL) (Hebr) iw-IL

简而言之

对于希腊,请取最后一个字段el-GR unicodeEXtension = -u number = -nu,然后从小写的-hebr中倒数第二个字段给您希腊的'el-GR-u-nu-grek'或希伯来语'iw-IL-u-n-hebr'
 Locale locale = new Locale.Builder().setLanguageTag('el-GR-u-nu-grek').build();

应该打印出希腊数字,但我看到它在某些国家/地区适用,但不适用于其他国家/地区。

最佳答案

要回答我自己的问题,因为这是一个相当复杂的主题,目前还没有很好地解释。

简而言之,根据我的评论,使用icu4j可能更好。由于这为国际号码/日期转换提供了更完整的解决方案。

困难在于制定所需的所有标准,因为它似乎确实正确支持所有语言环境等,这只是知道如何正确使用它的一种情况。

我将提供一个片段-此代码需要清理,但为您的Java应用程序提供了数字和日期转换的解决方案:

import groovy.transform.CompileStatic

/**
 *
 * @author Vahid Hedayati
 * Looks complex but will explain
 *
 * ar-SA u = unicode nu = number arab = arabic
 *
 * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
 * to get langauge code such as arab = subtag
 *
 * Rest explained here
 * http://stackoverflow.com/questions/43456068/java-locale-builder-setextensionlocale-unicode-locale-extension
 *
 *
 */
@CompileStatic
enum LocaleCalendarExtensions {
    SA('ar-SA-u-ca-arab'),
    AM('hy-AM-u-ca-arevmda'),
    CN('zh-TW-u-ca-hant'),
    CZ('cs-CZ-u-ca-latn'),
    DK('da-DK-u-ca-latn'),
    NL('nl-NL-u-ca-latn'),
    IE('ie-IE-u-ca-latn'),
    FR('fr-FR-u-ca-latn'),
    DE('de-DE-u-ca-latn'),
    GR('el-GR-u-ca-grek'),
    IL('iw-IL-u-ca-hebr'),
    IN('hi-IN-u-ca-hindu'),
    IT('it-IT-u-ca-latn'),
    JP('ja-JP-u-ca-jpan'),
    NO('nb-NO-u-ca-latn'),
    IR(''), //fa-IR-u-ca-fars'),
    PL('pl-PL-u-ca-latn'),
    PT('pt-PT-u-ca-latn'),
    RU('ru-RU-u-ca-cyrl'),
    ES('es-ES-u-ca-latn'),
    SE('sv-SE-u-ca-latn'),
    TH('th-TH-u-ca-thai'),
    TR('tr-TR-u-ca-latn'),
    PK(''),//ur-PK-u-ca-arab'),
    VN('vi-VN-u-ca-latn')

    String value

    LocaleCalendarExtensions(String val) {
        this.value = val
    }
    public String getValue(){
        return value
    }
    static LocaleCalendarExtensions byValue(String val) {
        values().find { it.value == val }
    }
    public static EnumSet<LocaleCalendarExtensions> getArabicSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(SA)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getJapanSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(JP)
        return ret_val
    }

    public static EnumSet<LocaleCalendarExtensions> getChinaSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(CN)
        return ret_val
    }

    public static EnumSet<LocaleCalendarExtensions> getFarsiSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )

        ret_val.add(IR)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getUrduSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(PK)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getAsianSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(JP)
        ret_val.add(CN)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getHebrewSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(IL)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getHinduSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(IN)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getThaiSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(TH)
        return ret_val
    }
    public static EnumSet<LocaleCalendarExtensions> getGreekSupport() {
        final EnumSet< LocaleCalendarExtensions > ret_val = EnumSet.noneOf( LocaleCalendarExtensions.class )
        ret_val.add(GR)
        return ret_val
    }
}

现在,如何将日期正确转换为国际语言环境:
 /**
     *
     * @param lang where lang code provider is ar en cn fr ur it is as per LocaleCalendarExtensions Enum main declarations
     * @param date given date
     * @param format definition in which case I have clause to deal with HH:mm and so on just read through below code
     * @return
     */
    public static String convertDate(String lang, java.util.Date date, String format) {
        StringBuilder output=new StringBuilder()
        if (lang != null && date) {
            def found = LocaleICUCalendarExtensions?.find{it.toString()==lang}
            if (found) {
                def found1 = LocaleExtensions?.valueOf(lang)
                com.ibm.icu.util.ULocale locale =  new com.ibm.icu.util.ULocale(found1.value)
                com.ibm.icu.util.Calendar calendar = com.ibm.icu.util.Calendar.getInstance(locale)
                calendar.setTime(date)
                com.ibm.icu.text.DateFormat df
                if (format == 'HH:mm') {
                    df = com.ibm.icu.text.DateFormat.getPatternInstance( com.ibm.icu.text.DateFormat.HOUR_MINUTE, locale)
                } else {
                    if (format=='dd MMM yyyy HH:mm:ss') {
                        df = com.ibm.icu.text.DateFormat.getDateInstance(DateFormat.FULL, locale)
                    } else if (format=='dd MMM') {
                        df = com.ibm.icu.text.DateFormat.getPatternInstance( com.ibm.icu.text.DateFormat.ABBR_MONTH_DAY, locale)
                    } else {
                        df = com.ibm.icu.text.DateFormat.getDateInstance(DateFormat.LONG, locale)
                    }
                    output << df.format(calendar)
                }

            }
        }
        return output.toString()
    }

要将号码转换为另一个国家/地区编号系统,请执行以下操作:
/**
     * Converts number to given locale
     * @param lang
     * @param number
     * @return
     */
    public static String convertNumber(String lang, number) {
        String output=''
        if (lang != null) {
            boolean arabic = (LocaleCalendarExtensions.arabicSupport.find { it.toString() == lang } ? true : false)
            boolean china = (LocaleCalendarExtensions.chinaSupport.find { it.toString() == lang } ? true : false)
            boolean japan = (LocaleCalendarExtensions.japanSupport.find { it.toString() == lang } ? true : false)
            boolean farsi = (LocaleCalendarExtensions.farsiSupport.find { it.toString() == lang } ? true : false)
            boolean urdu = (LocaleCalendarExtensions.urduSupport.find { it.toString() == lang } ? true : false)
            boolean hebrew = (LocaleCalendarExtensions.hebrewSupport.find { it.toString() == lang } ? true : false)
            boolean greek = (LocaleCalendarExtensions.greekSupport.find { it.toString() == lang } ? true : false)
            boolean hindu = (LocaleCalendarExtensions.hinduSupport.find { it.toString() == lang } ? true : false)
            boolean thai = (LocaleCalendarExtensions.thaiSupport.find { it.toString() == lang } ? true : false)
            if (arabic || hindu | thai || farsi||urdu) {
                def found = LocaleExtensions?.valueOf(lang)
                if (found) {
                    Locale locale = new Locale.Builder().setLanguageTag(found.value).build();
                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
                    NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
                    def numbers
                    if (number.toString().indexOf('.')>-1) {
                        numbers=number as Double
                    } else {
                        numbers=number as Long
                    }
                    output = (numberFormat?.format(numbers)) ?:''
                }
            }
            if (japan|china||hebrew||greek) {
                // to extend look up types here
                //http://www.atetric.com/atetric/javadoc/com.ibm.icu/icu4j/49.1/src-html/com/ibm/icu/util/ULocale.html
                //http://icu-project.org/~yoshito/jacoco_57.1/com.ibm.icu.util/ULocale.java.html
                com.ibm.icu.util.ULocale locale

                if (japan) {
                    locale= new com.ibm.icu.util.ULocale("ja_JP_JP")//ja_JP_JP  //
                }
                if (china) {
                    locale= new com.ibm.icu.util.ULocale("zh_Hans")//zh_CN_TRADITIONAL@collation=pinyin;
                }
                if (hebrew) {
                    locale= new com.ibm.icu.util.ULocale("he_IL")

                }
                if (greek) {
                    locale= new com.ibm.icu.util.ULocale("el_GR")
                }
                com.ibm.icu.text.NumberFormat nf = com.ibm.icu.text.NumberFormat.getInstance(locale)
                def numbers
                if (number.toString().indexOf('.')>-1) {
                    numbers=number as Double
                } else {
                    numbers=number as Long
                }
                output = nf.format(numbers)
            }
        }
        return output ?: number.toString()
    }

现在,如果您使用的是grails,则可以创建一个taglib并重写formatDate和formatNumber定义以使用上述代码:
 /**
     * override default date formatter if translation translate
     */

    def formatDate={attrs->
        String foundRecord
        if (attrs.locale) {
            String lang = attrs.locale.country
            foundRecord = NumberHelper.convertDate(lang, attrs.date, attrs.format)
        }
        if (!foundRecord || foundRecord=='null') {
            out << g.formatDate(attrs)
        } else {
            out << foundRecord
        }
    }


/**
 * Override default formatNumber and translate number if possible otherwsie run default
 */
def formatNumber={attrs->
    def foundRecord
    if (attrs.locale && attrs.number) {
        String lang = attrs.locale.country
        foundRecord = NumberHelper.convertNumber(lang, attrs.number)
    }
    if (!foundRecord) {
        out << g.formatNumber(attrs)
    } else {
        out << "${foundRecord}"
    }
}

上面的ICU4J枚举:
import groovy.transform.CompileStatic


@CompileStatic
enum LocaleICUCalendarExtensions {
    SA('ar_SA@calendar=islamic'),
AM('hy_AM@calendar=armenian'),
CN('zh_Hans@calendar=chinese'),
CZ('cs_CZ@calendar=latin'),
DK('da_DK@calendar=latin'),
NL('nl_NL@calendar=latin'),
IE('ie_IE@calendar=latin'),
FR('fr_FR@calendar=latin'),
DE('de_DE@calendar=latin'),
GR('el_GR@calendar=greek'),
IL('iw_IL@calendar=hebrew'),
IN('hi_IN@calendar=hindu'),
IT('it_IT@calendar=Latin'),
JP('ja_JP_TRADITIONAL@calendar=japanese'),
NO('nb_NO@calendar=latin'),
IR('fa_IR@calendar=persian'),
PL('pl_PL@calendar=latin'),
PT('pt_PT@calendar=latin'),
RU('ru_RU@calendar=cyrillic'),
ES('es_ES@calendar=latin'),
SE('sv_SE@calendar=latin'),
TH('th_TH_TRADITIONAL@calendar=buddhist'),
TR('tr_TR@calendar=latin'),
PK('ur_PK@calendar=pakistan'),
VN('vi_VN@calendar=latin')

    String value

    LocaleICUCalendarExtensions(String val) {
        this.value = val
    }
    public String getValue(){
        return value
    }
    static LocaleICUCalendarExtensions byValue(String val) {
        values().find { it.value == val }
    }
    public static EnumSet<LocaleICUCalendarExtensions> getArabicSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(SA)
        return ret_val
    }
    public static EnumSet<LocaleICUCalendarExtensions> getJapanSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(JP)
        return ret_val
    }

    public static EnumSet<LocaleICUCalendarExtensions> getChinaSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(CN)
        return ret_val
    }

    public static EnumSet<LocaleICUCalendarExtensions> getFarsiSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )

        ret_val.add(IR)
        return ret_val
    }
    public static EnumSet<LocaleICUCalendarExtensions> getUrduSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(PK)
        return ret_val
    }

    public static EnumSet<LocaleICUCalendarExtensions> getHebrewSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(IL)
        return ret_val
    }
    public static EnumSet<LocaleICUCalendarExtensions> getHinduSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(IN)
        return ret_val
    }
    public static EnumSet<LocaleICUCalendarExtensions> getThaiSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(TH)
        return ret_val
    }
    public static EnumSet<LocaleICUCalendarExtensions> getGreekSupport() {
        final EnumSet< LocaleICUCalendarExtensions > ret_val = EnumSet.noneOf( LocaleICUCalendarExtensions.class )
        ret_val.add(GR)
        return ret_val
    }
}

LocaleExtensions枚举有点像LocaleCalendar只是nu而不是ca
import groovy.transform.CompileStatic

/**
 * Looks complex but will explain
 *
 * ar-SA u = unicode nu = number arab = arabic
 *
 * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
 * to get langauge code such as arab = subtag
 *
 * Rest explained here
 * http://stackoverflow.com/questions/43456068/java-locale-builder-setextensionlocale-unicode-locale-extension
 *
 *
 */
@CompileStatic
enum LocaleExtensions {
    SA('ar-SA-u-nu-arab'),
    AM('hy-AM-u-nu-arevmda'),
    CN('zh-TW-u-nu-arab'), //'zh-TW-u-nu-hant'
    CZ('cs-CZ-u-nu-latn'),
    DK('da-DK-u-nu-latn'),
    NL('nl-NL-u-nu-latn'),
    IE('ie-IE-u-nu-latn'),
    FR('fr-FR-u-nu-latn'),
    DE('de-DE-u-nu-latn'),
    GR('el-GR-u-nu-grek'),
    IL('iw-IL-u-nu-hebr'),
    IN('hi-IN-u-nu-hindu'),
    IT('it-IT-u-nu-latn'),
    JP('ja-JP-u-nu-arab'),
    NO('nb-NO-u-nu-latn'),
    IR('fa-IR-u-nu-arab'),
    PL('pl-PL-u-nu-latn'),
    PT('pt-PT-u-nu-latn'),
    RU('ru-RU-u-nu-cyrl'),
    ES('es-ES-u-nu-latn'),
    SE('sv-SE-u-nu-latn'),
    TH('th-TH-u-nu-thai'),
    TR('tr-TR-u-nu-latn'),
    PK('ur-PK-u-nu-arab'),
    VN('vi-VN-u-nu-latn')

    String value

    LocaleExtensions(String val) {
        this.value = val
    }
    public String getValue(){
        return value
    }
    static LocaleExtensions byValue(String val) {
        values().find { it.value == val }
    }
    public static EnumSet<LocaleExtensions> getArabicSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(SA)
        //TODO
        ret_val.add(JP)
        ret_val.add(CN)
        return ret_val
    }
    public static EnumSet<LocaleExtensions> getFarsiSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(PK)
        ret_val.add(IR)
        return ret_val
    }

    public static EnumSet<LocaleExtensions> getAsianSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(JP)
        ret_val.add(CN)
        return ret_val
    }
    public static EnumSet<LocaleExtensions> getHebrewSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(IL)
        return ret_val
    }
    public static EnumSet<LocaleExtensions> getHinduSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(IN)
        return ret_val
    }
    public static EnumSet<LocaleExtensions> getThaiSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(TH)
        return ret_val
    }
    public static EnumSet<LocaleExtensions> getGreekSupport() {
        final EnumSet< LocaleExtensions > ret_val = EnumSet.noneOf( LocaleExtensions.class )
        ret_val.add(GR)
        return ret_val
    }
}

显然,这涵盖了多种语言环境,用伯纳德·曼宁(Bernard Manning)的战利品来说,对我来说是正确的

日期已被拆分为java默认支持的版本与icu4j的支持版本,然后当更好地理解之后,所有日期都移到了icu4j上,我认为编号系统仍在使用一半,并且可能也可以切换到icu4j。

无论如何,这与我开始将数字字符从拉丁语转换为阿拉伯语讨厌的讨厌东西的地方相去甚远-您最终在2016年1月1日以阿拉伯语而不是等价而正确的年份让我们说的是沙特语,我认为这类似于1354或就泰国2056而言

10-06 06:46