Skip to content

Commit

Permalink
Merge pull request dotnet#36832 from tarekgh/AddNlsToIcuTransitionSce…
Browse files Browse the repository at this point in the history
…narios
  • Loading branch information
tarekgh authored Aug 28, 2023
2 parents 1d12b59 + b45d0f2 commit 3157094
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
---
title: "Breaking change: Globalization APIs use ICU libraries on Windows Server"
title: "Breaking change: Globalization APIs use ICU libraries on Windows Server 2019"
description: Learn about the globalization breaking change in .NET 7 where ICU libraries are used for globalization functionality instead of NLS on Windows Server.
ms.date: 09/01/2022
---
# Globalization APIs use ICU libraries on Windows Server
# Globalization APIs use ICU libraries on Windows Server 2019

.NET 7 and later versions use [International Components for Unicode (ICU)](https://icu.unicode.org/) libraries for globalization functionality when running on Windows Server 2019 or later. (Non-server Windows versions have already been [using ICU since .NET 5](../5.0/icu-globalization-api.md).)
.NET 7 and later versions use [International Components for Unicode (ICU)](https://icu.unicode.org/) libraries for globalization functionality when running on Windows Server 2019. Non-server editions of Windows have been [using ICU since .NET 5](../5.0/icu-globalization-api.md). However, .NET 7 introduced support for loading ICU in earlier Windows client versions, specifically Windows 10 versions 1703, 1709, 1803, and 1809.

## Previous behavior

In .NET 5 and .NET 6, the .NET libraries used [National Language Support (NLS)](/windows/win32/intl/national-language-support) APIs for globalization functionality on Windows Server 2019. For example, NLS functions were used to compare strings, get culture information, and perform string casing in the appropriate culture.
In .NET 5 and .NET 6, the .NET libraries used [National Language Support (NLS)](/windows/win32/intl/national-language-support) APIs for globalization functionality on Windows Server 2019. For example, NLS functions were used to compare strings, get culture information, and perform string casing in the appropriate culture. This behavior also applied to Windows 10 client versions, such as 1703, 1709, 1803, and 1809.

## New behavior

Starting in .NET 7, if an app is running on Windows Server 2019 or later, .NET libraries use [ICU](https://icu.unicode.org/) globalization APIs, by default. (Non-server Windows versions have already been [using ICU since .NET 5](../5.0/icu-globalization-api.md), so there is no change for these versions.)
Starting in .NET 7, if an app is running on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, .NET libraries use [ICU](https://icu.unicode.org/) globalization APIs, by default. (Non-server Windows versions have already been [using ICU since .NET 5](../5.0/icu-globalization-api.md), so there is no change for these versions.)

## Behavioral differences

Expand All @@ -28,8 +28,8 @@ System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.
string text = string.Format("{0:C}", 100);
```

- In .NET 5 and .NET 6 on Windows Server 2019, the value of text is `"100,00 €"`.
- In .NET 7 on Windows Server 2019, the value of text is `"100,00 ¤"`, which uses the international currency symbol instead of the euro. In ICU, the design is that a currency is a property of a country or region, not a language.
- In .NET 5 and .NET 6 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, the value of text is `"100,00 €"`.
- In .NET 7 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, the value of text is `"100,00 ¤"`, which uses the international currency symbol instead of the euro. In ICU, the design is that a currency is a property of a country or region, not a language.

## Reason for change

Expand All @@ -43,7 +43,7 @@ string text = string.Format("{0:C}", 100);

## Recommended action

If you're using .NET 7.0 on Windows Server 2019, we recommend testing your app or service before shipping it to ensure the behavior is as expected and doesn't break any users.
If you're using .NET 7 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, or 1809, we recommend testing your app or service before shipping it to ensure the behavior is as expected and doesn't break any users.

If you wish to continue using NLS globalization APIs, you can set a [run-time switch](../../../runtime-config/globalization.md#nls) to revert to that behavior. For more information about the available switches, see the [.NET globalization and ICU](../../../../core/extensions/globalization-icu.md) article.

Expand Down
20 changes: 16 additions & 4 deletions docs/core/extensions/globalization-icu.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,26 @@ Starting with .NET 5, developers have more control over which underlying library

## ICU on Windows

Windows 10 May 2019 Update and later versions include [icu.dll](/windows/win32/intl/international-components-for-unicode--icu-) as part of the OS, and .NET 5 and later versions use ICU by default. When running on Windows, .NET 5 and later versions try to load `icu.dll` and, if it's available, use it for the globalization implementation. If the ICU library can't be found or loaded, such as when running on older versions of Windows, .NET 5 and later versions fall back to the NLS-based implementation.
Windows now incorporates a preinstalled [icu.dll](/windows/win32/intl/international-components-for-unicode--icu-) version as part of its features that's automatically employed for globalization tasks. This modification allows .NET to leverage this ICU library for its globalization support. In cases where the ICU library is unavailable or cannot be loaded, as is the case with older Windows versions, .NET 5 and subsequent versions revert to using the NLS-based implementation.

The following table shows which versions of .NET are capable of loading the ICU library across different Windows client and server versions:

.NET version| Windows version
---|---
.NET 5 or .NET 6|Windows client 10 version 1903 or later
.NET 5 or .NET 6|Windows Server 2022 or later
.NET 7 or later|Windows client 10 version 1703 or later
.NET 7 or later|Windows Server 2019 or later

> [!NOTE]
> .NET 7 and later versions have the capability to load ICU on older Windows versions, in contrast to .NET 6 and .NET 5.
> [!NOTE]
> Even when using ICU, the `CurrentCulture`, `CurrentUICulture`, and `CurrentRegion` members still use Windows operating system APIs to honor user settings.
### Behavioral differences

If you upgrade your app to target .NET 5, you might see changes in your app even if you don't realize you're using globalization facilities. This section lists one of the behavioral changes you might see, but there are others too.
If you upgrade your app to target .NET 5 or later, you might see changes in your app even if you don't realize you're using globalization facilities. This section lists one of the behavioral changes you might see, but there are others too.

#### String.IndexOf

Expand All @@ -49,7 +61,7 @@ Console.WriteLine($"{greeting.IndexOf("\0", StringComparison.Ordinal)}");
```

- In .NET Core 3.1 and earlier versions on Windows, the snippet prints `3` on each of the three lines.
- In .NET 5 and later versions on Windows 19H1 and later versions, the snippet prints `0`, `0`, and `3` (for the ordinal search).
- For .NET 5 and subsequent versions running on the Windows versions listed in the [ICU on Windows](#icu-on-windows) section table, the snippet prints `0`, `0`, and `3` (for the ordinal search).

By default, <xref:System.String.IndexOf(System.String)?displayProperty=nameWithType> performs a culture-aware linguistic search. ICU considers the null character `\0` to be a *zero-weight character*, and thus the character isn't found in the string when using a linguistic search on .NET 5 and later. However, NLS doesn't consider the null character `\0` to be a zero-weight character, and a linguistic search on .NET Core 3.1 and earlier locates the character at position 3. An ordinal search finds the character at position 3 on all .NET versions.

Expand All @@ -68,7 +80,7 @@ ICU provides the flexibility to create <xref:System.TimeZoneInfo> instances usin
- <xref:System.TimeZoneInfo.TryConvertIanaIdToWindowsId(System.String,System.String@)>
- <xref:System.TimeZoneInfo.TryConvertWindowsIdToIanaId%2A>

On Windows 10 May 2019 Update or any later versions, the mentioned APIs will consistently succeed. However, on older versions of Windows, these APIs will consistently fail. In such cases, you can enable the [app-local ICU](#app-local-icu) feature to ensure the success of these APIs. On non-Windows platforms, these APIs will always succeed regardless of the version.
On the Windows versions listed in the [ICU on Windows](#icu-on-windows) section table, the mentioned APIs will consistently succeed. However, on older versions of Windows, these APIs will consistently fail. In such cases, you can enable the [app-local ICU](#app-local-icu) feature to ensure the success of these APIs. On non-Windows platforms, these APIs will always succeed regardless of the version.

In addition, it's crucial for apps to ensure that they're not running in [globalization invariant mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md) or [NLS mode](#use-nls-instead-of-icu) to guarantee the success of these APIs.

Expand Down

0 comments on commit 3157094

Please sign in to comment.