WinRT应用程序和区域设置。根据用户的区域设置正确格式化日期和数字的方法是什么?

21

我在Windows 8 Metro应用程序(XAML&C#)中遇到了一些问题,涉及用户区域设置。似乎这些应用程序不会尊重用户的区域设置,因此即使你的Windows 8设置为以芬兰格式显示日期和时间,这些应用程序仍将使用美国格式进行显示。但这是一个如此严重的问题,我可能缺少了什么?

为了测试这个问题,我首先创建了一个WPF应用程序。该应用程序只打印出当前区域性和格式化的DateTime.Now:

    private void Culture_Loaded_1(object sender, RoutedEventArgs e)
    {
        this.Culture.Text = System.Globalization.CultureInfo.CurrentCulture.DisplayName;
    }

    private void Date_Loaded_1(object sender, RoutedEventArgs e)
    {
        this.Date.Text = DateTime.Now.ToString();
    }

这是我的默认区域设置: Regional settings

运行时,应用程序以芬兰格式显示日期:

Finnish formatting

然后我将区域设置更改为美国:

US Regional settings

再次运行该应用程序时,文化和格式发生了变化:

US wpf formatting

这正如我所预期的一样,一切都能正常工作,并且这也是我对WinRT应用程序的期望。

因此,下一步,我使用相同的代码创建了一个WinRT(XAML&C#)应用程序,并将区域设置恢复为芬兰语。问题是:

Winrt formatting

即使我已经通过区域设置定义了格式应该是“芬兰语”,但WinRT应用程序仍会显示带有美国格式的日期时间。然后,我修改了应用程序的项目文件并将fi-FI设置为默认语言:

Default language

这个更改也修改了应用程序的文化:

Finnish winrt formatting

奇怪。我将默认语言改回其默认值,格式恢复为美国格式。然后,我在项目中创建了“Strings-fi-FI”文件夹,并添加了一个空的“Resources.resw”文件。这个空文件似乎已经足够了,因为现在我得到了芬兰的格式:

Resource file Finnish formatting

一旦我删除空资源文件,格式就会恢复为美国格式:

Resource file removed US formatting winrt

非常奇怪。

这引出了一些问题,但我认为其中最主要的问题是:WinRT应用程序不像WPF应用程序那样遵循用户的区域设置,这是有意为之吗?

4个回答

15

有一段时间了,但问题并没有得到完全解答,所以让我分享一下我的小研究。Depechie 大多是对的,但他只提供了一个链接,并不确定。

是的,这个意外的变化是故意的。我们不应该再使用 CultureInfo,因为它包含遗留代码,微软希望我们改用 Windows.Globalization API。

要获取当前区域设置,我们可以使用:

GeographicRegion userRegion = new GeographicRegion();
string regionCode = userRegion.CodeTwoLetter;

但是我注意到它只包含区域信息,没有语言代码。要获取语言,我们可以使用:

string langRegionCode = Windows.Globalization.Language.CurrentInputMethodLanguageTag; // depends on keyboard settings
List<string> langs = Windows.System.UserProfile.GlobalizationPreferences.Languages; // all user  languages, like in languages control panel
List<string> applicationlangs = Windows.Globalization.ApplicationLanguages.Languages; // application languages (user languages resolved against languages declared as supported by application)

如果语言有方言,则以“语言-区域”格式返回 BCP47 语言标签,例如"en-US"; 如果该语言没有主要方言,则只返回语言本身,如 "pl"。

我们还可以设置一个主语言,它将覆盖所有其他语言:

Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "en-US";

(这是一个持久化设置,应该在用户请求时使用)

还有新的日期、时间和数字API:

Windows.Globalization.DateTimeFormatting.DateTimeFormatter dtf = new DateTimeFormatter("longdate", new[] { "en-US" }, "US", CalendarIdentifiers.Gregorian, ClockIdentifiers.TwentyFourHour);
string longDate = dtf.Format(DateTime.Now);

Windows.Globalization.NumberFormatting.DecimalFormatter deciamlFormatter = new DecimalFormatter(new string[] { "PL" }, "PL");
double d1 = (double)deciamlFormatter.ParseDouble("2,5"); // ParseDouble returns double?, not double

Windows.Globalization API中还有很多内容,但我认为这已经给我们一个大体的概念了。进一步阅读:

您也可以在Windows 8开发者中心论坛上找到有关该问题的一些主题,并获得一些Microsoft员工的答案,但他们主要会将您指向文档。


3
那么,实际上如何获取/尊重用户的区域格式设置? 我为了测试目的使用以下配置启动了Windows Phone 8.1模拟器: UI语言:德语,地区:美国,格式设置:爱尔兰我找不到获取用户将其格式设置为爱尔兰的信息的方法。 我唯一的愿望是按照用户想要看到的方式格式化日期时间。而区域格式并不自动意味着它是我设置设备或我选择的UI语言的区域。在我的设备上,我将UI设置为英语,但希望以德语格式查看所有时间戳和日期... - Kornelis
谢谢,以下内容非常棒,因为我需要ISO 3166-1 alpha2 https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2。GeographicRegion userRegion = new GeographicRegion(); string regionCode = userRegion.CodeTwoLetter; - Quincy
这对我有用,但现在我需要大数字,而CurrencyFormatter不支持小数,所以我需要一个解决方法... - Alberto Rivelli

4
这是一个有意的行动,Microsoft正在逐步放弃强制应用程序使用操作系统语言的做法。相反,每个应用程序使用由应用程序声明(在Windows.Globalization.ApplicationLanguages.ManifestLanguages中可观察到的清单语言)和用户声明(在Windows.System.UserProfile.GlobalizationPreferences.Languages中可观察到的用户语言)确定如何显示资源和全球化日期和时间的信息。这组语言称为应用程序语言(在Windows.Globalization.ApplicationLanguages.Languages中可观察到)。你看到的行为是因为你正在干扰用户语言和清单语言,所以会得到不同的应用程序语言。

4
有趣的方法,不过作为一名居住在英国(并目前在微软工作)的葡萄牙人,我对此完全不同意!这是我的看法:我的Win10手机语言设定为“英语美国”,国家设定为“英国”,地区格式为“葡萄牙语(葡萄牙)”。 Outlook以正确的pt-PT格式显示日期,但所有其他应用程序都坚持使用en-US,我认为这是错误的,并不符合我的预期!! - Pedro Lamas


0

尽管这篇文章是两年前发布的,但它似乎仍然相关。

我刚刚发现它,因为我正在寻找与此类似的答案。

我也想在我的WP8.1 WinRT应用程序中以区域格式显示日期。

这里发布的信息有所帮助,但拼凑起来有点困难。

这就是我想到的解决方案,它对我有效:

using Windows.Globalization;
using Windows.Globalization.DateTimeFormatting;

private string FormatDate(int year, int month, int day)
{
    GeographicRegion userRegion = new GeographicRegion();
    string regionCode = userRegion.CodeTwoLetter;
    var formatter = new DateTimeFormatter("year month day", new[] { regionCode });
    DateTime dateToFormat = new DateTime(year, month, day);
    var formattedDate = formatter.Format(dateToFormat);
    return formattedDate;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接