Apakah ada cara menetapkan budaya untuk seluruh aplikasi? Semua utas saat ini dan utas baru?

177

Apakah ada cara menetapkan budaya untuk seluruh aplikasi? Semua utas saat ini dan utas baru?

Kami memiliki nama budaya yang disimpan dalam database, dan ketika aplikasi kami mulai, kami melakukannya

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

Tapi, tentu saja, ini "hilang" ketika kita ingin melakukan sesuatu di utas baru. Apakah ada cara mengatur itu CurrentCulturedan CurrentUICultureuntuk seluruh aplikasi? Jadi utas baru juga mendapatkan budaya itu? Atau apakah ini suatu peristiwa yang dipicu kapan pun utas baru dibuat yang dapat saya hubungi?

Svish
sumber
4
Jika Anda menggunakan sumber daya, Anda dapat memaksanya secara manual dengan: Resource1.Culture = new System.Globalization.CultureInfo ("fr"); Dengan cara ini setiap kali Anda ingin mengambil string, itu dilokalkan dan dikembalikan
Reza S

Jawaban:

196

Di .NET 4.5, Anda bisa menggunakan CultureInfo.DefaultThreadCurrentCultureproperti untuk mengubah budaya AppDomain.

Untuk versi sebelum 4.5 Anda harus menggunakan refleksi untuk memanipulasi budaya AppDomain. Ada bidang statis pribadi di CultureInfo( m_userDefaultCulturedi. NET 2.0 mscorlib, s_userDefaultCulturedi .NET 4.0 mscorlib) yang mengontrol apa yang CurrentCulturekembali jika utas belum menyetel properti itu sendiri.

Ini tidak mengubah lokal utas thread dan mungkin bukan ide yang baik untuk mengirimkan kode yang mengubah budaya dengan cara ini. Mungkin berguna untuk pengujian.

Austin
sumber
9
Hati-hati dengan pengaturan ini dalam aplikasi ASP.NET. Mengatur budaya di AppDomain akan menetapkan budaya untuk semua pengguna. Jadi itu tidak akan baik bagi pengguna bahasa Inggris untuk melihat situs web dalam bahasa Jerman misalnya.
Dimitar Tsonev
2
Saya mewarisi aplikasi ASP.NET yang hanya berfungsi jika semua budaya berada di en-US. Ini adalah skenario di mana pengaturan ini sangat cocok untuk saat itu sampai cacat itu diperbaiki
Daniel Hilgarth
37

Ini banyak ditanyakan. Pada dasarnya, tidak ada, tidak untuk. NET 4.0. Anda harus melakukannya secara manual di awal setiap utas baru (atau ThreadPoolfungsi). Anda mungkin bisa menyimpan nama budaya (atau hanya objek budaya) di bidang statis untuk menyelamatkan karena harus memukul DB, tapi itu saja.

Marc Gravell
sumber
1
agak menyebalkan ... sepertinya kamu benar, hehe. Jadi kami melakukannya sekarang (dan memiliki budaya kelas statis), tetapi kami masih memiliki masalah dengan beberapa utas yang tidak dapat kami kendalikan. Seperti memproses utas di penampil laporan microsoft. Menemukan pekerjaan di sekitar. Terima kasih atas informasinya :)
Svish
8
Ini benar-benar menjengkelkan :( Alangkah baiknya jika ada cara untuk mengatur Budaya Saat Ini (UI) secara otomatis untuk aplikasi Anda dan minta semua utas baru mengambil nilai itu.
Jedidja
1
Sudah begitu lama sejak saya bekerja dengan ini sekarang jadi saya tidak ingat persis apa yang kami lakukan. Tapi saya pikir itu mungkin karena kita alih-alih menggunakan tanggal dalam dataset yang dikirim ke penampil laporan, kita memformat tanggal menjadi string terlebih dahulu, menggunakan budaya yang telah kita atur dalam aplikasi. Maka tidak penting lagi bahwa laporan yang memberikan utas menggunakan budaya yang salah. Jadi kami tidak mengatasi masalah dengan utas menggunakan budaya yang salah. Kami baru saja menyelesaikan masalah mendapatkan tanggal yang diformat secara salah :)
Svish
2
Dalam aplikasi kami, saya mencoba "menangkap" utas (dengan memanggil metode khusus dari tempat-tempat tertentu) dan menyimpannya dalam koleksi untuk digunakan nanti (dalam hal ini untuk mengatur budaya), yang tampaknya bekerja jauh.
Tn. TA
1
Tidak bisakah Anda menyimpan objek cultureinfo dalam sesi dan (jika Anda menggunakan halaman master) memeriksanya di codebehind masterpage Anda dan mengatur utas saat ini?
user609926
20

Jika Anda menggunakan sumber daya, Anda dapat memaksanya secara manual dengan:

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

Di manajer sumber daya, ada kode yang dibuat secara otomatis yaitu sebagai berikut:

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

Sekarang setiap kali Anda merujuk ke string individu Anda dalam sumber ini, itu menimpa budaya (utas atau proses) dengan resourceCulture yang ditentukan.

Anda dapat menentukan bahasa seperti dalam "fr", "de" dll. Atau memasukkan kode bahasa seperti pada 0x0409 untuk en-US atau 0x0410 untuk itu-IT. Untuk daftar kode bahasa lengkap, silakan merujuk ke: Pengidentifikasi Bahasa dan Lokal

Reza S
sumber
Ini bisa "tidak dipaksakan" dengan menetapkannya ke Null:Resource1.Culture = Null;
habakuk
8

Untuk .net 4.5 dan yang lebih tinggi, Anda harus menggunakan

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

Sebenarnya Anda dapat mengatur budaya utas default dan budaya UI, tetapi hanya dengan Framework 4.5+

Saya memasukkan konstruktor statis ini

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

dan letakkan breakpoint dalam metode Konversi ValueConverter untuk melihat apa yang tiba di ujung lainnya. CultureInfo.CurrentUICulture tidak lagi menjadi en-AS dan menjadi en-AU lengkap dengan peretasan kecil saya untuk membuatnya menghormati pengaturan regional untuk ShortTimePattern.

Hore, semuanya baik-baik saja di dunia! Atau tidak. Parameter budaya yang diteruskan ke metode Konversi masih en-AS. Mm, WTF ?! Tapi ini awal. Setidaknya begini

  • Anda dapat memperbaiki budaya UI satu kali saat aplikasi dimuat
  • selalu dapat diakses dari CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) akan menggunakan pengaturan regional khusus Anda

Jika Anda tidak dapat menggunakan versi 4.5 dari kerangka kerja maka menyerah pada pengaturan CurrentUICulture sebagai properti statis dari CultureInfo dan atur sebagai properti statis dari salah satu kelas Anda sendiri. Ini tidak akan memperbaiki perilaku default dari string.Format atau membuat StringFormat berfungsi dengan baik di bindings kemudian berjalan pohon logis aplikasi Anda untuk membuat ulang semua binding di aplikasi Anda dan mengatur budaya konverter mereka.

Peter Wone
sumber
1
Jawaban Austin sudah memberikan wawasan bahwa CultureInfo.DefaultThreadCurrentCulture dapat diatur untuk mengubah budaya AppDomain. CultureInfo.DefaultThreadCurrentUICulture adalah untuk CurrentUICulture sebagai CultureInfo.DefaultThreadCurrentCulture adalah untuk CurrentCulture. Sebenarnya tidak ada alasan untuk mendapatkan nilai langsung dari registri dalam kode Anda. Jika Anda ingin mengubah CurrentCulture ke beberapa budaya tertentu tetapi mempertahankan penggantian pengguna, maka Anda hanya perlu mendapatkan nilai dari DateTimeFormat's CurrentCulture sebelum Anda menimpanya.
Eric MSFT
1
Saya harus memeriksa tetapi sepertinya saya ingat mencoba itu tanpa keberhasilan, yang mengarah ke mendapatkannya dari registri. Apakah Anda benar-benar berpikir saya akan pergi ke semua masalah tanpa alasan? Akses registri adalah PITA raksasa di dunia baru UAC yang berani ini.
Peter Wone
4

Untuk ASP.NET5, yaitu ASPNETCORE, Anda dapat melakukan hal berikut di 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")
    }
});

Berikut serangkaian posting blog yang memberikan lebih banyak informasi.

Sean
sumber
1
Saya datang mencari cara untuk melakukan ini di situs ASP.NET 2.0 yang lama, dan sangat frustasi betapa mudahnya saya mengelolanya dengan situs Core yang berbeda sebagai perbandingan! Saya di perusahaan multinasional, dan untuk situs internal, semua format kami adalah en-AS untuk mencegah kebingungan tanggal. Tetapi situs lawas ini diatur untuk en-AS, en-CA dan fr-CA. Dan dengan cara "hack-y", jadi ketika saya pergi untuk memperbaikinya, semua konversi tipe mereka meledak di lapisan data! (Nilai uang Prancis menjadi "1 234,56 $"
Andrew S
1
@Sehingga tautan Anda rusak. Mungkin ini menunjuk pada ini , ini dan ini
Fer R
4

Jawaban ini adalah sedikit perluasan untuk jawaban hebat @ rastating. Anda dapat menggunakan kode berikut untuk semua versi .NET tanpa khawatir:

    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
        }
    }
}
polfosol ఠ_ఠ
sumber
4

DefaultThreadCurrentCulturedan DefaultThreadCurrentUICulturehadir dalam Kerangka 4.0 juga, tetapi mereka Pribadi. Menggunakan Refleksi, Anda dapat dengan mudah mengaturnya. Ini akan memengaruhi semua utas di mana CurrentCulturetidak diatur secara eksplisit (menjalankan utas juga).

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
HCAxel
sumber
1
Yang ini berhasil untuk saya. Meskipun menggunakan Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = budaya; Yang terlihat tidak sama. Untuk kejelasan ini sedang digunakan dalam aplikasi WPF di mana aplikasi itu sendiri mengubah budayanya namun kontrol pengguna dalam proyek lain menggunakan budaya peramban bukan budaya yang dipilih oleh pengguna
chillfire
3

Inilah solusi untuk c # MVC:

  1. Pertama: Buat atribut khusus dan ganti metode seperti ini:

    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. Kedua: Di App_Start, cari FilterConfig.cs, tambahkan atribut ini. (ini berfungsi untuk aplikasi SELURUH)

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

Itu dia !

Jika Anda ingin mendefinisikan budaya untuk setiap controller / action sebagai pengganti seluruh aplikasi, Anda dapat menggunakan atribut ini seperti ini:

[Culture]
public class StudentsController : Controller
{
}

Atau:

[Culture]
public ActionResult Index()
{
    return View();
}
Meng Xue
sumber
1

Solusi yang berfungsi untuk mengatur CultureInfo untuk semua utas dan jendela.

  1. Buka file App.xaml dan tambahkan atribut "Startup" baru untuk menetapkan pengendali event startup untuk aplikasi:
<Application ........
             Startup="Application_Startup"
>
  1. Buka file App.xaml.cs dan tambahkan kode ini ke handler startup yang dibuat (Application_Startup dalam kasus ini). App kelas akan terlihat seperti ini:
    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;
        }
    }
Rustam Shafigullin
sumber