วิธีที่ดีที่สุดในการใช้งานหลายภาษา / โลกาภิวัตน์ในโครงการ. NET ขนาดใหญ่


87

เร็ว ๆ นี้ฉันจะทำงานในโครงการ c # ขนาดใหญ่และต้องการสร้างการสนับสนุนหลายภาษาตั้งแต่เริ่มต้น ฉันได้เล่นและสามารถทำให้มันทำงานได้โดยใช้ไฟล์ทรัพยากรแยกกันสำหรับแต่ละภาษาจากนั้นใช้ตัวจัดการทรัพยากรเพื่อโหลดสตริง

มีแนวทางดีๆอื่น ๆ ที่ฉันสามารถพิจารณาได้หรือไม่?

คำตอบ:


91

ใช้โปรเจ็กต์แยกกับทรัพยากร

ฉันสามารถบอกสิ่งนี้ได้จากประสบการณ์ภายนอกโดยมีโซลูชันปัจจุบันกับ12 24โครงการซึ่งรวมถึง API, MVC, ไลบรารีโครงการ (ฟังก์ชันหลัก), WPF, UWP และ Xamarin ควรอ่านโพสต์ยาว ๆ นี้เพราะคิดว่าเป็นวิธีที่ดีที่สุด ด้วยความช่วยเหลือของเครื่องมือ VS สามารถส่งออกและนำเข้าได้อย่างง่ายดายเพื่อส่งไปยังหน่วยงานแปลหรือตรวจสอบโดยบุคคลอื่น

แก้ไข 02/2018:ยังคงแข็งแกร่งการแปลงเป็นไลบรารี. NET Standard ทำให้สามารถใช้งานได้กับ. NET Framework และ NET Core ฉันเพิ่มส่วนพิเศษสำหรับการแปลงเป็น JSON เพื่อให้ตัวอย่างเช่นเชิงมุมสามารถใช้งานได้

แก้ไข 2019:ก้าวไปข้างหน้ากับ Xamarin สิ่งนี้ยังคงใช้ได้กับทุกแพลตฟอร์ม เช่น Xamarin.Forms แนะนำให้ใช้ไฟล์ resx ด้วย (ฉันยังไม่ได้พัฒนาแอปใน Xamarin.Forms แต่เอกสารนี้เป็นวิธีที่จะอธิบายรายละเอียดในการเริ่มต้นใช้งานครอบคลุม: เอกสาร Xamarin.Forms ) เช่นเดียวกับการแปลงเป็น JSON เราสามารถแปลงเป็นไฟล์. xml สำหรับ Xamarin.Android

แก้ไข 2019 (2):ในขณะที่อัปเกรดเป็น UWP จาก WPF ฉันพบว่าใน UWP พวกเขาชอบใช้ประเภทไฟล์อื่น.reswซึ่งในแง่ของเนื้อหาเหมือนกัน แต่การใช้งานแตกต่างกัน ผมพบว่าวิธีที่แตกต่างกันของการทำเช่นนี้ซึ่งในความคิดของฉันทำงานได้ดีขึ้นแล้วการแก้ปัญหาเริ่มต้น

แก้ไข 2020:อัปเดตคำแนะนำสำหรับโปรเจ็กต์ขนาดใหญ่ (โมดูล) ที่อาจต้องใช้โปรเจ็กต์หลายภาษา

ไปดูกันเลย

ข้อดี

  • พิมพ์ผิดเกือบทุกที่
  • ใน WPF ResourceDirectoriesคุณไม่ได้มีการจัดการกับ
  • รองรับ ASP.NET, Class Libraries, WPF, Xamarin, .NET Core, .NET Standard เท่าที่ฉันได้ทดสอบ
  • ไม่จำเป็นต้องมีไลบรารีของบุคคลที่สามเพิ่มเติม
  • รองรับวัฒนธรรมสำรอง: en-US -> th
  • ไม่เพียง แต่แบ็คเอนด์เท่านั้น แต่ยังทำงานใน XAML สำหรับ WPF และ Xamarin.Forms ในรูปแบบ. cshtml สำหรับ MVC
  • ปรับแต่งภาษาได้อย่างง่ายดายโดยการเปลี่ยน Thread.CurrentThread.CurrentCulture
  • เครื่องมือค้นหาสามารถรวบรวมข้อมูลในภาษาต่างๆและผู้ใช้สามารถส่งหรือบันทึก URL เฉพาะภาษาได้

Con's

  • WPF XAML บางครั้งมีปัญหาสตริงที่เพิ่มใหม่จะไม่แสดงโดยตรง สร้างใหม่คือการแก้ไขอุณหภูมิ (vs2015)
  • UWP XAML ไม่แสดงคำแนะนำ Intellisense และไม่แสดงข้อความขณะออกแบบ
  • บอกฉัน.

ติดตั้ง

สร้างโครงการภาษาในการแก้ปัญหาของคุณให้มันชื่อเหมือนMyProject.Language เพิ่มโฟลเดอร์ชื่อ Resources และในโฟลเดอร์นั้นสร้างไฟล์ Resources สองไฟล์ (.resx) หนึ่งเรียกว่าResources.resxและอีกชื่อหนึ่งเรียกว่าResources.en.resx (หรือ. en-GB.resx สำหรับเฉพาะ) ในการใช้งานของฉันฉันมีภาษา NL (ดัตช์) เป็นภาษาเริ่มต้นดังนั้นสิ่งนั้นจะอยู่ในไฟล์แรกของฉันและภาษาอังกฤษจะอยู่ในไฟล์ที่สองของฉัน

การตั้งค่าควรมีลักษณะดังนี้:

โครงการตั้งค่าภาษา

คุณสมบัติสำหรับ Resources.resx ต้องเป็น: คุณสมบัติ

ตรวจสอบให้แน่ใจว่าเนมสเปซเครื่องมือที่กำหนดเองถูกตั้งค่าเป็นเนมสเปซโปรเจ็กต์ของคุณ เหตุผลคือใน WPF คุณไม่สามารถอ้างอิงถึงResourcesภายใน XAML

และภายในไฟล์ทรัพยากรตั้งค่าตัวปรับการเข้าถึงเป็นสาธารณะ:

ตัวปรับการเข้าถึง

หากคุณมีแอปพลิเคชันขนาดใหญ่เช่นนี้ (สมมติว่าเป็นโมดูลที่แตกต่างกัน) คุณสามารถพิจารณาสร้างโปรเจ็กต์หลาย ๆ โปรเจ็กต์ดังกล่าวข้างต้น ในกรณีนี้คุณสามารถนำหน้าคีย์และคลาสทรัพยากรของคุณด้วยโมดูลเฉพาะได้ ใช้โปรแกรมแก้ไขภาษาที่ดีที่สุดสำหรับ Visual Studio เพื่อรวมไฟล์ทั้งหมดไว้ในภาพรวมเดียว

ใช้ในโครงการอื่น

การอ้างอิงโครงการของคุณ: คลิกขวาที่ References -> Add Reference -> Prjects \ Solutions

ใช้เนมสเปซในไฟล์: using MyProject.Language;

ใช้แบบนี้ในส่วนหลัง: string someText = Resources.orderGeneralError; หากมีสิ่งอื่นที่เรียกว่าทรัพยากรให้ใส่ในเนมสเปซทั้งหมด

ใช้ใน MVC

ใน MVC คุณสามารถทำได้ตามที่คุณต้องการตั้งค่าภาษา แต่ฉันใช้ url ที่กำหนดพารามิเตอร์ซึ่งสามารถตั้งค่าได้ดังนี้:

RouteConfig.cs ด้านล่างการแมปอื่น ๆ

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 (อาจจะต้องมีการเพิ่มถ้าให้เพิ่มFilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);ไปที่Application_start()วิธีการในGlobal.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เพียงแค่ตั้งค่าข้อมูลวัฒนธรรม

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

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

หรือหากคุณไม่ต้องการกำหนดการใช้งานให้กรอกเนมสเปซทั้งหมดหรือคุณสามารถกำหนดเนมสเปซภายใต้ /Views/web.config:

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

บทช่วยสอนการใช้งาน mvc นี้: บล็อกการสอนที่ยอดเยี่ยม

ใช้ในไลบรารีคลาสสำหรับโมเดล

การใช้แบ็คเอนด์จะเหมือนกัน แต่เป็นเพียงตัวอย่างสำหรับใช้ในแอตทริบิวต์

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

หากคุณมี reshaper ระบบจะตรวจสอบโดยอัตโนมัติว่ามีชื่อทรัพยากรที่ระบุหรือไม่ หากคุณต้องการความปลอดภัยในการพิมพ์คุณสามารถใช้เทมเพลต T4 เพื่อสร้าง enum

ใช้ใน WPF

แน่นอนเพิ่มการอ้างอิงไปยังMyProjectของคุณเนมสเปซภาษาเรารู้วิธีใช้ในส่วนหลัง

ใน XAML ภายในส่วนหัวของหน้าต่างหรือ UserControl ให้เพิ่มการอ้างอิงเนมสเปซที่เรียกว่าlang:

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

จากนั้นภายในป้ายกำกับ:

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

เนื่องจากมีการพิมพ์อย่างมากคุณจึงแน่ใจว่ามีสตริงทรัพยากรอยู่ คุณอาจต้องคอมไพล์โครงการใหม่ในบางครั้งในระหว่างการตั้งค่าบางครั้ง WPF อาจมีปัญหากับเนมสเปซใหม่

อีกอย่างสำหรับ WPF ให้ตั้งค่าภาษาภายในไฟล์App.xaml.cs. คุณสามารถดำเนินการเองได้ (เลือกระหว่างการติดตั้ง) หรือปล่อยให้ระบบตัดสินใจ

ใช้ใน UWP

ใน UWP Microsoft ใช้โซลูชันนี้ซึ่งหมายความว่าคุณจะต้องสร้างไฟล์ทรัพยากรใหม่ นอกจากนี้คุณไม่สามารถใช้ข้อความซ้ำได้เนื่องจากต้องการให้คุณตั้งค่าการx:Uidควบคุมของคุณใน XAML เป็นคีย์ในทรัพยากรของคุณ และในทรัพยากรของคุณคุณต้องทำExample.Textเพื่อเติมTextBlockข้อความ ฉันไม่ชอบโซลูชันนั้นเลยเพราะฉันต้องการใช้ไฟล์ทรัพยากรของฉันซ้ำ ในที่สุดฉันก็คิดวิธีแก้ปัญหาต่อไปนี้ ฉันเพิ่งพบสิ่งนี้ในวันนี้ (2019-09-26) ดังนั้นฉันอาจจะกลับมาพร้อมอย่างอื่นหากปรากฎว่ามันไม่ได้ผลตามที่ต้องการ

เพิ่มสิ่งนี้ในโครงการของคุณ:

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

เพิ่มสิ่งนี้App.xaml.csในตัวสร้าง:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

ทุกที่ที่คุณต้องการในแอปของคุณใช้สิ่งนี้เพื่อเปลี่ยนภาษา:

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

ต้องใช้บรรทัดสุดท้ายเพื่อรีเฟรช UI ในขณะที่ฉันยังทำงานในโครงการนี้ฉันสังเกตเห็นว่าฉันต้องทำ 2 ครั้งนี้ ฉันอาจลงเอยด้วยการเลือกภาษาในครั้งแรกที่ผู้ใช้เริ่มต้น แต่เนื่องจากสิ่งนี้จะเผยแพร่ผ่าน Windows Store ภาษามักจะเท่ากับภาษาของระบบ

จากนั้นใช้ใน XAML:

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

ใช้ใน Angular (แปลงเป็น JSON)

ปัจจุบันเป็นเรื่องปกติมากขึ้นที่จะมีเฟรมเวิร์กเช่น Angular ร่วมกับส่วนประกอบดังนั้นหากไม่มี cshtml การแปลจะถูกเก็บไว้ในไฟล์ json ฉันจะไม่พูดถึงวิธีการทำงานฉันขอแนะนำให้ใช้ngx-translateแทนการแปลหลายเชิงมุม ดังนั้นหากคุณต้องการแปลงการแปลเป็นไฟล์ JSON มันค่อนข้างง่ายฉันใช้สคริปต์เทมเพลต T4 ที่แปลงไฟล์ Resources เป็นไฟล์ json ฉันขอแนะนำให้ติดตั้งตัวแก้ไข T4เพื่ออ่านไวยากรณ์และใช้อย่างถูกต้องเนื่องจากคุณต้องทำการแก้ไขบางอย่าง

สิ่งเดียวที่ควรทราบ: ไม่สามารถสร้างข้อมูลคัดลอกล้างข้อมูลและสร้างเป็นภาษาอื่นได้ ดังนั้นคุณต้องคัดลอกโค้ดด้านล่างหลาย ๆ ครั้งตามภาษาที่คุณมีและเปลี่ยนรายการก่อน "// เลือกภาษาที่นี่" ขณะนี้ไม่มีเวลาแก้ไข แต่อาจจะอัปเดตในภายหลัง (หากสนใจ)

เส้นทาง: 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 และคุณทำตามคำแนะนำของฉันในการสร้างโปรเจ็กต์หลายภาษาคุณจะต้องสร้างไฟล์ T4 สำหรับแต่ละโปรเจ็กต์ ตรวจสอบให้แน่ใจว่าไฟล์ json ถูกกำหนดอย่างมีเหตุผลไม่จำเป็นต้องเป็นen.jsonเช่นนั้นก็สามารถเป็นexample-en.jsonได้ หากต้องการรวมไฟล์ json หลายไฟล์เพื่อใช้กับngx-translateให้ทำตามคำแนะนำที่นี่

ใช้ใน Xamarin Android

ตามที่อธิบายไว้ข้างต้นในการอัปเดตฉันใช้วิธีเดียวกับที่ทำกับ Angular / JSON แต่ Android ใช้ไฟล์ XML ดังนั้นฉันจึงเขียนไฟล์ T4 ที่สร้างไฟล์ XML เหล่านั้น

เส้นทาง: 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-xxโฟลเดอร์ดังนั้นด้านบนจึงเป็นภาษาอังกฤษสำหรับในvalues-enโฟลเดอร์ แต่คุณต้องสร้างค่าเริ่มต้นที่จะเข้าไปในvaluesโฟลเดอร์ด้วย เพียงคัดลอกเทมเพลต T4 ด้านบนและเปลี่ยนโฟลเดอร์ในโค้ดด้านบน

เอาล่ะตอนนี้คุณสามารถใช้ไฟล์ทรัพยากรเดียวสำหรับโครงการทั้งหมดของคุณ สิ่งนี้ทำให้การส่งออกทุกอย่างไปยังเอกสารยกเว้นเป็นเรื่องง่ายมากและให้คนแปลและนำเข้าอีกครั้ง

ขอขอบคุณเป็นพิเศษกับส่วนขยาย VS ที่น่าทึ่งนี้ซึ่งใช้งานได้ดีกับresxไฟล์ ลองบริจาคให้เขาเพื่อผลงานที่ยอดเยี่ยมของเขา (ฉันไม่เกี่ยวอะไรกับเรื่องนี้ฉันแค่ชอบส่วนขยาย)


1. คุณจะเพิ่มภาษาอื่น ๆ หลังจากการปรับใช้งานได้อย่างไรโดยการเพิ่มทรัพยากรให้มากขึ้นใน Mylanguage และคอมไพล์ใหม่แล้วปรับใช้ (2) มี IDE หรือเครื่องมือใดที่คุณใช้ในการแปล (ฉันมีมากกว่า 40 รูปแบบใน winform) คุณสามารถแบ่งปันได้หรือไม่? (3) ฉันลองแล้ว แต่มันไม่ได้รับการแปลเมื่อฉันเปลี่ยนวัฒนธรรมเป็นภาษาอาหรับฉันจะสร้างคำถามและแจ้งให้คุณทราบ
Smith

5
1: เพียงแค่เผยแพร่ Resources.xx.resx และเปลี่ยน xx และทุกที่ที่ฉันมีคำสั่ง switch จะเพิ่มภาษา 2 ฉันใช้ส่วนขยาย ResxManager (โดย TomEnglert) สามารถติดตั้งผ่าน Tools -> Extensions ซึ่งเป็นวิธีที่ดีในการมีภาษาติดกัน แต่การแปลจริงจะทำโดยคนอื่น (ส่งออกและนำเข้าสู่ / จาก excel ด้วย ResxManager ได้ง่าย) 3. พบครั้งล่าสุดนี้เช่นกันโดยการเพิ่มไฟล์ตรวจสอบไฟล์ทั้งหมดที่ระบุไว้ด้านบน แต่มีจุดพักบางจุด ฉันไม่ได้ใช้สิ่งนี้ใน WinForms แม้ว่า
CularBytes

13
ฉันสามารถโหวตคำตอบของตัวเองได้หรือไม่? ฉันต้องตรวจสอบคำตอบของตัวเองอย่างโง่ ๆ เพื่อแก้ไขข้อบกพร่องในการสลับระหว่างภาษาใน WPF -.-
CularBytes

1
@TiagoBrenck สวัสดีเฉพาะในสถานการณ์นี้หากภาษาอังกฤษเป็นภาษาเริ่มต้นของคุณคุณสามารถสร้างไฟล์ resources.en-gb.resx และเพิ่มการเปลี่ยนแปลง 1% ในนั้น ตามค่าเริ่มต้นหากเลือกภาษา en-gb และไม่ได้แปลคำภาษาจะใช้ภาษาเริ่มต้น (resources.resx)
CularBytes

1
คุณจัดโครงสร้างคีย์ของไฟล์ทรัพยากรอย่างไร เนื่องจากฉันเห็นว่าคุณใช้ไฟล์ทรัพยากรเพียงไฟล์เดียวและคุณมีแอปขนาดใหญ่คุณแบ่งคีย์อย่างไร? บางอย่างเช่น "Feature.MyMessage" หรือ "Area.Feature.MyMessage"
Francesco Venturini

21

ฉันเคยเห็นโครงการที่ดำเนินการโดยใช้วิธีการต่างๆมากมายแต่ละโครงการมีข้อดีและข้อเสีย

  • หนึ่งในไฟล์ config (ไม่ใช่รายการโปรดของฉัน)
  • มีคนหนึ่งใช้ฐานข้อมูล - วิธีนี้ได้ผลดี แต่เป็นความเจ็บปวดที่คุณรู้ว่าต้องรักษาอะไร
  • ไฟล์ทรัพยากรที่ใช้แล้วหนึ่งไฟล์ตามที่คุณแนะนำและฉันต้องบอกว่าเป็นแนวทางที่ฉันชอบ
  • ขั้นพื้นฐานที่สุดทำได้โดยใช้ไฟล์รวมที่เต็มไปด้วยสตริง - น่าเกลียด

ฉันคิดว่าวิธีการใช้ทรัพยากรที่คุณเลือกมีความหมายมาก การดูคำตอบของคนอื่นก็น่าสนใจเช่นกันเพราะฉันมักจะสงสัยว่ามีวิธีที่ดีกว่าในการทำสิ่งนี้หรือไม่ ผมเคยเห็นทรัพยากรจำนวนมากที่ชี้ไปโดยใช้วิธีการทรัพยากรรวมทั้งคนหนึ่งที่นี่ใน SO


5

ฉันไม่คิดว่าจะมี "วิธีที่ดีที่สุด" จริงๆแล้วจะขึ้นอยู่กับเทคโนโลยีและประเภทของแอปพลิเคชันที่คุณกำลังสร้าง

Webapps สามารถจัดเก็บข้อมูลในฐานข้อมูลได้ตามที่ผู้โพสต์อื่นแนะนำ แต่ขอแนะนำให้ใช้ไฟล์ทรัพยากรแยกกัน นั่นคือไฟล์ทรัพยากรแยกจากแหล่งที่มาของ ไฟล์ทรัพยากรที่แยกจากกันช่วยลดความขัดแย้งในไฟล์เดียวกันและเมื่อโครงการของคุณเติบโตขึ้นคุณอาจพบว่าการแปลเป็นภาษาท้องถิ่นจะแยกจากตรรกะทางธุรกิจ (โปรแกรมเมอร์และนักแปล).

ผู้เชี่ยวชาญด้าน Microsoft WinForm และ WPF แนะนำให้ใช้แอสเซมบลีทรัพยากรแยกกันที่กำหนดเองสำหรับแต่ละโลแคล

ความสามารถของ WPF ในการปรับขนาดองค์ประกอบ UI ให้กับเนื้อหาช่วยลดงานเค้าโครงที่ต้องการเช่น: (คำภาษาญี่ปุ่นสั้นกว่าภาษาอังกฤษมาก)

หากคุณกำลังพิจารณา WPF: ฉันขอแนะนำให้อ่านบทความ msdn นี้ เพื่อความเป็นจริงฉันพบว่าเครื่องมือแปล WPF: msbuild, locbaml (และอาจเป็นสเปรดชีต excel) น่าเบื่อที่จะใช้ แต่มันก็ใช้งานได้

สิ่งที่เกี่ยวข้องเล็กน้อยเท่านั้น: ปัญหาทั่วไปที่ฉันพบคือการรวมระบบเดิมที่ส่งข้อความแสดงข้อผิดพลาด (โดยปกติจะเป็นภาษาอังกฤษ) ไม่ใช่รหัสข้อผิดพลาด สิ่งนี้บังคับให้เปลี่ยนระบบเดิมหรือแมปสตริงแบ็กเอนด์กับรหัสข้อผิดพลาดของฉันเองจากนั้นไปยังสตริงที่แปลเป็นภาษาท้องถิ่น ... yech รหัสข้อผิดพลาดเป็นเพื่อนของการแปล


4

+1 ฐานข้อมูล

แบบฟอร์มในแอปของคุณสามารถแปลตัวเองซ้ำได้ทันทีหากมีการแก้ไขฐานข้อมูล

เราใช้ระบบที่แมปการควบคุมทั้งหมดในไฟล์ XML (หนึ่งรายการต่อรูปแบบ) กับ ID ทรัพยากรภาษา แต่ ID ทั้งหมดอยู่ในฐานข้อมูล

โดยทั่วไปแทนที่จะให้การควบคุมแต่ละรายการถือ ID (การใช้อินเทอร์เฟซหรือใช้คุณสมบัติแท็กใน VB6) เราใช้ความจริงที่ว่าใน. NET โครงสร้างควบคุมสามารถค้นพบได้ง่ายผ่านการสะท้อนกลับ กระบวนการเมื่อโหลดแบบฟอร์มจะสร้างไฟล์ XML หากไม่มี ไฟล์ XML จะแมปการควบคุมกับ ID ทรัพยากรดังนั้นจึงจำเป็นต้องกรอกข้อมูลและแมปกับฐานข้อมูล นั่นหมายความว่าไม่จำเป็นต้องเปลี่ยนไบนารีที่คอมไพล์แล้วหากบางสิ่งไม่ได้ถูกแท็กหรือหากจำเป็นต้องแยกเป็น ID อื่น (บางคำในภาษาอังกฤษซึ่งอาจใช้เป็นทั้งคำนามและคำกริยาอาจต้องแปลเป็นสองคำที่ต่างกัน ในพจนานุกรมและไม่สามารถใช้ซ้ำได้ แต่คุณอาจไม่พบสิ่งนี้ในระหว่างการกำหนด ID ครั้งแรก)

สิ่งเดียวที่แอปมีส่วนร่วมมากขึ้นคือเมื่อใช้เฟสที่มีจุดแทรก

ซอฟต์แวร์แปลฐานข้อมูลเป็นหน้าจอการบำรุงรักษา CRUD พื้นฐานของคุณพร้อมตัวเลือกเวิร์กโฟลว์ต่างๆเพื่ออำนวยความสะดวกในการแปลคำแปลที่ขาดหายไป


ฉันชอบวิธีการของคุณคุณบอกฉันได้ไหมว่าไฟล์ xml ถูกสร้างขึ้นแล้วแมปกับฐานข้อมูลได้อย่างไร
Smith

ใน Form_Load หรืออะไรก็ตามฟังก์ชันการแปลถูกเรียกใช้ในอินสแตนซ์ของฟอร์ม โหลดไฟล์ XML สำหรับฟอร์มนั้นแล้ว ถ้าไม่มีมันถูกสร้างขึ้น ฉันไม่มีสคีมานอกมือ แต่โดยพื้นฐานแล้วมันแมปชื่อควบคุมในแบบฟอร์มกับรหัสการแปล ดังนั้นการควบคุมใด ๆ บนฟอร์มที่ไม่ได้อยู่ในไฟล์ XML จะได้รับรายการที่ไม่มีรหัสการแปล เนื่องจากจะถูกสร้างขึ้นตามความต้องการคุณสามารถสร้างแบบฟอร์มของคุณเรียกใช้แอปซึ่งจะสร้างหรืออัปเดตไฟล์ XML สำหรับการควบคุมที่ขาดหาย จากนั้นกรอกรหัสการแปลสำหรับรายการ
Cade Roux

4

ฉันได้ค้นหาและฉันพบสิ่งนี้:

หากคุณใช้ WPF หรือ Silverlight aproach ของคุณอาจใช้WPF LocalizationExtensionด้วยเหตุผลหลายประการ

มันเป็นโอเพ่นซอร์สมันฟรี (และจะอยู่ฟรี) อยู่ในสถานะคงที่จริง

ในแอปพลิเคชัน Windows คุณสามารถทำสิ่งนี้ได้:

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

และฉันคิดว่าในหน้า Wep การเปิดเผยอาจจะเหมือนกัน

โชคดี!


2

ฉันจะใช้ไฟล์ทรัพยากรหลายไฟล์ ไม่น่าจะยากที่จะกำหนดค่า อันที่จริงฉันเพิ่งตอบคำถามที่คล้ายกันเกี่ยวกับการตั้งค่าไฟล์ทรัพยากรที่ใช้ภาษาสากลร่วมกับไฟล์ทรัพยากรภาษาในรูปแบบ

การแปลเป็นภาษาท้องถิ่นใน Visual Studio 2008

ฉันจะพิจารณาว่าแนวทางที่ดีที่สุดอย่างน้อยที่สุดสำหรับการพัฒนา WinForm


ข้อเสียเปรียบของทรัพยากรคือคุณต้องรีสตาร์ทเพื่อเปลี่ยนภาษา มันอาจจะยอมรับได้สำหรับคนส่วนใหญ่ แต่มันเป็นสัตว์เลี้ยงของฉัน ...
Roman Starkov

2

คุณสามารถใช้เครื่องมือเชิงพาณิชย์เช่นSisulizer มันจะสร้างแอสเซมบลีดาวเทียมสำหรับแต่ละภาษา สิ่งเดียวที่คุณควรใส่ใจคืออย่าทำให้ชื่อคลาสของรูปแบบสับสน (ถ้าคุณใช้ obfuscator)



0

เราใช้ผู้ให้บริการที่กำหนดเองสำหรับการสนับสนุนหลายภาษาและใส่ข้อความทั้งหมดในตารางฐานข้อมูล ทำงานได้ดียกเว้นบางครั้งเราประสบปัญหาการแคชเมื่ออัปเดตข้อความในฐานข้อมูลโดยไม่ต้องอัปเดตเว็บแอปพลิเคชัน


0

ไฟล์ทรัพยากรมาตรฐานง่ายกว่า อย่างไรก็ตามหากคุณมีข้อมูลที่ขึ้นกับภาษาเช่นตารางการค้นหาคุณจะต้องจัดการชุดทรัพยากรสองชุด

ฉันยังไม่ได้ทำ แต่ในโครงการถัดไปฉันจะใช้ผู้ให้บริการทรัพยากรฐานข้อมูล ฉันพบวิธีการทำบน MSDN:

http://msdn.microsoft.com/en-us/library/aa905797.aspx

ฉันยังพบการใช้งานนี้:

ผู้ให้บริการ DBResource

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.