ASP.NET i18n Assembly | Localization Architektur Guide

ASP.NET i18n in Assemblies: Skalierbare Architektur für mehrsprachige Projekte
Maurice J. | Softwareentwickler
10/2020

Auslagerung von Ressourcen in separate Assemblys

ASP.NET Core als Basis

Der Artikel „Mehrsprachigkeit in ASP.NET Core“, der für diesen Blog als Grundlage dient, befasst sich mit der Implementierung von Mehrsprachigkeit in einer ASP.NET Core Anwendung. In diesem Artikel soll die Implementierung in einer separaten Assembly aufgezeigt werden.

Im vorangegangenen Beispiel befinden sich die Ressourcendateien in der gleichen Assembly wie die Web-Anwendung. Bei größeren Projekten ist es jedoch hilfreich, die Ressourcen in eine separate Assembly auszulagern.

Projektaufteilung

Zunächst wird das vorhandene Projekt aus dem Artikel „Mehrsprachigkeit in ASP.NET Core“ in 3 Projekte aufgeteilt: Web, Models und Ressourcen.

Das aktuelle Projekt erhält die Benennung Mehrsprachigkeit.Web. Die beiden neuen Projekte heißen entsprechend Mehrsprachigkeit.Models und Mehrsprachigkeit.Resources.

Der Models-Ordner wird in das neue Projekt Mehrsprachigkeit.Models und der Ressourcen-Ordner in das Projekt Mehrsprachigkeit.Resources verschoben. Für jede Ressource legen wir eine gleichnamige Public-Klasse an. Bereits beim Entwurf einer Anwendung sollte demnach gut überlegt sein, inwiefern einheitliche oder verschiedene Ressourcendateien eingepflegt werden sollen. Die Ressource „Contact“ wurde in „Models“ umbenannt und auf die oberste Ebene im Ressourcenordner verschoben.

Klassendefinition

Anschließend wird im Projekt „Resources“ folgende Klasse hinzugefügt:

1public class LocService<T>
2{
3    private readonly IStringLocalizer _localizer;
4
5    public LocService(IStringLocalizerFactory factory)
6    {
7        Type type = typeof(T);
8        var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
9
10        var myRelativePath = String.Join(".", type.Namespace.Split('.').Skip(2));
11        if (myRelativePath.Length > 0)
12            myRelativePath += ".";
13
14        _localizer = factory.Create(myRelativePath + type.Name, assemblyName.Name);
15    }
16
17    public LocalizedString GetLocalizedHtmlString(string key)
18    {
19        if (_localizer != null)
20            return _localizer[key];
21        else
22            return new LocalizedString(key, key);
23    }
24}

Diese Klasse wird im Controller und in der View verwendet, um anschließend die richtige Assembly und die richtige Ressource auszuwählen.

ConfigureServices

Wenn mit der Methode ConfigureServices aus der Klasse Startup.cs gearbeitet wird, müssen folgende Änderungen vorgenommen werden, damit die Ressourcen ebenfalls in der anderen Assembly gefunden werden können.

1public void ConfigureServices(IServiceCollection services)
2{
3    services.AddSingleton<LocService<Mehrsprachigkeit.Resources.Resources.Views.Home.Index>>();
4    services.AddSingleton<LocService<Mehrsprachigkeit.Resources.Resources.Controllers.HomeController>>();
5
6    services.AddControllersWithViews();
7    services.AddLocalization();
8    services.AddMvc()
9    .AddViewLocalization()
10    .AddDataAnnotationsLocalization(options =>
11    {
12        options.DataAnnotationLocalizerProvider = (type, factory) =>
13        {
14            var assemblyName = new AssemblyName(
15                typeof(Mehrsprachigkeit.Resources.Resources.Models)
16                .GetTypeInfo().Assembly.FullName);
17            return factory.Create("Resources.Models", assemblyName.Name);
18        };
19    });
20
21    services.Configure<RequestLocalizationOptions>(opts =>
22    {
23        var supportedCultures = new List<CultureInfo> {
24            new CultureInfo("de-DE"),
25            new CultureInfo("en-GB"),
26        };
27
28        opts.DefaultRequestCulture = new RequestCulture("de-DE");
29        opts.SupportedCultures = supportedCultures;
30        opts.SupportedUICultures = supportedCultures;
31    });
32}

Nun fügt man die LocService-Klasse per Dependency Injection im HomeController und in der Index View hinzu und ändert den Aufruf der StringLocalizer-Klasse mit der neuen Methode GetLocalizedHtmlString.

1public class HomeController : Controller
2{
3    private readonly LocService<Mehrsprachigkeit.Resources.Resources.Controllers.HomeController> _localizer;
4
5    public HomeController(LocService<Mehrsprachigkeit.Resources.Resources.Controllers.HomeController> localizer)
6    {
7        _localizer = localizer;
8    }
9
10    public IActionResult Index()
11    {
12        ViewData["Title"] = _localizer.GetLocalizedHtmlString("Hallo Welt vom Controller");
13        return View();
14    }
15}
16@using Microsoft.AspNetCore.Mvc.Localization
17@model Mehrsprachigkeit.Models.Models.Contact
18
19@inject Mehrsprachigkeit.Resources.LocService<Mehrsprachigkeit.Resources.Resources.Views.Home.Index> AccountLocalizer
20
21<h1>@ViewData["Title"]</h1>
22<h3 class="text-danger">@AccountLocalizer.GetLocalizedHtmlString("Hallo Welt von der View")</h3>
23
24@Html.LabelFor(c => c.Firstname)
25@Html.LabelFor(c => c.Lastname)

Nun wurden die Ressourcen erfolgreich in eine andere Assembly verschoben und der Aufruf der Lokalisierung entsprechend angepasst, sodass die Ressourcen in der anderen Assembly gefunden werden können.

Das Ergebnis

Die Mehrsprachigkeit in einem Projekt ohne verschiedene Assemblys ist relativ einfach zu realisieren. Sobald die Ressourcen jedoch in einer separaten Assembly programmiert werden sollen, erhöht sich die Komplexität deutlich. Wichtig ist hierbei, von Beginn an strategisch zu entscheiden, ob für jedes DataModel eine eigene Ressource angelegt werden soll oder ob eine einheitliche Ressource verwendet wird. Letzteres ist einfacher umzusetzen und wurde in diesem Blogartikel angewendet.

Expertentipp: Ohne eine zusätzliche Klasse wie LocService ist eine separate Assembly vermutlich nicht umsetzbar.

Mehr zum Thema

Pfeil nach rechts (Verlinkung)
NWB Plattform: Digitale Workflows & Rechtemanagement für Verlagsbranche
03/2025

NWB Vertragsplattform | Digitales Dokumentenmanagement

Pfeil nach rechts (Verlinkung)
Liskov Principle: Schnittstellenfehler & Sicherheitslücken vermeiden
12/2024

Solid Reihe - Liskov Substitution Principle

Pfeil nach rechts (Verlinkung)
Open/Closed Principle: Erweiterbare Software dank klarer Struktur
11/2024

Solid Reihe - Open Close Principle

Pfeil nach rechts (Verlinkung)
Clean Code in C#: Strukturierter, verständlicher und wartbarer Code
11/2024

Clean Code Prinzipien | Lesbarer C# Code Tutorial

Pfeil nach rechts (Verlinkung)

Gemeinsam Großes schaffen

Devware GmbH verpflichtet sich, Ihre Privatsphäre zu schützen. Wir benötigen Ihre Kontaktinformationen, um Sie bezüglich unserer Produkte und Dienstleistungen zu kontaktieren. Mit Klick auf Absenden geben Sie sich damit einverstanden. Weitere Informationen finden Sie unter Datenschutz.
Vielen Dank für Ihr Vertrauen.
Unser Team prüft Ihre Anfrage sorgfältig und meldet sich in der Regel innerhalb von 48 Stunden bei Ihnen zurück.
Falls es besonders eilig ist, erreichen Sie uns auch telefonisch:
+ 49 (0) 202 478 269 0.
Da ist etwas schief gegangen beim Absenden des Formulars.