Ç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:

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.JanuaryEnums.Month.DecemberDb.Northwind.Customer.CustomerNameDialogs.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: İngilizceen-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: İspanyolcaes-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):
| Anahtar | DilKimliği | Metin (Çeviri) |
|---|---|---|
| Dialogs.YesButton | içinde | Evet |
| Dialogs.YesButton | TR | Evet |
| Diyaloglar.NoButton | içinde | HAYIR |
| Diyaloglar.NoButton | TR | Hayı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-AR, ve'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-UK. Eğer bir çeviriyi ararsak en-UKşu sırayla aranır:
- tr-İngiltere
- ABD'de
- içinde
- 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 InitializeLocalTexts. Bu ç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.jsonMyCoolTexts.es.jsonuser.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:
MyCoolTexts.es.jsonsite.texts.en-US.jsonuser.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 :
| Anahtar | DilKimliği | Metin (Çeviri) |
|---|---|---|
| Site.Dashboard.WelcomeMessage | Serenity'ye hoş geldiniz | |
| Validation.DeleteForeignKeyError | Kayıt silinemiyor... | |
| Validation.SavePrimaryKeyError | Kayı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 :
| Anahtar | DilKimliği | Metin (Çeviri) |
|---|---|---|
| Site.Dashboard.WelcomeMessage | ABD'de | Serenity'ye hoş geldiniz |
| Validation.DeleteForeignKeyError | ABD'de | Kayı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
{
// ..
}
| Anahtar | DilKimliği | Metin (Çeviri) |
|---|---|---|
| APrefix.Site.Dashboard.WelcomeMessage | ABD'de | Serenity'ye hoş geldiniz |
| APrefix.Validation.DeleteForeignKeyError | ABD'de | Kayı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:
| Anahtar | DilKimliği | Metin (Çeviri) |
|---|---|---|
| Db.Administration.UserId | Kullanıcı kimliği | |
| Db.Yönetim.Kullanıcı adı | Kullanıcı adı | |
| Db.Yönetim.Kaynak | Kaynak | |
| Db.Administration.EntityPlural | Kullanıcılar | |
| Db.Administration.EntitySingular | Kullanı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 Module. Hiç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:
| Anahtar | DilKimliği | Metin (Ç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:
| Anahtar | DilKimliği | Metin (Ç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.