곧 대규모 C # 프로젝트에서 작업 할 예정이며 처음부터 다국어 지원을 구축하고 싶습니다. 나는 놀았고 각 언어에 대해 별도의 리소스 파일을 사용하여 작동하게 한 다음 리소스 관리자를 사용하여 문자열을로드 할 수 있습니다.
제가 살펴볼 수있는 다른 좋은 접근 방법이 있습니까?
곧 대규모 C # 프로젝트에서 작업 할 예정이며 처음부터 다국어 지원을 구축하고 싶습니다. 나는 놀았고 각 언어에 대해 별도의 리소스 파일을 사용하여 작동하게 한 다음 리소스 관리자를 사용하여 문자열을로드 할 수 있습니다.
제가 살펴볼 수있는 다른 좋은 접근 방법이 있습니까?
답변:
API, MVC, 프로젝트 라이브러리 (핵심 기능), WPF, UWP 및 Xamarin을 포함 하는 12 개의 24 개 프로젝트가 포함 된 현재 솔루션이있는 경험을 통해이를 알 수 있습니다 . 내가 그렇게하는 가장 좋은 방법이라고 생각하므로이 긴 게시물을 읽을 가치가 있습니다. VS 도구의 도움으로 쉽게 내보내고 가져올 수 있으며 번역 대행사로 보내거나 다른 사람이 검토 할 수 있습니다.
2018 년 2 월 수정 : 여전히 강력 해지 면서 .NET Standard 라이브러리로 변환하면 .NET Framework 및 NET Core에서도 사용할 수 있습니다. 예를 들어 angular에서 사용할 수 있도록 JSON으로 변환하기위한 추가 섹션을 추가했습니다.
EDIT 2019 : Xamarin을 통해 앞으로도 모든 플랫폼에서 계속 작동합니다. 예 : resx 파일을 사용하기위한 Xamarin.Forms 조언. (아직 Xamarin.Forms에서 앱을 개발하지 않았지만 시작하는 방법에 대한 자세한 설명은 Xamarin.Forms Documentation ). JSON으로 변환하는 것과 마찬가지로 Xamarin.Android 용 .xml 파일로 변환 할 수도 있습니다.
EDIT 2019 (2) : WPF에서 UWP로 업그레이드하는 동안 UWP에서 .resw
콘텐츠는 동일하지만 사용법이 다른 다른 파일 형식을 사용하는 것을 선호한다는 것을 발견했습니다 . 내 의견으로 는 기본 솔루션 보다 더 잘 작동하는 다른 방법을 찾았습니다 .
EDIT 2020 : 여러 언어 프로젝트가 필요할 수있는 대규모 (modulair) 프로젝트에 대한 몇 가지 제안을 업데이트했습니다.
그래서 그것에 도달합시다.
프로
ResourceDirectories
.Thread.CurrentThread.CurrentCulture
단점
설정
솔루션에서 언어 프로젝트를 만들고 MyProject.Language 와 같은 이름을 지정 합니다. Resources라는 폴더를 추가하고 해당 폴더에 두 개의 Resources 파일 (.resx)을 만듭니다. 하나는 Resources.resx 이고 다른 하나는 Resources.en.resx (또는 특정의 경우 .en-GB.resx)입니다. 내 구현에서 기본 언어로 NL (네덜란드어) 언어가 있으므로 첫 번째 파일에, 영어는 두 번째 파일에 들어갑니다.
설정은 다음과 같습니다.
Resources.resx의 속성은 다음과 같아야합니다.
사용자 지정 도구 네임 스페이스가 프로젝트 네임 스페이스로 설정되어 있는지 확인합니다. 그 이유는 WPF에서 Resources
XAML 내부를 참조 할 수 없기 때문 입니다.
리소스 파일 내에서 액세스 수정자를 Public으로 설정합니다.
이렇게 큰 애플리케이션 (다른 모듈이라고합시다)이있는 경우 위와 같이 여러 프로젝트를 만드는 것을 고려할 수 있습니다. 이 경우 키와 리소스 클래스에 특정 모듈을 접두사로 붙일 수 있습니다. Visual Studio 용 최고의 언어 편집기를 사용 하여 모든 파일을 단일 개요로 결합합니다.
다른 프로젝트에서 사용
프로젝트 참조 : References-> Add Reference-> Prjects \ Solutions를 마우스 오른쪽 버튼으로 클릭합니다.
파일에서 네임 스페이스 사용 : using MyProject.Language;
백엔드에서 그렇게 사용하십시오.
string someText = Resources.orderGeneralError;
Resources라는 다른 것이 있으면 전체 네임 스페이스에 넣으십시오.
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>
또는 usings를 정의하지 않으려면 전체 네임 스페이스를 채우거나 /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 구현 소스 자습서 : Awesome Tutorial Blog
모델에 클래스 라이브러리 사용
백엔드 사용은 동일하지만 속성에서 사용하는 예일뿐입니다.
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 템플릿을 사용하여 열거 형을 생성 할 수 있습니다.
물론 MyProject.Language 네임 스페이스 에 대한 참조를 추가하면 백엔드에서 사용하는 방법을 알고 있습니다.
XAML에서 Window 또는 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
. 직접 구현하거나 (설치 중에 선택) 시스템이 결정하도록 할 수 있습니다.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SetLanguageDictionary();
}
private void SetLanguageDictionary()
{
switch (Thread.CurrentThread.CurrentCulture.ToString())
{
case "nl-NL":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("nl-NL");
break;
case "en-GB":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
default://default english because there can be so many different system language, we rather fallback on english in this case.
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
}
}
}
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를 새로 고치려면 마지막 줄이 필요합니다. 이 프로젝트를 계속 진행하는 동안이 작업을 두 번해야한다는 것을 알았습니다. 사용자가 처음 시작할 때 언어 선택으로 끝날 수 있습니다. 그러나 이것은 Windows Store를 통해 배포되므로 일반적으로 언어는 시스템 언어와 동일합니다.
그런 다음 XAML에서 사용합니다.
<TextBlock Text="{CustomResource ExampleResourceKey}"></TextBlock>
요즘에는 Angular와 같은 프레임 워크를 구성 요소와 결합하여 cshtml없이 사용하는 것이 더 일반적입니다. 번역은 json 파일에 저장되며, 작동 방식을 다루지는 않을 것 입니다. 각도 다중 번역 대신 ngx-translate 를 강력히 권장 합니다. 따라서 번역을 JSON 파일로 변환하려면 매우 쉽습니다. 리소스 파일을 json 파일로 변환하는 T4 템플릿 스크립트를 사용합니다. 몇 가지 수정이 필요하므로 구문을 읽고 올바르게 사용하려면 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
. ngx-translate 와 함께 사용하기 위해 여러 json 파일을 결합하려면 여기 의 지침을 따르십시오.
위의 업데이트에서 설명한 것처럼 Angular / JSON과 동일한 방법을 사용합니다. 하지만 Android는 XML 파일을 사용하므로 이러한 XML 파일을 생성하는 T4 파일을 작성했습니다.
경로 : 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("&", "&");
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
. 그의 멋진 작품을 위해 그에게 기부 하는 것을 고려 해보세요 (저는 그것과 아무 관련이 없으며 확장 프로그램을 좋아합니다).
여러 가지 다른 접근 방식을 사용하여 구현 된 프로젝트를 보았습니다. 각각의 장점과 단점이 있습니다.
나는 당신이 선택한 자원 방법이 많은 의미가 있다고 말하고 싶습니다. 이런 일을하는 더 좋은 방법이 있는지 자주 궁금해해서 다른 사람들의 대답도 보는 것도 재미있을 것입니다. 나는 바로 여기 SO를 포함하여 리소스 사용 방법을 가리키는 수많은 리소스를 보았습니다 .
나는 "최선의 방법"이 있다고 생각하지 않는다. 실제로 구축하는 기술 및 응용 프로그램 유형에 따라 다릅니다.
웹앱은 다른 포스터가 제안한대로 데이터베이스에 정보를 저장할 수 있지만 별도의 리소스 파일을 사용하는 것이 좋습니다. 그것은 당신의 소스에서 분리 된 리소스 파일 입니다. 리소스 파일을 분리하면 동일한 파일에 대한 경합이 줄어들고 프로젝트가 커짐에 따라 현지화가 비즈니스 로직과 별도로 수행 될 수 있습니다. (프로그래머 및 번역가).
Microsoft WinForm 및 WPF 전문가는 각 로캘에 맞게 사용자 지정된 별도의 리소스 어셈블리를 사용할 것을 권장합니다.
콘텐츠에 맞게 UI 요소의 크기를 조정하는 WPF의 기능은 필요한 레이아웃 작업을 줄여줍니다. 예 : (일본어 단어는 영어보다 훨씬 짧습니다).
WPF를 고려중인 경우 : 이 msdn 기사 를 읽는 것이 좋습니다 . 사실 WPF 지역화 도구 인 msbuild, locbaml (및 엑셀 스프레드 시트)을 사용하는 것이 지루하지만 작동합니다.
약간 관련된 것 : 내가 직면하는 일반적인 문제는 오류 코드가 아닌 오류 메시지 (보통 영어)를 보내는 레거시 시스템을 통합하는 것입니다. 이것은 레거시 시스템을 변경하거나 백엔드 문자열을 내 오류 코드에 매핑 한 다음 현지화 된 문자열로 매핑합니다. 오류 코드는 현지화 친구입니다.
+1 데이터베이스
앱의 양식은 데이터베이스가 수정 된 경우 즉시 다시 번역 할 수도 있습니다.
모든 컨트롤이 XML 파일 (양식당 하나씩)에 언어 리소스 ID로 매핑되었지만 모든 ID가 데이터베이스에있는 시스템을 사용했습니다.
기본적으로 각 컨트롤에 ID (인터페이스 구현 또는 VB6의 태그 속성 사용)를 유지하는 대신 .NET에서는 리플렉션을 통해 컨트롤 트리를 쉽게 검색 할 수 있다는 사실을 사용했습니다. 양식이로드 될 때 프로세스가 누락 된 경우 XML 파일을 빌드합니다. XML 파일은 컨트롤을 해당 리소스 ID에 매핑하므로 단순히 입력하고 데이터베이스에 매핑하면됩니다. 이것은 태그가 지정되지 않았거나 다른 ID로 분할해야하는 경우 컴파일 된 바이너리를 변경할 필요가 없음을 의미합니다 (명사와 동사로 사용될 수있는 영어로 된 일부 단어는 두 개의 다른 단어로 번역해야 할 수 있음) 딕셔너리에서 재사용 할 수 없지만 초기 ID 할당 중에이를 발견하지 못할 수 있습니다.
앱이 더 많이 관여하는 유일한 경우는 삽입 점이있는 단계가 사용되는 경우입니다.
데이터베이스 번역 소프트웨어는 누락 된 번역 등을 쉽게 처리 할 수있는 다양한 워크 플로 옵션이있는 기본 CRUD 유지 관리 화면이었습니다.
나는 수색하고 있고 나는 이것을 발견했다 :
WPF 또는 Silverlight를 사용하는 경우 여러 가지 이유로 WPF LocalizationExtension 을 사용할 수 있습니다 .
IT의 오픈 소스 무료 (그리고 무료로 유지 될 것임)는 진정한 안정 상태입니다.
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 Page에서 aproach가 같을 수 있다고 생각합니다.
행운을 빕니다!
여러 리소스 파일을 가지고 갈 것입니다. 구성하기가 그렇게 어렵지 않습니다. 사실 저는 최근에 양식 언어 리소스 파일과 함께 전역 언어 기반 리소스 파일을 설정하는 것과 관련된 유사한 질문에 답변했습니다.
적어도 WinForm 개발을위한 최선의 접근 방식이라고 생각합니다.
표준 리소스 파일이 더 쉽습니다. 그러나 조회 테이블과 같은 언어 종속 데이터가있는 경우 두 개의 리소스 세트를 관리해야합니다.
나는 그것을하지 않았지만 다음 프로젝트에서는 데이터베이스 리소스 공급자를 구현할 것입니다. MSDN에서 수행하는 방법을 찾았습니다.
http://msdn.microsoft.com/en-us/library/aa905797.aspx
이 구현도 발견했습니다.