มีวิธีการสร้างวัฒนธรรมสำหรับแอปพลิเคชันทั้งหมดหรือไม่ เธรดปัจจุบันและเธรดใหม่ทั้งหมดหรือไม่


177

มีวิธีการสร้างวัฒนธรรมสำหรับแอปพลิเคชันทั้งหมดหรือไม่ เธรดปัจจุบันและเธรดใหม่ทั้งหมดหรือไม่

เรามีชื่อของวัฒนธรรมที่เก็บไว้ในฐานข้อมูลและเมื่อใบสมัครของเราเริ่มต้นเราจะทำ

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

แต่แน่นอนว่าสิ่งนี้จะ "หลงทาง" เมื่อเราต้องการทำอะไรในเธรดใหม่ มีวิธีการตั้งค่านั้นCurrentCultureและCurrentUICultureสำหรับแอปพลิเคชันทั้งหมดหรือไม่ ดังนั้นหัวข้อใหม่ที่ได้รับวัฒนธรรมนั้น หรือเป็นเหตุการณ์ที่เกิดขึ้นเมื่อใดก็ตามที่มีการสร้างกระทู้ใหม่ที่ฉันสามารถขอได้?


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

2
ฉันรับแอปพลิเคชั่น ASP.NET ที่ทำงานได้ก็ต่อเมื่อทุกวัฒนธรรมอยู่ในสหรัฐอเมริกา นี่เป็นสถานการณ์ที่การตั้งค่านี้สมบูรณ์แบบสำหรับช่วงเวลาจนกว่าข้อบกพร่องนั้นจะได้รับการแก้ไข
Daniel Hilgarth

37

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


1
น่ารำคาญ ... ดูเหมือนคุณพูดถูกฮิฮิ ดังนั้นเราจึงทำเช่นนั้นในขณะนี้ (และมีวัฒนธรรมเป็นคลาสแบบสแตติก) แต่เรายังคงมีปัญหากับเธรดบางตัวที่เราไม่สามารถควบคุมได้ เช่นเดียวกับการประมวลผลเธรดในตัวแสดงรายงานของ Microsoft พบว่ามีการทำงานรอบ ๆ ขอบคุณสำหรับข้อมูล :)
Svish

8
นี่เป็นเรื่องที่น่ารำคาญจริงๆ :( มันคงจะดีถ้ามีวิธีตั้งค่าวัฒนธรรมปัจจุบัน (UI) โดยอัตโนมัติสำหรับแอปพลิเคชันของคุณและให้เธรดใหม่ทั้งหมดรับค่านั้น
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" ฯลฯ หรือใส่รหัสภาษาใน 0x0409 สำหรับ en-US หรือ 0x0410 สำหรับ it-IT สำหรับรายการรหัสภาษาทั้งหมดโปรดดูที่: ตัวระบุภาษาและตำแหน่งที่ตั้ง


สามารถเป็น "unforced" ได้โดยการตั้งค่าเป็น 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 เพื่อดูสิ่งที่มาถึงที่ปลายอีกด้าน CultureInfo.CurrentUICulture หยุด en-US และกลายเป็น en-AU แทนพร้อมแฮ็คตัวน้อยของฉันเพื่อให้เป็นไปตามการตั้งค่าภูมิภาคสำหรับ ShortTimePattern

Hurray ทุกอย่างดีในโลก! หรือไม่. พารามิเตอร์ทางวัฒนธรรมที่ส่งผ่านไปยังวิธีการแปลงยังคงเป็นen-US เอ่อ WTF! แต่มันเป็นการเริ่มต้น อย่างน้อยก็ด้วยวิธีนี้

  • คุณสามารถแก้ไขวัฒนธรรม UI ได้เมื่อแอปของคุณโหลด
  • มันสามารถเข้าถึงได้จาก CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) จะใช้การตั้งค่าภูมิภาคที่คุณกำหนดเอง

หากคุณไม่สามารถใช้เวอร์ชัน 4.5 ของเฟรมเวิร์กยกเลิกการตั้งค่า CurrentUICulture เป็นคุณสมบัติแบบคงที่ของ CultureInfo และตั้งเป็นคุณสมบัติคงที่ของคลาสใดคลาสหนึ่งของคุณเอง สิ่งนี้จะไม่แก้ไขพฤติกรรมเริ่มต้นของ string.Format หรือทำให้ StringFormat ทำงานอย่างถูกต้องในการเชื่อมโยงจากนั้นเดินแผนผังเชิงตรรกะของแอปเพื่อสร้างการเชื่อมโยงทั้งหมดในแอปของคุณและสร้างวัฒนธรรมการแปลง


1
คำตอบของ Austin ได้ให้ข้อมูลเชิงลึกแล้วว่า CultureInfo.DefaultThreadCurrentCulture สามารถตั้งค่าให้เปลี่ยนวัฒนธรรมของ AppDomain ได้ CultureInfo.DefaultThreadCurrentUICulture ปัจจุบันคือ CultureUfo.DefaultThreadCurrentCulture ปัจจุบันกระแสวัฒนธรรม ไม่มีเหตุผลที่จะได้รับค่าโดยตรงจากรีจิสทรีในรหัสของคุณ หากคุณต้องการเปลี่ยน CurrentCulture เป็นวัฒนธรรมเฉพาะบางอย่าง แต่ยังคงแทนที่ผู้ใช้คุณจะต้องได้รับค่าจาก DateTimeFormat ของ CurrentCulture ก่อนที่คุณจะแทนที่มัน
Eric MSFT

1
ฉันจะต้องตรวจสอบ แต่ดูเหมือนจะจำได้ว่าพยายามไม่ประสบความสำเร็จนำไปสู่การได้รับจากรีจิสทรี คุณคิดว่าฉันจะไปที่ปัญหาทั้งหมดโดยไม่มีเหตุผล? การเข้าถึงรีจิสทรีเป็น PITA ยักษ์ในโลกใหม่ที่กล้าหาญของ UAC
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 แบบดั้งเดิมและมันน่าผิดหวังที่ฉันจัดการมันได้อย่างง่ายดายด้วยไซต์ Core อื่นในการเปรียบเทียบ! ฉันอยู่ใน บริษัท ข้ามชาติและสำหรับไซต์ภายในการจัดรูปแบบทั้งหมดของเราคือ en-US เพื่อป้องกันความสับสนในวันที่ แต่ไซต์ดั้งเดิมนี้ได้รับการตั้งค่าสำหรับ en-US, en-CA และ fr-CA และในแบบที่ "แฮ็ก -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

DefaultThreadCurrentCultureและDefaultThreadCurrentUICultureมีอยู่ใน Framework 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 = culture; ซึ่งดูเหมือนกันไม่ได้ เพื่อความชัดเจนสิ่งนี้กำลังถูกใช้ในแอพ WPF ที่ตัวแอพกำลังเปลี่ยนวัฒนธรรม แต่ผู้ใช้งานในโครงการอื่นกำลังใช้วัฒนธรรมเบราว์เซอร์ไม่ใช่วัฒนธรรมที่ผู้ใช้เลือก
chillfire

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และเพิ่มแอตทริบิวต์ "Startup" ใหม่เพื่อกำหนดตัวจัดการเหตุการณ์เริ่มต้นสำหรับแอป:
<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.