Có cách thiết lập văn hóa cho toàn bộ ứng dụng không? Tất cả các chủ đề hiện tại và chủ đề mới?


177

Có cách thiết lập văn hóa cho toàn bộ ứng dụng không? Tất cả các chủ đề hiện tại và chủ đề mới?

Chúng tôi có tên của văn hóa được lưu trữ trong cơ sở dữ liệu và khi ứng dụng của chúng tôi bắt đầu, chúng tôi làm

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

Nhưng, tất nhiên, điều này bị "mất" khi chúng ta muốn làm một cái gì đó trong một chủ đề mới. Có cách nào để thiết lập điều đó CurrentCultureCurrentUICulturecho toàn bộ ứng dụng không? Vì vậy, chủ đề mới cũng có được văn hóa đó? Hoặc là một số sự kiện được kích hoạt bất cứ khi nào một chủ đề mới được tạo ra mà tôi có thể nối lên?


4
Nếu bạn đang sử dụng tài nguyên, bạn có thể ép tài nguyên theo cách thủ công bằng cách: Resource1.CARM = new System.Globalization.CARMInfo ("fr"); Bằng cách này mỗi khi bạn muốn lấy một chuỗi, nó được bản địa hóa và trả về
Reza S

Câu trả lời:


196

Trong .NET 4.5, bạn có thể sử dụng thuộc CultureInfo.DefaultThreadCurrentCulturetính để thay đổi văn hóa của AppDomain.

Đối với các phiên bản trước 4.5, bạn phải sử dụng sự phản chiếu để thao túng văn hóa của AppDomain. Có một trường tĩnh riêng trên CultureInfo( m_userDefaultCulturetrong .NET 2.0 mscorlib, s_userDefaultCulturetrong .NET 4.0 mscorlib) để điều khiển những gì CurrentCulturetrả về nếu một luồng không tự đặt thuộc tính đó.

Điều này không thay đổi ngôn ngữ luồng gốc và có lẽ không nên gửi mã thay đổi văn hóa theo cách này. Nó có thể hữu ích để thử nghiệm mặc dù.


9
Hãy cẩn thận với cài đặt này trong các ứng dụng ASP.NET. Đặt văn hóa trên AppDomain sẽ đặt văn hóa cho tất cả người dùng. Vì vậy, sẽ không tốt cho người dùng tiếng Anh để xem trang web bằng tiếng Đức chẳng hạn.
Dimitar Tsonev 20/03/2015

2
Tôi đã kế thừa một ứng dụng ASP.NET chỉ hoạt động nếu tất cả các nền văn hóa đều ở en-US. Đây là một kịch bản trong đó cài đặt này là hoàn hảo cho đến thời điểm đó cho đến khi lỗ hổng đó được khắc phục
Daniel Hilgarth

37

Điều này được hỏi rất nhiều. Về cơ bản, không có, không dành cho .NET 4.0. Bạn phải làm thủ công khi bắt đầu mỗi luồng mới (hoặc ThreadPoolhàm). Có lẽ bạn có thể lưu trữ tên văn hóa (hoặc chỉ đối tượng văn hóa) trong trường tĩnh để tiết kiệm việc phải đánh DB, nhưng đó là về nó.


1
hơi khó chịu ... có vẻ như bạn đúng, hehe. Vì vậy, chúng tôi làm điều đó ngay bây giờ (và có văn hóa một lớp tĩnh), nhưng chúng tôi vẫn gặp vấn đề với một số luồng mà chúng tôi không có quyền kiểm soát. Giống như xử lý các chủ đề trong trình xem báo cáo microsoft. Tìm thấy một công việc xung quanh mặc dù. Cảm ơn bạn đã thông tin :)
Svish

8
Điều này thực sự gây phiền nhiễu :( Sẽ thật tuyệt nếu có cách tự động đặt Văn hóa (UI) hiện tại cho ứng dụng của bạn và có tất cả các luồng mới nhận giá trị đó.
Jedidja

1
Đã quá lâu kể từ khi tôi làm việc với nó bây giờ vì vậy tôi không nhớ chính xác những gì chúng tôi đã làm. Nhưng tôi nghĩ có thể là chúng tôi thay vì sử dụng ngày trong tập dữ liệu được gửi đến người xem báo cáo, chúng tôi đã định dạng ngày thành một chuỗi trước, sử dụng văn hóa mà chúng tôi đã đặt trong ứng dụng. Sau đó, điều thực sự không còn quan trọng nữa là các chủ đề kết xuất báo cáo đã sử dụng văn hóa sai. Vì vậy, chúng tôi đã không giải quyết vấn đề với các chủ đề sử dụng văn hóa sai. Chúng tôi chỉ giải quyết vấn đề lấy ngày được định dạng sai :)
Svish

2
Trong ứng dụng của chúng tôi, tôi đã thử "chụp" các luồng (bằng cách gọi một phương thức đặc biệt từ một số nơi nhất định) và lưu trữ chúng trong một bộ sưu tập để sử dụng sau này (trong trường hợp này là đặt văn hóa), dường như đang hoạt động đến nay.
Ông TA

1
Bạn không thể lưu trữ đối tượng văn hóa trong phiên và (nếu bạn đang sử dụng trang chính) kiểm tra nó trong cơ sở mã trang chủ của bạn và đặt chuỗi hiện tại?
dùng609926

20

Nếu bạn đang sử dụng tài nguyên, bạn có thể buộc nó bằng tay:

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

Trong trình quản lý tài nguyên, có một mã được tạo tự động như sau:

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

Bây giờ mỗi khi bạn tham chiếu chuỗi riêng lẻ của mình trong tài nguyên này, nó sẽ ghi đè lên văn hóa (luồng hoặc quy trình) bằng tài nguyên được chỉ định.

Bạn có thể chỉ định ngôn ngữ như trong "fr", "de", v.v. hoặc đặt mã ngôn ngữ như trong 0x0409 cho en-US hoặc 0x0410 cho nó-IT. Để biết danh sách đầy đủ các mã ngôn ngữ, vui lòng tham khảo: Mã định danh và ngôn ngữ


Nó có thể "không bị ràng buộc" bằng cách đặt nó thành Null:Resource1.Culture = Null;
habakuk

8

Đối với .net 4.5 trở lên, bạn nên sử dụng

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

6

Trên thực tế, bạn có thể đặt văn hóa luồng và văn hóa UI mặc định, nhưng chỉ với Framework 4.5+

Tôi đặt trong hàm tạo tĩnh này

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

và đặt một điểm dừng trong phương thức Chuyển đổi của ValueConverter để xem những gì đã đến ở đầu kia. CultureInfo.

Hurrah, tất cả đều tốt trên thế giới! Hay không. Tham số nuôi cấy được truyền cho phương thức Convert vẫn là en-US. Erm, WTF?! Nhưng đó là một sự khởi đầu. Ít nhất là theo cách này

  • bạn có thể sửa văn hóa UI một lần khi tải ứng dụng của bạn
  • nó luôn luôn có thể truy cập từ CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) sẽ sử dụng cài đặt khu vực tùy chỉnh của bạn

Nếu bạn không thể sử dụng phiên bản 4.5 của khung thì hãy từ bỏ cài đặt Hiện tại là một thuộc tính tĩnh của CultureInfo và đặt nó làm thuộc tính tĩnh của một trong các lớp của riêng bạn. Điều này sẽ không khắc phục hành vi mặc định của chuỗi.Format hoặc làm cho StringFormat hoạt động chính xác trong các liên kết sau đó đi theo cây logic của ứng dụng của bạn để tạo lại tất cả các ràng buộc trong ứng dụng của bạn và đặt văn hóa trình chuyển đổi của chúng.


1
Câu trả lời của Austin đã cung cấp cái nhìn sâu sắc rằng CultureInfo.DefaultThreadCiverseCARM có thể được đặt để thay đổi văn hóa của AppDomain. CultureInfo.DefaultThreadCiverseUICARM dành cho CurrentUICARM với tên gọi CultureInfo.DefaultThreadCiverseCARM dành cho CurrentCARM. Thực sự không có lý do gì để nhận được giá trị trực tiếp từ sổ đăng ký trong mã của bạn. Nếu bạn muốn thay đổi Văn hóa hiện tại thành một số văn hóa cụ thể nhưng vẫn giữ lại phần ghi đè của người dùng, thì bạn chỉ cần lấy giá trị từ DateTimeFormat của CurrentCARM trước khi bạn ghi đè lên nó.
Eric MSFT

1
Tôi sẽ phải kiểm tra nhưng dường như tôi nhớ đã thử điều đó mà không thành công, dẫn đến việc lấy nó từ sổ đăng ký. Bạn có thực sự nghĩ rằng tôi sẽ đi đến tất cả những rắc rối mà không có lý do? Truy cập đăng ký là một PITA khổng lồ trong thế giới mới dũng cảm này của UAC.
Peter Wone

4

Đối với ASP.NET5, tức là ASPNETCORE, bạn có thể thực hiện các bước sau 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")
    }
});

Đây là một loạt các bài đăng trên blog cung cấp thêm thông tin.


1
Tôi đã tìm kiếm một cách để làm điều này trong một trang web ASP.NET 2.0 cũ và thật khó chịu khi tôi dễ dàng quản lý nó với một trang web Core khác! Tôi đang ở trong một công ty đa quốc gia và đối với các trang web nội bộ, tất cả các định dạng của chúng tôi là en-US để tránh nhầm lẫn ngày. Nhưng trang web kế thừa này được thiết lập cho en-US, en-CA và fr-CA. Và theo cách "hack-y", vì vậy khi tôi đi sửa nó, tất cả các chuyển đổi loại của chúng sẽ nổ tung trong lớp dữ liệu! (Giá trị tiền của Pháp là "1 234,56 $"
Andrew S

1
@Sean liên kết của bạn bị hỏng. Có lẽ nó chỉ vào điều này , điều nàyđiều này
Fer R

4

Câu trả lời này là một chút mở rộng cho câu trả lời tuyệt vời của @ rastating. Bạn có thể sử dụng mã sau đây cho tất cả các phiên bản .NET mà không phải lo lắng:

    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

DefaultThreadCurrentCultureDefaultThreadCurrentUICulturecũng có mặt trong Framework 4.0, nhưng chúng là Private. Sử dụng Reflection bạn có thể dễ dàng thiết lập chúng. Điều này sẽ ảnh hưởng đến tất cả các luồng CurrentCulturekhông được đặt rõ ràng (chạy các luồng cũng vậy).

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
Cái này làm việc cho tôi Mặc dù sử dụng Thread.CienThread.CiverseCARM = văn hóa; Thread.CienThread.CienUICARM = văn hóa; Mà trông không giống nhau. Để rõ ràng, điều này đang được sử dụng trong một ứng dụng WPF nơi chính ứng dụng đang thay đổi văn hóa của nó, tuy nhiên người dùng trong các dự án khác đang sử dụng văn hóa trình duyệt chứ không phải văn hóa do người dùng chọn
chillfire 8/12/2015

3

Đây là giải pháp cho c # MVC:

  1. Đầu tiên: Tạo một thuộc tính tùy chỉnh và phương thức ghi đè như thế này:

    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. Thứ hai: Trong App_Start, tìm FilterConfig.cs, thêm thuộc tính này. (điều này hoạt động cho ứng dụng WHOLE)

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

Đó là nó !

Nếu bạn muốn xác định văn hóa cho từng bộ điều khiển / hành động thay cho toàn bộ ứng dụng, bạn có thể sử dụng thuộc tính này như sau:

[Culture]
public class StudentsController : Controller
{
}

Hoặc là:

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

1

Giải pháp làm việc để thiết lập CultureInfo cho tất cả các luồng và cửa sổ.

  1. Mở tệp App.xaml và thêm thuộc tính "Khởi động" mới để gán trình xử lý sự kiện khởi động cho ứng dụng:
<Application ........
             Startup="Application_Startup"
>
  1. Mở tệp App.xaml.cs và thêm mã này để tạo trình xử lý khởi động (Application_Startup trong trường hợp này). Ứng dụng lớp sẽ trông như thế này:
    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;
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.