Freigeben über


Lokalisierung in .NET

Lokalisierung ist der Prozess der Übersetzung der Ressourcen einer Anwendung in lokalisierte Versionen für jede Kultur, die von der Anwendung unterstützt wird. Sie sollten mit dem Lokalisierungsschritt fortfahren, nachdem Sie den Schritt " Lokalisierbarkeit" abgeschlossen haben, um zu überprüfen, ob die globalisierte Anwendung für die Lokalisierung bereit ist.

Eine Anwendung, die für die Lokalisierung bereit ist, wird in zwei konzeptionelle Blöcke unterteilt: ein Block, der alle Benutzeroberflächenelemente und einen Block enthält, der ausführbaren Code enthält. Der Benutzeroberflächenblock enthält nur lokalisierbare Benutzeroberflächenelemente wie Zeichenfolgen, Fehlermeldungen, Dialogfelder, Menüs, eingebettete Objektressourcen usw. für die neutrale Kultur. Der Codeblock enthält nur den Anwendungscode, der von allen unterstützten Kulturen verwendet werden soll. Die Common Language Runtime unterstützt ein Ressourcenmodell der Satellitenassembly, das den ausführbaren Code einer Anwendung von seinen Ressourcen trennt. Weitere Informationen zum Implementieren dieses Modells finden Sie unter Ressourcen in .NET.

Fügen Sie für jede lokalisierte Version Ihrer Anwendung eine neue Satellitenassembly hinzu, die den lokalisierten Benutzeroberflächenblock enthält, der in die entsprechende Sprache für die Zielkultur übersetzt wird. Der Codeblock für alle Kulturen sollte unverändert bleiben. Die Kombination einer lokalisierten Version des Benutzeroberflächenblocks mit dem Codeblock erzeugt eine lokalisierte Version Ihrer Anwendung.

In diesem Artikel erfahren Sie, wie Sie die IStringLocalizer<T> Und IStringLocalizerFactory Implementierungen verwenden. Der gesamte Beispielquellcode in diesem Artikel basiert auf den Microsoft.Extensions.Localization Paketen und Microsoft.Extensions.Hosting NuGet. Weitere Informationen zum Hosting finden Sie unter .NET Generic Host.

Ressourcendateien

Der primäre Mechanismus zum Isolieren lokalisierbarer Zeichenfolgen ist mit Ressourcendateien. Eine Ressourcendatei ist eine XML-Datei mit der .resx-Dateierweiterung. Ressourcendateien werden vor der Ausführung der verbrauchenden Anwendung übersetzt, d. h. sie stellen übersetzte Inhalte im Ruhezustand dar. Ein Ressourcendateiname enthält in der Regel einen Gebietsschemabezeichner und weist die folgende Form auf:

<FullTypeName><.Locale>.resx

Ort:

  • Dies <FullTypeName> stellt lokalisierbare Ressourcen für einen bestimmten Typ dar.
  • Das optionale <.Locale> gibt das Gebietsschema des Inhalts der Ressourcendatei an.

Angeben von Gebietsschemas

Das Locale sollte zumindest die Sprache definieren, kann aber auch die Kultur (regionale Sprache) und sogar das Land oder die Region festlegen. Diese Segmente werden häufig durch das - Zeichen getrennt. Mit der zusätzlichen Angabe einer Kultur werden die „Kulturfallbackregeln“ dort angewendet, wo die besten Übereinstimmungen priorisiert werden. Das Gebietsschema sollte einem bekannten Sprachtag zugeordnet werden. Weitere Informationen finden Sie unter CultureInfo.Name.

Fallbackszenarien für Kultur

Stellen Sie sich vor, Ihre lokalisierte Anwendung unterstützt verschiedene serbische Gebietsschemas und hat die folgenden Ressourcendateien für ihren MessageService:

Datei Regionalsprache Ländercode
MessageService.sr-Cyrl-RS.resx (Kyrillisch, Serbien) RS
MessageService.sr-Cyrl.resx Kyrillisch
MessageService.sr-Latn-BA.resx (Lateinisch, Bosnien und Herzegowina) B.A.
MessageService.sr-Latn-ME.resx (Lateinisch, Montenegro) ICH
MessageService.sr-Latn-RS.resx (Lateinisch, Serbien) RS
MessageService.sr-Latn.resx Latein
MessageService.sr.resx Latein
MessageService.resx

Die Standardregionalsprache für die Sprache.

Wenn Ihre Anwendung mit CultureInfo.CurrentCulture auf eine Kultur von "sr-Cyrl-RS" festgelegt ausgeführt wird, versucht die Lokalisierung, die Dateien in der folgenden Reihenfolge aufzulösen:

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

Wenn Ihre Anwendung jedoch mit CultureInfo.CurrentCulture auf eine Kultur von "sr-Latn-BA" festgelegt ausgeführt wird, versucht die Lokalisierung, die Dateien in der folgenden Reihenfolge aufzulösen:

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

Die Kulturfallbackregel ignoriert Gebietsschemas, wenn keine entsprechenden Übereinstimmungen vorhanden sind. Dies bedeutet, dass Ressourcendatei Nummer vier ausgewählt wird, wenn keine Übereinstimmung gefunden wird. Wenn die Kultur auf "fr-FR" festgelegt würde, würde die Lokalisierung in der Datei MessageService.resx enden, was problematisch sein kann. Weitere Informationen finden Sie im Ressourcenfallbackprozess.

Ressourcensuche

Ressourcendateien werden automatisch als Teil einer Suchroutine aufgelöst. Wenn sich der Projektdateiname vom Stammnamespace Ihres Projekts unterscheidet, kann sich der Assemblyname unterscheiden. Dadurch kann verhindert werden, dass die Ressourcensuche andernfalls erfolgreich ist. Verwenden Sie RootNamespaceAttribute, um Lokalisierungsdiensten einen Hinweis zu geben, um dieses Ungleichgewicht zu beheben. Wenn angegeben, wird sie während der Ressourcensuche verwendet.

Das Beispielprojekt heißt "example.csproj", das eine example.dll und example.exeerstellt. Der Namespace wird jedoch Localization.Example verwendet. Wenden Sie ein assembly Level-Attribut an, um diesen Konflikt zu korrigieren:

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

Registrieren von Lokalisierungsdiensten

Rufen Sie zum Registrieren von Lokalisierungsdiensten eine der AddLocalization Erweiterungsmethoden während der Konfiguration von Diensten auf. Dadurch wird die Abhängigkeitsinjektion (DI) der folgenden Typen aktiviert:

Konfigurieren von Lokalisierungsoptionen

Die AddLocalization(IServiceCollection, Action<LocalizationOptions>) Überladung akzeptiert einen setupAction Parameter vom Typ Action<LocalizationOptions>. Auf diese Weise können Sie Lokalisierungsoptionen konfigurieren.

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

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

// Omitted for brevity.

Ressourcendateien können überall in einem Projekt leben, aber es gibt gängige Methoden, die sich als erfolgreich erwiesen haben. Häufig wird der Weg des geringsten Widerstands gewählt. Der vorhergehende C#-Code:

  • Erstellt den Standardmäßigen Host-App-Generator.
  • Ruft AddLocalization für die Dienstsammlung auf und legt LocalizationOptions.ResourcesPath als "Resources" fest.

Dies würde dazu führen, dass die Lokalisierungsdienste im Ressourcenverzeichnis nach Ressourcendateien suchen.

Verwenden von IStringLocalizer<T> und IStringLocalizerFactory

Nachdem Sie die Lokalisierungsdienste registriert (und optional konfiguriert haben), können Sie die folgenden Typen mit DI verwenden:

Um einen Nachrichtendienst zu erstellen, der lokalisierte Zeichenfolgen zurückgeben kann, beachten Sie Folgendes 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;
    }
}

Im oben stehenden C#-Code ist Folgendes passiert:

  • Ein IStringLocalizer<MessageService> localizer Feld wird deklariert.
  • Der primäre Konstruktor definiert einen IStringLocalizer<MessageService> Parameter und erfasst ihn als localizer Argument.
  • Die GetGreetingMessage-Methode ruft IStringLocalizer.Item[String] auf und übergibt "GreetingMessage" als Argument.

Dies IStringLocalizer unterstützt auch parametrisierte Zeichenfolgenressourcen, beachten Sie Folgendes 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;
    }
}

Im oben stehenden C#-Code ist Folgendes passiert:

  • Ein IStringLocalizer _localizer Feld wird deklariert.
  • Der primäre Konstruktor verwendet einen IStringLocalizerFactory Parameter, der zum Erstellen eines IStringLocalizer Aus dem ParameterizedMessageService Typs verwendet wird, und weist ihn dem _localizer Feld zu.
  • Die GetFormattedMessage-Methode ruft IStringLocalizer.Item[String, Object[]] auf und übergibt "DinnerPriceFormat", ein dateTime-Objekt und dinnerPrice als Argument.

Von Bedeutung

Dies IStringLocalizerFactory ist nicht erforderlich. Stattdessen wird bevorzugt, IStringLocalizer<T> zu erfordern, um Dienste zu nutzen.

Beide IStringLocalizer.Item[]-Indexer geben LocalizedString zurück, wobei implizite Konvertierungen in string? vorliegen.

Alles zusammenfügen

Als Beispiel für eine Anwendung, die beide Nachrichtendienste zusammen mit Lokalisierungs- und Ressourcendateien verwendet, betrachten wir die folgende Datei 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();

Im oben stehenden C#-Code ist Folgendes passiert:

  • RootNamespaceAttribute legt "Localization.Example" als Stammnamespace fest.
  • Console.OutputEncoding wird Encoding.Unicodezugeordnet.
  • Wenn ein einzelnes Argument an args übergeben wird, wird CultureInfo.CurrentCulture und CultureInfo.CurrentUICulture das Ergebnis von CultureInfo.GetCultureInfo(String) in Abhängigkeit von arg[0] zugewiesen.
  • Host wird mit Standardwerten erstellt.
  • Die Lokalisierungsdienste (MessageService) und ParameterizedMessageService werden für IServiceCollection für DI registriert.
  • Um Störungen zu beseitigen, wird die Protokollierung so konfiguriert, dass alle Protokollierungsebenen unterhalb des Warnungsniveaus ignoriert werden.
  • Das MessageService wird aus der IServiceProvider Instanz aufgelöst, und die dadurch entstehende Nachricht wird protokolliert.
  • ParameterizedMessageService wird aus der IServiceProvider-Instanz aufgelöst, und die sich ergebende formatierte Meldung wird protokolliert.

Jede der *MessageService Klassen definiert eine Menge von .resx-Dateien, die jeweils einen einzelnen Eintrag enthalten. Dies ist der Beispielinhalt für die MessageService Ressourcendateien, beginnend mit 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>

Dies ist der Beispielinhalt für die ParameterizedMessageService Ressourcendateien, beginnend mit 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>

Tipp

Alle XML-Kommentare, Schemas und <resheader> Elemente der Ressourcendatei werden absichtlich aus Platzgründen weggelassen.

Beispielausführungen

In den folgenden Beispielausführungen werden die verschiedenen lokalisierten Ausgaben bei bestimmten Zielgebietsschemas gezeigt.

Berücksichtigen Sie Folgendes: "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 ¤.

Wenn Sie ein Argument für die .NET CLI auslassen, um das Projekt auszuführen, wird die Standardsystemkultur verwendet , in diesem Fall "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.

Beim Übergeben "sr-Cryl-RS"werden die richtigen entsprechenden Ressourcendateien gefunden und die Lokalisierung angewendet:

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

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

Die Beispielanwendung stellt keine Ressourcendateien für "fr-CA" zur Verfügung, aber wenn sie mit dieser Kultur aufgerufen wird, werden die nicht lokalisierten Ressourcendateien verwendet.

Warnung

Da die Kultur erkannt wird, aber die richtigen Ressourcendateien fehlen, führt die Anwendung der Formatierung zu einer teilweisen Lokalisierung.

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

Siehe auch