Lokalizacja na platformie .NET
Lokalizacja to proces tłumaczenia zasobów aplikacji na zlokalizowane wersje dla każdej kultury obsługiwanej przez aplikację. Należy przejść do kroku lokalizacji dopiero po wykonaniu kroku Przegląd możliwości lokalizacji, aby sprawdzić, czy zglobalizowana aplikacja jest gotowa do lokalizacji.
Aplikacja gotowa do lokalizacji jest podzielona na dwa bloki koncepcyjne: blok zawierający wszystkie elementy interfejsu użytkownika i blok zawierający kod wykonywalny. Blok interfejsu użytkownika zawiera tylko lokalizowalne elementy interfejsu użytkownika, takie jak ciągi, komunikaty o błędach, okna dialogowe, menu, zasoby obiektów osadzonych itd. dla kultury neutralnej. Blok kodu zawiera tylko kod aplikacji, który ma być używany przez wszystkie obsługiwane kultury. Środowisko uruchomieniowe języka wspólnego obsługuje model zasobów zestawu satelitarnego, który oddziela kod wykonywalny aplikacji od zasobów. Aby uzyskać więcej informacji na temat implementowania tego modelu, zobacz Zasoby na platformie .NET.
Dla każdej zlokalizowanej wersji aplikacji dodaj nowy zestaw satelitarny zawierający zlokalizowany blok interfejsu użytkownika przetłumaczony na odpowiedni język kultury docelowej. Blok kodu dla wszystkich kultur powinien pozostać taki sam. Kombinacja zlokalizowanej wersji bloku interfejsu użytkownika z blokiem kodu tworzy zlokalizowaną wersję aplikacji.
W tym artykule dowiesz się, jak używać IStringLocalizer<T> implementacji i IStringLocalizerFactory . Cały przykładowy kod źródłowy w tym artykule opiera się na pakietach Microsoft.Extensions.Localization
NuGet i Microsoft.Extensions.Hosting
. Aby uzyskać więcej informacji na temat hostingu, zobacz Host ogólny platformy .NET.
Pliki zasobów
Podstawowym mechanizmem izolowania ciągów lokalizowalnych jest użycie plików zasobów. Plik zasobu to plik XML z rozszerzeniem pliku resx . Pliki zasobów są tłumaczone przed wykonaniem aplikacji zużywanej — innymi słowy reprezentują przetłumaczoną zawartość w spoczynku. Nazwa pliku zasobu najczęściej zawiera identyfikator ustawień regionalnych i przyjmuje następujący formularz:
<FullTypeName><.Locale>.resx
Gdzie:
- Reprezentuje
<FullTypeName>
zasoby lokalizowalne dla określonego typu. - Opcjonalnie
<.Locale>
reprezentuje ustawienia regionalne zawartości pliku zasobu.
Określanie ustawień regionalnych
Ustawienia regionalne powinny definiować język na minimalnym poziomie, ale może również definiować kulturę (język regionalny), a nawet kraj lub region. Te segmenty są często rozdzielane znakiem -
. Dzięki dodatkowej specyfiki kultury reguły "powrotu kultury" są stosowane w przypadku określania priorytetów najlepszych dopasowań. Ustawienia regionalne powinny być mapowanie na dobrze znany tag języka. Aby uzyskać więcej informacji, zobacz CultureInfo.Name.
Scenariusze rezerwowe dotyczące kultury
Załóżmy, że zlokalizowana aplikacja obsługuje różne serbskie ustawienia regionalne i ma następujące pliki zasobów dla tej MessageService
aplikacji:
Plik | Język regionalny | Kod kraju |
---|---|---|
MessageService.sr-Cyrl-RS.resx | (Cyrylica, Serbia) | OS |
MessageService.sr-Cyrl.resx | Cyrylica | |
MessageService.sr-Latn-BA.resx | (Łaciński, Bośnia i Hercegowina) | BA |
MessageService.sr-Latn-ME.resx | (Łaciński, Czarnogóra) | ME |
MessageService.sr-Latn-RS.resx | (Łaciński, Serbia) | OS |
MessageService.sr-Latn.resx | Łacińskiej | |
MessageService.sr.resx | † łaciński | |
MessageService.resx |
† Domyślny język regionalny dla języka.
Gdy aplikacja jest uruchomiona z CultureInfo.CurrentCulture zestawem do kultury "sr-Cyrl-RS"
lokalizacji próbuje rozpoznać pliki w następującej kolejności:
- MessageService.sr-Cyrl-RS.resx
- MessageService.sr-Cyrl.resx
- MessageService.sr.resx
- MessageService.resx
Jeśli jednak aplikacja była uruchomiona z CultureInfo.CurrentCulture zestawem na kulturę "sr-Latn-BA"
lokalizacji, próbuje rozpoznać pliki w następującej kolejności:
- MessageService.sr-Latn-BA.resx
- MessageService.sr-Latn.resx
- MessageService.sr.resx
- MessageService.resx
Reguła rezerwowa "kultury" będzie ignorować ustawienia regionalne, jeśli nie ma odpowiednich dopasowań, co oznacza, że plik zasobu numer cztery jest wybierany, jeśli nie można odnaleźć dopasowania. Jeśli dla kultury ustawiono "fr-FR"
wartość , lokalizacja zakończy się na pliku MessageService.resx , który może być problematyczny. Aby uzyskać więcej informacji, zobacz Proces rezerwowy zasobu.
Wyszukiwanie zasobów
Pliki zasobów są automatycznie rozpoznawane jako część procedury wyszukiwania. Jeśli nazwa pliku projektu różni się od głównej przestrzeni nazw projektu, nazwa zestawu może się różnić. Może to uniemożliwić pomyślne wyszukiwanie zasobów. Aby rozwiązać ten problem, użyj elementu , RootNamespaceAttribute aby podać wskazówkę dla usług lokalizacji. Po podaniu jest on używany podczas wyszukiwania zasobów.
Przykładowy projekt nosi nazwę example.csproj, który tworzy example.dll i example.exe — jednak Localization.Example
używana jest przestrzeń nazw. assembly
Zastosuj atrybut poziomu, aby poprawić tę niezgodność:
[assembly: RootNamespace("Localization.Example")]
Rejestrowanie usług lokalizacji
Aby zarejestrować usługi lokalizacyjne, należy wywołać jedną z AddLocalization metod rozszerzenia podczas konfiguracji usług. Umożliwi to wstrzyknięcie zależności (DI) następujących typów:
- Microsoft.Extensions.Localization.IStringLocalizer<T>
- Microsoft.Extensions.Localization.IStringLocalizerFactory
Konfigurowanie opcji lokalizacji
Przeciążenie AddLocalization(IServiceCollection, Action<LocalizationOptions>) akceptuje setupAction
parametr typu Action<LocalizationOptions>
. Umożliwia to skonfigurowanie opcji lokalizacji.
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
// Omitted for brevity.
Pliki zasobów mogą działać w dowolnym miejscu w projekcie, ale istnieją typowe rozwiązania, które okazały się skuteczne. Częściej niż nie następuje ścieżka najmniejszego oporu. Poprzedni kod języka C#:
- Tworzy domyślnego konstruktora aplikacji hosta.
- Wywołuje
AddLocalization
kolekcję usług, określając LocalizationOptions.ResourcesPath jako"Resources"
.
Spowoduje to, że usługi lokalizacyjne będą szukać w katalogu Resources dla plików zasobów.
Używanie i IStringLocalizer<T>
IStringLocalizerFactory
Po zarejestrowaniu (i opcjonalnie skonfigurowanych) usługach lokalizacji można użyć następujących typów z di:
Aby utworzyć usługę komunikatów, która może zwracać zlokalizowane ciągi, rozważ następujące kwestie MessageService
:
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;
namespace Localization.Example;
public sealed class MessageService(IStringLocalizer<MessageService> localizer)
{
[return: NotNullIfNotNull(nameof(localizer))]
public string? GetGreetingMessage()
{
LocalizedString localizedString = localizer["GreetingMessage"];
return localizedString;
}
}
W poprzednim kodzie języka C#:
IStringLocalizer<MessageService> localizer
Zadeklarowane jest pole.- Podstawowy konstruktor definiuje
IStringLocalizer<MessageService>
parametr i przechwytuje go jakolocalizer
argument. - Metoda
GetGreetingMessage
wywołuje IStringLocalizer.Item[String] przekazywanie"GreetingMessage"
jako argument.
Obiekt IStringLocalizer
obsługuje również sparametryzowane zasoby ciągów, należy wziąć pod uwagę następujące ParameterizedMessageService
kwestie:
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;
namespace Localization.Example;
public class ParameterizedMessageService(IStringLocalizerFactory factory)
{
private readonly IStringLocalizer _localizer =
factory.Create(typeof(ParameterizedMessageService));
[return: NotNullIfNotNull(nameof(_localizer))]
public string? GetFormattedMessage(DateTime dateTime, double dinnerPrice)
{
LocalizedString localizedString = _localizer["DinnerPriceFormat", dateTime, dinnerPrice];
return localizedString;
}
}
W poprzednim kodzie języka C#:
IStringLocalizer _localizer
Zadeklarowane jest pole.- Podstawowy konstruktor przyjmuje
IStringLocalizerFactory
parametr , który jest używany do utworzenia elementuIStringLocalizer
na podstawieParameterizedMessageService
typu i przypisuje go do_localizer
pola. - Metoda
GetFormattedMessage
wywołuje metodę IStringLocalizer.Item[String, Object[]]dateTime
, przekazując"DinnerPriceFormat"
obiekt idinnerPrice
jako argumenty.
Ważne
Element IStringLocalizerFactory
nie jest wymagany. Zamiast tego preferowane jest korzystanie z usług, aby wymagać .IStringLocalizer<T>
Oba IStringLocalizer.Item[] indeksatory zwracają element LocalizedString, który ma niejawne konwersje na string?
.
Zebranie wszystkich elementów
Aby uzyskać przykład aplikacji przy użyciu obu usług komunikatów, wraz z lokalizacjami i plikami zasobów, rozważ następujący plik Program.cs :
using System.Globalization;
using Localization.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using static System.Console;
using static System.Text.Encoding;
[assembly: RootNamespace("Localization.Example")]
OutputEncoding = Unicode;
if (args is [var cultureName])
{
CultureInfo.CurrentCulture =
CultureInfo.CurrentUICulture =
CultureInfo.GetCultureInfo(cultureName);
}
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddLocalization();
builder.Services.AddTransient<MessageService>();
builder.Services.AddTransient<ParameterizedMessageService>();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
IServiceProvider services = host.Services;
ILogger logger =
services.GetRequiredService<ILoggerFactory>()
.CreateLogger("Localization.Example");
MessageService messageService =
services.GetRequiredService<MessageService>();
logger.LogWarning(
"{Msg}",
messageService.GetGreetingMessage());
ParameterizedMessageService parameterizedMessageService =
services.GetRequiredService<ParameterizedMessageService>();
logger.LogWarning(
"{Msg}",
parameterizedMessageService.GetFormattedMessage(
DateTime.Today.AddDays(-3), 37.63));
await host.RunAsync();
W poprzednim kodzie języka C#:
- Zestawy RootNamespaceAttribute
"Localization.Example"
są ustawiane jako główna przestrzeń nazw. - Element Console.OutputEncoding jest przypisany do Encoding.Unicode.
- Po przekazaniu pojedynczego argumentu do
args
elementu CultureInfo.CurrentCulture i CultureInfo.CurrentUICulture zostaną przypisane wyniki podanego CultureInfo.GetCultureInfo(String) elementuarg[0]
. - Zostanie Host utworzony z wartościami domyślnymi.
- Usługi lokalizacyjne ,
MessageService
iParameterizedMessageService
są zarejestrowane w usłudzeIServiceCollection
di. - Aby usunąć szum, rejestrowanie jest skonfigurowane do ignorowania dowolnego poziomu dziennika niższego niż ostrzeżenie.
- Element
MessageService
jest rozpoznawany zIServiceProvider
wystąpienia, a jego wynikowy komunikat jest rejestrowany. - Element
ParameterizedMessageService
jest rozpoznawany zIServiceProvider
wystąpienia, a wynikowy sformatowany komunikat jest rejestrowany.
Każda z *MessageService
klas definiuje zestaw plików resx z jednym wpisem. Oto przykładowa zawartość MessageService
plików zasobów rozpoczynająca się od messageService.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Hi friends, the ".NET" developer community is excited to see you here!</value>
</data>
</root>
MessageService.sr-Cyrl-RS.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!</value>
</data>
</root>
MessageService.sr-Latn.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!</value>
</data>
</root>
Oto przykładowa zawartość ParameterizedMessageService
plików zasobów, począwszy od parametrizedMessageService.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>On {0:D} my dinner cost {1:C}.</value>
</data>
</root>
ParametrizedMessageService.sr-Cyrl-RS.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>У {0:D} моја вечера је коштала {1:C}.</value>
</data>
</root>
ParameterizedMessageService.sr-Latn.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>U {0:D} moja večera je koštala {1:C}.</value>
</data>
</root>
Napiwek
Wszystkie komentarze, schemat i <resheader>
elementy pliku zasobów są celowo pomijane w celu zwięzłości.
Przykładowe uruchomienia
W poniższym przykładzie pokazano różne zlokalizowane dane wyjściowe, biorąc pod uwagę docelowe ustawienia regionalne.
Rozważ następujące kwestie "sr-Latn"
:
dotnet run --project .\example\example.csproj sr-Latn
warn: Localization.Example[0]
Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!
warn: Localization.Example[0]
U utorak, 03. avgust 2021. moja večera je koštala 37,63 ¤.
W przypadku pominięcia argumentu do interfejsu wiersza polecenia platformy .NET w celu uruchomienia projektu używana jest domyślna kultura systemowa — w tym przypadku "en-US"
:
dotnet run --project .\example\example.csproj
warn: Localization.Example[0]
Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
On Tuesday, August 3, 2021 my dinner cost $37.63.
Podczas przekazywania "sr-Cryl-RS"
polecenia zostaną znalezione odpowiednie pliki zasobów i zastosowana lokalizacja:
dotnet run --project .\example\example.csproj sr-Cryl-RS
warn: Localization.Example[0]
Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!
warn: Localization.Example[0]
У уторак, 03. август 2021. моја вечера је коштала 38 RSD.
Przykładowa aplikacja nie udostępnia plików zasobów dla "fr-CA"
programu , ale gdy jest wywoływana z tej kultury, używane są nielokalizowane pliki zasobów.
Ostrzeżenie
Ponieważ kultura jest znaleziona, ale poprawne pliki zasobów nie są, podczas formatowania jest stosowane, kończy się częściową lokalizacją:
dotnet run --project .\example\example.csproj fr-CA
warn: Localization.Example[0]
Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
On mardi 3 août 2021 my dinner cost 37,63 $.