Comment convertir Microsoft Locale ID (LCID) dans le code de la langue ou de l'objet en Java Locale

StackOverflow https://stackoverflow.com/questions/1192361

  •  19-09-2019
  •  | 
  •  
Était-ce utile?

La solution 2

Comme il a commencé à ressembler il n'y a pas de solution Java prêt à faire la cartographie, nous avons pris les 20 minutes pour ~ rouler quelque chose de notre propre, au moins pour l'instant.

Nous avons pris l'information de la bouche du cheval, par exemple http: // msdn. microsoft.com/en-us/goglobal/bb964664.aspx et copier-coller ce (via Excel) dans un fichier .properties comme ceci:

1078 = Afrikaans - South Africa
1052 = Albanian - Albania
1118 = Amharic - Ethiopia
1025 = Arabic - Saudi Arabia
5121 = Arabic - Algeria 
...

(Vous pouvez télécharger le fichier si vous avez des besoins similaires.)

Ensuite, il y a une classe très simple qui lit les informations à partir du fichier .properties dans une carte, et a une méthode pour faire la conversion.

Map<String, String> lcidToDescription;

public String getDescription(String lcid) { ... }

Et oui, cela ne correspond pas en fait à code de langue ou objet Locale (ce que j'ai demandé à l'origine), mais « Langue de Microsoft - Pays / Région " la description. Il est avéré cela suffisait pour notre besoin actuel.

Avertissement: ceci est vraiment une façon minimaliste, « factice » de le faire vous-même en Java, et en gardant évidemment (et maintenir) une copie des informations de cartographie LCID dans votre base de code est pas très élégant. (D'autre part, ne voudrais-je inclure un énorme pot de bibliothèque ou quoi que ce soit trop compliqué juste pour cette application simple.) Ainsi, malgré cette réponse, ne hésitez pas à poster des solutions plus élégantes existantes ou de bibliothèques si vous connaissez quelque chose comme ça.

Autres conseils

Vous pouvez utiliser GetLocaleInfo pour faire ce (vous assumant en cours d'exécution sur Windows (Win2K +)).

Ce code C ++ montre comment utiliser la fonction:

#include "windows.h"

int main()
{
  HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE);
  if(INVALID_HANDLE_VALUE == stdout) return 1;

  LCID Locale = 0x0c01; //Arabic - Egypt
  int nchars = GetLocaleInfoW(Locale, LOCALE_SISO639LANGNAME, NULL, 0);
  wchar_t* LanguageCode = new wchar_t[nchars];
  GetLocaleInfoW(Locale, LOCALE_SISO639LANGNAME, LanguageCode, nchars);

  WriteConsoleW(stdout, LanguageCode, nchars, NULL, NULL);
  delete[] LanguageCode;
  return 0;
}

Il ne faudrait pas beaucoup de travail pour en faire un JNA appel. (Astuce:. Produire des constantes comme ints pour trouver leurs valeurs)

JNA code de l'échantillon:

est un avec JNI peu plus impliqué, mais il est gérable pour une tâche relativement facile.

À tout le moins, je regarderais en utilisant les appels natifs pour construire votre base de données de conversion. Je ne suis pas sûr que Windows a un moyen d'énumérer les LCID, mais il y a forcément quelque chose en .Net. En tant que chose au niveau de la construction, ce n'est pas un fardeau énorme. Je voudrais éviter la maintenance manuelle de la liste.

Le code suivant va créer un programme mappage entre les codes Microsoft LCID et Java Paramètres régionaux, ce qui rend plus facile de garder la cartographie mise à jour:

import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * @author Gili Tzabari
 */
public final class Locales
{
    /**
     * Maps a Microsoft LCID to a Java Locale.
     */
    private final Map<Integer, Locale> lcidToLocale = new HashMap<>(LcidToLocaleMapping.NUM_LOCALES);

    public Locales()
    {
        // Try loading the mapping from cache
        File file = new File("lcid-to-locale.properties");
        Properties properties = new Properties();
        try (FileInputStream in = new FileInputStream(file))
        {
            properties.load(in);
            for (Object key: properties.keySet())
            {
                String keyString = key.toString();
                Integer lcid = Integer.parseInt(keyString);
                String languageTag = properties.getProperty(keyString);
                lcidToLocale.put(lcid, Locale.forLanguageTag(languageTag));
            }
            return;
        }
        catch (IOException unused)
        {
            // Cache does not exist or is invalid, regenerate...
            lcidToLocale.clear();
        }

        LcidToLocaleMapping mapping;
        try
        {
            mapping = new LcidToLocaleMapping();
        }
        catch (IOException e)
        {
            // Unrecoverable runtime failure
            throw new AssertionError(e);
        }
        for (Locale locale: Locale.getAvailableLocales())
        {
            if (locale == Locale.ROOT)
            {
                // Special case that doesn't map to a real locale
                continue;
            }
            String language = locale.getDisplayLanguage(Locale.ENGLISH);
            String country = locale.getDisplayCountry(Locale.ENGLISH);
            country = mapping.getCountryAlias(country);
            String script = locale.getDisplayScript();
            for (Integer lcid: mapping.listLcidFor(language, country, script))
            {
                lcidToLocale.put(lcid, locale);
                properties.put(lcid.toString(), locale.toLanguageTag());
            }
        }

        // Cache the mapping
        try (FileOutputStream out = new FileOutputStream(file))
        {
            properties.store(out, "LCID to Locale mapping");
        }
        catch (IOException e)
        {
            // Unrecoverable runtime failure
            throw new AssertionError(e);
        }
    }

    /**
     * @param lcid a Microsoft LCID code
     * @return a Java locale
     * @see https://msdn.microsoft.com/en-us/library/cc223140.aspx
     */
    public Locale fromLcid(int lcid)
    {
        return lcidToLocale.get(lcid);
    }
}

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.bitbucket.cowwoc.preconditions.Preconditions;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Generates a mapping between Microsoft LCIDs and Java Locales.
 * <p>
 * @see http://stackoverflow.com/a/32324060/14731
 * @author Gili Tzabari
 */
final class LcidToLocaleMapping
{
    private static final int NUM_COUNTRIES = 194;
    private static final int NUM_LANGUAGES = 13;
    private static final int NUM_SCRIPTS = 5;
    /**
     * The number of locales we are expecting. This value is only used for performance optimization.
     */
    public static final int NUM_LOCALES = 238;
    private static final List<String> EXPECTED_HEADERS = ImmutableList.of("lcid", "language", "location");
    // [language] - [comment] ([script])
    private static final Pattern languagePattern = Pattern.compile("^(.+?)(?: - (.*?))?(?: \\((.+)\\))?$");
    /**
     * Maps a country to a list of entries.
     */
    private static final SetMultimap<String, Mapping> COUNTRY_TO_ENTRIES = HashMultimap.create(NUM_COUNTRIES,
        NUM_LOCALES / NUM_COUNTRIES);
    /**
     * Maps a language to a list of entries.
     */
    private static final SetMultimap<String, Mapping> LANGUAGE_TO_ENTRIES = HashMultimap.create(NUM_LANGUAGES,
        NUM_LOCALES / NUM_LANGUAGES);
    /**
     * Maps a language script to a list of entries.
     */
    private static final SetMultimap<String, Mapping> SCRIPT_TO_ENTRIES = HashMultimap.create(NUM_SCRIPTS,
        NUM_LOCALES / NUM_SCRIPTS);
    /**
     * Maps a Locale country name to a LCID country name.
     */
    private static final Map<String, String> countryAlias = ImmutableMap.<String, String>builder().
        put("United Arab Emirates", "U.A.E.").
        build();

    /**
     * A mapping between a country, language, script and LCID.
     */
    private static final class Mapping
    {
        public final String country;
        public final String language;
        public final String script;
        public final int lcid;

        Mapping(String country, String language, String script, int lcid)
        {
            Preconditions.requireThat(country, "country").isNotNull();
            Preconditions.requireThat(language, "language").isNotNull().isNotEmpty();
            Preconditions.requireThat(script, "script").isNotNull();
            this.country = country;
            this.language = language;
            this.script = script;
            this.lcid = lcid;
        }

        @Override
        public int hashCode()
        {
            return country.hashCode() + language.hashCode() + script.hashCode() + lcid;
        }

        @Override
        public boolean equals(Object obj)
        {
            if (!(obj instanceof Locales))
                return false;
            Mapping other = (Mapping) obj;
            return country.equals(other.country) && language.equals(other.language) && script.equals(other.script) &&
                lcid == other.lcid;
        }
    }
    private final Logger log = LoggerFactory.getLogger(LcidToLocaleMapping.class);

    /**
     * Creates a new LCID to Locale mapping.
     * <p>
     * @throws IOException if an I/O error occurs while reading the LCID table
     */
    LcidToLocaleMapping() throws IOException
    {
        Document doc = Jsoup.connect("https://msdn.microsoft.com/en-us/library/cc223140.aspx").get();
        Element mainBody = doc.getElementById("mainBody");
        Elements elements = mainBody.select("table");
        assert (elements.size() == 1): elements;
        for (Element table: elements)
        {
            boolean firstRow = true;
            for (Element row: table.select("tr"))
            {
                if (firstRow)
                {
                    // Make sure that columns are ordered as expected
                    List<String> headers = new ArrayList<>(3);
                    Elements columns = row.select("th");
                    for (Element column: columns)
                        headers.add(column.text().toLowerCase());
                    assert (headers.equals(EXPECTED_HEADERS)): headers;
                    firstRow = false;
                    continue;
                }
                Elements columns = row.select("td");
                assert (columns.size() == 3): columns;
                Integer lcid = Integer.parseInt(columns.get(0).text(), 16);
                Matcher languageMatcher = languagePattern.matcher(columns.get(1).text());
                if (!languageMatcher.find())
                    throw new AssertionError();
                String language = languageMatcher.group(1);
                String script = languageMatcher.group(2);
                if (script == null)
                    script = "";
                String country = columns.get(2).text();
                Mapping mapping = new Mapping(country, language, script, lcid);
                COUNTRY_TO_ENTRIES.put(country, mapping);
                LANGUAGE_TO_ENTRIES.put(language, mapping);
                if (!script.isEmpty())
                    SCRIPT_TO_ENTRIES.put(script, mapping);
            }
        }
    }

    /**
     * Returns the LCID codes associated with a [country, language, script] combination.
     * <p>
     * @param language a language
     * @param country  a country (empty string if any country should match)
     * @param script   a language script (empty string if any script should match)
     * @return an empty list if no matches are found
     * @throws NullPointerException     if any of the arguments are null
     * @throws IllegalArgumentException if language is empty
     */
    public Collection<Integer> listLcidFor(String language, String country, String script)
        throws NullPointerException, IllegalArgumentException
    {
        Preconditions.requireThat(language, "language").isNotNull().isNotEmpty();
        Preconditions.requireThat(country, "country").isNotNull();
        Preconditions.requireThat(script, "script").isNotNull();
        Set<Mapping> result = LANGUAGE_TO_ENTRIES.get(language);
        if (result == null)
        {
            log.warn("Language '" + language + "' had no corresponding LCID");
            return Collections.emptyList();
        }
        if (!country.isEmpty())
        {
            Set<Mapping> entries = COUNTRY_TO_ENTRIES.get(country);
            result = Sets.intersection(result, entries);
        }

        if (!script.isEmpty())
        {
            Set<Mapping> entries = SCRIPT_TO_ENTRIES.get(script);
            result = Sets.intersection(result, entries);
        }
        return result.stream().map(entry -> entry.lcid).collect(Collectors.toList());
    }

    /**
     * @param name the locale country name
     * @return the LCID country name
     */
    public String getCountryAlias(String name)
    {
        String result = countryAlias.get(name);
        if (result == null)
            return name;
        return result;
    }
}

dépendances Maven:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>18.0</version>
    </dependency>
    <dependency>
        <groupId>org.bitbucket.cowwoc</groupId>
        <artifactId>preconditions</artifactId>
        <version>1.25</version>
    </dependency>
    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>1.8.3</version>
    </dependency>

Utilisation:

System.out.println("Language: " + new Locales().fromLcid(1033).getDisplayLanguage());

imprimera. "Langue:"

Signification, LCID 1033 cartes à la langue anglaise.

NOTE : Cela ne génère que les correspondances pour les environnements locaux disponibles sur votre machine virtuelle Java d'exécution. Cela signifie que vous obtenez seulement un sous-ensemble de toutes les versions localisées possibles. Cela dit, je ne pense pas qu'il est techniquement possible d'instancier que votre machine virtuelle Java Paramètres régionaux ne prend pas en charge, il est sans doute le meilleur que nous pouvons faire ...

Le premier coup a été le sur google pour "Java LCID" est Javadoc:

gnu.java.awt.font.opentype.NameDecoder
  

java.util.Locale private static   getWindowsLocale (int LCID)

Maps a Windows LCID into a Java Locale.

Parameters:
    lcid - the Windows language ID whose Java locale is to be retrieved. 
Returns:
    an suitable Locale, or null if the mapping cannot be performed.

Je ne sais pas où aller sur le téléchargement de cette bibliothèque, mais il est GNU, donc il ne devrait pas être trop difficile à trouver.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top