Globalisierung und Lokalisierung in ASP.NET Core

Von Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, und Hisham Bin Ateya

Eine mehrsprachige Website ermöglicht es, eine größere Zielgruppe zu erreichen. ASP.NET Core bietet Dienste und Middleware zur Lokalisierung in verschiedene Sprachen und Kulturen.

Die Internationalisierung umfasst dieGlobalisierung und die Lokalisierung. Globalisierung bezeichnet das Entwerfen von Anwendungen, die verschiedene Kulturen unterstützen. Durch die Globalisierung wird die Unterstützung von Eingabe, Anzeige und Ausgabe mehrerer definierter Sprachskripts hinzugefügt, die zu bestimmten geografischen Bereichen gehören.

Durch die Lokalisierung wird eine globalisierte App, die bereits auf Lokalisierbarkeit vorbereitet wurde, auf eine bestimmte Kultur bzw. ein bestimmtes Gebietsschema angepasst. Weitere Informationen finden Sie unter Begriffe für die Globalisierung und Lokalisierung am Ende dieses Dokuments.

Die Lokalisierung von Apps umfasst die folgenden Aufgaben:

  1. Stellen Sie sicher, dass der Inhalt der App lokalisierbar ist.
  2. Stellen Sie die lokalisierten Ressourcen für die unterstützten Sprachen und Kulturen bereit.
  3. Implementieren Sie eine Strategie zum Auswählen der Sprache bzw. Kultur für jede Anforderung.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Stellen Sie sicher, dass der Inhalt der App lokalisierbar ist.

IStringLocalizer und IStringLocalizer<T> wurden zur Förderung der Produktivität bei der Entwicklung von lokalisierten Apps entwickelt. IStringLocalizer verwendet ResourceManager und ResourceReader, um kulturspezifische Ressourcen zur Laufzeit bereitzustellen. Die Schnittstelle besitzt einen Indexer und IEnumerable für die Rückgabe von lokalisierten Zeichenfolgen. IStringLocalizer erfordert nicht, dass die Zeichenfolgen der Standardsprache in einer Ressourcendatei gespeichert werden. Sie können eine App entwickeln, die für die Lokalisierung ausgelegt ist, und müssen in den frühen Entwicklungsphasen keine Ressourcendateien erstellen. Im folgenden Codebeispiel wird dargestellt, wie die Zeichenfolge „About Title“ für die Lokalisierung umschlossen wird.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

Im vorangehenden Codebeispiel stammt die Implementierung von IStringLocalizer<T> aus Dependency Injection. Wenn kein lokalisierter Wert von „About Title“ gefunden wird, wird der Indexerschlüssel zurückgegeben, d.h. die Zeichenfolge „About Title“. Sie können die Literalzeichenfolgen der App in der Standardsprache beibehalten und diese in der Lokalisierung umschließen, damit Sie sich auf die Entwicklung der App konzentrieren können. Entwickeln Sie Ihre App mit Ihrer Standardsprache, und bereiten Sie sie auf die Lokalisierung vor, ohne zuerst eine Standardressourcendatei zu erstellen. Alternativ können Sie das herkömmliche Verfahren verwenden und einen Schlüssel zum Abrufen der Zeichenfolge in der Standardsprache angeben. Der neue Workflow, der keine Standardsprache in der RESX-Datei verwendet und die Literalzeichenfolgen einfach umschließt, kann für viele Entwickler den Aufwand beim Lokalisieren einer App reduzieren. Andere Entwickler bevorzugen weiterhin den herkömmlichen Workflow, weil es dabei einfacher ist, mit längeren Literalzeichenfolgen zu arbeiten und lokalisierte Zeichenfolgen zu aktualisieren.

Verwenden Sie die Implementierung von IHtmlLocalizer<T> für Ressourcen, die HTML enthalten. Mit IHtmlLocalizer werden Argumente HTML-codiert, die in der Ressourcenzeichenfolge formatiert sind. Die Ressourcenzeichenfolgen werden jedoch nicht HTML-codiert. Im folgenden Beispiel wird hervorgehoben, dass nur der Wert des Parameters name HTML-codiert ist.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

Hinweis

Im Allgemeinen wird nur Text lokalisiert, nicht HTML.

Auf der untersten Ebene können Sie IStringLocalizerFactory aus Dependency Injection abrufen:

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

Im obigen Codebeispiel werden beide factory.Create-Methoden veranschaulicht.

Sie können Ihre lokalisierten Zeichenfolgen in Steuerelemente und Bereiche aufteilen oder nur einen Container verwenden. In der Beispiel-App wird eine Dummyklasse namens SharedResource für freigegebene Ressourcen verwendet.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Einige Entwickler verwenden die Klasse Startup, damit globale oder freigegebene Zeichenfolgen enthalten sind. Im folgenden Beispiel werden die Lokalisierer InfoController und SharedResource verwendet:

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

Lokalisierung der Ansicht

Der Dienst IViewLocalizer gibt lokalisierte Zeichenfolgen für eine Ansicht an. Die Klasse ViewLocalizer implementiert diese Schnittstelle und sucht den Speicherort der Ressource über den Dateipfad der Ansicht. Im folgenden Codebeispiel wird die Verwendung der Standardimplementierung von IViewLocalizer veranschaulicht:

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

Die Standardimplementierung von IViewLocalizer sucht die Ressourcendatei über den Dateinamen der Ansicht. Es gibt keine Option zur Nutzung einer globalen freigegebenen Ressourcendatei. ViewLocalizer implementiert den Lokalisierer mithilfe von IHtmlLocalizer, damit Razor die lokalisierte Zeichenfolge nicht HTML-codiert. Sie können Ressourcenzeichenfolgen parametrisieren, und IViewLocalizer codiert die Parameter mit HTML, aber nicht die Ressourcenzeichenfolgen. Sehen Sie sich das folgende Razor-Markup an:

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

Eine französische Ressourcendatei könnte Folgendes beinhalten:

Key Wert
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

Die gerenderte Ansicht würde das HTML-Markup der Ressourcendatei enthalten.

Hinweis

Im Allgemeinen wird nur Text lokalisiert, nicht HTML.

Fügen Sie IHtmlLocalizer<T> ein, um eine freigegebene Ressourcendatei in einer Ansicht zu verwenden:

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

Lokalisierung von DataAnnotations

Fehlermeldungen über DataAnnotations werden mit IStringLocalizer<T> lokalisiert. Durch Verwendung der Option ResourcesPath = "Resources" können die Fehlermeldungen in RegisterViewModel unter einem der folgenden Pfade gespeichert werden:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

In ASP.NET Core MVC 1.1.0 und höher werden Attribute lokalisiert, die keine Validierungsattribute darstellen. ASP.NET Core MVC 1.0 sucht nicht nach lokalisierten Zeichenfolgen für Attribute, die keine Validierungsattribute darstellen.

Verwenden einer Ressourcenzeichenfolge für mehrere Klassen

Das folgende Codebeispiel zeigt, wie eine Ressourcenzeichenfolge für Validierungsattribute mit mehreren Klassen verwendet wird:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

Im obigen Codebeispiel bezeichnet SharedResource die Klasse, die der RESX-Datei entspricht, in der Ihre Validierungsmeldungen gespeichert sind. DataAnnotations verwendet bei diesem Ansatz nur SharedResource anstelle der Ressource für jede Klasse.

Stellen Sie die lokalisierten Ressourcen für die unterstützten Sprachen und Kulturen bereit.

SupportedCultures und SupportedUICultures

ASP.NET Core ermöglicht Ihnen, zwei Werte für die Kultur anzugeben: SupportedCultures und SupportedUICultures. Das Objekt CultureInfo für SupportedCultures bestimmt die Ergebnisse von kulturabhängigen Funktionen, wie z.B. das Format von Datumswerten, Uhrzeiten, Zahlen und Währungen. SupportedCultures bestimmt auch die Sortierreihenfolge von Texten, Groß-/Kleinschreibungskonventionen und Zeichenfolgenvergleichen. Weitere Informationen darüber, wie der Server die Kultur abruft, finden Sie unter CultureInfo.CurrentCulture. SupportedUICultures bestimmt, welche übersetzten Zeichenfolgen (aus den RESX-Dateien) von ResourceManager abgerufen werden. Die ResourceManager-Klasse sucht nach kulturspezifischen Zeichenfolgen, die durch CurrentUICulture bestimmt werden. Jeder Thread in .NET enthält die Objekte CurrentCulture und CurrentUICulture. ASP.NET Core überprüft diese Werte beim Rendern von kulturspezifischen Funktionen. Wenn die Kultur des aktuellen Threads zum Beispiel auf „en-US“ (Englisch, USA) festgelegt ist, gibt DateTime.Now.ToLongDateString() „Thursday, February 18, 2016“ aus, wenn CurrentCulture jedoch auf „es-ES“ (Spanisch, Spanien) festgelegt ist, wird „jueves, 18 de febrero de 2016“ ausgegeben.

Ressourcendateien

Eine Ressourcendatei ist ein nützlicher Mechanismus für das Trennen von lokalisierbaren Zeichenfolgen von Code. Übersetzte Zeichenfolgen für die Sprache, die nicht die Standardsprache darstellt, werden in RESX-Ressourcendateien isoliert. Möglicherweise möchten Sie z.B. eine spanische Ressourcendatei namens Welcome.es.resx erstellen, die übersetzte Zeichenfolgen enthält. „es“ ist der Sprachcode für Spanisch. Erstellen dieser Ressourcendatei in Visual Studio:

  1. Führen Sie im Projektmappen-Explorer einen Rechtsklick auf den Ordner aus, der die Ressourcendatei enthalten soll, und klicken Sie dann auf Hinzufügen > Neues Element.

    Geschachteltes Kontextmenü: Im Projektmappen-Explorer ist ein Kontextmenü für Ressourcen geöffnet. Ein zweites Kontextmenü ist unter „Hinzufügen“ geöffnet, der Befehl „Neues Element“ wird angezeigt und hervorgehoben.

  2. Geben Sie „resource“ (Ressource) im Feld Search installed templates (Installierte Vorlagen durchsuchen) ein, und benennen Sie die Datei.

    Dialogfeld „Neues Element hinzufügen“

  3. Geben Sie den Schlüsselwert (native Zeichenfolge) in der Spalte Name und die übersetzte Zeichenfolge in der Spalte Wert ein.

    Welcome.es.resx-Datei (die Willkommensressourcendatei für Spanisch) mit dem Wort „Hello“ in der Spalte „Name“ und dem Wort „Hola“ (Hallo in Spanisch) in der Spalte „Wert“

    Die Datei Welcome.es.resx wird in Visual Studio angezeigt.

    Die Ressourcendatei „Welcome Spanish (es)“ im Projektmappen-Explorer

Benennung von Ressourcendateien

Ressourcen werden nach dem vollständigen Typnamen ihrer Klasse, abzüglich des Assemblynamens, benannt. Eine französische Ressourcendatei, deren Hauptassembly für die Klasse LocalizationWebsite.Web.Startup``LocalizationWebsite.Web.dll ist, würde zum Beispiel den Namen Startup.fr.resx erhalten. Eine Ressource für die Klasse LocalizationWebsite.Web.Controllers.HomeController würde den Namen Controllers.HomeController.fr.resx erhalten. Wenn der Namespace Ihrer Zielklasse nicht dem Assemblynamen entspricht, benötigen Sie den vollständigen Typnamen. Eine Ressource für den Typ ExtraNamespace.Tools im Beispielprojekt würde z.B. den Namen ExtraNamespace.Tools.fr.resx erhalten.

Im Beispielprojekt legt die Methode ConfigureServices die ResourcesPath-Eigenschaft auf „Resources“ fest. Der relative Projektpfad für den Controller „Home“ der französischen Ressourcendatei lautet also Resources/Controllers.HomeController.fr.resx. Alternativ können Sie Ordner zum Organisieren von Ressourcendateien verwenden. Für den Controller „Home“ würde der Pfad Resources/Controllers/HomeController.fr.resx lauten. Wenn Sie die Option ResourcesPath nicht verwenden, würde sich die RESX-Datei im Basisprojektverzeichnis befinden. Die Ressourcendatei für HomeController würde den Namen Controllers.HomeController.fr.resx tragen. Ob Sie die Benennungskonventionen mit Punkten oder wie Pfade verwenden, hängt davon ab, wie Sie Ihre Ressourcendateien organisieren möchten.

Ressourcenname Punkt- oder Pfadbenennung
Resources/Controllers.HomeController.fr.resx Punkt
Resources/Controllers/HomeController.fr.resx Pfad

Ressourcendateien, die @inject IViewLocalizer in Razor-Ansichten verwenden, folgen einem ähnlichen Muster. Die Ressourcendatei für eine Ansicht kann mit der Punkt- oder Pfadbenennung benannt werden. Ressourcendateien der Razor-Ansicht imitieren den Pfad ihrer zugehörigen Ansichtsdatei. Wenn ResourcesPath zum Beispiel auf „Resources“ festgelegt wird, ist die französische Ressourcendatei, die der Ansicht Views/Home/About.cshtml zugeordnet ist, eine der folgenden zwei:

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

Wenn Sie nicht die Option ResourcesPath verwenden, befindet sich die RESX-Datei für eine Ansicht im selben Ordner wie die Ansicht.

RootNamespaceAttribute

Das RootNamespaceAttribute-Attribut stellt den Stammnamespace einer Assembly bereit, wenn der Stammnamespace einer Assembly sich vom Assemblynamen unterscheidet.

Warnung

Dies kann vorkommen, wenn der Name eines Projekts kein gültiger .NET-Bezeichner ist. Beispielsweise verwendet my-project-name.csproj den Stammnamespace my_project_name und den Assemblynamen my-project-name, der zu diesem Fehler führt.

Wenn der Stammnamespace einer Assembly sich vom Assemblynamen unterscheidet, dann geschieht Folgendes:

  • Die Lokalisierung funktioniert standardmäßig nicht.
  • Die Lokalisierung schlägt aufgrund der Art und Weise, wie nach Ressourcen innerhalb der Assembly gesucht wird, fehl. RootNamespace ist ein Buildzeitwert, der für den ausgeführten Prozess nicht verfügbar ist.

Wenn sich RootNamespace vom AssemblyName unterscheidet, schließen Sie Folgendes in AssemblyInfo.cs ein (mit den durch die aktuellen Werte ersetzten Parameterwerten):

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

Der vorangehende Code ermöglicht die erfolgreiche Auflösung von RESX-Dateien.

Kulturfallbackverhalten

Bei der Suche nach einer Ressource initiiert die Lokalisierung „Kulturfallbackverhalten“. Wenn die angeforderte Kultur nicht gefunden wird, setzt sie diese Kultur auf die übergeordnete Kultur zurück. Die Eigenschaft CultureInfo.Parent stellt übrigens die übergeordnete Kultur dar. Das bedeutet in der Regel (aber nicht immer), dass der nationale Bezeichner aus der ISO entfernt wird. Beispielsweise ist der in Mexiko gesprochene spanische Sprache „es-MX“. „es“—Spanisch ist das übergeordnete Element und bezieht sich nicht auf ein einzelnes Land.

Nehmen Sie an, dass Ihre Website eine Anforderung für eine Willkommensressource mit der Kultur „fr-CA“ erhält. Das Lokalisierungssystem sucht der Reihenfolge nach nach der folgenden Ressource und wählt die erste Übereinstimmung aus:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (wenn NeutralResourcesLanguage „fr-CA“ ist)

Wenn Sie beispielsweise den Kulturkennzeichner „.fr“ entfernen und die Kultur auf „Französisch“ festgelegt ist, wird die Standardressourcendatei gelesen, und Zeichenfolgen werden lokalisiert. Der Ressourcen-Manager kennzeichnet eine Standard- oder Fallbackressource, wenn keine Entsprechung für die angeforderte Kultur gefunden wird. Wenn Sie nur den Schlüssel zurückgeben möchten, während eine Ressource für die angefragte Kultur fehlt, darf keine Standardressourcendatei festgelegt sein.

Erstellen von Ressourcendateien mit Visual Studio

Wenn Sie eine Ressourcendatei in Visual Studio erstellen, ohne eine Kultur im Dateinamen (z.B. Welcome.resx) festzulegen, erstellt Visual Studio eine C#-Klasse mit einer Eigenschaft für jede Zeichenfolge. Das ist in der Regel nicht das, was Sie mit ASP.NET Core erreichen wollen. In der Regel gibt es keine Standard-RESX-Ressourcendatei (eine RESX-Datei ohne den Kulturnamen). Es wird empfohlen, dass Sie eine RESX-Datei mit einem Kulturnamen erstellen (z.B. Welcome.fr.resx). Wenn Sie eine RESX-Datei mit einem Kulturnamen erstellen, erstellt Visual Studio keine Klassendatei.

Hinzufügen von anderen Kulturen

Jede Kombination von Sprache und Kultur (mit Ausnahme der Standardsprache) erfordert eine eindeutige Ressourcendatei. Sie erstellen Ressourcendateien für verschiedene Kulturen und Gebietsschemas, indem Sie neue Ressourcendateien erstellen, in denen ISO-Sprachcodes im Dateinamen enthalten sind (z.B. en-us fr-ca, und en-gb). Diese ISO-Codes werden zwischen dem Dateinamen und der Erweiterung .resx platziert, z.B. Welcome.es-MX.resx (Spanisch/Mexiko).

Implementieren Sie eine Strategie zum Auswählen der Sprache bzw. Kultur für jede Anforderung.

Konfigurieren der Lokalisierung

Die Lokalisierung wird über die Methode Startup.ConfigureServices konfiguriert:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization fügt die Lokalisierungsdienste dem Dienstcontainer hinzu. Im obigen Codebeispiel wird der Ressourcenpfad auf „Resources“ festgelegt.

  • AddViewLocalization fügt Unterstützung für lokalisierte Ansichtsdateien hinzu. In diesem Beispiel basiert die Lokalisierung der Ansicht auf dem Suffix der Ansichtsdatei. Zum Beispiel „fr“ in der Datei Index.fr.cshtml.

  • AddDataAnnotationsLocalization fügt Unterstützung für lokalisierte DataAnnotations-Validierungsmeldungen durch Abstraktionen von IStringLocalizer hinzu.

Lokalisierungsmiddleware

Die aktuell angefragte Kultur wird in der Middleware für die Lokalisierung festgelegt. Die Middleware für die Lokalisierung wird in der Startup.Configure-Methode aktiviert. Die Lokalisierungsmiddleware muss vor Middleware konfiguriert werden, die möglicherweise die Anforderungskultur prüft (z.B. app.UseMvcWithDefaultRoute()).

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.

UseRequestLocalization initialisiert ein RequestLocalizationOptions-Objekt. Bei jeder Anforderung wird die Liste von RequestCultureProvider in RequestLocalizationOptions aufgelistet und der erste Anbieter, der erfolgreich die Anforderungskultur bestimmen kann, wird verwendet. Die Standardanbieter stammen aus der Klasse RequestLocalizationOptions:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

Die Reihenfolge der Standardliste fängt bei den spezifischsten Anbietern an und endet mit den allgemeinsten. Im Verlauf des Artikels erfahren Sie, wie Sie die Reihenfolge ändern und einen benutzerdefinierten Kulturanbieter hinzufügen. Wenn kein Anbieter die Anforderungskultur bestimmen kann, wird DefaultRequestCulture verwendet.

QueryStringRequestCultureProvider

Einige Apps verwenden eine Abfragezeichenfolge, um die CultureInfo festzulegen. Bei Apps, die die Ansätze cookie oder Accept-Language-Header verwenden, ist das Hinzufügen einer Abfragezeichenfolge zur URL für das Debuggen und Testen von Code nützlich. Standardmäßig ist QueryStringRequestCultureProvider als erster Lokalisierungsanbieter in der Liste RequestCultureProvider registriert. Sie übergeben die Abfragezeichenfolge-Parameter culture und ui-culture. Im folgenden Beispiel ist die spezifische Kultur (Sprache und Region) auf Spanisch/Mexiko festgelegt:

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

Wenn Sie nur eine der beiden Abfragezeichenfolgen (culture oder ui-culture) übergeben, setzt der Anbieter für Abfragezeichenfolgen beide Werte entsprechend der übergebenen Abfrage fest. Wenn beispielsweise nur die Kultur festgelegt wird, werden sowohl Culture als auch UICulture wie folgt festgelegt:

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

Produktions-Apps bieten oft einen Mechanismus zum Festlegen der Kultur mithilfe des ASP.NET Core-Kulturcookies. Verwenden Sie die Methode MakeCookieValue zum Erstellen eines cookies.

CookieRequestCultureProvider DefaultCookieName gibt den Standardcookienamen zurück, mit dem ermittelt wird, welche Kulturinformationen der Benutzer bevorzugt. Der Standardcookiename lautet .AspNetCore.Culture.

Das cookieformat ist c=%LANGCODE%|uic=%LANGCODE%, wobei c für Culture steht und uic für UICulture, zum Beispiel:

c=en-UK|uic=en-US

Wenn Sie nur eine Kulturinformation und eine Benutzeroberflächenkultur angeben, wird die angegebene Kultur sowohl für die Kulturinformation als auch die Benutzeroberflächenkultur verwendet.

Der Accept-Language-HTTP-Header

Der Accept-Language-Header ist in den meisten Browsern konfigurierbar und war ursprünglich dafür gedacht, die Sprache des Benutzers anzugeben. Diese Einstellung gibt an, was im Browser zum Senden festgelegt ist oder vom zugrunde liegenden Betriebssystem geerbt wurde. Der Accept-Language-HTTP-Header einer Browseranfrage ist keine unfehlbare Methode zum Erkennen der bevorzugten Sprache des Benutzers (siehe Setting language preferences in a browser (Festlegen der bevorzugten Sprache in einem Browser)). In einer Produktions-App sollten Benutzer die Möglichkeit haben, ihre bevorzugte Kultur anzupassen.

Festlegen des Accept-Language-HTTP-Headers in Internet Explorer

  1. Klicken Sie auf das Zahnradsymbol und dann auf Internetoptionen.

  2. Klicken Sie auf Sprachen.

    Internetoptionen

  3. Klicken Sie auf Spracheinstellungen festlegen.

  4. Klicken Sie auf Sprache hinzufügen.

  5. Fügen Sie die Sprache hinzu.

  6. Klicken Sie auf die Sprache und dann auf Nach oben.

Der Content-Language-HTTP-Header

Der Content-Language-Entitätsheader:

  • Wird verwendet, um die für die Zielgruppe vorgesehenen Sprachen zu beschreiben.
  • Ermöglicht einem Benutzer, gemäß seiner bevorzugten Sprache zu differenzieren.

Entitätsheader werden in HTTP-Anforderungen und -Antworten verwendet.

Der Content-Language-Header kann durch Festlegen der Eigenschaft ApplyCurrentCultureToResponseHeaders hinzugefügt werden.

Hinzufügen des Content-Language-Headers:

  • Ermöglicht RequestLocalizationMiddleware, den Content-Language-Header mit der CurrentUICulture festzulegen.
  • Macht das explizite Festlegen des Content-Language-Antwortheaders überflüssig.
app.UseRequestLocalization(new RequestLocalizationOptions
{
    ApplyCurrentCultureToResponseHeaders = true
});

Verwenden eines benutzerdefinierten Anbieters

Angenommen, Sie möchten Ihren Kunden das Speichern ihrer Sprache und Kultur in Ihren Datenbanken ermöglichen. In diesem Fall können Sie einen Anbieter codieren, der diese Werte für den Benutzer abruft. Im folgenden Codebeispiel wird veranschaulicht, wie Sie einen benutzerdefinierten Anbieter hinzufügen:

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return new ProviderCultureResult("en");
    }));
});

Verwenden Sie RequestLocalizationOptions, um Lokalisierungsanbieter hinzuzufügen oder zu entfernen.

Programmgesteuertes Festlegen der Kultur

Das Beispielprojekt Localization.StarterWeb auf GitHub enthält eine Benutzeroberfläche zum Festlegen von Culture. Die Datei Views/Shared/_SelectLanguagePartial.cshtml ermöglicht Ihnen das Auswählen der Kultur aus der Liste von unterstützten Kulturen:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Die Datei Views/Shared/_SelectLanguagePartial.cshtml wird dem Abschnitt footer der Layoutdatei hinzugefügt, damit sie für alle Ansichten verfügbar ist:

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

Die Methode SetLanguage legt das Kulturcookie fest.

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

Sie können _SelectLanguagePartial.cshtml dem Beispielcode für dieses Projekt nicht hinzufügen. Das Projekt Localization.StarterWeb auf GitHub enthält Code, der RequestLocalizationOptions durch den Container von Dependency Injection an eineRazor-Teilansicht übermittelt.

Routendaten und Abfragezeichenfolgen für die Modellbindung

Weitere Informationen finden Sie unter Globalisierungsverhalten der Routendaten und Abfragezeichenfolgen für die Modellbindung.

Begriffe für die Globalisierung und Lokalisierung

Der Lokalisierungsprozess für Ihre App erfordert ein grundlegendes Verständnis von relevanten Zeichensätzen, die häufig in der modernen Softwareentwicklung verwendet werden, und von den Problemen, die mit ihnen zusammenhängen. Obwohl alle Computer Text als Zahlen (Codes) speichern, speichern verschiedene Systeme denselben Text mit anderen Zahlen. Der Lokalisierungsprozess bezieht sich auf das Übersetzen der Benutzeroberfläche (UI) der App für eine spezifische Kultur bzw. ein bestimmtes Gebietsschema.

Lokalisierbarkeit ist ein Zwischenschritt zum Überprüfen, ob eine globalisierte App bereit für die Lokalisierung ist.

Das Format RFC 4646 für den Kulturnamen ist <languagecode2>-<country/regioncode2>, wobei <languagecode2> der Sprachcode und <country/regioncode2> der Unterkulturcode. Zum Beispiel steht es-CL für Spanisch (Chile), en-US für Englisch (USA) und en-AU für Englisch (Australien). RFC 4646 ist eine Kombination der ISO 639, bei der zwei Kleinbuchstaben den Kulturcode beschreiben, der einer Sprache zugeordnet ist, und der ISO 3166, bei der zwei Großbuchstaben den Unterkulturcode beschreiben, der einem Land oder einer Region zugeordnet ist. Weitere Informationen finden Sie unter System.Globalization.CultureInfo.

Die Internationalisierung (Internationalization) wird oft mit „I18N“ abgekürzt. Diese Abkürzung verwendet den ersten und den letzten Buchstaben und die Anzahl der dazwischen liegenden Buchstaben, 18 steht also für die Menge der Buchstaben zwischen dem ersten „I“ und dem letzten „N“. Das gleiche gilt für Globalisierung (Globalization, G11N) und Lokalisierung (Localization, L10N).

Begriffe:

  • Globalisierung (G11N): Der Prozess, durch den eine App mehrere Sprachen und Regionen unterstützen soll.
  • Lokalisierung (L10N): Der Prozess, durch den eine App auf eine Sprache und Region angepasst wird.
  • Internationalisierung (I18N): Beschreibt sowohl Globalisierung als auch Lokalisierung.
  • Kultur: Beschreibt eine Sprache und optional auch eine Region.
  • Neutrale Kultur: Eine Kultur, die eine bestimmte Sprache beschreibt, aber keine Region. (Zum Beispiel „en“, „es“)
  • Spezifische Kultur: Eine Kultur, die eine bestimmte Sprache und Region beschreibt. (Zum Beispiel „en-US“, „en-GB“, „es-CL“)
  • Übergeordnete Kultur: Eine neutrale Kultur, die eine spezifische Kultur enthält. („en“ ist z.B. die übergeordnete Kultur von „en-US“ und „en-GB“)
  • Gebietsschema: Ein Gebietsschema ist identisch mit einer Kultur.

Hinweis

Sie können unter Umständen keine Dezimaltrennzeichen in Dezimalfelder eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung Ihrer App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.

Hinweis

Web-Apps vor ASP.NET Core 3.0 schreiben ein Protokoll vom Typ LogLevel.Warning pro Anforderung, wenn die angeforderte Kultur nicht unterstützt wird. Durch die Protokollierung einer LogLevel.Warning pro Anforderung können große Protokolldateien mit redundanten Informationen entstehen. Dieses Verhalten wurde in ASP.NET 3.0 geändert. Die RequestLocalizationMiddleware schreibt ein Protokoll vom Typ LogLevel.Debug, wodurch die Größe der Produktionsprotokolle reduziert wird.

Zusätzliche Ressourcen

Von Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, und Hisham Bin Ateya

Eine mehrsprachige Website ermöglicht es, eine größere Zielgruppe zu erreichen. ASP.NET Core bietet Dienste und Middleware zur Lokalisierung in verschiedene Sprachen und Kulturen.

Die Internationalisierung umfasst dieGlobalisierung und die Lokalisierung. Globalisierung bezeichnet das Entwerfen von Anwendungen, die verschiedene Kulturen unterstützen. Durch die Globalisierung wird die Unterstützung von Eingabe, Anzeige und Ausgabe mehrerer definierter Sprachskripts hinzugefügt, die zu bestimmten geografischen Bereichen gehören.

Durch die Lokalisierung wird eine globalisierte App, die bereits auf Lokalisierbarkeit vorbereitet wurde, auf eine bestimmte Kultur bzw. ein bestimmtes Gebietsschema angepasst. Weitere Informationen finden Sie unter Begriffe für die Globalisierung und Lokalisierung am Ende dieses Dokuments.

Die Lokalisierung von Apps umfasst die folgenden Aufgaben:

  1. Stellen Sie sicher, dass der Inhalt der App lokalisierbar ist.
  2. Stellen Sie die lokalisierten Ressourcen für die unterstützten Sprachen und Kulturen bereit.
  3. Implementieren Sie eine Strategie zum Auswählen der Sprache bzw. Kultur für jede Anforderung.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Erzielen von Lokalisierbarkeit für App-Inhalte

IStringLocalizer und IStringLocalizer<T> wurden zur Förderung der Produktivität bei der Entwicklung von lokalisierten Apps entwickelt. IStringLocalizer verwendet ResourceManager und ResourceReader, um kulturspezifische Ressourcen zur Laufzeit bereitzustellen. Die Schnittstelle besitzt einen Indexer und IEnumerable für die Rückgabe von lokalisierten Zeichenfolgen. IStringLocalizer erfordert nicht, dass die Zeichenfolgen der Standardsprache in einer Ressourcendatei gespeichert werden. Sie können eine App entwickeln, die für die Lokalisierung ausgelegt ist, und müssen in den frühen Entwicklungsphasen keine Ressourcendateien erstellen. Im folgenden Codebeispiel wird dargestellt, wie die Zeichenfolge „About Title“ für die Lokalisierung umschlossen wird.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

Im vorangehenden Codebeispiel stammt die Implementierung von IStringLocalizer<T> aus Dependency Injection. Wenn kein lokalisierter Wert von „About Title“ gefunden wird, wird der Indexerschlüssel zurückgegeben, d.h. die Zeichenfolge „About Title“. Sie können die Literalzeichenfolgen der App in der Standardsprache beibehalten und diese in der Lokalisierung umschließen, damit Sie sich auf die Entwicklung der App konzentrieren können. Entwickeln Sie Ihre App mit Ihrer Standardsprache, und bereiten Sie sie auf die Lokalisierung vor, ohne zuerst eine Standardressourcendatei zu erstellen. Alternativ können Sie das herkömmliche Verfahren verwenden und einen Schlüssel zum Abrufen der Zeichenfolge in der Standardsprache angeben. Der neue Workflow, der keine Standardsprache in der RESX-Datei verwendet und die Literalzeichenfolgen einfach umschließt, kann für viele Entwickler den Aufwand beim Lokalisieren einer App reduzieren. Andere Entwickler bevorzugen weiterhin den herkömmlichen Workflow, weil es dabei einfacher ist, mit längeren Literalzeichenfolgen zu arbeiten und lokalisierte Zeichenfolgen zu aktualisieren.

Verwenden Sie die Implementierung von IHtmlLocalizer<T> für Ressourcen, die HTML enthalten. Mit IHtmlLocalizer werden Argumente HTML-codiert, die in der Ressourcenzeichenfolge formatiert sind. Die Ressourcenzeichenfolgen werden jedoch nicht HTML-codiert. Im folgenden Beispiel wird hervorgehoben, dass nur der Wert des Parameters name HTML-codiert ist.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

Hinweis

Im Allgemeinen wird nur Text lokalisiert, nicht HTML.

Auf der untersten Ebene können Sie IStringLocalizerFactory aus Dependency Injection abrufen:

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

Im obigen Codebeispiel werden beide factory.Create-Methoden veranschaulicht.

Sie können Ihre lokalisierten Zeichenfolgen in Steuerelemente und Bereiche aufteilen oder nur einen Container verwenden. In der Beispiel-App wird eine Dummyklasse namens SharedResource für freigegebene Ressourcen verwendet.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Einige Entwickler verwenden die Klasse Startup, damit globale oder freigegebene Zeichenfolgen enthalten sind. Im folgenden Beispiel werden die Lokalisierer InfoController und SharedResource verwendet:

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

Lokalisierung der Ansicht

Der Dienst IViewLocalizer gibt lokalisierte Zeichenfolgen für eine Ansicht an. Die Klasse ViewLocalizer implementiert diese Schnittstelle und sucht den Speicherort der Ressource über den Dateipfad der Ansicht. Im folgenden Codebeispiel wird die Verwendung der Standardimplementierung von IViewLocalizer veranschaulicht:

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

Die Standardimplementierung von IViewLocalizer sucht die Ressourcendatei über den Dateinamen der Ansicht. Es gibt keine Option zur Nutzung einer globalen freigegebenen Ressourcendatei. ViewLocalizer implementiert den Lokalisierer mithilfe von IHtmlLocalizer, damit Razor die lokalisierte Zeichenfolge nicht HTML-codiert. Sie können Ressourcenzeichenfolgen parametrisieren, und IViewLocalizer codiert die Parameter mit HTML, aber nicht die Ressourcenzeichenfolgen. Sehen Sie sich das folgende Razor-Markup an:

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

Eine französische Ressourcendatei könnte Folgendes beinhalten:

Key Wert
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

Die gerenderte Ansicht würde das HTML-Markup der Ressourcendatei enthalten.

Hinweis

Im Allgemeinen wird nur Text lokalisiert, nicht HTML.

Fügen Sie IHtmlLocalizer<T> ein, um eine freigegebene Ressourcendatei in einer Ansicht zu verwenden:

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

Lokalisierung von DataAnnotations

Fehlermeldungen über DataAnnotations werden mit IStringLocalizer<T> lokalisiert. Durch Verwendung der Option ResourcesPath = "Resources" können die Fehlermeldungen in RegisterViewModel unter einem der folgenden Pfade gespeichert werden:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

Nichtvalidierungsattribute werden lokalisiert.

Verwenden einer Ressourcenzeichenfolge für mehrere Klassen

Das folgende Codebeispiel zeigt, wie eine Ressourcenzeichenfolge für Validierungsattribute mit mehreren Klassen verwendet wird:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

Im obigen Codebeispiel bezeichnet SharedResource die Klasse, die der RESX-Datei entspricht, in der Ihre Validierungsmeldungen gespeichert sind. DataAnnotations verwendet bei diesem Ansatz nur SharedResource anstelle der Ressource für jede Klasse.

Stellen Sie die lokalisierten Ressourcen für die unterstützten Sprachen und Kulturen bereit.

SupportedCultures und SupportedUICultures

ASP.NET Core ermöglicht Ihnen, zwei Werte für die Kultur anzugeben: SupportedCultures und SupportedUICultures. Das Objekt CultureInfo für SupportedCultures bestimmt die Ergebnisse von kulturabhängigen Funktionen, wie z.B. das Format von Datumswerten, Uhrzeiten, Zahlen und Währungen. SupportedCultures bestimmt auch die Sortierreihenfolge von Texten, Groß-/Kleinschreibungskonventionen und Zeichenfolgenvergleichen. Weitere Informationen zur Art und Weise, wie der Server die Kultur erhält, finden Sie unter CultureInfo.CurrentCulture und CultureInfo.CurrentUICulture. SupportedUICultures bestimmt, welche übersetzten Zeichenfolgen (aus den .resx-Dateien) von ResourceManager abgerufen werden. Die ResourceManager-Klasse sucht nach kulturspezifischen Zeichenfolgen, die durch CurrentUICulture bestimmt werden. Jeder Thread in .NET enthält die Objekte CurrentCulture und CurrentUICulture. Das Framework überprüft diese Werte beim Rendern von kulturspezifischen Funktionen. Wenn die Kultur des aktuellen Threads auf en-US (Englisch, USA) festgelegt ist, zeigt DateTime.Now.ToLongDateString() Thursday, February 18, 2016 an. Wenn CurrentCulture jedoch auf es-ES (Spanisch, Spanien) festgelegt ist, lautet die Ausgabe jueves, 18 de febrero de 2016.

Ressourcendateien

Eine Ressourcendatei ist ein nützlicher Mechanismus für das Trennen von lokalisierbaren Zeichenfolgen von Code. Übersetzte Zeichenfolgen für die Sprache, die nicht die Standardsprache darstellt, werden in RESX-Ressourcendateien isoliert. Möglicherweise möchten Sie z.B. eine spanische Ressourcendatei namens Welcome.es.resx erstellen, die übersetzte Zeichenfolgen enthält. „es“ ist der Sprachcode für Spanisch. Erstellen dieser Ressourcendatei in Visual Studio:

  1. Führen Sie im Projektmappen-Explorer einen Rechtsklick auf den Ordner aus, der die Ressourcendatei enthalten soll, und klicken Sie dann auf Hinzufügen > Neues Element.

    Geschachteltes Kontextmenü: Im Projektmappen-Explorer ist ein Kontextmenü für Ressourcen geöffnet. Ein zweites Kontextmenü ist unter „Hinzufügen“ geöffnet, der Befehl „Neues Element“ wird angezeigt und hervorgehoben.

  2. Geben Sie „resource“ (Ressource) im Feld Search installed templates (Installierte Vorlagen durchsuchen) ein, und benennen Sie die Datei.

    Dialogfeld „Neues Element hinzufügen“

  3. Geben Sie den Schlüsselwert (native Zeichenfolge) in der Spalte Name und die übersetzte Zeichenfolge in der Spalte Wert ein.

    Welcome.es.resx-Datei (die Willkommensressourcendatei für Spanisch) mit dem Wort „Hello“ in der Spalte „Name“ und dem Wort „Hola“ (Hallo in Spanisch) in der Spalte „Wert“

    Die Datei Welcome.es.resx wird in Visual Studio angezeigt.

    Die Ressourcendatei „Welcome Spanish (es)“ im Projektmappen-Explorer

Benennung von Ressourcendateien

Ressourcen werden nach dem vollständigen Typnamen ihrer Klasse, abzüglich des Assemblynamens, benannt. Eine französische Ressourcendatei, deren Hauptassembly für die Klasse LocalizationWebsite.Web.Startup``LocalizationWebsite.Web.dll ist, würde zum Beispiel den Namen Startup.fr.resx erhalten. Eine Ressource für die Klasse LocalizationWebsite.Web.Controllers.HomeController würde den Namen Controllers.HomeController.fr.resx erhalten. Wenn der Namespace Ihrer Zielklasse nicht dem Assemblynamen entspricht, benötigen Sie den vollständigen Typnamen. Eine Ressource für den Typ ExtraNamespace.Tools im Beispielprojekt würde z.B. den Namen ExtraNamespace.Tools.fr.resx erhalten.

Im Beispielprojekt legt die Methode ConfigureServices die ResourcesPath-Eigenschaft auf „Resources“ fest. Der relative Projektpfad für den Controller „Home“ der französischen Ressourcendatei lautet also Resources/Controllers.HomeController.fr.resx. Alternativ können Sie Ordner zum Organisieren von Ressourcendateien verwenden. Für den Controller „Home“ würde der Pfad Resources/Controllers/HomeController.fr.resx lauten. Wenn Sie die Option ResourcesPath nicht verwenden, würde sich die RESX-Datei im Basisprojektverzeichnis befinden. Die Ressourcendatei für HomeController würde den Namen Controllers.HomeController.fr.resx tragen. Ob Sie die Benennungskonventionen mit Punkten oder wie Pfade verwenden, hängt davon ab, wie Sie Ihre Ressourcendateien organisieren möchten.

Ressourcenname Punkt- oder Pfadbenennung
Resources/Controllers.HomeController.fr.resx Punkt
Resources/Controllers/HomeController.fr.resx Pfad

Ressourcendateien, die @inject IViewLocalizer in Razor-Ansichten verwenden, folgen einem ähnlichen Muster. Die Ressourcendatei für eine Ansicht kann mit der Punkt- oder Pfadbenennung benannt werden. Ressourcendateien der Razor-Ansicht imitieren den Pfad ihrer zugehörigen Ansichtsdatei. Wenn ResourcesPath zum Beispiel auf „Resources“ festgelegt wird, ist die französische Ressourcendatei, die der Ansicht Views/Home/About.cshtml zugeordnet ist, eine der folgenden zwei:

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

Wenn Sie nicht die Option ResourcesPath verwenden, befindet sich die RESX-Datei für eine Ansicht im selben Ordner wie die Ansicht.

RootNamespaceAttribute

Das RootNamespaceAttribute-Attribut stellt den Stammnamespace einer Assembly bereit, wenn der Stammnamespace einer Assembly sich vom Assemblynamen unterscheidet.

Warnung

Dies kann vorkommen, wenn der Name eines Projekts kein gültiger .NET-Bezeichner ist. Beispielsweise verwendet my-project-name.csproj den Stammnamespace my_project_name und den Assemblynamen my-project-name, der zu diesem Fehler führt.

Wenn der Stammnamespace einer Assembly sich vom Assemblynamen unterscheidet, dann geschieht Folgendes:

  • Die Lokalisierung funktioniert standardmäßig nicht.
  • Die Lokalisierung schlägt aufgrund der Art und Weise, wie nach Ressourcen innerhalb der Assembly gesucht wird, fehl. RootNamespace ist ein Buildzeitwert, der für den ausgeführten Prozess nicht verfügbar ist.

Wenn sich RootNamespace vom AssemblyName unterscheidet, schließen Sie Folgendes in AssemblyInfo.cs ein (mit den durch die aktuellen Werte ersetzten Parameterwerten):

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

Der vorangehende Code ermöglicht die erfolgreiche Auflösung von RESX-Dateien.

Kulturfallbackverhalten

Bei der Suche nach einer Ressource initiiert die Lokalisierung „Kulturfallbackverhalten“. Wenn die angeforderte Kultur nicht gefunden wird, setzt sie diese Kultur auf die übergeordnete Kultur zurück. Die Eigenschaft CultureInfo.Parent stellt übrigens die übergeordnete Kultur dar. Das bedeutet in der Regel (aber nicht immer), dass der nationale Bezeichner aus der ISO entfernt wird. Beispielsweise ist der in Mexiko gesprochene spanische Sprache „es-MX“. „es“—Spanisch ist das übergeordnete Element und bezieht sich nicht auf ein einzelnes Land.

Nehmen Sie an, dass Ihre Website eine Anforderung für eine Willkommensressource mit der Kultur „fr-CA“ erhält. Das Lokalisierungssystem sucht der Reihenfolge nach nach der folgenden Ressource und wählt die erste Übereinstimmung aus:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (wenn NeutralResourcesLanguage „fr-CA“ ist)

Wenn Sie beispielsweise den Kulturkennzeichner „.fr“ entfernen und die Kultur auf „Französisch“ festgelegt ist, wird die Standardressourcendatei gelesen, und Zeichenfolgen werden lokalisiert. Der Ressourcen-Manager kennzeichnet eine Standard- oder Fallbackressource, wenn keine Entsprechung für die angeforderte Kultur gefunden wird. Wenn Sie nur den Schlüssel zurückgeben möchten, während eine Ressource für die angefragte Kultur fehlt, darf keine Standardressourcendatei festgelegt sein.

Erstellen von Ressourcendateien mit Visual Studio

Wenn Sie eine Ressourcendatei in Visual Studio erstellen, ohne eine Kultur im Dateinamen (z.B. Welcome.resx) festzulegen, erstellt Visual Studio eine C#-Klasse mit einer Eigenschaft für jede Zeichenfolge. Das ist in der Regel nicht das, was Sie mit ASP.NET Core erreichen wollen. In der Regel gibt es keine Standard-RESX-Ressourcendatei (eine RESX-Datei ohne den Kulturnamen). Es wird empfohlen, dass Sie eine RESX-Datei mit einem Kulturnamen erstellen (z.B. Welcome.fr.resx). Wenn Sie eine RESX-Datei mit einem Kulturnamen erstellen, erstellt Visual Studio keine Klassendatei.

Hinzufügen von anderen Kulturen

Jede Kombination von Sprache und Kultur (mit Ausnahme der Standardsprache) erfordert eine eindeutige Ressourcendatei. Sie erstellen Ressourcendateien für verschiedene Kulturen und Gebietsschemas, indem Sie neue Ressourcendateien erstellen, in denen ISO-Sprachcodes im Dateinamen enthalten sind (z.B. en-us fr-ca, und en-gb). Diese ISO-Codes werden zwischen dem Dateinamen und der Erweiterung .resx platziert, z.B. Welcome.es-MX.resx (Spanisch/Mexiko).

Implementieren Sie eine Strategie zum Auswählen der Sprache bzw. Kultur für jede Anforderung.

Konfigurieren der Lokalisierung

Die Lokalisierung wird über die Methode Startup.ConfigureServices konfiguriert:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization fügt die Lokalisierungsdienste dem Dienstcontainer hinzu. Im obigen Codebeispiel wird der Ressourcenpfad auf „Resources“ festgelegt.

  • AddViewLocalization fügt Unterstützung für lokalisierte Ansichtsdateien hinzu. In diesem Beispiel basiert die Lokalisierung der Ansicht auf dem Suffix der Ansichtsdatei. Zum Beispiel „fr“ in der Datei Index.fr.cshtml.

  • AddDataAnnotationsLocalization fügt Unterstützung für lokalisierte DataAnnotations-Validierungsmeldungen durch Abstraktionen von IStringLocalizer hinzu.

Lokalisierungsmiddleware

Die aktuell angefragte Kultur wird in der Middleware für die Lokalisierung festgelegt. Die Middleware für die Lokalisierung wird in der Startup.Configure-Methode aktiviert. Die Lokalisierungsmiddleware muss vor Middleware konfiguriert werden, die möglicherweise die Anforderungskultur prüft (z. B. app.UseMvcWithDefaultRoute()). Lokalisierungsmiddleware muss hinter der Routing-Middleware stehen, wenn RouteDataRequestCultureProvider verwendet wird. Weitere Informationen zur Middlewarereihenfolge finden Sie unter ASP.NET Core-Middleware.

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.

UseRequestLocalization initialisiert ein RequestLocalizationOptions-Objekt. Bei jeder Anforderung wird die Liste von RequestCultureProvider in RequestLocalizationOptions aufgelistet und der erste Anbieter, der erfolgreich die Anforderungskultur bestimmen kann, wird verwendet. Die Standardanbieter stammen aus der Klasse RequestLocalizationOptions:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

Die Reihenfolge der Standardliste fängt bei den spezifischsten Anbietern an und endet mit den allgemeinsten. Im Verlauf des Artikels erfahren Sie, wie Sie die Reihenfolge ändern und einen benutzerdefinierten Kulturanbieter hinzufügen. Wenn kein Anbieter die Anforderungskultur bestimmen kann, wird DefaultRequestCulture verwendet.

QueryStringRequestCultureProvider

Einige Apps verwenden eine Abfragezeichenfolge, um die CultureInfo festzulegen. Bei Apps, die die Ansätze cookie oder Accept-Language-Header verwenden, ist das Hinzufügen einer Abfragezeichenfolge zur URL für das Debuggen und Testen von Code nützlich. Standardmäßig ist QueryStringRequestCultureProvider als erster Lokalisierungsanbieter in der Liste RequestCultureProvider registriert. Sie übergeben die Abfragezeichenfolge-Parameter culture und ui-culture. Im folgenden Beispiel ist die spezifische Kultur (Sprache und Region) auf Spanisch/Mexiko festgelegt:

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

Wenn Sie nur eine der beiden Abfragezeichenfolgen (culture oder ui-culture) übergeben, setzt der Anbieter für Abfragezeichenfolgen beide Werte entsprechend der übergebenen Abfrage fest. Wenn beispielsweise nur die Kultur festgelegt wird, werden sowohl Culture als auch UICulture wie folgt festgelegt:

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

Produktions-Apps bieten oft einen Mechanismus zum Festlegen der Kultur mithilfe des ASP.NET Core-Kulturcookies. Verwenden Sie die Methode MakeCookieValue zum Erstellen eines cookies.

CookieRequestCultureProvider DefaultCookieName gibt den Standardcookienamen zurück, mit dem ermittelt wird, welche Kulturinformationen der Benutzer bevorzugt. Der Standardcookiename lautet .AspNetCore.Culture.

Das cookieformat ist c=%LANGCODE%|uic=%LANGCODE%, wobei c für Culture steht und uic für UICulture, zum Beispiel:

c=en-UK|uic=en-US

Wenn Sie nur eine Kulturinformation und eine Benutzeroberflächenkultur angeben, wird die angegebene Kultur sowohl für die Kulturinformation als auch die Benutzeroberflächenkultur verwendet.

Der Accept-Language-HTTP-Header

Der Accept-Language-Header ist in den meisten Browsern konfigurierbar und war ursprünglich dafür gedacht, die Sprache des Benutzers anzugeben. Diese Einstellung gibt an, was im Browser zum Senden festgelegt ist oder vom zugrunde liegenden Betriebssystem geerbt wurde. Der Accept-Language-HTTP-Header einer Browseranfrage ist keine unfehlbare Methode zum Erkennen der bevorzugten Sprache des Benutzers (siehe Setting language preferences in a browser (Festlegen der bevorzugten Sprache in einem Browser)). In einer Produktions-App sollten Benutzer die Möglichkeit haben, ihre bevorzugte Kultur anzupassen.

Festlegen des Accept-Language-HTTP-Headers in Internet Explorer

  1. Klicken Sie auf das Zahnradsymbol und dann auf Internetoptionen.

  2. Klicken Sie auf Sprachen.

    Internetoptionen

  3. Klicken Sie auf Spracheinstellungen festlegen.

  4. Klicken Sie auf Sprache hinzufügen.

  5. Fügen Sie die Sprache hinzu.

  6. Klicken Sie auf die Sprache und dann auf Nach oben.

Verwenden eines benutzerdefinierten Anbieters

Angenommen, Sie möchten Ihren Kunden das Speichern ihrer Sprache und Kultur in Ihren Datenbanken ermöglichen. In diesem Fall können Sie einen Anbieter codieren, der diese Werte für den Benutzer abruft. Im folgenden Codebeispiel wird veranschaulicht, wie Sie einen benutzerdefinierten Anbieter hinzufügen:

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return new ProviderCultureResult("en");
    }));
});

Verwenden Sie RequestLocalizationOptions, um Lokalisierungsanbieter hinzuzufügen oder zu entfernen.

Programmgesteuertes Festlegen der Kultur

Das Beispielprojekt Localization.StarterWeb auf GitHub enthält eine Benutzeroberfläche zum Festlegen von Culture. Die Datei Views/Shared/_SelectLanguagePartial.cshtml ermöglicht Ihnen das Auswählen der Kultur aus der Liste von unterstützten Kulturen:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Die Datei Views/Shared/_SelectLanguagePartial.cshtml wird dem Abschnitt footer der Layoutdatei hinzugefügt, damit sie für alle Ansichten verfügbar ist:

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

Die Methode SetLanguage legt das Kulturcookie fest.

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

Sie können _SelectLanguagePartial.cshtml dem Beispielcode für dieses Projekt nicht hinzufügen. Das Projekt Localization.StarterWeb auf GitHub enthält Code, der RequestLocalizationOptions durch den Container von Dependency Injection an eineRazor-Teilansicht übermittelt.

Routendaten und Abfragezeichenfolgen für die Modellbindung

Weitere Informationen finden Sie unter Globalisierungsverhalten der Routendaten und Abfragezeichenfolgen für die Modellbindung.

Begriffe für die Globalisierung und Lokalisierung

Der Lokalisierungsprozess für Ihre App erfordert ein grundlegendes Verständnis von relevanten Zeichensätzen, die häufig in der modernen Softwareentwicklung verwendet werden, und von den Problemen, die mit ihnen zusammenhängen. Obwohl alle Computer Text als Zahlen (Codes) speichern, speichern verschiedene Systeme denselben Text mit anderen Zahlen. Der Lokalisierungsprozess bezieht sich auf das Übersetzen der Benutzeroberfläche (UI) der App für eine spezifische Kultur bzw. ein bestimmtes Gebietsschema.

Lokalisierbarkeit ist ein Zwischenschritt zum Überprüfen, ob eine globalisierte App bereit für die Lokalisierung ist.

Das Format RFC 4646 für den Kulturnamen ist <languagecode2>-<country/regioncode2>, wobei <languagecode2> der Sprachcode und <country/regioncode2> der Unterkulturcode. Zum Beispiel steht es-CL für Spanisch (Chile), en-US für Englisch (USA) und en-AU für Englisch (Australien). RFC 4646 ist eine Kombination der ISO 639, bei der zwei Kleinbuchstaben den Kulturcode beschreiben, der einer Sprache zugeordnet ist, und der ISO 3166, bei der zwei Großbuchstaben den Unterkulturcode beschreiben, der einem Land oder einer Region zugeordnet ist. Weitere Informationen finden Sie unter System.Globalization.CultureInfo.

Die Internationalisierung (Internationalization) wird oft mit „I18N“ abgekürzt. Diese Abkürzung verwendet den ersten und den letzten Buchstaben und die Anzahl der dazwischen liegenden Buchstaben, 18 steht also für die Menge der Buchstaben zwischen dem ersten „I“ und dem letzten „N“. Das gleiche gilt für Globalisierung (Globalization, G11N) und Lokalisierung (Localization, L10N).

Begriffe:

  • Globalisierung (G11N): Der Prozess, durch den eine App mehrere Sprachen und Regionen unterstützen soll.
  • Lokalisierung (L10N): Der Prozess, durch den eine App auf eine Sprache und Region angepasst wird.
  • Internationalisierung (I18N): Beschreibt sowohl Globalisierung als auch Lokalisierung.
  • Kultur: Beschreibt eine Sprache und optional auch eine Region.
  • Neutrale Kultur: Eine Kultur, die eine bestimmte Sprache beschreibt, aber keine Region. (Zum Beispiel „en“, „es“)
  • Spezifische Kultur: Eine Kultur, die eine bestimmte Sprache und Region beschreibt. (Zum Beispiel „en-US“, „en-GB“, „es-CL“)
  • Übergeordnete Kultur: Eine neutrale Kultur, die eine spezifische Kultur enthält. („en“ ist z.B. die übergeordnete Kultur von „en-US“ und „en-GB“)
  • Gebietsschema: Ein Gebietsschema ist identisch mit einer Kultur.

Hinweis

Sie können unter Umständen keine Dezimaltrennzeichen in Dezimalfelder eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung Ihrer App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.

Hinweis

Web-Apps vor ASP.NET Core 3.0 schreiben ein Protokoll vom Typ LogLevel.Warning pro Anforderung, wenn die angeforderte Kultur nicht unterstützt wird. Durch die Protokollierung einer LogLevel.Warning pro Anforderung können große Protokolldateien mit redundanten Informationen entstehen. Dieses Verhalten wurde in ASP.NET 3.0 geändert. Die RequestLocalizationMiddleware schreibt ein Protokoll vom Typ LogLevel.Debug, wodurch die Größe der Produktionsprotokolle reduziert wird.

Zusätzliche Ressourcen