Provide localized resources for languages and cultures in an ASP.NET Core app
Note
This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 9 version of this article.
By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, and Hisham Bin Ateya
One task for localizing an app is to provide localized strings in resource files. This article is about working with resource files.
SupportedCultures
and SupportedUICultures
ASP.NET Core has two collections of culture values, SupportedCultures
and SupportedUICultures
. The CultureInfo object for SupportedCultures
determines the results of culture-dependent functions, such as date, time, number, and currency formatting. SupportedCultures
also determines the sorting order of text, casing conventions, and string comparisons. See StringComparer.CurrentCulture for more info on how the server gets the culture. The SupportedUICultures
determines which translated strings (from .resx files) are looked up by the ResourceManager. The ResourceManager
simply looks up culture-specific strings that are determined by CurrentUICulture
. Every thread in .NET has CurrentCulture
and CurrentUICulture
objects. ASP.NET Core inspects these values when rendering culture-dependent functions. For example, if the current thread's culture is set to "en-US" (English, United States), DateTime.Now.ToLongDateString()
displays "Thursday, February 18, 2016", but if CurrentCulture
is set to "es-ES" (Spanish, Spain) the output will be "jueves, 18 de febrero de 2016".
Resource files
NOTE: ResX Viewer and Editor provides an alternate mechanism to work with resource files using Visual Studio Code.
A resource file is a useful mechanism for separating localizable strings from code. Translated strings for the non-default language are isolated in .resx resource files. For example, you might want to create a Spanish resource file named Welcome.es.resx containing translated strings. "es" is the language code for Spanish. To create this resource file in Visual Studio:
In Solution Explorer, right click on the folder that will contain the resource file, and then select Add > New Item.
In the Search installed templates box, enter "resource" and name the file.
Enter the key value (native string) in the Name column and the translated string in the Value column.
Visual Studio shows the Welcome.es.resx file.
Resource file naming
Resources are named for the full type name of their class minus the assembly name. For example, a French resource in a project whose main assembly is LocalizationWebsite.Web.dll
for the class LocalizationWebsite.Web.Startup
would be named Startup.fr.resx. A resource for the class LocalizationWebsite.Web.Controllers.HomeController
would be named Controllers.HomeController.fr.resx. If your targeted class's namespace isn't the same as the assembly name you will need the full type name. For example, in the sample project a resource for the type ExtraNamespace.Tools
would be named ExtraNamespace.Tools.fr.resx.
In the sample project, the ConfigureServices
method sets the ResourcesPath
to "Resources", so the project relative path for the home controller's French resource file is Resources/Controllers.HomeController.fr.resx. Alternatively, you can use folders to organize resource files. For the home controller, the path would be Resources/Controllers/HomeController.fr.resx. If you don't use the ResourcesPath
option, the .resx file would go in the project base directory. The resource file for HomeController
would be named Controllers.HomeController.fr.resx. The choice of using the dot or path naming convention depends on how you want to organize your resource files.
Resource name | Dot or path naming |
---|---|
Resources/Controllers.HomeController.fr.resx | Dot |
Resources/Controllers/HomeController.fr.resx | Path |
Resource files using @inject IViewLocalizer
in Razor views follow a similar pattern. The resource file for a view can be named using either dot naming or path naming. Razor view resource files mimic the path of their associated view file. Assuming we set the ResourcesPath
to "Resources", the French resource file associated with the Views/Home/About.cshtml
view could be either of the following:
Resources/Views/Home/About.fr.resx
Resources/Views.Home.About.fr.resx
If you don't use the ResourcesPath
option, the .resx file for a view would be located in the same folder as the view.
RootNamespaceAttribute
The RootNamespaceAttribute attribute provides the root namespace of an assembly when the root namespace of an assembly is different than the assembly name.
Warning
This can occur when a project's name is not a valid .NET identifier. For instance my-project-name.csproj
will use the root namespace my_project_name
and the assembly name my-project-name
leading to this error.
If the root namespace of an assembly is different than the assembly name:
- Localization does not work by default.
- Localization fails due to the way resources are searched for within the assembly.
RootNamespace
is a build-time value which is not available to the executing process.
If the RootNamespace
is different from the AssemblyName
, include the following in AssemblyInfo.cs
(with parameter values replaced with the actual values):
using System.Reflection;
using Microsoft.Extensions.Localization;
[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]
The preceding code enables the successful resolution of resx files.
Culture fallback behavior
When searching for a resource, localization engages in "culture fallback". Starting from the requested culture, if not found, it reverts to the parent culture of that culture. As an aside, the CultureInfo.Parent property represents the parent culture. This usually (but not always) means removing the national signifier from the language-and-culture code. For example, the dialect of Spanish spoken in Mexico is "es-MX". It has the parent "es"—Spanish non-specific to any country.
Imagine your site receives a request for a "Welcome" resource using culture "fr-CA". The localization system looks for the following resources, in order, and selects the first match:
- Welcome.fr-CA.resx
- Welcome.fr.resx
- Welcome.resx (if the
NeutralResourcesLanguage
is "fr-CA")
As an example, if you remove the ".fr" culture designator and you have the culture set to French, the default resource file is read and strings are localized. The Resource manager designates a default or fallback resource for when nothing meets your requested culture. If you want to just return the key when missing a resource for the requested culture you must not have a default resource file.
Generate resource files with Visual Studio
If you create a resource file in Visual Studio without a culture in the file name (for example, Welcome.resx), Visual Studio will create a C# class with a property for each string. That's usually not what you want with ASP.NET Core. You typically don't have a default .resx resource file (a .resx file without the culture name). We suggest you create the .resx file with a culture name (for example Welcome.fr.resx). When you create a .resx file with a culture name, Visual Studio won't generate the class file.
Add other cultures
Each language and culture combination (other than the default language) requires a unique resource file. You create resource files for different cultures and locales by creating new resource files in which the language codes are part of the file name (for example, en-us, fr-ca, and en-gb). These codes are placed between the file name and the .resx file extension, as in Welcome.es-MX.resx (Spanish/Mexico).
Next steps
Localizing an app also involves the following tasks:
- Make the app's content localizable.
- Implement a strategy to select the language/culture for each request
Additional resources
- Url culture provider using middleware as filters in ASP.NET Core
- Applying the RouteDataRequest CultureProvider globally with middleware as filters
- Globalization and localization in ASP.NET Core
- Make an ASP.NET Core app's content localizable
- Strategies for selecting language and culture in a localized ASP.NET Core app
- Troubleshoot ASP.NET Core localization
- Globalizing and localizing .NET applications
- Localization.StarterWeb project used in the article.
- Resources in .resx Files
- Microsoft Multilingual App Toolkit
- Localization & Generics
By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, and Hisham Bin Ateya
One task for localizing an app is to provide localized strings in resource files. This article is about working with resource files.
SupportedCultures
and SupportedUICultures
ASP.NET Core has two collections of culture values, SupportedCultures
and SupportedUICultures
. The CultureInfo object for SupportedCultures
determines the results of culture-dependent functions, such as date, time, number, and currency formatting. SupportedCultures
also determines the sorting order of text, casing conventions, and string comparisons. See StringComparer.CurrentCulture for more info on how the server gets the culture. The SupportedUICultures
determines which translated strings (from .resx files) are looked up by the ResourceManager. The ResourceManager
simply looks up culture-specific strings that are determined by CurrentUICulture
. Every thread in .NET has CurrentCulture
and CurrentUICulture
objects. ASP.NET Core inspects these values when rendering culture-dependent functions. For example, if the current thread's culture is set to "en-US" (English, United States), DateTime.Now.ToLongDateString()
displays "Thursday, February 18, 2016", but if CurrentCulture
is set to "es-ES" (Spanish, Spain) the output will be "jueves, 18 de febrero de 2016".
Resource files
A resource file is a useful mechanism for separating localizable strings from code. Translated strings for the non-default language are isolated in .resx resource files. For example, you might want to create a Spanish resource file named Welcome.es.resx containing translated strings. "es" is the language code for Spanish. To create this resource file in Visual Studio:
In Solution Explorer, right click on the folder that will contain the resource file, and then select Add > New Item.
In the Search installed templates box, enter "resource" and name the file.
Enter the key value (native string) in the Name column and the translated string in the Value column.
Visual Studio shows the Welcome.es.resx file.
Resource file naming
Resources are named for the full type name of their class minus the assembly name. For example, a French resource in a project whose main assembly is LocalizationWebsite.Web.dll
for the class LocalizationWebsite.Web.Startup
would be named Startup.fr.resx. A resource for the class LocalizationWebsite.Web.Controllers.HomeController
would be named Controllers.HomeController.fr.resx. If your targeted class's namespace isn't the same as the assembly name you will need the full type name. For example, in the sample project a resource for the type ExtraNamespace.Tools
would be named ExtraNamespace.Tools.fr.resx.
In the sample project, the ConfigureServices
method sets the ResourcesPath
to "Resources", so the project relative path for the home controller's French resource file is Resources/Controllers.HomeController.fr.resx. Alternatively, you can use folders to organize resource files. For the home controller, the path would be Resources/Controllers/HomeController.fr.resx. If you don't use the ResourcesPath
option, the .resx file would go in the project base directory. The resource file for HomeController
would be named Controllers.HomeController.fr.resx. The choice of using the dot or path naming convention depends on how you want to organize your resource files.
Resource name | Dot or path naming |
---|---|
Resources/Controllers.HomeController.fr.resx | Dot |
Resources/Controllers/HomeController.fr.resx | Path |
Resource files using @inject IViewLocalizer
in Razor views follow a similar pattern. The resource file for a view can be named using either dot naming or path naming. Razor view resource files mimic the path of their associated view file. Assuming we set the ResourcesPath
to "Resources", the French resource file associated with the Views/Home/About.cshtml
view could be either of the following:
Resources/Views/Home/About.fr.resx
Resources/Views.Home.About.fr.resx
If you don't use the ResourcesPath
option, the .resx file for a view would be located in the same folder as the view.
RootNamespaceAttribute
The RootNamespaceAttribute attribute provides the root namespace of an assembly when the root namespace of an assembly is different than the assembly name.
Warning
This can occur when a project's name is not a valid .NET identifier. For instance my-project-name.csproj
will use the root namespace my_project_name
and the assembly name my-project-name
leading to this error.
If the root namespace of an assembly is different than the assembly name:
- Localization does not work by default.
- Localization fails due to the way resources are searched for within the assembly.
RootNamespace
is a build-time value which is not available to the executing process.
If the RootNamespace
is different from the AssemblyName
, include the following in AssemblyInfo.cs
(with parameter values replaced with the actual values):
using System.Reflection;
using Microsoft.Extensions.Localization;
[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]
The preceding code enables the successful resolution of resx files.
Culture fallback behavior
When searching for a resource, localization engages in "culture fallback". Starting from the requested culture, if not found, it reverts to the parent culture of that culture. As an aside, the CultureInfo.Parent property represents the parent culture. This usually (but not always) means removing the national signifier from the language-and-culture code. For example, the dialect of Spanish spoken in Mexico is "es-MX". It has the parent "es"—Spanish non-specific to any country.
Imagine your site receives a request for a "Welcome" resource using culture "fr-CA". The localization system looks for the following resources, in order, and selects the first match:
- Welcome.fr-CA.resx
- Welcome.fr.resx
- Welcome.resx (if the
NeutralResourcesLanguage
is "fr-CA")
As an example, if you remove the ".fr" culture designator and you have the culture set to French, the default resource file is read and strings are localized. The Resource manager designates a default or fallback resource for when nothing meets your requested culture. If you want to just return the key when missing a resource for the requested culture you must not have a default resource file.
Generate resource files with Visual Studio
If you create a resource file in Visual Studio without a culture in the file name (for example, Welcome.resx), Visual Studio will create a C# class with a property for each string. That's usually not what you want with ASP.NET Core. You typically don't have a default .resx resource file (a .resx file without the culture name). We suggest you create the .resx file with a culture name (for example Welcome.fr.resx). When you create a .resx file with a culture name, Visual Studio won't generate the class file.
Add other cultures
Each language and culture combination (other than the default language) requires a unique resource file. You create resource files for different cultures and locales by creating new resource files in which the language codes are part of the file name (for example, en-us, fr-ca, and en-gb). These codes are placed between the file name and the .resx file extension, as in Welcome.es-MX.resx (Spanish/Mexico).
Next steps
Localizing an app also involves the following tasks:
- Make the app's content localizable.
- Implement a strategy to select the language/culture for each request
Additional resources
- Globalization and localization in ASP.NET Core
- Make an ASP.NET Core app's content localizable
- Strategies for selecting language and culture in a localized ASP.NET Core app
- Troubleshoot ASP.NET Core localization
- Globalizing and localizing .NET applications
- Localization.StarterWeb project used in the article.
- Resources in .resx Files
- Microsoft Multilingual App Toolkit
- Localization & Generics
ASP.NET Core