Ana içeriğe atla

Çok Dilli Yapılandırma


Çoğu web uygulamasının çeşitli dilleri desteklemesi gerekir. Youtube ve Wikipedia gibi siteler birçok dilde çalışmaktadır.

Bir kullanıcı böyle bir siteyi ilk kez ziyaret ettiğinde, genellikle işletim sistemi dili ve bölgesel ayarlar tarafından belirlenen tarayıcı dili ayarına bağlı olarak kendisi için bir dil otomatik olarak seçilir.

Otomatik seçim bekledikleri sonucu vermezse, kullanıcılar tercih ettikleri dili ayarlayabilir ve bu seçim, istemci tarafı çerezinde veya kullanıcı profili tablosunda saklanır.

Bir dil seçildiğinde tüm metinler seçilen dilde görüntülenir.

Serenity platformu, başından itibaren yerelleştirme göz önünde bulundurularak tasarlanmıştır.

Tarayıcınızın dilini ayarlayarak veya Serenity demosunun ( https://demo.serenity.is ) dil açılır menüsünden dili değiştirerek bunu kendiniz görebilirsiniz.

Mesela Türkçeye geçerseniz; ve tarayıcınızı yenileyin, demoyu Türkçe olarak göreceksiniz:

Türkçe Müşteri Sayfası

Burada veriler çevrilmez ancak kullanıcı tarafından girilen verilerin kültür uzantı tabloları gibi yöntemlerle çevrilmesi de mümkündür.

.NET'in kendisinde yerelleştirme

.NET uygulamaları genellikle dize kaynak dosyalarını (.resx) ve uydu derlemelerini kullanır:

.NET'teki yerelleştirme sistemi çoğu uygulama için iyi çalışır. Uydu derlemelerinde gördüğümüz temel sorun, bir derleme adımı gerektirmesi ve uygulamanın kendisi konuşlandırıldıktan sonra üçüncü şahıslar tarafından çeviri yapılmasına, yeni dillerin eklenmesine veya çevirilerin düzenlenmesine pek uygun olmamasıdır.

Serenity'de yerelleştirme

Serenity, aşağıdaki potansiyel avantajları elde etmek için özel bir yerelleştirme sistemi kullanır:

  • Mevcut dilleri uygulamanın kendisine ekleyin/kaldırın
  • Yerelleştirmeleri çalışma zamanında düzenleyin, böylece çevirmen gibi üçüncü taraflarca yapılabilir
  • Çevirileri JSON dosyaları olarak saklayın/dağıtın
  • İstenirse çevirileri veritabanı gibi başka bir ortamda saklayın

ITextLocalizer Arayüzü

Yerelleştirme ITextLocalizer arayüzüyle başlar :

public interface ITextLocalizer
{
    string TryGet(string key);
}

Bu, yalnızca geçerli kullanıcı arayüzü dili ( ) için bir çeviriyi kendi aracılığıyla TryGetalma olanağı sağlayan bir yönteme sahip çok basit bir arayüzdür .CultureInfo.CurrentUICulturetext key

Yerel Metin Tuşları

Aynı dizenin bağlama bağlı olarak farklı çevirileri olabileceğinden, Serenity local text keyssıradan çevrilmemiş metinler yerine kullanır.

FaceÖrneğin, bir kişinin yüzü veya bir nesnenin ön yüzeyi gibi bağlama bağlı olarak kelime farklı anlamlara ve farklı çevirilere sahip olabilir.

Metin tuşları genel olarak aşağıdaki biçimde tanımlanır:

  • Enums.Month.January
  • Enums.Month.December
  • Db.Northwind.Customer.CustomerName
  • Dialogs.YesButton

Bu form aynı zamanda bunları amaçlarına/bağlamlarına göre de sınıflandırır. Örneğin, Enums.Month.önek anahtarları, adı verilen bir numaralandırmanın değerlerine yönelik olanlardır MonthÖnekli anahtarlar modüldeki Db.Northwind.Customer.bir varlığın alanları içindir .CustomerNorthwind

LocalText Sınıfı

LocalText sınıfı bir a'yı saklar ve arayüzü kullanarak geçerli kullanıcı arayüzü dili ( ) içinlocal text key çevirisini alma olanağı sağlar .CultureInfo.CurrentUICultureITextLocalizer

public class LocalText
{
    public const string InvariantLanguageID = "";
    public static readonly LocalText Empty;

    public LocalText(string key);

    public string Key { get; private set; }
    public static implicit operator LocalText(string key);
    public string ToString(ITextLocalizer localizer);
}

Bir LocalTextörnek, bir metin anahtarını ileterek yapıcısı aracılığıyla veya herhangi bir dizeden örtülü atama yoluyla oluşturulabilir.

Ayrıca buna benzer olarak LocalTextadlandırılan statik bir örnek de vardır .EmptyString.Empty

Dil Tanımlayıcıları ve Değişmez Dil

Dil kimliği, dillere yönelik tanımlayıcılar veya sınıflandırıcılar olarak harfleri ve/veya sayıları atayan bir koddur.

Dil kimlikleri biçiminde RFC 1766 standardına uygundur <languagecode2>-<country/regioncode2>; burada dil kodu2, ISO 639-1'den türetilen küçük harfli iki harfli bir koddur ve ülke/bölge kodu2, ISO 3166'dan türetilen iki harfli büyük harfli bir koddur.

Bazı örnek dil kimlikleri şunlardır:

  • en: İngilizce
  • en-US: Amerika Birleşik Devletleri'nde kullanıldığı şekliyle İngilizce (ABD, ISO 3166-1 ülke kodudur)
  • en-GB: Birleşik Krallık'ta kullanıldığı şekliyle İngilizce (GB, ISO 3166-1 ülke kodudur)
  • es: İspanyolca
  • es-AR: Arjantin'de kullanıldığı şekliyle İspanyolca

'ye benzer şekilde CultureInfo.InvariantCulture, değişmez dil ( LocalText.InvariantLanguageID) boş tanımlayıcıya sahip varsayılan dildir.

Aksi belirtilmediği sürece, derlemelerinizdeki yerel metinlerin, örneğin C# kodunda tanımlananların, değişmez dilde yazıldığı kabul edilir. Yani kaynak metinlerin başka dillere çevrileceği dildir.

Genellikle İngilizce olarak kabul edilse de, doğal dilinizi değişmez dil olarak kabul edebilirsiniz.

ILocalTextRegistry Arayüzü

Daha önce de belirttiğimiz gibi arayüz ITextLocalizerçevirilere erişmek için kullandığımız arayüz ama bu çevirileri nereden alabilir? Bu, ILocalTextRegistry arayüzünü uygulayan sınıfın sorumluluğundadır :

public interface ILocalTextRegistry
{
    string TryGet(string languageID, string key, bool pending);
    void Add(string languageID, string key, string text);
}

TryGetBu arayüz , bir metin anahtarının belirli bir dilde çevirisini döndüren yönteme sahiptir .

AddAyrıca çevirileri kaydetmek için kullanılan başka bir yöntem adı da vardır.`

Arayüzün varsayılan uygulaması, bu çevirileri bir dizi sözlük nesnesi kullanarak bellekte saklayan LocalTextRegistryILocalTextRegistry sınıfıdır .

Yerel metin tablosu, aşağıdaki gibi bir bellek içi tablodur (sözlük):

AnahtarDilKimliğiMetin (Çeviri)
Dialogs.YesButtoniçindeEvet
Dialogs.YesButtonTREvet
Diyaloglar.NoButtoniçindeHAYIR
Diyaloglar.NoButtonTRHayır

Dil Yedekleri

İstenilen dilde ve bu dillerden birinde bir çeviri mevcut değilse , hem ILocalTextRegistry.TryGetve ITextLocalizer.TryGetyöntemlerinin geri dönmesi gerekir .nullfallback languages

'de bir çeviri bulunamadığında , yakından ilişkili oldukları için dilde en-USbir çeviri aramak kabul edilebilir .en

İki harfli dil kimlikleri (tarafsız diller), 4 harfli ülkeye özgü kodların dolaylı olarak dil yedekleridir. Yani esdil, ve'nin dil geri dönüşüdür es-ARve'nin endil geri dönüşüdür .en-USen-GB

Değişmez dil, örtülü olarak tüm dillerin son geri dönüşüdür.

Sağlayıcılar ayrıca dil geri dönüşlerini açıkça ayarlamayı da destekleyebilir, böylece gerekirse en-USdil geri dönüşü olarak ayarlayabilirsiniz .en-UK

Yerel bir metin anahtarının çevirisini aramak şu şekilde çalışır:

  • Geçerli dilde anahtarın çevirisi varsa onu iade edin.
  • Bir çeviri için açıkça tanımlanmış her dil geri dönüşünü kontrol edin.
  • Dil kimliği 4 harfli ülkeye özgü bir kodsa çeviri için tarafsız dili kontrol edin.
  • Çeviri için değişmez dili kontrol edin.
  • Aksi halde null değerini döndür

Diyelim ki en-USdil geri dönüşü olarak ayarladık en-UKEğer bir çeviriyi ararsak en-UKşu sırayla aranır:

  1. tr-İngiltere
  2. ABD'de
  3. içinde
  4. değişmez

Yerel Metin Sisteminin Başlatılması

Yerelleştirme sisteminin gerektirdiği hizmetlerin varsayılan uygulamaları, CoreServiceCollections.AddTextRegistryStartup.cs yöntemi aracılığıyla dosyaya kaydedilir .

Startup.csYöntem dahili olarak aşağıdakiler tarafından çağrıldığından bunu dosyada bulamayabilirsiniz AddServiceHandlers:

services.AddServiceHandlers(); // this internally calls AddTextRegistry

Ayrıca dosyada, uygulamanızdaki bir dizi sınıftan ve JSON dosyaları gibi diğer kaynaklardan yerel metin anahtarlarını ve çevirilerini yerel metin kaydına ekleyen bir InitializeLocalTextyöntem de vardır :Startup.cs

public static void InitializeLocalTexts(IServiceProvider services)
{
    var env = services.GetRequiredService<IWebHostEnvironment>();
    services.AddBaseTexts(env.WebRootFileProvider)
        .AddJsonTexts(env.WebRootFileProvider, "Scripts/site/texts")
        .AddJsonTexts(env.ContentRootFileProvider, "App_Data/texts");
}

Çevirileri Manuel Olarak Kaydetme

Yöntemden yerel metin kaydına çeviriler ekleyebilirsiniz InitializeLocalTextsBu çevirilerin kaynakları bir veritabanı tablosu, bir XML dosyası, gömülü kaynaklar vb. olabilir.

public static void InitializeLocalTexts(IServiceProvider services)
{
    var env = services.GetRequiredService<IWebHostEnvironment>();
    services.AddBaseTexts(env.WebRootFileProvider)
    // ..
    var registry = services.GetRequiredService<ILocalTextRegistry>();
    // load these texts from some source like a database table
    registry.Add("es", "Dialogs.YesButton", "Sí");
    registry.Add("fr", "Dialogs.YesButton", "Oui");
    // ..
}

Lütfen burada sıralamanın önemli olduğunu unutmayın; örneğin daha sonra eklenen metinler, aynı metin anahtarı ve dil kimliği çiftleri için kendilerinden önce eklenebilecek metinleri geçersiz kılacaktır.

JSON Yerel Metinleri

Serenity, basit bir anahtar/değer sözlüğü içeren JSON dosyaları aracılığıyla yerel metin kaydını destekler:

{
  "Forms.Administration.User.DisplayName": "Display Name",
  "Forms.Administration.User.Email": "E-mail",
  "Forms.Administration.User.EntitySingular": "User",
  "Forms.Administration.User.EntityPlural": "Users"
}

JSON dosyalarındaki tüm yerel metin anahtarlarını ve çevirileri bir klasöre kaydetmek için dosya sağlayıcısı ve klasör yolu ile AddJsonTexts'i arayın:

services.AddJsonTexts(env.ContentRootFileProvider, "my/folder/with/localtext/jsonfiles")

Klasördeki dosya adları bir kurala uymalıdır:

{Some Prefix You Choose}.{LanguageID}.json

{LanguageID}iki veya dört harfli dil kodu nerede . Değişmez dil için dil kodu olarak değişmezi kullanın .

Bazı örnek dosya adları şunlardır:

  • site.texts.en-US.json
  • MyCoolTexts.es.json
  • user.texts.invariant.json

Bir klasördeki dosyalar ayrıştırılır ve dosya adı sırasına göre kayıt defterine eklenir. Dolayısıyla yukarıdaki örnek dosya adları için sıralama şu şekilde olacaktır:

  1. MyCoolTexts.es.json
  2. site.texts.en-US.json
  3. user.texts.invariant.json

Bu sıralama, bazı dillerde aynı anahtara sahip bir çevirinin eklenmesi önceki çeviriyi geçersiz kılacağından önemlidir.

JSON Yerel Metinlerini İçeren Varsayılan Klasörler

Fark etmiş olabileceğiniz gibi, yöntem InitializeLocalTextsönceden AddJsonTextsbelirlenmiş iki klasörü gerektirir:

.AddJsonTexts(env.WebRootFileProvider, "Scripts/site/texts")
.AddJsonTexts(env.ContentRootFileProvider, "App_Data/texts");

Bunlardan ilki, uygulamaya özel çevirilerinizi içeren bir klasördür.

Altındaki ise sayfa üzerinden yapılan kullanıcı çevirilerinin varsayılan olarak kaydedildiği App_Data/textsklasördür . Administration/TranslationsBu dosyalardaki metinlerin yayınlanmadan önce uygulama çeviri dosyalarına aktarılması tavsiye edilir ~/Scripts/site/texts.

İç İçe Yerel Metinler

Serenity, çevirileri kaydetmek için LocalText nesnelerini içeren iç içe geçmiş statik sınıfları tanımlamanıza olanak tanır:

[NestedLocalTexts]
public static partial class Texts
{
    public static class Site
    {
        public static class Dashboard
        {
            public static LocalText WelcomeMessage = "Welcome to Serenity";
        }
    }

    public static class Validation
    {
        public static LocalText DeleteForeignKeyError =
            "Can't delete record. '{0}' table has records that depends on this one!";
        public static LocalText SavePrimaryKeyError =
            "Can't save record. There is another record with the same {1} value!";
    }
}

Bu tanımlar, dize tuşlarını ezberlemenize gerek kalmadan yerelleştirilmiş metinlere intelli-sense desteğiyle başvurmanıza olanak tanır.

Bu gömülü çeviri tanımları, genellikle değişmez dildeki varsayılan çevirileri tanımlamak için kullanılır.

Bu Texts sınıfıyla tanımlanan çevirilerin bir tablosunu burada bulabilirsiniz :

AnahtarDilKimliğiMetin (Çeviri)
Site.Dashboard.WelcomeMessageSerenity'ye hoş geldiniz
Validation.DeleteForeignKeyErrorKayıt silinemiyor...
Validation.SavePrimaryKeyErrorKayıt kaydedilemiyor...

Yerel metin anahtarları, aralarına nokta eklenmiş iç içe geçmiş statik sınıf adlarından oluşturulur. En üstteki statik sınıf (Metinler) adı göz ardı edilir, ancak tutarlılık açısından buna Metinler gibi bir ad vermek iyi bir fikirdir .

Aksi belirtilmedikçe, bu metinlerin dil kimliği, değişmez dil (boş dize) olarak kabul edilir.

İç içe yerel metin kayıt sınıfları için en üstteki sınıf (örn. Texts here), NestedLocalTextsAttribute niteliğine sahip olmalıdır .

public sealed class NestedLocalTextsAttribute : Attribute
{
    public string LanguageID { get; set; }
    public string Prefix { get; set; }
}

LanguageIDve adında iki isteğe bağlı özelliği vardır Prefix.

LanguageIDçevirilerin bulunduğu dili tanımlamanıza olanak tanır.

Varsayılan metinleri değişmez dilde kaydetmek iyi bir fikirdir (metinler İngilizce olmasa bile), çünkü bu, tüm diller için nihai dil geri dönüşü olacaktır.

Eğer şu şekilde kullanırsak:

[NestedLocalTexts(LanguageID = "en-US")]
public static partial class Texts
{
}

LanguageIDÇeviriler tablosundaki sütun "en-US" olacaktır :

AnahtarDilKimliğiMetin (Çeviri)
Site.Dashboard.WelcomeMessageABD'deSerenity'ye hoş geldiniz
Validation.DeleteForeignKeyErrorABD'deKayıt silinemiyor...

Özellik Prefixdeğeri, yerel metin anahtarları için önek olarak kullanılır:

[NestedLocalTexts(LanguageID = "en-US", Prefix = "APrefix.")]
public static partial class Texts
{
    // ..
}
AnahtarDilKimliğiMetin (Çeviri)
APrefix.Site.Dashboard.WelcomeMessageABD'deSerenity'ye hoş geldiniz
APrefix.Validation.DeleteForeignKeyErrorABD'deKayıt silinemiyor...

NestedLocalText'ler, yöntemdeki çağrı Startup.csaracılığıyla otomatik olarak dosyaya kaydedilir .AddBaseTextsInitializeLocalTexts

Satır Metinleri

DisplayNameBir varlık sınıfının ( Row) bir özelliği için tanımlanan herhangi bir öznitelik, otomatik olarak yerel bir metin anahtarını ve bunun çevirisini kaydeder:

namespace Serene.Administration
{
    [Module("Administration")]
    [DisplayName("Users"), InstanceName("User")]
    public sealed class UserRow
    {
        [DisplayName("User Id"), Identity, IdProperty]
        public int? UserId { ... }

        [DisplayName("Username"), Size(100), NotNull, QuickSearch, LookupInclude, NameProperty]
        public string Username { ... }

        [DisplayName("Source"), Size(4), NotNull, Insertable(false), Updatable(false), DefaultValue("site")]
        public string Source
        {
            get => fields.Source[this];
            set => fields.Source[this] = value;
        }
    //...
    }
}

Yukarıdaki örnekte UserRow, başlangıçta aşağıdaki yerel metinler kaydedilmiştir:

AnahtarDilKimliğiMetin (Çeviri)
Db.Administration.UserIdKullanıcı kimliği
Db.Yönetim.Kullanıcı adıKullanıcı adı
Db.Yönetim.KaynakKaynak
Db.Administration.EntityPluralKullanıcılar
Db.Administration.EntitySingularKullanıcı

Metin öznitelikten okunur ve anahtar ( bu örnekte bulunan) varlık ve özellik adından DisplayNametüretilir .local text prefix"Db.Administration."

EntityPluralve EntitySingularvarlık sınıfının başlığa (örn. Kullanıcılar) ve örnek adına karşılık gelen özel anahtarlardır. Değerleri satır sınıfından okunur DisplayNameve niteliklerden okunur.InstanceName

Her varlığın, bu örnekteki modül adından hesaplanan ve öznitelik "Administration"aracılığıyla ayarlanan bir yerel metin öneki vardır ModuleHiçbir Moduleöznitelik mevcut değilse modül adı, ad alanından hesaplanır.

Yerel metin öneki, satır sınıfına bir LocalTextPrefixAttribute yerleştirilerek de ayarlanabilir .

LocalTextPrefixBaşka bir yol da özelliği sınıf yapıcısında ayarlamaktır RowFieldsancak önerilmez.

Satır metinleri de yöntemdeki çağrı Startup.csyoluyla dosyaya otomatik olarak kaydedilir .AddBaseTextsInitializeLocalTexts

Numaralandırma Metinleri

Numaralandırma değerleri için görüntü metni ile belirtilebilir DescriptionAttribute.

namespace MyApplication
{
    public enum Sample
    {
        [Description("First Value")]
        Value1 = 1,
        [Description("Second Value")]
        Value2 = 2
    }
}

Bu numaralandırma ve Açıklama nitelikleri aşağıdaki yerel metin anahtarlarını ve çevirilerini tanımlar:

AnahtarDilKimliğiMetin (Çeviri)
Enums.MyApplication.Sample.Value1İlk Değer
Enums.MyApplication.Sample.Value2İkinci Değer

Numaralandırma değerlerine ilişkin çevrilmiş açıklamalara erişmek için bu anahtarları kullanabilir veya numaralandırma türleri için tanımlanan GetText() uzantı yöntemini kullanabilirsiniz (bu uzantı yöntemini kullanılabilir kılmak için Serenity ad alanını içe aktarın).

Console.WriteLine(MyApplication.Sample.Value1.GetText(localizer));

...geri dönen

> First Value

Enum metinleri de yöntemdeki çağrı Startup.csyoluyla dosyaya otomatik olarak kaydedilir .AddBaseTextsInitializeLocalTexts

EnumKey Özelliği

Numaralandırma çevirileri, yerel metin anahtarları oluşturmak için numaralandırma türünün tam adını önek olarak kullanır. Bu önek EnumKeyAttribute ile geçersiz kılınabilir:

namespace MyApplication
{
    [EnumKey("Something")]
    public enum Sample
    {
        [Description("First Value")]
        Value1 = 1,
        [Description("Second Value")]
        Value2 = 2
    }
}

Artık tanımlanan anahtarlar ve çeviriler şunlardır:

AnahtarDilKimliğiMetin (Çeviri)
Enums.Something.Value1İlk Değer
Enums.Something.Value2İkinci Değer

Modüler TypeScript kullanırken sorunlara neden olduğu bilindiğinden, enum anahtarının geçersiz kılınmasının ÖNERİLMEDİĞİNİ lütfen unutmayın.

Bu blogdaki popüler yayınlar

Code generetor ile oluşturulan dosyaların açıklamaları

  1. Sunum (Presentation/UI) Katmanı (Kullanıcı arayüzü - HTML, TypeScript, Dialog, Grid) 🔹 XYZPage.ts 📌 Ne İşe Yarar? Kullanıcı arayüzünün TypeScript tarafındaki tanımıdır. Serenity'nin Dialog ve Grid bileşenlerini içeren bir TypeScript sınıfıdır. 📌 Çok Katmanlı Mimarideki Yeri: Sunum Katmanı (Presentation Layer) Kullanıcıdan veri almak ve göstermek için kullanılır. 🔹 XYZGrid.ts 📌 Ne İşe Yarar? Tablo (Grid) yapısını oluşturur ve verileri listeler. Filtreleme, sıralama ve sayfalama işlemleri için kullanılır. columnsKey ile hangi kolonların gösterileceğini belirler. 📌 Çok Katmanlı Mimarideki Yeri: Sunum Katmanı (Presentation Layer) Kullanıcının verileri listelediği ve etkileşimde bulunduğu yerdir. 🔹 XYZDialog.ts 📌 Ne İşe Yarar? CRUD (Create, Read, Update, Delete) işlemlerini yöneten pencere (modal) bileşeni Kullanıcı form aracılığıyla veri ekler, günceller veya siler. XYZForm.cs ile birlikte çalışır. 📌 Çok Katmanlı Mimarideki Yeri: Sunum Katmanı (Presentation Layer) Kull...

Serenity Web Nedir?

   Serenity  , açık kaynak teknolojileri üzerine kurulu bir ASP.NET Core/TypeScript uygulama platformudur. Standart kodlardan kaçınarak, tekrarlanan görevlere harcanan zamanı azaltarak ve en iyi yazılım tasarımı uygulamalarını uygulayarak bakım maliyetlerini düşürürken geliştirmeyi kolaylaştırmayı amaçlamaktadır. Serene  , Serenity platformunu temel alan ücretsiz, açık kaynaklı başlangıç ​​uygulama şablonumuzdur.  Bu dokümantasyon aracılığıyla eğitimimiz ve diğer örnekler için esas olarak Serene'yi kullanacağız. StartSharp  , ücretli müşterilerimize sunduğumuz premium uygulama şablonudur.  Daha gösterişli bir temaya ve bazı ekstra özelliklere  ek olarak Serene'deki her şeyi içerir  .  İkisi de Serenity platformunu temel alıyor. Adında Ne Var Serenity'nin sözlük anlamları  barış  ,  rahatlık  ve  sakinliktir  . Serenity ile bunu başarmaya çalışıyoruz.  Umarız yükledikten ve kullandıktan sonra siz de bu ş...