Localization
The localization of this site is through AntDesign.Extensions.Localization
libraries to achieve, mainly provide interactive localization services.
It can integrate with official or third-party localization providers to switch languages at runtime without forced reload. In addition, it includes a simple embedded JSON provider.
Installation
dotnet add package AntDesign.Extensions.Localization
Use interactive localization service
Add the following code to the 'Program.cs' file:
builder.Services.AddInteractiveStringLocalizer(); services.AddLocalization(options => { options.ResourcesPath = "Resources"; });
Create resource files in the
Resources
directory of the project in the format{ResourceName}.{language}.resx
, for exampleIndex.en-US.resx
andindex.en-cn.resx
.Index.en-US.resx:
key value Hello Hello! Goodbye Goodbye! Index.zh-CN.resx:
key value Hello Hello! Goodbye Goodbye!
It should be noted that, IStringLocalizer<T>
needs to specify a generic type parameter as the positioning of the resx file, so you need to ensure that the resource file has a corresponding public type.
Or manually modify the csproj file as follows:
<ItemGroup>
<Compile Update="Resources\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
When in use, inject the
IStringLocalizer<T>
service in razor, for example:@inject IStringLocalizer<Index> localizer <p>@localizer["Hello"]</p> <p>@localizer["Goodbye"]</p>
Switch UI languages interactively
@implements IDisposable @inject ILocalizationService LocalizationService <Button OnClick="()=>LocalizationService.SetLanguage("en-US")" >English</Button> <Button OnClick="()=>LocalizationService.SetLanguage("zh-CN")" >中文</Button> @code { protected override void OnInitialized() { LocalizationService.LanguageChanged += OnLanguageChanged; } private void OnLanguageChanged(object sender, CultureInfo args) { InvokeAsync(StateHasChanged); } public void Dispose() { LocalizationService.LanguageChanged -= OnLanguageChanged; } }
To use a third-party Localization provider, or other configurations, refer to the Official Documentation。
Localization of form validation messages
The default validator for the Form component is ObjectGraphDataAnnotationsValidator, supports DataAnnotations localization。
Demo: Form-localization
Note: Configuration of validation information in AntDesign locales is not currently supported.
DisplayAttribute supports localization
Some UI bindings in the component use the DisplayAttribute feature of the entity model or enumeration type as a Label display, such as FormItem, EnumSelect, EnumRadioGroup, EnumCheckboxGroup, and so on.
public class Model
{
[Display(Name = nameof(Resources.App.UserName), ResourceType = typeof(Resources.App))]
public string Username { get; set; }
}
public enum Province
{
[Display(Name = nameof(Resources.App.Shanghai), ResourceType = typeof(Resources.App))]
Shanghai,
Jiangsu
}
Use the simple embedded JSON provider
While we recommend the official localization solution, you can also use the solution of this documentation site to implement localization with a simple embedded JSON provider. It should be noted that it only supports direct injection of IStringLocalizer, not its generics (IStringLocalizer
In
Program.cs
file, please add the following code, this method in internal has invoked theAddInteractiveStringLocalizer
.builder.Services.AddSimpleEmbeddedJsonLocalization(options => { options.ResourcesPath = "Resources"; });
Create resource files in the 'Resources' directory of the project in the format
{language}.json
, for exampleen-US.json
andzh-CN.json
.// en-US.json { "Hello": "Hello!", "Goodbye": "Goodbye!" } // zh-CN.json { "Hello": "你好!", "Goodbye": "再见!" }
Set the build action for the JSON file, set to "embedded resource"
<ItemGroup> <EmbeddedResource Include="Resources\*.json" /> </ItemGroup>
Inject the
IStringLocalizer
service (without generics) in razor when used, for example:@inject IStringLocalizer localizer <p>@localizer["Hello"]</p> <p>@localizer["Goodbye"]</p>
Language identifier on the route
From the beginning of this site, we have implemented the language identifier of the route. It has the following features:
- When you enter the page, it can automatically add a
{locale}
parameter to the route according to the browser environment, such as/en-US/Index
. - It can also switch languages according to the existing identifier on the route, so when you want to switch languages, you only need to navigate to the path of the corresponding language.
Here's how it works:
- First, in
Routes.Razor
file, implementation theOnNavigateAsync
method forRouter
components, calledLocalizationService.SetLanguage
method to switch the language.
@using System.Reflection
@using System.Globalization
<ConfigProvider>
<Router AppAssembly="typeof(App).Assembly" OnNavigateAsync="OnNavigateAsync">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
<NotFound>
<Result Status="404" />
</NotFound>
</Router>
<AntContainer />
</ConfigProvider>
@inject ILocalizationService LocalizationService;
@inject NavigationManager NavigationManager;
@code{
async Task OnNavigateAsync(NavigationContext navigationContext)
{
var relativeUri = navigationContext.Path;
var currentCulture = LocalizationService.CurrentCulture;
var segment = relativeUri.IndexOf('/') > 0 ? relativeUri.Substring(0, relativeUri.IndexOf('/')) : relativeUri;
if (string.IsNullOrWhiteSpace(segment))
{
NavigationManager.NavigateTo($"{currentCulture.Name}/{relativeUri}");
return;
}
else
{
if (segment.IsIn("zh-CN", "en-US"))
{
LocalizationService.SetLanguage(CultureInfo.GetCultureInfo(segment));
}
else if (currentCulture.Name.IsIn("zh-CN", "en-US"))
{
NavigationManager.NavigateTo($"{currentCulture.Name}/{relativeUri}");
}
else
{
NavigationManager.NavigateTo($"en-US/{relativeUri}");
return;
}
}
}
}
- Finally, you need to add the
{locale}
parameter to all page components, so that the switched route matches the corresponding page.
@page "/{locale}/Index"
@inject IStringLocalizer<Index> localizer
<p>@localizer["Hello"]</p>
@code {
[Parameter]
public string Locale { get; set; }
}