# HG changeset patch # User naoto # Date 1565214986 25200 # Node ID 314e62bbdb168fd89fe37ba57519dcd0129c805f # Parent b948b920e29fc90a604e88906b9f4a779bd6a392 8215181: Accounting currency format support Reviewed-by: lancea, rriggs diff -r b948b920e29f -r 314e62bbdb16 make/jdk/src/classes/build/tools/cldrconverter/Bundle.java --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java Wed Aug 07 22:43:49 2019 +0200 +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java Wed Aug 07 14:56:26 2019 -0700 @@ -50,7 +50,8 @@ private final static String[] NUMBER_PATTERN_KEYS = { "NumberPatterns/decimal", "NumberPatterns/currency", - "NumberPatterns/percent" + "NumberPatterns/percent", + "NumberPatterns/accounting" }; private final static String[] COMPACT_NUMBER_PATTERN_KEYS = { @@ -222,8 +223,12 @@ if (value == null) { value = (String) parentsMap.remove(key); } - if (value.length() == 0) { - CLDRConverter.warning("empty pattern for " + key); + if (value == null || value.isEmpty()) { + if (!key.endsWith("accounting")) { + // print warning unless it is for "accounting", + // which may be missing. + CLDRConverter.warning("empty pattern for " + key); + } } numberPatterns[i] = value; } diff -r b948b920e29f -r 314e62bbdb16 make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java Wed Aug 07 22:43:49 2019 +0200 +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java Wed Aug 07 14:56:26 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -596,19 +596,24 @@ } break; case "currencyFormat": - // for FormatData - // copy string for later assembly into NumberPatterns - if (attributes.getValue("type").equals("standard")) { - pushStringEntry(qName, attributes, "NumberPatterns/currency"); - } else { - pushIgnoredContainer(qName); + { + // for FormatData + // copy string for later assembly into NumberPatterns + String cfStyle = attributes.getValue("type"); + if (cfStyle.equals("standard")) { + pushStringEntry(qName, attributes, "NumberPatterns/currency"); + } else if (cfStyle.equals("accounting")) { + pushStringEntry(qName, attributes, "NumberPatterns/accounting"); + } else { + pushIgnoredContainer(qName); + } } break; case "percentFormat": // for FormatData // copy string for later assembly into NumberPatterns if (attributes.getValue("type").equals("standard")) { - pushStringEntry(qName, attributes, "NumberPatterns/percent"); + pushStringEntry(qName, attributes, "NumberPatterns/percent"); } else { pushIgnoredContainer(qName); } diff -r b948b920e29f -r 314e62bbdb16 src/java.base/share/classes/java/text/NumberFormat.java --- a/src/java.base/share/classes/java/text/NumberFormat.java Wed Aug 07 22:43:49 2019 +0200 +++ b/src/java.base/share/classes/java/text/NumberFormat.java Wed Aug 07 14:56:26 2019 -0700 @@ -575,6 +575,15 @@ /** * Returns a currency format for the specified locale. * + *

If the specified locale contains the "{@code cf}" ( + * + * currency format style) + * Unicode extension, + * the returned currency format uses the style if it is available. + * Otherwise, the style uses the default "{@code standard}" currency format. + * For example, if the style designates "{@code account}", negative + * currency amounts use a pair of parentheses in some locales. + * * @param inLocale the desired locale * @return the {@code NumberFormat} instance for currency formatting */ diff -r b948b920e29f -r 314e62bbdb16 src/java.base/share/classes/sun/util/locale/provider/NumberFormatProviderImpl.java --- a/src/java.base/share/classes/sun/util/locale/provider/NumberFormatProviderImpl.java Wed Aug 07 22:43:49 2019 +0200 +++ b/src/java.base/share/classes/sun/util/locale/provider/NumberFormatProviderImpl.java Wed Aug 07 14:56:26 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ private static final int NUMBERSTYLE = 0; private static final int CURRENCYSTYLE = 1; private static final int PERCENTSTYLE = 2; - private static final int SCIENTIFICSTYLE = 3; + private static final int ACCOUNTINGSTYLE = 3; private static final int INTEGERSTYLE = 4; private final LocaleProviderAdapter.Type type; @@ -184,6 +184,12 @@ String[] numberPatterns = adapter.getLocaleResources(override).getNumberPatterns(); DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override); int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice; + if (choice == CURRENCYSTYLE && + numberPatterns.length > ACCOUNTINGSTYLE && + !numberPatterns[ACCOUNTINGSTYLE].isEmpty() && + "account".equalsIgnoreCase(override.getUnicodeLocaleType("cf"))) { + entry = ACCOUNTINGSTYLE; + } DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols); if (choice == INTEGERSTYLE) { diff -r b948b920e29f -r 314e62bbdb16 test/jdk/java/util/Locale/bcp47u/CurrencyFormatTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/Locale/bcp47u/CurrencyFormatTests.java Wed Aug 07 14:56:26 2019 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * @test + * @bug 8215181 + * @summary Tests the "u-cf" extension + * @modules jdk.localedata + * @run testng/othervm CurrencyFormatTests + */ + +import static org.testng.Assert.assertEquals; + +import java.text.NumberFormat; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test NumberFormat with BCP47 u-cf extensions. Note that this test depends + * on the particular CLDR release. Results may vary on other CLDR releases. + */ +@Test +public class CurrencyFormatTests { + + @DataProvider(name="getInstanceData") + Object[][] getInstanceData() { + return new Object[][] { + // Locale, amount, expected + // US dollar + {Locale.US, -100, "-$100.00"}, + {Locale.forLanguageTag("en-US-u-cf-standard"), -100, "-$100.00"}, + {Locale.forLanguageTag("en-US-u-cf-account"), -100, "($100.00)"}, + {Locale.forLanguageTag("en-US-u-cf-bogus"), -100, "-$100.00"}, + + // Euro + {Locale.forLanguageTag("en-AT"), -100, "-\u20ac\u00a0100,00"}, + {Locale.forLanguageTag("en-AT-u-cf-standard"), -100, "-\u20ac\u00a0100,00"}, + {Locale.forLanguageTag("en-AT-u-cf-account"), -100, "-\u20ac\u00a0100,00"}, + {Locale.forLanguageTag("en-AT-u-cf-bogus"), -100, "-\u20ac\u00a0100,00"}, + + // Rupee + {Locale.forLanguageTag("en-IN"), -100, "-\u20b9\u00a0100.00"}, + {Locale.forLanguageTag("en-IN-u-cf-standard"), -100, "-\u20b9\u00a0100.00"}, + {Locale.forLanguageTag("en-IN-u-cf-account"), -100, "(\u20b9100.00)"}, + {Locale.forLanguageTag("en-IN-u-cf-bogus"), -100, "-\u20b9\u00a0100.00"}, + + // Swiss franc + {Locale.forLanguageTag("en-CH"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-CH-u-cf-standard"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-CH-u-cf-account"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-CH-u-cf-bogus"), -100, "CHF-100.00"}, + + // Region override + {Locale.forLanguageTag("en-US-u-rg-CHZZZZ"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-US-u-rg-CHZZZZ-cf-standard"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-US-u-rg-CHZZZZ-cf-account"), -100, "CHF-100.00"}, + {Locale.forLanguageTag("en-US-u-rg-CHZZZZ-cf-bogus"), -100, "CHF-100.00"}, + }; + } + + @Test(dataProvider="getInstanceData") + public void test_getInstance(Locale locale, int amount, String expected) { + assertEquals(NumberFormat.getCurrencyInstance(locale).format(amount), expected); + } +}