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 Common Language Runtime ondersteunt een resourcemodel voor satelliet-assembly dat de uitvoerbare code van een toepassing scheidt van de 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.

Resourcebestanden

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 landcode en heeft de volgende vorm:

<FullTypeName><.Locale>.resx

Waar:

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

Lokale instellingen specificeren

De locale moet op zijn minst de taal definiëren, 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 overeenkomen met een goed bekende taaltag. Zie CultureInfo.Name voor meer informatie.

Scenario's voor culturele noodsituaties

Stel dat uw gelokaliseerde app verschillende Servische lokalisaties ondersteunt en de volgende bronbestanden beschikbaar heeft voor MessageService:

Bestand Streektaal 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) MIJ
MessageService.sr-Latn-RS.resx (Latijns, Servië) RS
MessageService.sr-Latn.resx Latijn
MessageService.sr.resx Latijn
MessageService.resx

De standaard regionale taal voor de taal.

Wanneer uw app wordt uitgevoerd met de CultureInfo.CurrentCulture ingesteld op een cultuur van "sr-Cyrl-RS" probeert de app bestanden op te lossen in de volgende volgorde:

  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 ingesteld op een cultuur voor "sr-Latn-BA"-lokalisatie, probeert de app 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 was ingesteld op "fr-FR", zou de lokalisatie uiteindelijk terechtkomen 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 bronnen anders succesvol is. Om deze mismatch op te lossen, gebruikt u het RootNamespaceAttribute om een hint voor de lokalisatieservices te geven. Wanneer deze is opgegeven, wordt deze gebruikt bij het opzoeken van een resource.

Het voorbeeldproject heet example.csproj, waarmee een example.dll en example.exewordt gemaakt. De Localization.Example naamruimte wordt echter 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:

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 IStringLocalizer.Item[String] aan en geeft "GreetingMessage" als argument door.

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.
  • De methode GetFormattedMessage roept IStringLocalizer.Item[String, Object[]] aan en geeft "DinnerPriceFormat", een dateTime object, en dinnerPrice door als argumenten.

Belangrijk

Dit IStringLocalizerFactory is niet vereist. In plaats daarvan verdient het gebruik van diensten de voorkeur wanneer de IStringLocalizer<T> vereist is.

Beide IStringLocalizer.Item[] indexers retourneren een LocalizedString, wat impliciete conversies naar string? heeft.

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 stelt "Localization.Example" in als de hoofdnaamruimte.
  • De Console.OutputEncoding is toegewezen aan Encoding.Unicode.
  • Wanneer één argument wordt doorgegeven aan args, worden zowel CultureInfo.CurrentCulture als CultureInfo.CurrentUICulture toegewezen aan het resultaat van CultureInfo.GetCultureInfo(String) gegeven de arg[0].
  • De Host wordt gemaakt met standaardinstellingen.
  • De lokalisatieservices, MessageService, en ParameterizedMessageService zijn geregistreerd bij de IServiceCollection voor 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 wordt afgeleid vanuit het IServiceProvider exemplaar en het resulterende opgemaakte bericht wordt gelogd.

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>

Aanbeveling

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

Voorbeelduitvoeringen

In de volgende uitvoeringen worden de verschillende gelokaliseerde uitkomsten weergegeven, afgestemd op specifieke doellocaties.

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