Bagikan melalui


Lokalisasi dalam .NET

Pelokalan adalah proses menerjemahkan sumber daya aplikasi ke dalam versi yang dilokalkan untuk setiap budaya yang akan didukung aplikasi. Anda harus melanjutkan ke langkah pelokalan hanya setelah menyelesaikan langkah tinjauan Localizability untuk memverifikasi bahwa aplikasi globalisasi siap untuk pelokalan.

Aplikasi yang siap untuk pelokalan dipisahkan menjadi dua blok konseptual: blok yang berisi semua elemen antarmuka pengguna dan blok yang berisi kode yang dapat dieksekusi. Blok antarmuka pengguna hanya berisi elemen antarmuka pengguna yang dapat dilokalkan seperti string, pesan kesalahan, kotak dialog, menu, sumber daya objek yang disematkan, dan sebagainya untuk budaya netral. Blok kode hanya berisi kode aplikasi yang akan digunakan oleh semua budaya yang didukung. Lingkungan runtime bahasa umum mendukung model sumber daya rakitan satelit yang memisahkan kode eksekusi aplikasi dari sumber dayanya. Untuk informasi selengkapnya tentang menerapkan model ini, lihat Sumber Daya di .NET.

Untuk setiap versi aplikasi yang dilokalkan, tambahkan rakitan satelit baru yang berisi blok antarmuka pengguna yang dilokalkan yang diterjemahkan ke dalam bahasa yang sesuai untuk budaya target. Blok kode untuk semua budaya harus tetap sama. Kombinasi versi blok antarmuka pengguna yang dilokalkan dengan blok kode menghasilkan versi aplikasi Anda yang dilokalkan.

Dalam artikel ini, Anda akan mempelajari cara menggunakan implementasi IStringLocalizer<T> dan IStringLocalizerFactory. Semua contoh kode sumber dalam artikel ini bergantung pada Microsoft.Extensions.Localization paket NuGet dan Microsoft.Extensions.Hosting . Untuk informasi selengkapnya tentang hosting, lihat Host Generik .NET.

File sumber daya

Mekanisme utama untuk mengisolasi string yang dapat dilokalkan adalah dengan file sumber daya. File sumber daya adalah file XML dengan ekstensi file .resx . Berkas sumber daya diterjemahkan sebelum eksekusi aplikasi yang menggunakannya—dengan kata lain, berkas tersebut mewakili konten terjemahan dalam keadaan diam. Nama file sumber daya paling umum mengandung pengidentifikasi lokal, dan mengikuti bentuk berikut:

<FullTypeName><.Locale>.resx

Lokasi:

  • <FullTypeName> mewakili sumber daya yang dapat dilokalkan untuk jenis tertentu.
  • Opsional <.Locale> mewakili lokal konten file sumber daya.

Menentukan lokalisasi

Definisi lokal harus mencakup bahasa, paling tidak, tetapi juga dapat mencakup budaya (bahasa regional), dan bahkan negara atau wilayah. Segmen-segmen ini biasanya dibatasi oleh - karakter. Dengan kekhususan budaya yang ditambahkan, aturan turunan budaya diterapkan di mana kecocokan terbaik diprioritaskan. Pengaturan lokal harus menghubungkan ke tag bahasa yang terkenal. Untuk informasi selengkapnya, lihat CultureInfo.Name .

Skenario cadangan budaya

Bayangkan bahwa aplikasi lokal Anda mendukung berbagai lokal Serbia, dan memiliki file sumber daya berikut untuk :MessageService

Arsip Bahasa regional Kode Negara
MessageService.sr-Cyrl-RS.resx (Sirilik, Serbia) RS
MessageService.sr-Cyrl.resx Sirilik
MessageService.sr-Latn-BA.resx (Latin, Bosnia & Herzegovina) Bachelor of Arts
MessageService.sr-Latn-ME.resx (Latin, Montenegro) saya
MessageService.sr-Latn-RS.resx (Latin, Serbia) RS
MessageService.sr-Latn.resx Bahasa latin
MessageService.sr.resx Bahasa latin
MessageService.resx

Bahasa wilayah default untuk bahasa tersebut.

Saat aplikasi Anda berjalan dengan CultureInfo.CurrentCulture diatur ke budaya "sr-Cyrl-RS" pelokalan mencoba menyelesaikan file dalam urutan berikut:

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

Namun, ketika aplikasi Anda berjalan dengan CultureInfo.CurrentCulture diatur ke pengaturan budaya "sr-Latn-BA", pelokalan mencoba menyelesaikan file dalam urutan berikut:

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

Aturan "culture fallback" akan mengabaikan lokal ketika tidak ada kecocokan yang sesuai, yang berarti sistem akan memilih file sumber daya keempat jika tidak dapat menemukan kecocokan. Jika budaya diatur ke "fr-FR", pelokalan akhirnya akan jatuh ke file MessageService.resx yang dapat bermasalah. Untuk informasi selengkapnya, lihat Proses pencadangan sumber daya.

Pencarian sumber daya

File sumber daya secara otomatis diselesaikan sebagai bagian dari rutinitas pencarian. Jika nama file proyek Anda berbeda dari namespace akar proyek, nama rakitan mungkin berbeda. Ini dapat mencegah pencarian sumber daya yang seharusnya berhasil. Untuk mengatasi ketidakcocokan ini, gunakan RootNamespaceAttribute untuk memberikan petunjuk ke layanan pelokalan. Saat disediakan, ini digunakan selama pencarian sumber daya.

Contoh proyek diberi nama example.csproj, yang membuat example.dll dan example.exe—namun, Localization.Example namespace digunakan. assembly Terapkan atribut tingkat untuk memperbaiki ketidakcocokan ini:

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

Mendaftarkan layanan lokalisasi

Untuk mengaktifkan layanan pelokalan, panggil salah satu metode ekstensi AddLocalization selama konfigurasi layanan. Ini akan mengaktifkan injeksi dependensi (DI) dari jenis berikut:

Mengatur opsi pelokalan

Penggunaan berlebih AddLocalization(IServiceCollection, Action<LocalizationOptions>) menerima parameter jenis setupAction dari tipe Action<LocalizationOptions>. Ini memungkinkan Anda untuk mengonfigurasi opsi pelokalan.

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

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

// Omitted for brevity.

File sumber daya dapat hidup di mana saja dalam proyek, tetapi ada praktik umum yang terbukti berhasil. Lebih sering daripada tidak, jalur resistensi paling sedikit diikuti. Kode C# sebelumnya:

  • Membuat aplikasi host dengan konfigurasi bawaan.
  • Panggilan AddLocalization pada koleksi layanan, dengan menentukan LocalizationOptions.ResourcesPath sebagai "Resources".

Ini akan menyebabkan layanan pelokalan mencari di direktori Sumber Daya untuk berkas sumber daya.

Gunakan IStringLocalizer<T> dan IStringLocalizerFactory

Setelah mendaftar ( dan secara opsional mengonfigurasi) layanan pelokalan, Anda dapat menggunakan jenis berikut dengan DI:

Untuk membuat layanan pesan yang mampu mengembalikan string yang dilokalkan, pertimbangkan hal berikut MessageService:

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public sealed class MessageService(IStringLocalizer<MessageService> localizer)
{
    [return: NotNullIfNotNull(nameof(localizer))]
    public string? GetGreetingMessage()
    {
        LocalizedString localizedString = localizer["GreetingMessage"];

        return localizedString;
    }
}

Dalam kode C# sebelumnya:

  • Bidang IStringLocalizer<MessageService> localizer dideklarasikan.
  • Konstruktor utama mendefinisikan IStringLocalizer<MessageService> parameter dan menangkapnya sebagai localizer argumen.
  • Metode GetGreetingMessage memanggil IStringLocalizer.Item[String] dengan meneruskan "GreetingMessage" sebagai argumen.

juga IStringLocalizer mendukung sumber daya string berparameter, pertimbangkan hal berikut ParameterizedMessageService:

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public class ParameterizedMessageService(IStringLocalizerFactory factory)
{
    private readonly IStringLocalizer _localizer =
        factory.Create(typeof(ParameterizedMessageService));

    [return: NotNullIfNotNull(nameof(_localizer))]
    public string? GetFormattedMessage(DateTime dateTime, double dinnerPrice)
    {
        LocalizedString localizedString = _localizer["DinnerPriceFormat", dateTime, dinnerPrice];

        return localizedString;
    }
}

Dalam kode C# sebelumnya:

  • Bidang IStringLocalizer _localizer dideklarasikan.
  • Konstruktor utama mengambil IStringLocalizerFactory parameter, yang digunakan untuk membuat IStringLocalizer dari jenis ParameterizedMessageService, dan menetapkannya ke bidang _localizer.
  • Metode GetFormattedMessage memanggil IStringLocalizer.Item[String, Object[]], dengan meneruskan "DinnerPriceFormat", sebuah objek dateTime, dan dinnerPrice sebagai argumen.

Penting

IStringLocalizerFactory Tidak diperlukan. Sebaliknya, lebih diutamakan agar layanan yang mengonsumsi memerlukan IStringLocalizer<T>.

Kedua IStringLocalizer.Item[] pengindeks mengembalikan LocalizedString, yang memiliki konversi implisit ke string?.

Satukan semuanya

Untuk mencontohkan aplikasi menggunakan layanan pesan, bersama dengan pelokalan dan file sumber daya, pertimbangkan file Program.cs berikut:

using System.Globalization;
using Localization.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using static System.Console;
using static System.Text.Encoding;

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

OutputEncoding = Unicode;

if (args is [var cultureName])
{
    CultureInfo.CurrentCulture =
        CultureInfo.CurrentUICulture =
            CultureInfo.GetCultureInfo(cultureName);
}

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization();
builder.Services.AddTransient<MessageService>();
builder.Services.AddTransient<ParameterizedMessageService>();
builder.Logging.SetMinimumLevel(LogLevel.Warning);

using IHost host = builder.Build();

IServiceProvider services = host.Services;

ILogger logger =
    services.GetRequiredService<ILoggerFactory>()
        .CreateLogger("Localization.Example");

MessageService messageService =
    services.GetRequiredService<MessageService>();
logger.LogWarning(
    "{Msg}",
    messageService.GetGreetingMessage());

ParameterizedMessageService parameterizedMessageService =
    services.GetRequiredService<ParameterizedMessageService>();
logger.LogWarning(
    "{Msg}",
    parameterizedMessageService.GetFormattedMessage(
        DateTime.Today.AddDays(-3), 37.63));

await host.RunAsync();

Dalam kode C# sebelumnya:

  • RootNamespaceAttribute mengatur "Localization.Example" sebagai ruang nama akar.
  • Console.OutputEncoding diberikan kepada Encoding.Unicode.
  • Ketika argumen tunggal diteruskan ke args, CultureInfo.CurrentCulture dan CultureInfo.CurrentUICulture diberi hasil dari CultureInfo.GetCultureInfo(String) diberikan arg[0].
  • Host dibuat dengan default.
  • Layanan lokalisasi, MessageService, dan ParameterizedMessageService didaftarkan ke IServiceCollection untuk keperluan DI.
  • Untuk menghapus kebisingan, pengelogan dikonfigurasi untuk mengabaikan tingkat log apa pun yang lebih rendah dari peringatan.
  • MessageService diselesaikan dari instance IServiceProvider dan pesan yang dihasilkan dicatat.
  • ParameterizedMessageService diselesaikan dari IServiceProvider instans dan pesan berformat yang dihasilkan dicatat.

*MessageService Masing-masing kelas mendefinisikan satu set file .resx, masing-masing dengan satu entri. Berikut adalah contoh konten untuk MessageService file sumber daya, dimulai dengan MessageService.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Hi friends, the ".NET" developer community is excited to see you here!</value>
  </data>
</root>

MessageService.sr-Cyrl-RS.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!</value>
  </data>
</root>

MessageService.sr-Latn.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!</value>
  </data>
</root>

Berikut adalah contoh konten untuk ParameterizedMessageService file sumber daya, dimulai dengan ParameterizedMessageService.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>On {0:D} my dinner cost {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Cyrl-RS.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>У {0:D} моја вечера је коштала {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Latn.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>U {0:D} moja večera je koštala {1:C}.</value>
  </data>
</root>

Petunjuk / Saran

Semua komentar XML, skema, dan elemen <resheader> file sumber daya sengaja dihilangkan demi ringkasnya.

Contoh pelaksanaan

Contoh pengoperasian berikut menunjukkan berbagai output yang dilokalkan untuk lokal yang ditargetkan.

Pertimbangkan "sr-Latn":

dotnet run --project .\example\example.csproj sr-Latn

warn: Localization.Example[0]
      Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!
warn: Localization.Example[0]
      U utorak, 03. avgust 2021. moja večera je koštala 37,63 ¤.

Saat menghilangkan argumen ke .NET CLI untuk menjalankan proyek, budaya sistem default digunakan—dalam hal "en-US"ini :

dotnet run --project .\example\example.csproj

warn: Localization.Example[0]
      Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
      On Tuesday, August 3, 2021 my dinner cost $37.63.

Saat meneruskan "sr-Cryl-RS", file sumber daya yang sesuai yang benar ditemukan dan pelokalan diterapkan:

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

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

Aplikasi sampel tidak menyediakan file sumber daya untuk "fr-CA", tetapi ketika dipanggil dengan budaya tersebut, file sumber daya yang tidak dilokalkan digunakan.

Peringatan

Karena budaya telah ditemukan tetapi file sumber daya yang benar tidak ditemukan, ketika pemformatan diterapkan, Anda akhirnya mendapatkan pelokalan yang parsial.

dotnet run --project .\example\example.csproj fr-CA

warn: Localization.Example[0]
     Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
     On mardi 3 août 2021 my dinner cost 37,63 $.

Lihat juga