简体   繁体   English

以编程方式列出 Windows 10 中所有支持的区域设置

[英]Programmatically listing all supported locales in Windows 10

Windows 10 supports custom locales, locales that do not have an LCID like older locales from older versions of Windows. Windows 10 支持自定义区域设置,即没有 LCID 的区域设置,如旧版 Windows 中的旧区域设置。 In each update to Windows 10, Microsoft has been adding lesser used locales for minority and indigenous languages.在 Windows 10 的每次更新中,微软一直在为少数民族和土著语言添加较少使用的语言环境。

A recent update to Windows 10 added the the Võro kiil ( vro ) locale.最近对 Windows 10 的更新添加了 Võro kiil ( vro ) 语言环境。 When using EnumSystemLocalesEx to enumerate all supported locales, vro does not appear in any form.使用EnumSystemLocalesEx枚举所有支持的语言环境时, vro不会以任何形式出现。 However, in the system settings UI for adding a new language or keyboard, Võro kiil does appear.但是,在用于添加新语言或键盘的系统设置 UI 中,确实会出现 Võro kiil。

However, if the user then enables this language, when you call EnumSystemLocalesEx , vro , vro-Latn and vro-Latn-001 are now listed.但是,如果用户再使这种语言,当你调用EnumSystemLocalesExvrovro-Latnvro-Latn-001现已上市。 If the user then removes this locale from the UI, it no longer appears in the results of this function call.如果用户随后从 UI 中删除此区域设置,则它不再出现在此函数调用的结果中。

The question: is there a way (supported or otherwise) to get a list of all the known locales to the operating system regardless of whether the user has enabled them or not?问题:有没有办法(支持或以其他方式)获取操作系统的所有已知语言环境的列表,而不管用户是否启用它们?

I find it very bizarre that this output includes other minority languages like Skolt Sami without requiring the user to enable it in advance.我觉得很奇怪,这个输出包括其他少数民族语言,比如 Skolt Sami,而不需要用户提前启用它。

I will quite happily accept an answer that uses the .NET framework if the API does not exist in the C/C++ APIs, so long as I can actually get this data.如果 C/C++ API 中不存在 API,我会很乐意接受使用 .NET 框架的答案,只要我能实际获得这些数据。


Example code to generate the locale output:生成语言环境输出的示例代码:

#include <cstdio>
#include "stdafx.h"
#include "windows.h"

BOOL CALLBACK Callback(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
{
    wprintf(L"%ls\n", pStr);
    return TRUE;
}

int main()
{
    EnumSystemLocalesEx(Callback, 0, 0, 0);
    return 0;
}

With Võro kiil enabled from the "Region and Language" screen in System Settings, the final three results are vro-Latn , vro-Latn-001 and vro .随着在系统设置中的“区域和语言选项”屏幕中启用Võrokiil,最后的三个结果是vro-Latnvro-Latn-001vro When not enabled, they do not appear in the output at all.未启用时,它们根本不会出现在输出中。


Using .NET APIs seems to have the same behaviour.使用 .NET API 似乎具有相同的行为。

#include "stdafx.h"

using namespace System;
using namespace System::Globalization;
int main()
{
    System::Collections::IEnumerator^ enum0 = CultureInfo::GetCultures(CultureTypes::AllCultures)->GetEnumerator();
    while (enum0->MoveNext())
    {
        CultureInfo^ ci = safe_cast<CultureInfo^>(enum0->Current);
        Console::WriteLine("{0}", ci->Name);
    }
}

In effect, the new language model for Windows means that there is no "list" beyond those that have historical LCIDs.实际上,Windows 的新语言模型意味着除了具有历史 LCID 的那些之外没有“列表”。

The Windows 8.1 and 10 settings tools link to bcp47langs.dll and winlangdb.dll , which provide functions for enabling languages and input methods so long as the provided input is a valid ISO 639-3 language code. Windows 8.1 和 10 设置工具链接到bcp47langs.dllwinlangdb.dll ,只要提供的输入是有效的 ISO 639-3 语言代码,它们就会提供启用语言和输入法的功能。

In some cases, if you want your language to appear in the UI or via these APIs, you must provide at least the script and sometimes the region.在某些情况下,如果您希望您的语言出现在 UI 中或通过这些 API 出现,您必须至少提供脚本,有时还必须提供区域。 An example is myv-Cyrl for the Erzya language. Erzya 语言的myv-Cyrl就是一个例子。

Using these APIs使用这些 API

Using an MSIL disassembler on a cmdlet bundled with PowerShell, I found ap/invoke definition that has allowed me to successfully use these APIs from C# and Rust code.在与 PowerShell 捆绑的 cmdlet 上使用 MSIL 反汇编程序,我发现 ap/invoke 定义使我能够从 C# 和 Rust 代码成功使用这些 API。

Here it is, for posterity:在这里,为了后代:

// Decompiled with JetBrains decompiler
// Type: Microsoft.InternationalSettings.Commands.LPAPIWrapper
// Assembly: Microsoft.InternationalSettings.Commands, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: E0B49792-544F-4FBD-8C35-D4DA177385AF
// Assembly location: C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.InternationalSettings.Commands\v4.0_3.0.0.0__31bf3856ad364e35\Microsoft.InternationalSettings.Commands.dll

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Microsoft.InternationalSettings.Commands
{
  internal class LPAPIWrapper
  {
    public static uint GEO_NATION = 1;
    public static uint GEO_FRIENDLYNAME = 8;
    public static uint GEOCLASS_NATION = 16;
    public static uint GEOCLASS_REGION = 14;

    [DllImport("kernelbase.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int NlsUpdateLocale(string LocaleName, int Flags);

    [DllImport("intl.cpl", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int IntlUpdateSystemLocale(string LocaleName, int dwFlags);

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SystemParametersInfo(
      uint Action,
      uint UnsignedParam,
      IntPtr Param,
      uint WinIni);

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SendNotifyMessage(
      IntPtr wWwnd,
      uint Msg,
      IntPtr wParam,
      string lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetSystemDefaultLocaleName(
      StringBuilder LocaleName,
      int LocaleNameSize);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetUserGeoID(uint GeoClass);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetUserGeoID(int GeoId);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetGeoInfo(
      int Location,
      uint GeoType,
      StringBuilder GeoData,
      int Length,
      ushort LangID);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetUserLanguages(char Delimiter, [MarshalAs(UnmanagedType.HString)] ref string UserLanguages);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetUserLanguageInputMethods(
      string Language,
      char Delimiter,
      [MarshalAs(UnmanagedType.HString)] ref string InputMethods);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int LcidFromBcp47([MarshalAs(UnmanagedType.HString)] string LanguageTag, ref int Lcid);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetPendingUserDisplayLanguage([MarshalAs(UnmanagedType.HString)] ref string language);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetUserDisplayLanguageOverride([MarshalAs(UnmanagedType.HString)] ref string language);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetUserDisplayLanguageOverride(string LanguageTag);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int ClearUserDisplayLanguageOverride();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetHttpAcceptLanguageOptOut(ref bool IsOptOut);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetHttpAcceptLanguageOptOut();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int ClearHttpAcceptLanguageOptOut();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetUserLocaleFromLanguageProfileOptOut(ref bool IsOptOut);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetUserLocaleFromLanguageProfileOptOut();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int ClearUserLocaleFromLanguageProfileOptOut();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int RemoveInputsForAllLanguagesInternal();

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetInputMethodOverride(string TipString);

    [DllImport("bcp47langs.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int Bcp47GetIsoLanguageCode([MarshalAs(UnmanagedType.HString)] string languageTag, [MarshalAs(UnmanagedType.HString)] ref string isoLanguageCode);

    [DllImport("ext-ms-win-globalization-input-l1-1-2.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int WGIGetDefaultInputMethodForLanguage(
      [MarshalAs(UnmanagedType.HString)] string Language,
      [MarshalAs(UnmanagedType.HString)] ref string DefaultTipString);

    [DllImport("ext-ms-win-globalization-input-l1-1-2.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int WGITransformInputMethodsForLanguage(
      [MarshalAs(UnmanagedType.HString)] string TipString,
      [MarshalAs(UnmanagedType.HString)] string Language,
      [MarshalAs(UnmanagedType.HString)] ref string TransformedTipString);

    [DllImport("winlangdb.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetUserLanguages(char Delimiter, [MarshalAs(UnmanagedType.HString)] string UserLanguages);

    [DllImport("winlangdb.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetLanguageNames(
      string Language,
      StringBuilder Autonym,
      StringBuilder EnglishName,
      StringBuilder LocalName,
      StringBuilder ScriptName);

    [DllImport("ext-ms-win-globalization-input-l1-1-2.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int WGIIsImeInputMethod([MarshalAs(UnmanagedType.HString)] string TipString, ref int result);

    [DllImport("winlangdb.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int EnsureLanguageProfileExists();

    [DllImport("input.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int InstallLayoutOrTip(string TipString, int Flags);

    [DllImport("input.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int SetDefaultLayoutOrTip(string TipString, int Flags);

    [DllImport("input.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetLayoutDescription(
      string LayoutId,
      StringBuilder LayoutDescription,
      ref int DescriptionLength);

    private LPAPIWrapper()
    {
    }
  }
}
 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM