C# 在ASP.NET C中使用许多资源文件(Resources.resx)#

C# 在ASP.NET C中使用许多资源文件(Resources.resx)#,c#,asp.net-mvc,resx,C#,Asp.net Mvc,Resx,我正在实现一个多语言的ASP.NETMVC5站点,一切正常。我有一个助手来检查用户的语言,我的所有控制器都从我自己的BaseController扩展来检查必须使用的语言 我不知道它到底是如何工作的,现在,我想添加多个资源文件以获得更多的“舒适性”,并组织我的字符串。。。例如,我想要Resource-Login.resx和Resource-Login.es.resx,等等 我已经阅读了这个官方教程(),但是我找不到关于它是如何工作的信息 在我读过的教程中,有一句话引起了我的注意: 现在右键单击“资

我正在实现一个多语言的ASP.NETMVC5站点,一切正常。我有一个助手来检查用户的语言,我的所有控制器都从我自己的BaseController扩展来检查必须使用的语言

我不知道它到底是如何工作的,现在,我想添加多个资源文件以获得更多的“舒适性”,并组织我的字符串。。。例如,我想要Resource-Login.resx和Resource-Login.es.resx,等等

我已经阅读了这个官方教程(),但是我找不到关于它是如何工作的信息

在我读过的教程中,有一句话引起了我的注意:

现在右键单击“资源”项目,然后选择“添加->新建项目” 上下文菜单命令。选择“资源文件”并命名它 “Resources.resx”。这将是我们的默认文化(en US),因为它 没有特别的结尾

特殊的结局造就了“魔法”?ResourceManager如何知道自己必须如何工作

如果我的代码的这一部分是一个好的实践

// Modify current thread's cultures            
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
我粘贴我正在使用的代码:

助手:

public static class CultureHelper
{
    // Valid cultures
    private static readonly List<string> _validCultures = new List<string> { "af", "af-ZA", "sq", "sq-AL", "gsw-FR", "am-ET", "ar", "ar-DZ", "ar-BH", "ar-EG", "ar-IQ", "ar-JO", "ar-KW", "ar-LB", "ar-LY", "ar-MA", "ar-OM", "ar-QA", "ar-SA", "ar-SY", "ar-TN", "ar-AE", "ar-YE", "hy", "hy-AM", "as-IN", "az", "az-Cyrl-AZ", "az-Latn-AZ", "ba-RU", "eu", "eu-ES", "be", "be-BY", "bn-BD", "bn-IN", "bs-Cyrl-BA", "bs-Latn-BA", "br-FR", "bg", "bg-BG", "ca", "ca-ES", "zh-HK", "zh-MO", "zh-CN", "zh-Hans", "zh-SG", "zh-TW", "zh-Hant", "co-FR", "hr", "hr-HR", "hr-BA", "cs", "cs-CZ", "da", "da-DK", "prs-AF", "div", "div-MV", "nl", "nl-BE", "nl-NL", "en", "en-AU", "en-BZ", "en-CA", "en-029", "en-IN", "en-IE", "en-JM", "en-MY", "en-NZ", "en-PH", "en-SG", "en-ZA", "en-TT", "en-GB", "en-US", "en-ZW", "et", "et-EE", "fo", "fo-FO", "fil-PH", "fi", "fi-FI", "fr", "fr-BE", "fr-CA", "fr-FR", "fr-LU", "fr-MC", "fr-CH", "fy-NL", "gl", "gl-ES", "ka", "ka-GE", "de", "de-AT", "de-DE", "de-LI", "de-LU", "de-CH", "el", "el-GR", "kl-GL", "gu", "gu-IN", "ha-Latn-NG", "he", "he-IL", "hi", "hi-IN", "hu", "hu-HU", "is", "is-IS", "ig-NG", "id", "id-ID", "iu-Latn-CA", "iu-Cans-CA", "ga-IE", "xh-ZA", "zu-ZA", "it", "it-IT", "it-CH", "ja", "ja-JP", "kn", "kn-IN", "kk", "kk-KZ", "km-KH", "qut-GT", "rw-RW", "sw", "sw-KE", "kok", "kok-IN", "ko", "ko-KR", "ky", "ky-KG", "lo-LA", "lv", "lv-LV", "lt", "lt-LT", "wee-DE", "lb-LU", "mk", "mk-MK", "ms", "ms-BN", "ms-MY", "ml-IN", "mt-MT", "mi-NZ", "arn-CL", "mr", "mr-IN", "moh-CA", "mn", "mn-MN", "mn-Mong-CN", "ne-NP", "no", "nb-NO", "nn-NO", "oc-FR", "or-IN", "ps-AF", "fa", "fa-IR", "pl", "pl-PL", "pt", "pt-BR", "pt-PT", "pa", "pa-IN", "quz-BO", "quz-EC", "quz-PE", "ro", "ro-RO", "rm-CH", "ru", "ru-RU", "smn-FI", "smj-NO", "smj-SE", "se-FI", "se-NO", "se-SE", "sms-FI", "sma-NO", "sma-SE", "sa", "sa-IN", "sr", "sr-Cyrl-BA", "sr-Cyrl-SP", "sr-Latn-BA", "sr-Latn-SP", "nso-ZA", "tn-ZA", "si-LK", "sk", "sk-SK", "sl", "sl-SI", "es", "es-AR", "es-BO", "es-CL", "es-CO", "es-CR", "es-DO", "es-EC", "es-SV", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", "es-PY", "es-PE", "es-PR", "es-ES", "es-US", "es-UY", "es-VE", "sv", "sv-FI", "sv-SE", "syr", "syr-SY", "tg-Cyrl-TJ", "tzm-Latn-DZ", "ta", "ta-IN", "tt", "tt-RU", "te", "te-IN", "th", "th-TH", "bo-CN", "tr", "tr-TR", "tk-TM", "ug-CN", "uk", "uk-UA", "wen-DE", "ur", "ur-PK", "uz", "uz-Cyrl-UZ", "uz-Latn-UZ", "vi", "vi-VN", "cy-GB", "wo-SN", "sah-RU", "ii-CN", "yo-NG" };
    // Include ONLY cultures you are implementing
    private static readonly List<string> _cultures = new List<string> {
    "en",  // first culture is the DEFAULT
    "es" // Spanish NEUTRAL culture


};
    /// <summary>
    /// Returns true if the language is a right-to-left language. Otherwise, false.
    /// </summary>
    public static bool IsRighToLeft()
    {
        return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToLeft;

    }
    /// <summary>
    /// Returns a valid culture name based on "name" parameter. If "name" is not valid, it returns the default culture "en-US"
    /// </summary>
    /// <param name="name" />Culture's name (e.g. en-US)</param>
    public static string GetImplementedCulture(string name)
    {
        // make sure it's not null
        if (string.IsNullOrEmpty(name))
            return GetDefaultCulture(); // return Default culture
        // make sure it is a valid culture first
        if (_validCultures.Where(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Count() == 0)
            return GetDefaultCulture(); // return Default culture if it is invalid
        // if it is implemented, accept it
        if (_cultures.Where(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Count() > 0)
            return name; // accept it
        // Find a close match. For example, if you have "en-US" defined and the user requests "en-GB", 
        // the function will return closes match that is "en-US" because at least the language is the same (ie English)  
        var n = GetNeutralCulture(name);
        foreach (var c in _cultures)
            if (c.StartsWith(n))
                return c;
        // else 
        // It is not implemented
        return GetDefaultCulture(); // return Default culture as no match found
    }
    /// <summary>
    /// Returns default culture name which is the first name decalared (e.g. en-US)
    /// </summary>
    /// <returns></returns>
    public static string GetDefaultCulture()
    {
        return _cultures[0]; // return Default culture
    }
    public static string GetCurrentCulture()
    {
        return Thread.CurrentThread.CurrentCulture.Name;
    }
    public static string GetCurrentNeutralCulture()
    {
        return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name);
    }
    public static string GetNeutralCulture(string name)
    {
        if (!name.Contains("-")) return name;

        return name.Split('-')[0]; // Read first part only. E.g. "en", "es"
    }
}
public class BaseController : Controller
{
    protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
    {
        string cultureName = RouteData.Values["culture"] as string;

        // Attempt to read the culture cookie from Request
        if (cultureName == null)
            cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ? Request.UserLanguages[0] : null; // obtain it from HTTP header AcceptLanguages

        // Validate culture name
        cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe


        if (RouteData.Values["culture"] as string != cultureName)
        {

            // Force a valid culture in the URL
            RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too

            // Redirect user
            Response.RedirectToRoute(RouteData.Values);
        }


        // Modify current thread's cultures            
        Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;


        return base.BeginExecuteCore(callback, state);
    }
}
RouteConfig(用于在请求中添加/en/es以检测语言)


我不确定你的问题到底是什么。。。。 但是上面的代码看起来还可以。我建造了类似的东西

是的,结局创造了奇迹:

Resource-Login.resx    Default
Resource-Login.es.resx Spanish
是的,你可以有多种资源。 有不同的方法引用它们,但这是一种:

<h1 id="titular-question">@ViewResources.Freelancer.Job.Index.TitularQuestion</h1>
@viewsources.freegorer.Job.Index.TitularQuestion
然后确保正确配置资源:

谢谢!;)魔术就是魔术!!你也使用Thread.CurrentThread.CurrentCulture吗?我两者都使用。一个用于翻译,另一个用于日期格式。为什么需要helper类?您可以使用culture info类检查它是否是有效的区域性,如果不是,则使用默认值。框架将负责使用更适合您传递的字符串区域性的资源文件。我有一个类似的项目设置。但是我有两个文件:
Index.en US.resx
Index.es es.resx
我注意到,有了这两个文件,代码永远不会被编译。在正确编译代码之前,我需要添加一个
Index.resx
。知道为什么吗?也许你总是需要一个默认值。否则,回退就不起作用。但这只是一个猜测。
<h1 id="titular-question">@ViewResources.Freelancer.Job.Index.TitularQuestion</h1>