Büyük .NET projesinde çoklu dil / küreselleşmeyi uygulamanın en iyi yolu


87

Yakında büyük bir c # projesi üzerinde çalışacağım ve en başından itibaren çoklu dil desteği oluşturmak istiyorum. Etrafta oyun oynadım ve her dil için ayrı bir kaynak dosyası kullanarak çalışmasını sağlayabilirim, ardından dizeleri yüklemek için bir kaynak yöneticisi kullanabilirim.

İnceleyebileceğim başka iyi yaklaşımlar var mı?

Yanıtlar:


91

Kaynaklarla ayrı bir proje kullanın

API, MVC, Proje Kitaplıkları (Çekirdek işlevsellikler), WPF, UWP ve Xamarin içeren 12 24 proje ile güncel bir çözüme sahip olduğumdan bunu deneyimlerimden anlayabilirim. Bunu yapmanın en iyi yolu olduğunu düşündüğüm için bu uzun yazıyı okumaya değer. VS araçlarının yardımıyla, çeviri bürolarına gönderilebilir veya başkaları tarafından gözden geçirilebilir.

DÜZENLEME 02/2018: Hala güçlü olmak, onu bir .NET Standard kitaplığına dönüştürmek, onu .NET Framework ve NET Core'da bile kullanmayı mümkün kılıyor. JSON'a dönüştürmek için fazladan bir bölüm ekledim, böylece örneğin açısal bunu kullanabilir.

DÜZENLEME 2019: Xamarin ile birlikte, bu hala tüm platformlarda çalışıyor. Örneğin, Xamarin.Forms, resx dosyalarının da kullanılmasını öneriyor. (Henüz Xamarin.Forms'da bir uygulama geliştirmedim, ancak başlangıç ​​için ayrıntılı olan belgeler, onu kapsar: Xamarin.Forms Belgeleri ). JSON'a dönüştürmek gibi, Xamarin.Android için de .xml dosyasına dönüştürebiliriz.

DÜZENLEME 2019 (2): WPF'den UWP'ye yükseltme yaparken, UWP'de .reswiçerik açısından aynı olan ancak kullanım farklı olan başka bir dosya türünü kullanmayı tercih ettiklerini gördüm . Bunu yapmanın, bence varsayılan çözümden daha iyi çalışan farklı bir yolunu buldum .

EDIT 2020: Birden çok dil projesi gerektirebilecek daha büyük (modulair) projeler için bazı öneriler güncellendi.

Öyleyse başlayalım.

Profesyoneller

  • Hemen hemen her yerde güçlü bir şekilde yazılmıştır.
  • WPF'de uğraşmak zorunda değilsiniz ResourceDirectories.
  • ASP.NET, Class Libraries, WPF, Xamarin, .NET Core, .NET Standard için test ettiğim kadarıyla destekleniyor.
  • Ekstra üçüncü taraf kitaplıklarına gerek yoktur.
  • Kültür geri dönüşünü destekler: en-US -> tr.
  • Yalnızca arka uç değil, aynı zamanda WPF ve Xamarin.Forms için XAML'de, MVC için .cshtml'de çalışır.
  • Değiştirerek dili kolayca değiştirin. Thread.CurrentThread.CurrentCulture
  • Arama motorları farklı dillerde Tarama yapabilir ve kullanıcı dile özgü url'ler gönderebilir veya kaydedebilir.

Eksileri

  • WPF XAML bazen hatalı olabilir, yeni eklenen dizeler doğrudan görünmez. Yeniden oluşturma geçici düzeltme (vs2015).
  • UWP XAML, akıllıca önerileri göstermez ve tasarım sırasında metni göstermez.
  • Bana söyle.

Kurmak

Çözümünüzde dil projesi oluşturun, ona MyProject.Language gibi bir isim verin . Kaynaklar adında bir klasör ekleyin ve bu klasörde iki Kaynak dosyası (.resx) oluşturun. Biri Resources.resx ve diğeri Resources.en.resx (veya spesifik olarak .en-GB.resx) olarak adlandırıldı. Uygulamamda, varsayılan dil olarak NL (Hollandaca) dilim var, bu yüzden bu ilk dosyamda ve İngilizce ikinci dosyamda yer alıyor.

Kurulum şu şekilde görünmelidir:

dil kurulum projesi

Resources.resx'in özellikleri şöyle olmalıdır: özellikleri

Özel araç ad alanının proje ad alanınız olarak ayarlandığından emin olun. Bunun nedeni, ResourcesWPF'de XAML'nin içine başvuramazsınız.

Kaynak dosyasının içinde erişim değiştiriciyi Genel olarak ayarlayın:

erişim değiştirici

Bu kadar büyük bir uygulamanız varsa (diyelim farklı modüller) yukarıdaki gibi birden fazla proje oluşturmayı düşünebilirsiniz. Bu durumda, Anahtarlarınızı ve kaynak sınıflarınızı belirli bir Modül ile önekleyebilirsiniz. Tüm dosyaları tek bir genel bakışta birleştirmek için Visual Studio için var olan en iyi dil düzenleyicisini kullanın .

Başka bir projede kullanmak

Projenize referans: Referanslar -> Referans Ekle -> Prjects \ Solutions'a sağ tıklayın.

Bir dosyada ad alanı kullanın: using MyProject.Language;

Bunu arka uçta olduğu gibi kullanın: string someText = Resources.orderGeneralError; Kaynaklar adında başka bir şey varsa, o zaman ad alanının tamamını girin.

MVC'de kullanma

MVC'de dili ayarlamak istediğiniz gibi yapabilirsiniz, ancak aşağıdaki gibi ayarlanabilen parametreli url'ler kullandım:

RouteConfig.cs Diğer eşlemelerin altında

routes.MapRoute(
    name: "Locolized",
    url: "{lang}/{controller}/{action}/{id}",
    constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },   // en or en-US
    defaults: new { controller = "shop", action = "index", id = UrlParameter.Optional }
);

FilterConfig.cs eklemek eğer öyleyse (eklenebilir gerekebilir FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);için Application_start()de yönteminGlobal.asax

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ErrorHandler.AiHandleErrorAttribute());
        //filters.Add(new HandleErrorAttribute());
        filters.Add(new LocalizationAttribute("nl-NL"), 0);
    }
}

LocalizationAttribute

public class LocalizationAttribute : ActionFilterAttribute
{
    private string _DefaultLanguage = "nl-NL";
    private string[] allowedLanguages = { "nl", "en" };

    public LocalizationAttribute(string defaultLanguage)
    {
        _DefaultLanguage = defaultLanguage;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string lang = (string) filterContext.RouteData.Values["lang"] ?? _DefaultLanguage;
        LanguageHelper.SetLanguage(lang);
    }
}

LanguageHelper sadece Kültür bilgilerini ayarlar.

//fixed number and date format for now, this can be improved.
public static void SetLanguage(LanguageEnum language)
{
    string lang = "";
    switch (language)
    {
        case LanguageEnum.NL:
            lang = "nl-NL";
            break;
        case LanguageEnum.EN:
            lang = "en-GB";
            break;
        case LanguageEnum.DE:
            lang = "de-DE";
            break;
    }
    try
    {
        NumberFormatInfo numberInfo = CultureInfo.CreateSpecificCulture("nl-NL").NumberFormat;
        CultureInfo info = new CultureInfo(lang);
        info.NumberFormat = numberInfo;
        //later, we will if-else the language here
        info.DateTimeFormat.DateSeparator = "/";
        info.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
        Thread.CurrentThread.CurrentUICulture = info;
        Thread.CurrentThread.CurrentCulture = info;
    }
    catch (Exception)
    {

    }
}

.Cshtml'de kullanım

@using MyProject.Language;
<h3>@Resources.w_home_header</h3>

veya kullanımları tanımlamak istemiyorsanız, ad alanının tamamını doldurun VEYA ad alanını /Views/web.config altında tanımlayabilirsiniz:

<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
  <namespaces>
    ...
    <add namespace="MyProject.Language" />
  </namespaces>
</pages>
</system.web.webPages.razor>

Bu mvc uygulama kaynağı öğreticisi: Harika öğretici blog

Modeller için sınıf kitaplıklarında kullanma

Arka uç kullanımı aynıdır, ancak özniteliklerde kullanmak için sadece bir örnek

using MyProject.Language;
namespace MyProject.Core.Models
{
    public class RegisterViewModel
    {
        [Required(ErrorMessageResourceName = "accountEmailRequired", ErrorMessageResourceType = typeof(Resources))]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }
}

Yeniden şekillendirirseniz, verilen kaynak adının var olup olmadığını otomatik olarak kontrol edecektir. Tür güvenliğini tercih ediyorsanız, bir numara oluşturmak için T4 şablonlarını kullanabilirsiniz.

WPF'de kullanma.

Elbette MyProject.Language ad alanınıza bir referans ekleyin , arka uçta nasıl kullanılacağını biliyoruz.

XAML'de, bir Window veya UserControl başlığının içine, langşu şekilde adlandırılan bir ad alanı başvurusu ekleyin :

<UserControl x:Class="Babywatcher.App.Windows.Views.LoginView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyProject.App.Windows.Views"
              xmlns:lang="clr-namespace:MyProject.Language;assembly=MyProject.Language" <!--this one-->
             mc:Ignorable="d" 
            d:DesignHeight="210" d:DesignWidth="300">

Ardından, bir etiketin içinde:

    <Label x:Name="lblHeader" Content="{x:Static lang:Resources.w_home_header}" TextBlock.FontSize="20" HorizontalAlignment="Center"/>

Kesinlikle yazıldığı için kaynak dizesinin var olduğundan eminsin. Bazen kurulum sırasında projeyi yeniden derlemeniz gerekebilir, WPF bazen yeni ad alanları ile hatalı olabilir.

WPF için bir şey daha, dili App.xaml.cs. Kendi uygulamanızı yapabilir (kurulum sırasında seçebilirsiniz) veya sistemin karar vermesine izin verebilirsiniz.

UWP'de kullanma

UWP'de Microsoft bu çözümü kullanır , yani yeni kaynak dosyaları oluşturmanız gerekecektir. Ayrıca metni yeniden kullanamazsınız çünkü x:UidXAML'deki kontrolünüzü kaynaklarınızdaki bir anahtara ayarlamanızı isterler . Ve kaynaklarınızda Example.Textbir TextBlockmetnini doldurmanız gerekir . Bu çözümü hiç beğenmedim çünkü kaynak dosyalarımı yeniden kullanmak istiyorum. Sonunda aşağıdaki çözümü buldum. Bunu bugün yeni öğrendim (2019-09-26), bu yüzden istediğim gibi çalışmadığı ortaya çıkarsa başka bir şeyle geri gelebilirim.

Bunu projenize ekleyin:

using Windows.UI.Xaml.Resources;

public class MyXamlResourceLoader : CustomXamlResourceLoader
{
    protected override object GetResource(string resourceId, string objectType, string propertyName, string propertyType)
    {
        return MyProject.Language.Resources.ResourceManager.GetString(resourceId);
    }
}

Bunu yapıcıya ekleyin App.xaml.cs:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

Uygulamanızda istediğiniz yerde, dili değiştirmek için bunu kullanın:

ApplicationLanguages.PrimaryLanguageOverride = "nl";
Frame.Navigate(this.GetType());

Kullanıcı arayüzünü yenilemek için son satır gereklidir. Hala bu proje üzerinde çalışırken, bunu 2 kez yapmam gerektiğini fark ettim. Kullanıcı ilk başladığında bir dil seçimi yapabilirim. Ancak bu, Windows Mağazası aracılığıyla dağıtılacağından, dil genellikle sistem diline eşittir.

Ardından XAML'de kullanın:

<TextBlock Text="{CustomResource ExampleResourceKey}"></TextBlock>

Angular'da kullanma (JSON'a dönüştür)

Günümüzde Angular gibi bileşenlerle kombinasyon halinde, yani cshtml'siz bir çerçeveye sahip olmak daha yaygın. Çeviriler json dosyalarında saklanır, bunun nasıl çalıştığını anlatmayacağım , sadece açısal çoklu çeviri yerine ngx-translate'i şiddetle tavsiye ederim . Çevirileri bir JSON dosyasına dönüştürmek istiyorsanız, oldukça kolaydır, Resources dosyasını bir json dosyasına dönüştüren bir T4 şablon komut dosyası kullanıyorum. Sözdizimini okumak ve doğru kullanmak için T4 editörü kurmanızı tavsiye ederim çünkü bazı değişiklikler yapmanız gerekiyor.

Unutulmaması gereken tek şey: Veriyi oluşturmak, kopyalamak, verileri temizlemek ve başka bir dil için oluşturmak mümkün değildir. Bu nedenle, aşağıdaki kodu sahip olduğunuz diller kadar kopyalamanız ve '// burada dili seçin' öncesinde girişi değiştirmeniz gerekir. Şu anda bunu düzeltmek için zaman yok, ancak muhtemelen daha sonra güncellenecek (ilgileniyorsanız).

Yol: MyProject.Language / T4 / CreateLocalizationEN.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".json" #>
<#


var fileNameNl = "../Resources/Resources.resx";
var fileNameEn = "../Resources/Resources.en.resx";
var fileNameDe = "../Resources/Resources.de.resx";
var fileNameTr = "../Resources/Resources.tr.resx";

var fileResultName = "../T4/CreateLocalizationEN.json";//choose language here
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);
//var fileDestinationPath = "../../MyProject.Web/ClientApp/app/i18n/";

var fileNameDestNl = "nl.json";
var fileNameDestEn = "en.json";
var fileNameDestDe = "de.json";
var fileNameDestTr = "tr.json";

var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

string[] fileNamesResx = new string[] {fileNameEn }; //choose language here
string[] fileNamesDest = new string[] {fileNameDestEn }; //choose language here

for(int x = 0; x < fileNamesResx.Length; x++)
{
    var currentFileNameResx = fileNamesResx[x];
    var currentFileNameDest = fileNamesDest[x];
    var currentPathResx = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", currentFileNameResx);
    var currentPathDest =pathBaseDestination + "/MyProject.Web/ClientApp/app/i18n/" + currentFileNameDest;
    using(var reader = new ResXResourceReader(currentPathResx))
    {
        reader.UseResXDataNodes = true;
#>
        {
<#
            foreach(DictionaryEntry entry in reader)
            {
                var name = entry.Key;
                var node = (ResXDataNode)entry.Value;
                var value = node.GetValue((ITypeResolutionService) null); 
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
#>
            "<#=name#>": "<#=value#>",
<#

    
            }
#>
        "WEBSHOP_LASTELEMENT": "just ignore this, for testing purpose"
        }
<#
    }
    File.Copy(fileResultPath, currentPathDest, true);
}


#>

Modulair uygulamanız varsa ve birden fazla dilde proje oluşturma önerimi takip ettiyseniz, her biri için bir T4 dosyası oluşturmanız gerekecektir. Json dosyalarının mantıksal olarak tanımlandığından emin olun, olması gerekmez en.json, aynı zamanda olabilir example-en.json. İle kullanmak için birden fazla json dosyaları birleştirmek için NGX-translate , talimatları takip buraya

Xamarin.Android'de kullanın

Güncellemelerde yukarıda açıklandığı gibi Angular / JSON ile yaptığım yöntemi kullanıyorum. Ancak Android XML dosyalarını kullanıyor, bu yüzden bu XML dosyalarını oluşturan bir T4 dosyası yazdım.

Yol: MyProject.Language / T4 / CreateAppLocalizationEN.tt

#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".xml" #>
<#
var fileName = "../Resources/Resources.en.resx";
var fileResultName = "../T4/CreateAppLocalizationEN.xml";
var fileResultRexPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileName);
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);

    var fileNameDest = "strings.xml";

    var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

    var currentPathDest =pathBaseDestination + "/MyProject.App.AndroidApp/Resources/values-en/" + fileNameDest;

    using(var reader = new ResXResourceReader(fileResultRexPath))
    {
        reader.UseResXDataNodes = true;
        #>
        <resources>
        <#

                foreach(DictionaryEntry entry in reader)
                {
                    var name = entry.Key;
                    //if(!name.ToString().Contains("WEBSHOP_") && !name.ToString().Contains("DASHBOARD_"))//only include keys with these prefixes, or the country ones.
                    //{
                    //  if(name.ToString().Length != 2)
                    //  {
                    //      continue;
                    //  }
                    //}
                    var node = (ResXDataNode)entry.Value;
                    var value = node.GetValue((ITypeResolutionService) null); 
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("&", "&amp;");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("<<", "");
                     //if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("'", "\'");
#>
              <string name="<#=name#>">"<#=value#>"</string>
<#      
                }
#>
            <string name="WEBSHOP_LASTELEMENT">just ignore this</string>
<#
        #>
        </resources>
        <#
        File.Copy(fileResultPath, currentPathDest, true);
    }

#>

Android values-xxklasörlerle çalışır , bu nedenle yukarıdaki values-enklasörde İngilizce için geçerlidir . Ancak, valuesklasöre giren bir varsayılan oluşturmanız da gerekir . Sadece T4 şablonunun üstüne kopyalayın ve yukarıdaki koddaki klasörü değiştirin.

İşte gidiyorsunuz, artık tüm projeleriniz için tek bir kaynak dosyası kullanabilirsiniz. Bu, her şeyi özel bir belgeye aktarmayı çok kolaylaştırır ve birinin onu çevirip tekrar içeri aktarmasına izin verir.

Dosyalarla harika çalışan bu harika VS eklentisine özel teşekkürler resx. Müthiş çalışması için ona bağış yapmayı düşünün (bununla hiçbir ilgim yok, sadece uzantıyı seviyorum).


1. Konuşlandırmadan sonra daha fazla dili nasıl eklersiniz? Dil Diline daha fazla kaynak ekleyerek ve yeniden derleyip sonra yeniden konuşlandırarak? (2) Çeviri için kullandığınız herhangi bir IDE veya Araç var mı (Winform'da 40'tan fazla formum var), paylaşabilir misiniz? (3) Denedim ve kültürü Arapçaya değiştirdiğimde çeviriyi alamadım, bir soru oluşturacağım ve size haber vereceğim
Smith

5
1: Resources.xx.resx'i ikiye bölün ve xx'i değiştirin ve switch ifadelerinin olduğu her yerde dili ekleyin. 2 ResxManager (TomEnglert tarafından) uzantısını kullanıyorum, Araçlar -> Uzantılar yoluyla yüklenebilir, dillerin yan yana olması için güzel bir yoldur, ancak gerçek çeviri başka biri tarafından yapılır (ResxManager ile excel'e / excel'den kolay dışa aktarma ve içe aktarma). 3. Bu son kez de bir tane ekleyerek karşılaşıldı, yukarıda listelenen tüm dosyaları, ancak bazı kesme noktalarını kontrol edin. Bunu WinForms'ta kullanmadım.
CularBytes

13
Kendi cevabımı yükseltebilir miyim?
WPF'de

1
@TiagoBrenck Merhaba, yalnızca bu özel durumda, varsayılan diliniz İngilizce ise, bir resource.en-gb.resx dosyası oluşturabilir ve% 1 değişiklikleri buraya ekleyebilirsiniz. Varsayılan olarak, en-gb dili seçiliyse ve sözcükler çevrilmediyse, varsayılan dili (kaynaklar.resx) kullanır.
CularBytes

1
Kaynak dosyasının anahtarlarını nasıl yapılandırdınız? Sadece bir Kaynak dosyası kullandığınızı gördüğüm ve size göre çok büyük bir uygulamanız olduğuna göre, anahtarları nasıl böldünüz? "Feature.MyMessage" veya "Area.Feature.MyMessage" gibi bir şey
Francesco Venturini

21

Bir dizi farklı yaklaşım kullanılarak uygulanan projeler gördüm, her birinin kendine özgü avantajları ve dezavantajları var.

  • Biri yapılandırma dosyasında yaptı (benim favorim değil)
  • Biri bunu bir veritabanı kullanarak yaptı - bu oldukça iyi çalıştı, ancak neyin bakımını yapacağınızı bildiğiniz için bir sıkıntıydı.
  • Bir kaynak dosyalarını önerdiğiniz şekilde kullandı ve bunun benim favori yaklaşımım olduğunu söylemeliyim.
  • En basit olanı dizelerle dolu bir içerme dosyası kullanarak yaptı - çirkin.

Seçtiğiniz kaynak yönteminin çok mantıklı olduğunu söyleyebilirim. Böyle şeyleri yapmanın daha iyi bir yolu olup olmadığını sık sık merak ettiğimden, başkalarının cevaplarını görmek de ilginç olurdu. Ben sayısız kaynaklar gördüğüm dahil kullanarak kaynaklar yöntemi tüm gelin burada SO üzerinde biri .


5

"En iyi yol" olduğunu sanmıyorum. Gerçekten geliştirdiğiniz teknolojilere ve uygulama türüne bağlı olacaktır.

Web uygulamaları, diğer posterlerin önerdiği gibi bilgileri veritabanında saklayabilir, ancak ayrı kaynak dosyaları kullanmanızı öneririm. Bu, kaynağınızdan ayrı olan kaynak dosyalarıdır . Ayrı kaynak dosyaları, aynı dosyalar için çekişmeyi azaltır ve projeniz büyüdükçe yerelleştirmenin iş mantığından ayrı yapılacağını görebilirsiniz. (Programcılar ve Çevirmenler).

Microsoft WinForm ve WPF uzmanları, her yerel ayara göre özelleştirilmiş ayrı kaynak derlemeleri kullanmanızı önerir.

WPF'nin UI öğelerini içeriğe göre boyutlandırma yeteneği, gereken düzen çalışmasını düşürür, örneğin: (Japonca sözcükler İngilizceden çok daha kısadır).

WPF'yi düşünüyorsanız: Bu msdn makalesini okumanızı öneririm. Dürüst olmak gerekirse, WPF yerelleştirme araçlarını buldum: msbuild, locbaml (ve belki de bir excel elektronik tablosu) kullanımı sıkıcı, ancak işe yarıyor.

Yalnızca biraz ilgili bir şey: Karşılaştığım yaygın bir sorun, hata kodları değil, hata mesajları (genellikle İngilizce) gönderen eski sistemleri entegre etmektir. Bu, ya eski sistemlerde yapılan değişiklikleri ya da arka uç dizelerini kendi hata kodlarıma ve ardından yerelleştirilmiş dizelere eşlemeyi zorlar ... yech. Hata kodları yerelleştirme dostudur


4

+1 Veritabanı

Veritabanında düzeltmeler yapılırsa uygulamanızdaki formlar kendilerini anında yeniden çevirebilir.

Tüm kontrollerin bir XML dosyasında (form başına bir tane) dil kaynak kimlikleriyle eşlendiği, ancak tüm kimliklerin veritabanında olduğu bir sistem kullandık.

Temel olarak, her bir denetimin kimliği tutması yerine (bir arabirim uygulamak veya VB6'da etiket özelliğini kullanmak) yerine, .NET'te denetim ağacının yansıma yoluyla kolayca keşfedilebilir olduğu gerçeğini kullandık. Formun yüklendiği bir işlem, eksik olması durumunda XML dosyasını oluşturur. XML dosyası, kontrolleri kaynak kimlikleriyle eşleştirirdi, bu yüzden bunun sadece doldurulması ve veritabanına eşlenmesi gerekiyordu. Bu, bir şey etiketlenmemişse veya başka bir kimliğe bölünmesi gerekiyorsa derlenmiş ikiliyi değiştirmeye gerek olmadığı anlamına geliyordu (hem isim hem de fiil olarak kullanılabilen bazı İngilizce kelimelerin iki farklı kelimeye çevrilmesi gerekebilir. sözlükte yer alır ve tekrar kullanılmaz, ancak bunu kimliklerin ilk ataması sırasında keşfedemeyebilirsiniz)

Uygulamanın daha fazla dahil olduğu tek durum, ekleme noktaları olan bir aşamanın kullanılmasıdır.

Veritabanı çeviri yazılımı, eksik çevirilerin vb. Üzerinden geçmeyi kolaylaştırmak için çeşitli iş akışı seçenekleriyle temel CRUD bakım ekranınızdı.


Metodunuzu beğendim, bana xml dosyasının nasıl oluşturulduğunu ve ardından veritabanına eşlendiğini söyleyebilir misiniz?
Smith

Form_Load'da veya her neyse, çeviri işlevi form örneğinde çağrıldı. Bu form için XML dosyası yüklendi. Eğer yoksa yaratıldı. Şema elimde değil, ancak temelde bir formdaki kontrol adını bir çeviri kimliğiyle eşleştirdi. Bu nedenle, XML dosyasında bulunmayan form üzerindeki herhangi bir denetim, çeviri kimliği olmayan bir giriş alır. Talep üzerine oluşturulacaklarından, sadece formunuzu oluşturabilir, eksik kontroller için XML dosyasını oluşturacak veya güncelleyecek uygulamayı çalıştırabilirsiniz. Ardından öğeler için çeviri kimliklerini girin.
Cade Roux

4

Arıyordum ve şunu buldum:

WPF veya Silverlight kullanıyorsanız, yaklaşımınız birçok nedenden dolayı WPF LocalizationExtension kullanmak olabilir .

BT'nin Açık Kaynağı ÜCRETSİZDİR (ve ücretsiz kalacaktır) gerçek bir sabit durumda

Bir Windows Uygulamasında şu şekilde bir şeyler yapabilirsiniz:

public partial class App : Application  
{  
     public App()  
     {             
     }  
 
     protected override void OnStartup(StartupEventArgs e)  
     {  
         Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); ;  
         Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE"); ;  
 
          FrameworkElement.LanguageProperty.OverrideMetadata(  
              typeof(FrameworkElement),  
              new FrameworkPropertyMetadata(  
                  XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));  
          base.OnStartup(e);  
    }  
} 

Ve bir Wep Sayfasında yaklaşımın aynı olabileceğini düşünüyorum.

İyi şanslar!


2

Birden çok kaynak dosyasıyla giderdim. Yapılandırması o kadar zor olmamalı. Aslında yakın zamanda, form dili kaynak dosyalarıyla bağlantılı olarak küresel dil tabanlı bir kaynak dosyalarının ayarlanmasıyla ilgili benzer bir soruyu yanıtladım.

Visual Studio 2008'de yerelleştirme

En azından WinForm geliştirme için en iyi yaklaşım olduğunu düşünürdüm.


Kaynakların bir dezavantajı, dilleri değiştirmek için yeniden başlatmanız gerekmesidir. Muhtemelen çoğu için kabul edilebilir, ama bu benim evcil hayvanım ...
Roman Starkov

2

Sisulizer gibi ticari araçları kullanabilirsiniz . Her dil için uydu montajı oluşturacaktır. Dikkat etmeniz gereken tek şey, sınıf adlarını gizlememek (obfuscator kullanıyorsanız).


0

Çoğu açık kaynaklı proje bu amaç için GetText kullanır . Nasıl ve daha önce bir .Net projesinde kullanılıp kullanılmadığını bilmiyorum.


0

Çoklu dil desteği için özel bir sağlayıcı kullanıyoruz ve tüm metinleri bir veritabanı tablosuna koyuyoruz. Web uygulamasını güncellemeden veritabanındaki metinleri güncellerken bazen önbelleğe alma sorunlarıyla karşılaşmamız dışında iyi çalışıyor.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.