Membuat konten aplikasi ASP.NET Core dapat dilokalkan

Oleh Hisham Bin Ateya, Damien Bowden, Bart Calixto dan Nadeem Afana

Salah satu tugas untuk melokalisasi aplikasi adalah membungkus konten yang dapat dilokalkan dengan kode yang memfasilitasi penggantian konten tersebut untuk budaya yang berbeda.

IStringLocalizer

IStringLocalizer dan IStringLocalizer<T> dirancang untuk meningkatkan produktivitas saat mengembangkan aplikasi yang dilokalkan. IStringLocalizerResourceManager menggunakan dan ResourceReader untuk menyediakan sumber daya khusus budaya pada waktu proses. Antarmuka memiliki pengindeks dan IEnumerable untuk mengembalikan string yang dilokalkan. IStringLocalizer tidak memerlukan penyimpanan string bahasa default dalam file sumber daya. Anda dapat mengembangkan aplikasi yang ditargetkan untuk pelokalan dan tidak perlu membuat file sumber daya di awal pengembangan.

Contoh kode berikut menunjukkan cara membungkus string "Tentang Judul" untuk pelokalan.

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"];
    }
}

Dalam kode sebelumnya, IStringLocalizer<T> implementasi berasal dari Injeksi Dependensi. Jika nilai "Tentang Judul" yang dilokalkan tidak ditemukan, maka kunci pengindeks dikembalikan, yaitu, string "Tentang Judul".

Anda dapat meninggalkan string literal bahasa default di aplikasi dan membungkusnya di localizer, sehingga Anda dapat fokus pada pengembangan aplikasi. Anda mengembangkan aplikasi dengan bahasa default Anda dan menyiapkannya untuk langkah pelokalan tanpa terlebih dahulu membuat file sumber daya default.

Atau, Anda dapat menggunakan pendekatan tradisional dan menyediakan kunci untuk mengambil string bahasa default. Bagi banyak pengembang, alur kerja baru tidak memiliki file .resx bahasa default dan hanya membungkus literal string dapat mengurangi overhead pelokalan aplikasi. Pengembang lain lebih suka alur kerja tradisional karena dapat lebih mudah untuk bekerja dengan literal string panjang dan lebih mudah untuk memperbarui string yang dilokalkan.

IHtmlLocalizer

IHtmlLocalizer<TResource> Gunakan implementasi untuk sumber daya yang berisi HTML. IHtmlLocalizer Argumen pengodean HTML yang diformat dalam string sumber daya, tetapi tidak mengodekan html string sumber daya itu sendiri. Dalam kode yang disorot berikut, hanya nilai parameter yang name dikodekan HTML.

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();
    }

CATATAN: Umumnya, hanya melokalisasi teks, bukan HTML.

IStringLocalizerFactory

Pada tingkat terendah, IStringLocalizerFactory dapat diambil dari Injeksi Dependensi:

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."];

        return View();
    }

Kode sebelumnya menunjukkan masing-masing dari dua metode pembuatan pabrik.

Sumber Daya Bersama

Anda dapat mempartisi string yang dilokalkan berdasarkan pengontrol atau area, atau hanya memiliki satu kontainer. Di aplikasi sampel, kelas penanda bernama SharedResource digunakan untuk sumber daya bersama. Kelas penanda tidak pernah disebut:

// Dummy class to group shared resources

namespace Localization;

public class SharedResource
{
}

Dalam sampel berikut, InfoController dan SharedResource localizer digunakan:

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;
    }

Lihat pelokalan

Layanan ini IViewLocalizer menyediakan string yang dilokalkan untuk tampilan. Kelas ViewLocalizer mengimplementasikan antarmuka ini dan menemukan lokasi sumber daya dari jalur file tampilan. Kode berikut menunjukkan cara menggunakan implementasi default dari IViewLocalizer:

@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>

Implementasi IViewLocalizer default menemukan file sumber daya berdasarkan nama file tampilan. Tidak ada opsi untuk menggunakan file sumber daya bersama global. ViewLocalizer mengimplementasikan localizer menggunakan IHtmlLocalizer, jadi Razor tidak mengodekan HTML string yang dilokalkan. Anda dapat membuat parameter string sumber daya, dan IViewLocalizer mengodekan html parameter tetapi bukan string sumber daya. Pertimbangkan markup berikut Razor :

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

File sumber daya Prancis dapat berisi nilai berikut:

Tombol Nilai
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

Tampilan yang dirender akan berisi markup HTML dari file sumber daya.

Umumnya, hanya melokalisasi teks, bukan HTML.

Untuk menggunakan file sumber daya bersama dalam tampilan, masukkan IHtmlLocalizer<T>:

@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>

Pelokalan DataAnnotasi

Pesan kesalahan DataAnnotations dilokalkan dengan IStringLocalizer<T>. Menggunakan opsi ResourcesPath = "Resources", pesan kesalahan di RegisterViewModel dapat disimpan di salah satu jalur berikut:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
using System.ComponentModel.DataAnnotations;

namespace Localization.ViewModels.Account;

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; }
}

Atribut non-validasi dilokalkan.

Cara menggunakan satu string sumber daya untuk beberapa kelas

Kode berikut menunjukkan cara menggunakan satu string sumber daya untuk atribut validasi dengan beberapa kelas:

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

Dalam kode sebelumnya, SharedResource adalah kelas yang sesuai dengan file .resx tempat pesan validasi disimpan. Dengan pendekatan ini, DataAnnotations hanya menggunakan SharedResource, daripada sumber daya untuk setiap kelas.

Mengonfigurasi layanan pelokalan

Layanan pelokalan dikonfigurasi dalam Program.cs:

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

builder.Services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization menambahkan layanan pelokalan ke kontainer layanan, termasuk implementasi untuk IStringLocalizer<T> dan IStringLocalizerFactory. Kode sebelumnya juga mengatur jalur sumber daya ke "Sumber Daya".

  • AddViewLocalization menambahkan dukungan untuk file tampilan yang dilokalkan. Dalam sampel ini, pelokalan tampilan didasarkan pada akhiran file tampilan. Misalnya "fr" dalam Index.fr.cshtml file.

  • AddDataAnnotationsLocalization menambahkan dukungan untuk pesan validasi yang dilokalkan DataAnnotations melalui IStringLocalizer abstraksi.

Catatan

Anda mungkin tidak dapat memasukkan koma desimal di bidang desimal. Untuk mendukung validasi jQuery untuk lokal non-Bahasa Inggris yang menggunakan koma (",") untuk format tanggal desimal, dan non-Bahasa Inggris AS, Anda harus mengambil langkah-langkah untuk meng globalisasi aplikasi Anda. Lihat komentar GitHub 4076 ini untuk instruksi tentang menambahkan koma desimal.

Langkah berikutnya

Melokalisasi aplikasi juga melibatkan tugas-tugas berikut:

Sumber Daya Tambahan:

Oleh Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, dan Hisham Bin Ateya

Salah satu tugas untuk melokalisasi aplikasi adalah membungkus konten yang dapat dilokalkan dengan kode yang memfasilitasi penggantian konten tersebut untuk budaya yang berbeda.

IStringLocalizer

IStringLocalizer dan IStringLocalizer<T> dirancang untuk meningkatkan produktivitas saat mengembangkan aplikasi yang dilokalkan. IStringLocalizerResourceManager menggunakan dan ResourceReader untuk menyediakan sumber daya khusus budaya pada waktu proses. Antarmuka memiliki pengindeks dan IEnumerable untuk mengembalikan string yang dilokalkan. IStringLocalizer tidak memerlukan penyimpanan string bahasa default dalam file sumber daya. Anda dapat mengembangkan aplikasi yang ditargetkan untuk pelokalan dan tidak perlu membuat file sumber daya di awal pengembangan.

Contoh kode berikut menunjukkan cara membungkus string "Tentang Judul" untuk pelokalan.

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"];
        }
    }
}

Dalam kode sebelumnya, IStringLocalizer<T> implementasi berasal dari Injeksi Dependensi. Jika nilai "Tentang Judul" yang dilokalkan tidak ditemukan, maka kunci pengindeks dikembalikan, yaitu, string "Tentang Judul".

Anda dapat meninggalkan string literal bahasa default di aplikasi dan membungkusnya di localizer, sehingga Anda dapat fokus pada pengembangan aplikasi. Anda mengembangkan aplikasi dengan bahasa default Anda dan menyiapkannya untuk langkah pelokalan tanpa terlebih dahulu membuat file sumber daya default.

Atau, Anda dapat menggunakan pendekatan tradisional dan menyediakan kunci untuk mengambil string bahasa default. Bagi banyak pengembang, alur kerja baru tidak memiliki file .resx bahasa default dan hanya membungkus literal string dapat mengurangi overhead pelokalan aplikasi. Pengembang lain lebih suka alur kerja tradisional karena dapat lebih mudah untuk bekerja dengan literal string panjang dan lebih mudah untuk memperbarui string yang dilokalkan.

IHtmlLocalizer

IHtmlLocalizer<T> Gunakan implementasi untuk sumber daya yang berisi HTML. IHtmlLocalizer Argumen pengodean HTML yang diformat dalam string sumber daya, tetapi tidak mengodekan html string sumber daya itu sendiri. Dalam kode yang disorot berikut, hanya nilai parameter yang name dikodekan HTML.

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();
        }

Catatan

Umumnya, hanya melokalisasi teks, bukan HTML.

IStringLocalizerFactory

Pada tingkat terendah, Anda bisa keluar IStringLocalizerFactory dari Injeksi Dependensi:

{
    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."];

Kode sebelumnya menunjukkan masing-masing dari dua metode pembuatan pabrik.

Sumber Daya Bersama

Anda dapat mempartisi string yang dilokalkan berdasarkan pengontrol atau area, atau hanya memiliki satu kontainer. Di aplikasi sampel, kelas dummy bernama SharedResource digunakan untuk sumber daya bersama.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Beberapa pengembang menggunakan Startup kelas untuk berisi string global atau bersama. Dalam sampel berikut, InfoController dan SharedResource localizer digunakan:

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;
    }

Lihat pelokalan

Layanan ini IViewLocalizer menyediakan string yang dilokalkan untuk tampilan. Kelas ViewLocalizer mengimplementasikan antarmuka ini dan menemukan lokasi sumber daya dari jalur file tampilan. Kode berikut menunjukkan cara menggunakan implementasi default dari IViewLocalizer:

@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>

Implementasi IViewLocalizer default menemukan file sumber daya berdasarkan nama file tampilan. Tidak ada opsi untuk menggunakan file sumber daya bersama global. ViewLocalizer mengimplementasikan localizer menggunakan IHtmlLocalizer, jadi Razor tidak mengodekan HTML string yang dilokalkan. Anda dapat membuat parameter string sumber daya, dan IViewLocalizer mengodekan html parameter tetapi bukan string sumber daya. Pertimbangkan markup berikut Razor :

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

File sumber daya Prancis dapat berisi nilai berikut:

Tombol Nilai
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

Tampilan yang dirender akan berisi markup HTML dari file sumber daya.

Catatan

Umumnya, hanya melokalisasi teks, bukan HTML.

Untuk menggunakan file sumber daya bersama dalam tampilan, masukkan IHtmlLocalizer<T>:

@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>

Pelokalan DataAnnotasi

Pesan kesalahan DataAnnotations dilokalkan dengan IStringLocalizer<T>. Menggunakan opsi ResourcesPath = "Resources", pesan kesalahan di RegisterViewModel dapat disimpan di salah satu jalur berikut:

  • 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; }
}

Dalam ASP.NET Core MVC 1.1.0 dan yang lebih baru, atribut non-validasi dilokalkan.

Cara menggunakan satu string sumber daya untuk beberapa kelas

Kode berikut menunjukkan cara menggunakan satu string sumber daya untuk atribut validasi dengan beberapa kelas:

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

Dalam kode sebelumnya, SharedResource adalah kelas yang sesuai dengan file .resx tempat pesan validasi disimpan. Dengan pendekatan ini, DataAnnotations hanya menggunakan SharedResource, daripada sumber daya untuk setiap kelas.

Mengonfigurasi layanan pelokalan

Layanan pelokalan dikonfigurasi dalam Startup.ConfigureServices metode :

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

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization menambahkan layanan pelokalan ke kontainer layanan, termasuk implementasi untuk IStringLocalizer<T> dan IStringLocalizerFactory. Kode sebelumnya juga mengatur jalur sumber daya ke "Sumber Daya".

  • AddViewLocalization menambahkan dukungan untuk file tampilan yang dilokalkan. Dalam sampel ini, pelokalan tampilan didasarkan pada akhiran file tampilan. Misalnya "fr" dalam Index.fr.cshtml file.

  • AddDataAnnotationsLocalization menambahkan dukungan untuk pesan validasi yang dilokalkan DataAnnotations melalui IStringLocalizer abstraksi.

Catatan

Anda mungkin tidak dapat memasukkan koma desimal di bidang desimal. Untuk mendukung validasi jQuery untuk lokal non-Bahasa Inggris yang menggunakan koma (",") untuk format tanggal desimal, dan non-Bahasa Inggris AS, Anda harus mengambil langkah-langkah untuk meng globalisasi aplikasi Anda. Lihat komentar GitHub 4076 ini untuk instruksi tentang menambahkan koma desimal.

Langkah berikutnya

Melokalisasi aplikasi juga melibatkan tugas-tugas berikut:

Sumber Daya Tambahan: