001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.text.DecimalFormatSymbols;
005import java.text.spi.DecimalFormatSymbolsProvider;
006import java.util.Locale;
007import java.util.function.Function;
008import java.util.stream.Stream;
009
010/**
011 * JOSM implementation of the {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} class,
012 * consistent with ISO 80000-1.
013 * This class will only be used with Java 9 and later runtimes, as Java 8 implementation relies
014 * on Java Extension Mechanism only, while Java 9 supports application classpath.
015 * See {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider} javadoc for more details.
016 * @since 12931
017 */
018public class JosmDecimalFormatSymbolsProvider extends DecimalFormatSymbolsProvider {
019
020    @Override
021    public DecimalFormatSymbols getInstance(Locale locale) {
022        DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
023        // Override digit group separator to be consistent across languages with ISO 80000-1, chapter 7.3.1
024        symbols.setGroupingSeparator('\u202F'); // U+202F: NARROW NO-BREAK SPACE
025        return symbols;
026    }
027
028    @Override
029    public Locale[] getAvailableLocales() {
030        return Stream.of(
031                Stream.of("", "AU", "IE", "US", "UK").map(country -> new Locale("en", country, "")),
032                Stream.of("", "AT", "CH", "DE").map(country -> new Locale("de", country, "")),
033                I18n.getAvailableTranslations()
034        ).flatMap(Function.identity()).toArray(Locale[]::new);
035    }
036
037    /**
038     * Returns a new {@code double} initialized to the value represented by the specified {@code String},
039     * allowing both dot and comma decimal separators.
040     *
041     * @param  s   the string to be parsed.
042     * @return the {@code double} value represented by the string argument.
043     * @throws NullPointerException  if the string is null
044     * @throws NumberFormatException if the string does not contain a parsable {@code double}.
045     * @see    Double#parseDouble(String)
046     * @since 13050
047     */
048    public static double parseDouble(String s) {
049        return Double.parseDouble(s.replace(',', '.'));
050    }
051}