Description
We have customers that operate in multiple regions of Switzerland and use the locales de-CH, fr-CH and it-CH.
The standard fr-CH number format changed when we upgraded from java 8 to java 11.
old:
1'000.00 (single quote as thousands separator and dot as decimal separator)
new:
1 000,00 (nonbreaking space as thousands separator and comma as decimal separator)
To "fix" the issue we implemented a custom DecimalFormatSymbolsProvider to use the de-CH DecimalFormatSymbols for all swiss locales:
public class SwissDecimalFormatSymbolsProvider extends DecimalFormatSymbolsProvider { @Override public Locale[] getAvailableLocales() { return new Locale[] { Locale.forLanguageTag("de-CH"), Locale.forLanguageTag("fr-CH"), Locale.forLanguageTag("it-CH") }; } @Override public DecimalFormatSymbols getInstance(Locale locale) { return new DecimalFormatSymbols(Locale.forLanguageTag("de-CH")); } }
This works everywhere as expected except for when people use a "custom" freemarker number format.
E.g.
number?currency -> 1'000.00 CHF (correct de-CH DecimalFormatSymbols)
number?string(",##0.00") -> 1 000,00 (wrong fr-CH DecimalFormatSymbols)
I looked at the source code of the constructor of ExtendedDecimalFormatParser and DecimalFormatSymbols are "retrieved" by using the constructor of the DecimalFormatSymbols class.
private ExtendedDecimalFormatParser(String formatString, Locale locale) { src = formatString; this.symbols = new DecimalFormatSymbols(locale); }
This initialises DecimalFormatSymbols for the current locale ("fr-CH") instead of applying DecimalFormatSymbolsProviders.
/** * Create a DecimalFormatSymbols object for the given locale. * This constructor can only construct instances for the locales * supported by the Java runtime environment, not for those * supported by installed * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider} * implementations. For full locale coverage, use the * {@link #getInstance(Locale) getInstance} method. * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION} * for the numbering system, the instance is initialized with the specified numbering * system if the JRE implementation supports it. For example, * <pre> * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai")) * </pre> * This may return a {@code NumberFormat} instance with the Thai numbering system, * instead of the Latin numbering system. * * @param locale the desired locale * @exception NullPointerException if <code>locale</code> is null */ public DecimalFormatSymbols( Locale locale ) { initialize( locale ); }