Xaki is a .NET library for adding multi-language support to POCO classes. It includes a lightweight service for persisting and retrieving data to and from databases using any ORM.
Xaki works well with all versions of Entity Framework and includes ASP.NET Core support for automatic localization to language codes provided by routes, querystrings, cookies, and HTTP headers.
Setting up classes to be multi-language starts by implementing ILocalizable
and adding LocalizedAttribute
to multi-language properties:
public class Planet : ILocalizable
{
public int PlanetId { get; set; }
[Localized]
public string Name { get; set; }
}
Internally multi-language content is stored as serialized JSON:
planet.Name = "{'en':'Earth','ru':'Земля́','ja':'地球'}";
To localize a list, say pulled from a database with Entity Framework, you can use the provided IObjectLocalizer.Localize<T>()
method:
[HttpGet]
public async Task<IActionResult> Index()
{
var planets = await _context.Planets.ToListAsync();
planets = _localizer.Localize<Planet>(planets).ToList();
return View(planets);
}
For ASP.NET Core projects you'll add the Xaki and Xaki.AspNetCore NuGet packages to your project. While these packages are beta you'll install from MyGet:
Install-Package Xaki.AspNetCore
dotnet add package Xaki.AspNetCore
You may also want to add the NuGet feed above to your nuget.config file at the root of your solution:
Xaki follows the usual pattern to add and configure services in an ASP.NET Core host, to add Xaki and request localization update Startup.cs
to include:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddMvc().AddXaki(new XakiOptions
{
RequiredLanguages = new[] { "en", "zh", "ar", "es", "hi" },
OptionalLanguages = new[] { "pt", "ru", "ja", "de", "el" }
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseXaki(); // must precede UseMvc()
app.UseMvc();
}
For a sample ASP.NET Core app see https://github.com/mehalick/Xaki/tree/master/samples/Xaki.Sample.
Any Entity Framework POCO can be localizable by implementing ILocalizable
with one or more properties decorated with LocalizedAttribute
:
public class Planet : ILocalizable
{
public int PlanetId { get; set; }
[Localized]
public string Name { get; set; }
}
Similar to ASP.NET Core's IStringLocalizer
and IHtmlLocalizer
you can localize objects and collections with IObjectLocalizer
, simply add it to any controller:
[Route("planets")]
public class PlanetsController : Controller
{
private readonly DataContext _context;
private readonly IObjectLocalizer _localizer;
public PlanetsController(DataContext context, IObjectLocalizer localizer)
{
_context = context;
_localizer = localizer;
}
}
You can now fetch entities and send the localized versions to your views:
[HttpGet]
public async Task<IActionResult> Index()
{
var planets = await _context.Planets.ToListAsync();
planets = _localizer.Localize<Planet>(planets).ToList();
return View(planets);
}
IObjectLocalizer
uses ASP.NET Core's RequestLocalizationMiddleware
to resolve the current language and culture using:
- Querystrings
- Cookies
- Accept-Language Header
For more information see https://andrewlock.net/adding-localisation-to-an-asp-net-core-application/.
If you'd like to customize how IObjectLocalizer
resolves languages you can create your own resolver by implementing Xaki.AspNetCore.LanguageResolvers.ILanguageResolver
.
The Xaki.AspNetCore library includes a tag helper and model binder to make edit views and actions extremely simple.
To convert any input into a rich localization editor simply replace <input for="Name" />
with <input localized-for="Name" />
:
<form asp-action="Edit">
<input asp-for="PlanetId" type="hidden" />
<div class="form-group">
<label>Name</label>
<input localized-for="Name" />
</div>
<button type="submit" class="btn btn-dark">Submit</button>
</form>
You'll automatically get a rich localization editor:
The editor automatically lists the individual language textboxes in the order they are specified in Startup.cs
and client-side validation is included:
The Xaki.AspNetCore library includes LocalizableModelBinder
which is automatically registered via services.AddMvc().AddXaki()
.
This allows the localization tag helper to correctly model bind to ILocalized
entities and view models in your actions:
[HttpPost("{planetId:int}")]
public async Task<IActionResult> Edit(Planet planet)
{
_context.Entry(planet).State = EntityState.Modified;
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Here your localized properties are automatically bound: