전체 응용 프로그램의 문화를 설정하는 방법이 있습니까? 모든 현재 스레드와 새 스레드?


177

전체 응용 프로그램의 문화를 설정하는 방법이 있습니까? 모든 현재 스레드와 새 스레드?

우리는 데이터베이스에 저장된 문화의 이름을 가지고 있으며 응용 프로그램이 시작될 때

CultureInfo ci = new CultureInfo(theCultureString);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;

그러나 물론 새로운 스레드에서 무언가를 원할 때 "손실"됩니다. 것을 설정하는 방법이 CurrentCultureCurrentUICulture전체 응용 프로그램은? 그래서 새로운 스레드도 그 문화를 얻습니까? 아니면 새 스레드를 만들 때마다 연결될 수있는 이벤트가 발생합니까?


4
리소스를 사용하는 경우 다음과 같이 수동으로 리소스를 강제 할 수 있습니다. Resource1.Culture = new System.Globalization.CultureInfo ( "fr"); 이렇게하면 문자열을 검색 할 때마다 지역화되어 반환됩니다.
Reza S

답변:


196

.NET 4.5에서는이 CultureInfo.DefaultThreadCurrentCulture속성을 사용하여 AppDomain의 문화권을 변경할 수 있습니다 .

4.5 이전 버전의 경우 리플렉션을 사용하여 AppDomain의 문화를 조작해야합니다. 스레드가 해당 속성을 자체적으로 설정하지 않은 경우 반환되는 내용을 제어 하는 개인 정적 필드 CultureInfo( m_userDefaultCulture.NET 2.0 mscorlib, s_userDefaultCulture.NET 4.0 mscorlib)가 CurrentCulture있습니다.

이것은 기본 스레드 로케일을 변경하지 않으며 문화를 이런 식으로 변경하는 코드를 제공하는 것은 좋지 않습니다. 그래도 테스트에 유용 할 수 있습니다.


9
ASP.NET 응용 프로그램에서이 설정에주의하십시오. AppDomain에서 문화권을 설정하면 모든 사용자의 문화권이 설정됩니다. 따라서 영어 사용자가 예를 들어 독일어로 웹 사이트를 보는 것은 좋지 않습니다.
Dimitar Tsonev 2016 년

2
모든 문화권이 en-US 인 경우에만 작동하는 ASP.NET 응용 프로그램을 상속했습니다. 이것은이 설정은 그 결함이 수정 될 때까지의 시간에 대한 완벽한 시나리오입니다
다니엘 Hilgarth

37

이것은 많은 질문을받습니다. 기본적으로 .NET 4.0에는 없습니다. 각각의 새 스레드 (또는 ThreadPool기능) 가 시작될 때 수동으로 수행해야합니다 . 문화권 이름 (또는 문화권 객체)을 정적 필드에 저장하여 DB를 칠 필요가 없도록 할 수는 있지만 그게 전부입니다.


1
짜증나게 ... 네 말이 맞아 보인다 그래서 우리는 지금 (그리고 문화에 정적 클래스를가집니다), 그러나 우리는 여전히 통제 할 수없는 일부 스레드에 문제가 있습니다. Microsoft 보고서 뷰어에서 스레드를 처리하는 것과 같습니다. 그래도 해결 방법을 찾았습니다. 정보 주셔서 감사합니다 :)
Svish

8
이것은 정말 성가신 일입니다. (응용 프로그램에 대해 Current (UI) Culture를 자동으로 설정하고 모든 새 스레드가 해당 값을 가져 오는 방법이 있다면 좋을 것입니다.
Jedidja

1
내가 지금이 일을 한 지 오래 되었기 때문에 우리가 한 일을 정확히 기억하지 못합니다. 그러나 보고서 뷰어로 전송 된 데이터 세트에서 날짜를 사용하는 대신 애플리케이션에서 설정 한 문화를 사용하여 날짜를 문자열로 먼저 형식화 한 것으로 생각됩니다. 그런 다음 보고서 렌더링 스레드가 잘못된 문화권을 사용한 것은 더 이상 중요하지 않았습니다. 따라서 잘못된 문화권을 사용하는 스레드 관련 문제를 해결하지 못했습니다. 우리는 방금 날짜를 잘못 형식화하는 문제를 해결했습니다 :)
Svish

2
우리의 응용 프로그램에서는 스레드를 "캡처"(특정 위치에서 특수 메소드를 호출하여)하고 나중에 사용하기 위해 컬렉션에 저장했습니다 (이 경우 문화를 설정하기 위해).
Mr. TA

1
cultureinfo 객체를 세션에 저장하고 마스터 페이지를 사용하는 경우 마스터 페이지 코드 숨김에서 확인하고 현재 스레드를 설정할 수 없습니까?
user609926

20

리소스를 사용하는 경우 다음을 통해 수동으로 리소스를 강제 실행할 수 있습니다.

Resource1.Culture = new System.Globalization.CultureInfo("fr"); 

자원 관리자에는 다음과 같은 자동 생성 코드가 있습니다.

/// <summary>
///   Overrides the current thread's CurrentUICulture property for all
///   resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
    get {
        return resourceCulture;
    }
    set {
        resourceCulture = value;
    }
}

이제이 리소스 내에서 개별 문자열을 참조 할 때마다 지정된 resourceCulture를 사용하여 문화권 (스레드 또는 프로세스)을 재정의합니다.

"fr", "de"등의 언어를 지정하거나 en-US의 경우 0x0409, it-IT의 경우 0x0410과 같이 언어 코드를 입력 할 수 있습니다. 언어 코드의 전체 목록은 언어 식별자 및 로캘을 참조하십시오.


Null로 설정하여 "강제 해제"할 수 있습니다.Resource1.Culture = Null;
habakuk

8

.net 4.5 이상의 경우

var culture = new CultureInfo("en-US");
        CultureInfo.DefaultThreadCurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentUICulture = culture;

6

실제로 기본 스레드 문화권 및 UI 문화권을 설정할 있지만 Framework 4.5 이상에서만 가능합니다.

이 정적 생성자를 넣었습니다.

static MainWindow()
{
  CultureInfo culture = CultureInfo
    .CreateSpecificCulture(CultureInfo.CurrentCulture.Name);
  var dtf = culture.DateTimeFormat;
  dtf.ShortTimePattern = (string)Microsoft.Win32.Registry.GetValue(
    "HKEY_CURRENT_USER\\Control Panel\\International", "sShortTime", "hh:mm tt");
  CultureInfo.DefaultThreadCurrentUICulture = culture;
}

ValueConverter의 Convert 메서드에 중단 점을 넣어 다른 쪽 끝에 도착한 것을 확인하십시오. CultureInfo.CurrentUICulture는 en-US로 중단되었으며 대신 ShortTimePattern의 지역 설정을 존중하기 위해 작은 핵으로 완성되었습니다.

Hurrah, 세상은 모두 잘 지내고 있습니다! 아님 Convert 메서드에 전달 된 culture 매개 변수는 여전히 en-US입니다. 음, WTF ?! 그러나 시작입니다. 적어도 이런 식으로

  • 앱이로드 될 때 UI 문화를 한 번 수정할 수 있습니다
  • 그것은 항상 접근 할 수 있습니다 CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) 맞춤 지역 설정을 사용합니다

버전 4.5의 프레임 워크를 사용할 수 없다면 CurrentUICulture를 CultureInfo의 정적 속성으로 설정하지 말고 자신의 클래스 중 하나의 정적 속성으로 설정하십시오. 이것은 문자열의 기본 동작을 수정하지 않습니다. 바인딩에서 바인딩 또는 StringFormat이 제대로 작동하도록 한 다음 앱의 논리 트리를 따라 이동하여 앱의 모든 바인딩을 다시 만들고 변환기 문화를 설정하십시오.


1
Austin의 답변은 이미 CultureInfo.DefaultThreadCurrentCulture가 AppDomain의 문화를 변경하도록 설정할 수 있다는 통찰력을 제공했습니다. CultureInfo.DefaultThreadCurrentCulture는 CurrentCulture이므로 CultureInfo.DefaultThreadCurrentUICulture는 CurrentUICulture입니다. 실제로 코드의 레지스트리에서 직접 값을 가져올 이유가 없습니다. CurrentCulture를 특정 문화권으로 변경하고 사용자 재정의를 유지하려면 CurrentCulture의 DateTimeFormat에서 값을 가져 와서 재정의해야합니다.
Eric MSFT

1
확인해야하지만 성공하지 않고 레지스트리에서 가져 오는 것을 기억합니다. 내가 아무 문제없이 내가 그 모든 문제에 가겠다 고 정말로 생각하십니까? 레지스트리 액세스는이 용감한 새로운 UAC 세계에서 거대한 PITA입니다.
Peter Wone

4

ASP.NET5, 즉 ASPNETCORE의 경우 다음을 수행 할 수 있습니다 configure.

app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture(new CultureInfo("en-gb")),
    SupportedCultures = new List<CultureInfo>
    {
        new CultureInfo("en-gb")
    },
            SupportedUICultures = new List<CultureInfo>
    {
        new CultureInfo("en-gb")
    }
});

자세한 정보를 제공 하는 일련의 블로그 게시물 이 있습니다.


1
레거시 ASP.NET 2.0 사이트에서이 작업을 수행 할 수있는 방법을 찾고 있는데 다른 코어 사이트와 비교했을 때 얼마나 쉽게 관리 할 수 ​​없는지 고민하고 있습니다! 저는 다국적 회사에 있으며 내부 사이트의 경우 날짜 혼동을 방지하기 위해 모든 형식이 en-US입니다. 그러나이 레거시 사이트는 en-US, en-CA 및 fr-CA를 위해 설정되었습니다. 그리고 "hack-y"방식으로 고칠 때 모든 유형 변환이 데이터 계층에서 폭발합니다! (프랑스 돈 가치는 "1 234,56 $"
Andrew S

1
@Sean 링크가 끊어졌습니다. 어쩌면 그것은 이것 , 이것 그리고 이것을
Fer R

4

이 답변은 @rastating의 훌륭한 답변을 약간 확장 한 것입니다. 걱정없이 모든 버전의 .NET에 다음 코드를 사용할 수 있습니다.

    public static void SetDefaultCulture(CultureInfo culture)
    {
        Type type = typeof (CultureInfo);
        try
        {
            // Class "ReflectionContext" exists from .NET 4.5 onwards.
            if (Type.GetType("System.Reflection.ReflectionContext", false) != null)
            {
                type.GetProperty("DefaultThreadCurrentCulture")
                    .SetValue(System.Threading.Thread.CurrentThread.CurrentCulture,
                        culture, null);

                type.GetProperty("DefaultThreadCurrentUICulture")
                    .SetValue(System.Threading.Thread.CurrentThread.CurrentCulture,
                        culture, null);
            }
            else //.NET 4 and lower
            {
                type.InvokeMember("s_userDefaultCulture",
                    BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                    null,
                    culture,
                    new object[] {culture});

                type.InvokeMember("s_userDefaultUICulture",
                    BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                    null,
                    culture,
                    new object[] {culture});

                type.InvokeMember("m_userDefaultCulture",
                    BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                    null,
                    culture,
                    new object[] {culture});

                type.InvokeMember("m_userDefaultUICulture",
                    BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                    null,
                    culture,
                    new object[] {culture});
            }
        }
        catch
        {
            // ignored
        }
    }
}

4

DefaultThreadCurrentCultureDefaultThreadCurrentUICulture프레임 워크 4.0에 존재도,하지만 그들은 개인 있습니다. Reflection을 사용하면 쉽게 설정할 수 있습니다. 이것은 CurrentCulture명시 적으로 설정되지 않은 모든 스레드에 영향을 미칩니다 (스레드를 실행하는 것도).

Public Sub SetDefaultThreadCurrentCulture(paCulture As CultureInfo)
    Thread.CurrentThread.CurrentCulture.GetType().GetProperty("DefaultThreadCurrentCulture").SetValue(Thread.CurrentThread.CurrentCulture, paCulture, Nothing)
    Thread.CurrentThread.CurrentCulture.GetType().GetProperty("DefaultThreadCurrentUICulture").SetValue(Thread.CurrentThread.CurrentCulture, paCulture, Nothing)
End Sub

1
이것은 나를 위해 일했습니다. Thread.CurrentThread.CurrentCulture = culture를 사용하지만; Thread.CurrentThread.CurrentUICulture = 문화; 어느 것도 똑같아 보입니다. 명확성을 위해 이것은 앱 자체가 문화를 바꾸는 WPF 앱에서 사용되고 있지만 다른 프로젝트의 사용자
컨트롤

3

c # MVC 솔루션은 다음과 같습니다.

  1. 첫 번째 : 다음과 같이 사용자 정의 속성을 작성하고 메소드를 대체하십시오.

    public class CultureAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Retreive culture from GET
            string currentCulture = filterContext.HttpContext.Request.QueryString["culture"];
    
            // Also, you can retreive culture from Cookie like this :
            //string currentCulture = filterContext.HttpContext.Request.Cookies["cookie"].Value;
    
            // Set culture
            Thread.CurrentThread.CurrentCulture = new CultureInfo(currentCulture);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(currentCulture);
        }
    }
  2. 두 번째 : App_Start에서 FilterConfig.cs를 찾아이 속성을 추가하십시오. (이것은 WHOLE 응용 프로그램에서 작동합니다)

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // Add custom attribute here
            filters.Add(new CultureAttribute());
        }
    }    

그게 다야!

전체 애플리케이션 대신 각 컨트롤러 / 액션에 대한 문화권을 정의하려는 경우 다음과 같이이 속성을 사용할 수 있습니다.

[Culture]
public class StudentsController : Controller
{
}

또는:

[Culture]
public ActionResult Index()
{
    return View();
}

1

모든 스레드 및 창에 CultureInfo를 설정하는 작업 솔루션.

  1. App.xaml 파일을 열고 새로운 "스타트 업"속성을 추가하여 앱의 시작 이벤트 핸들러를 지정하십시오.
<Application ........
             Startup="Application_Startup"
>
  1. App.xaml.cs 파일을 열고 생성 된 시작 처리기 (이 경우 Application_Startup)에이 코드를 추가하십시오. 클래스 앱은 다음과 같습니다.
    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            CultureInfo cultureInfo = CultureInfo.GetCultureInfo("en-US");
            System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
            System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
            Thread.CurrentThread.CurrentCulture = cultureInfo;
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.