Delen via


Lokalisatie in .NET

Lokalisatie is het proces van het vertalen van de resources van een toepassing in gelokaliseerde versies voor elke cultuur die door de toepassing wordt ondersteund. Ga pas verder met de lokalisatiestap nadat u de stap Localizability review hebt voltooid om te controleren of de geglobaliseerde toepassing gereed is voor lokalisatie.

Een toepassing die gereed is voor lokalisatie, is onderverdeeld in twee conceptuele blokken: een blok met alle elementen van de gebruikersinterface en een blok dat uitvoerbare code bevat. Het gebruikersinterfaceblok bevat alleen lokaliseerbare elementen van de gebruikersinterface, zoals tekenreeksen, foutberichten, dialoogvensters, menu's, ingesloten objectresources, enzovoort voor de neutrale cultuur. Het codeblok bevat alleen de toepassingscode die door alle ondersteunde culturen moet worden gebruikt. De algemene taalruntime ondersteunt een resourcemodel voor satellietassembly dat de uitvoerbare code van een toepassing scheidt van de bijbehorende resources. Zie Resources in .NET voor meer informatie over het implementeren van dit model.

Voeg voor elke gelokaliseerde versie van uw toepassing een nieuwe satellietassembly toe die het gelokaliseerde gebruikersinterfaceblok bevat dat is vertaald in de juiste taal voor de doelcultuur. Het codeblok voor alle culturen moet hetzelfde blijven. De combinatie van een gelokaliseerde versie van het gebruikersinterfaceblok met het codeblok produceert een gelokaliseerde versie van uw toepassing.

In dit artikel leert u hoe u de IStringLocalizer<T> en IStringLocalizerFactory implementaties gebruikt. Alle voorbeeldbroncode in dit artikel is afhankelijk van de Microsoft.Extensions.Localization en Microsoft.Extensions.Hosting NuGet-pakketten. Zie .NET Generic Host voor meer informatie over hosting.

Bronbestanden

Het primaire mechanisme voor het isoleren van lokaliseerbare tekenreeksen is met resourcebestanden. Een resourcebestand is een XML-bestand met de extensie .resx . Resourcebestanden worden vertaald vóór de uitvoering van de verbruikende toepassing, met andere woorden, ze vertegenwoordigen vertaalde inhoud in rust. Een resourcebestandsnaam bevat meestal een landinstellings-id en krijgt de volgende vorm:

<FullTypeName><.Locale>.resx

Hierin:

  • De <FullTypeName> vertegenwoordigt lokaliseerbare resources voor een specifiek type.
  • De optionele <.Locale> vertegenwoordigt de landinstelling van de inhoud van het bronbestand.

Landinstellingen opgeven

De landinstelling moet de taal definiëren, minimaal, maar kan ook de cultuur (regionale taal) en zelfs het land of de regio definiëren. Deze segmenten worden meestal gescheiden door het - teken. Met de toegevoegde specificiteit van een cultuur worden de 'cultuurterugvalregels' toegepast waar de beste overeenkomsten prioriteit krijgen. De landinstelling moet worden toegewezen aan een bekende taaltag. Zie CultureInfo.Name voor meer informatie.

Scenario's voor terugval van cultuur

Stel dat uw gelokaliseerde app verschillende Servische landinstellingen ondersteunt en de volgende bronbestanden voor MessageServicede app heeft:

Bestand Regionale taal Landcode
MessageService.sr-Cyrl-RS.resx (Cyrillisch, Servië) RS
MessageService.sr-Cyrl.resx Cyrillisch
MessageService.sr-Latn-BA.resx (Latijns, Bosnië en Herzegovina) BA
MessageService.sr-Latn-ME.resx (Latijns, Montenegro) ME
MessageService.sr-Latn-RS.resx (Latijns, Servië) RS
MessageService.sr-Latn.resx Latijnse
MessageService.sr.resx † Latijns
MessageService.resx

† De standaard regionale taal voor de taal.

Wanneer uw app wordt uitgevoerd met de CultureInfo.CurrentCulture set op een lokalisatiecultuur "sr-Cyrl-RS" , probeert u bestanden in de volgende volgorde op te lossen:

  1. MessageService.sr-Cyrl-RS.resx
  2. MessageService.sr-Cyrl.resx
  3. MessageService.sr.resx
  4. MessageService.resx

Als uw app echter werd uitgevoerd met de CultureInfo.CurrentCulture set op een lokalisatiecultuur "sr-Latn-BA" , probeert u bestanden in de volgende volgorde op te lossen:

  1. MessageService.sr-Latn-BA.resx
  2. MessageService.sr-Latn.resx
  3. MessageService.sr.resx
  4. MessageService.resx

De regel 'cultuurterugval' negeert landinstellingen wanneer er geen overeenkomende overeenkomsten zijn, wat betekent dat resourcebestand nummer vier is geselecteerd als er geen overeenkomst kan worden gevonden. Als de cultuur is ingesteld "fr-FR", zou lokalisatie uiteindelijk vallen in het bestand MessageService.resx , wat problematisch kan zijn. Zie het terugvalproces voor resources voor meer informatie.

Resourcezoekactie

Resourcebestanden worden automatisch opgelost als onderdeel van een opzoekroutine. Als de naam van het projectbestand anders is dan de hoofdnaamruimte van uw project, kan de assemblynaam verschillen. Dit kan voorkomen dat het opzoeken van resources anders lukt. Als u dit niet wilt oplossen, gebruikt u de RootNamespaceAttribute functie om een hint voor de lokalisatieservices te bieden. Wanneer deze is opgegeven, wordt deze gebruikt tijdens het opzoeken van resources.

Het voorbeeldproject heet example.csproj, waarmee een example.dll en example.exe wordt gemaakt, maar de Localization.Example naamruimte wordt gebruikt. Pas een assembly niveaukenmerk toe om dit verschil te corrigeren:

[assembly: RootNamespace("Localization.Example")]

Lokalisatieservices registreren

Als u lokalisatieservices wilt registreren, roept u een van de AddLocalization extensiemethoden aan tijdens de configuratie van services. Hiermee wordt afhankelijkheidsinjectie (DI) van de volgende typen ingeschakeld:

Lokalisatieopties configureren

De AddLocalization(IServiceCollection, Action<LocalizationOptions>) overbelasting accepteert een setupAction parameter van het type Action<LocalizationOptions>. Hiermee kunt u lokalisatieopties configureren.

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization(options =>
{
    options.ResourcesPath = "Resources";
});

// Omitted for brevity.

Resourcebestanden kunnen zich overal in een project bevinden, maar er zijn veelvoorkomende procedures die succesvol zijn gebleken. Vaker dan niet, wordt het pad van de minste weerstand gevolgd. De voorgaande C#-code:

  • Hiermee maakt u de standaard opbouwfunctie voor host-apps.
  • Roept AddLocalization de serviceverzameling aan, waarbij deze LocalizationOptions.ResourcesPath wordt opgegeven als "Resources".

Hierdoor zoeken de lokalisatieservices in de map Resources naar resourcebestanden.

Gebruiken IStringLocalizer<T> en IStringLocalizerFactory

Nadat u de lokalisatieservices hebt geregistreerd (en optioneel hebt geconfigureerd), kunt u de volgende typen gebruiken met DI:

Als u een berichtenservice wilt maken die gelokaliseerde tekenreeksen kan retourneren, kunt u het volgende MessageServiceoverwegen:

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;
    }
}

In de voorgaande C#-code:

  • Een IStringLocalizer<MessageService> localizer veld wordt gedeclareerd.
  • De primaire constructor definieert een IStringLocalizer<MessageService> parameter en legt deze vast als argument localizer .
  • De GetGreetingMessage methode roept het IStringLocalizer.Item[String] doorgeven "GreetingMessage" als argument aan.

Het IStringLocalizer biedt ook ondersteuning voor geparameteriseerde tekenreeksresources. Houd rekening met het volgende ParameterizedMessageService:

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;
    }
}

In de voorgaande C#-code:

  • Een IStringLocalizer _localizer veld wordt gedeclareerd.
  • De primaire constructor gebruikt een IStringLocalizerFactory parameter die wordt gebruikt om een IStringLocalizer van het ParameterizedMessageService type te maken en deze toe te wijzen aan het _localizer veld.
  • Met de GetFormattedMessage methode wordt IStringLocalizer.Item[String, Object[]]een object aangeroepen, doorgegeven"DinnerPriceFormat"dateTime, en dinnerPrice als argumenten.

Belangrijk

Dit IStringLocalizerFactory is niet vereist. In plaats daarvan heeft het de voorkeur voor het verbruik van services om de IStringLocalizer<T>.

Beide IStringLocalizer.Item[] indexeerfuncties retourneren een LocalizedString, die impliciete conversies naar string?.

Alles samenvoegen

Als u een app wilt illustreren met behulp van zowel berichtservices als lokalisatie- en resourcebestanden, kunt u het volgende Program.cs-bestand overwegen:

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();

In de voorgaande C#-code:

  • De RootNamespaceAttribute sets "Localization.Example" als de hoofdnaamruimte.
  • De Console.OutputEncoding is toegewezen aan Encoding.Unicode.
  • Wanneer één argument wordt doorgegeven aan args, wordt het CultureInfo.CurrentUICultureCultureInfo.CurrentCulture resultaat van CultureInfo.GetCultureInfo(String) de arg[0]gegeven .
  • De Host wordt gemaakt met standaardinstellingen.
  • De lokalisatieservices en MessageServiceParameterizedMessageService zijn geregistreerd bij de IServiceCollection for DI.
  • Als u ruis wilt verwijderen, wordt logboekregistratie geconfigureerd om een logboekniveau lager dan een waarschuwing te negeren.
  • De MessageService oplossing wordt opgelost vanuit het IServiceProvider exemplaar en het resulterende bericht wordt vastgelegd.
  • De ParameterizedMessageService oplossing wordt opgelost vanuit het IServiceProvider exemplaar en het resulterende opgemaakte bericht wordt geregistreerd.

Elk van de *MessageService klassen definieert een set RESX-bestanden , elk met één vermelding. Hier volgt de voorbeeldinhoud voor de MessageService resourcebestanden, te beginnen met 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>

Hier volgt de voorbeeldinhoud voor de ParameterizedMessageService resourcebestanden, te beginnen met ParameterizedMessageService.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>

ParameterizedMessageService.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>

Tip

Alle XML-opmerkingen, schema's en <resheader> elementen van het resourcebestand worden opzettelijk weggelaten ter beknoptheid.

Voorbeelduitvoeringen

In het volgende voorbeeld worden de verschillende gelokaliseerde uitvoer weergegeven, op basis van de doellandinstellingen.

Overweeg "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 ¤.

Wanneer u een argument weglaat bij de .NET CLI om het project uit te voeren , wordt de standaardsysteemcultuur gebruikt, in dit geval "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.

Bij het doorgeven "sr-Cryl-RS"worden de juiste bijbehorende bronbestanden gevonden en de lokalisatie toegepast:

dotnet run --project .\example\example.csproj sr-Cryl-RS

warn: Localization.Example[0]
      Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!
warn: Localization.Example[0]
      У уторак, 03. август 2021. моја вечера је коштала 38 RSD.

De voorbeeldtoepassing biedt geen bronbestanden voor "fr-CA", maar wanneer deze cultuur wordt aangeroepen, worden de niet-gelokaliseerde resourcebestanden gebruikt.

Waarschuwing

Omdat de cultuur wordt gevonden, maar de juiste bronbestanden niet zijn, krijgt u bij het toepassen van opmaak gedeeltelijke lokalisatie:

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 $.

Zie ook