Search code examples
asp.net-mvclocalizationinternationalizationhttphandler

ASP.NET MVC Retrieve localized resources programmatically


I have a HTTP Handler that reads all resources files in the ASP.NET MVC assembly and converts them to a Javascript object. The code works well apart from 1 rather big detail as I need to be able to predefine the culture. I cannot use the useful web config's auto UI cultures, instead I want to use database configuration. As soon as this code runs, it still takes the local culture of my computer. Is there any way to set the culture? I was thinking of using the ResourceManager but I'm failing to do so.

public void ProcessRequest(HttpContext context)
{
 // Check current assembly
 Assembly currentAssembly = null;

  Type appType = HttpContext.Current.ApplicationInstance.GetType();
  if (appType.Namespace == "ASP")
  {
    currentAssembly = appType.BaseType.Assembly;
  }
  else
  {
    currentAssembly = appType.Assembly;
   }

   // Get resource files in this assembly, in this cased reference by Resources namespace            
    IEnumerable<Type> resources = currentAssembly.GetTypes().Where(x => x.Namespace == "Resources");

        // Generate Javascript namespace through which each resource file will be referenced
        context.Response.ContentType = "text/javascript";
        context.Response.Write("var Resources = {};\n");

        foreach (Type resource in resources)
        {
            // For each type, add an object to the namespace
            context.Response.Write(string.Format("Resources.{0} = {{}};\n", resource.Name));

            // Get all resource keys and values for every resource file
            IDictionary<String, String> resourceKeyValues =
                resource
                .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.GetProperty)
                .Where(x => x.PropertyType == typeof(string))
                .ToDictionary(x => x.Name, x => x.GetValue(null, null).ToString());

            // Include each key + value
            foreach (String key in resourceKeyValues.Keys)
            {
                context.Response.Write(string.Format("Resources.{0}.{1} = '{2}';\n", resource.Name, key, resourceKeyValues[key].Replace("'", "\'")));
            }
        }
    }

Solution

  • I managed to combine two approaches with the requested result. Initially I based my code on this article and ignored Rick Strahl's approach. Due to this issue, I investigated his article into greater depth and came across this article.

    This is what I came up with:

    public void ProcessRequest(HttpContext context)
        {
            // Check current assembly
            Assembly currentAssembly = null;
    
            Type appType = HttpContext.Current.ApplicationInstance.GetType();
            if (appType.Namespace == "ASP")
            {
                currentAssembly = appType.BaseType.Assembly;
            }
            else
            {
                currentAssembly = appType.Assembly;
            }
    
            ClaimsIdentity claimsIdentity = (ClaimsIdentity)HttpContext.Current.User.Identity;
            string language = claimsIdentity.FindFirst(ClaimTypes.Locality).Value;
            CultureInfo requestedCulture = new CultureInfo(language);
    
            // Get resource files in this assembly, in this cased reference by Resources namespace            
            IEnumerable<Type> resources = currentAssembly.GetTypes().Where(x => x.Namespace == "Resources");
    
            context.Response.ContentType = "text/javascript";
            context.Response.Write("var Resources = {};\n");
    
            foreach (Type resource in resources)
            {
                // For each type, add an object to the namespace
                context.Response.Write(string.Format("Resources.{0} = {{}};\n", resource.Name));
                Dictionary<object, object> dictionary = this.ReadResources(resource.Name, requestedCulture);
    
                foreach (KeyValuePair<object, object> key in dictionary)
                {
                    context.Response.Write(string.Format("Resources.{0}.{1} = '{2}';\n", resource.Name, key.Key, key.Value.ToString().Replace("'", "\'")));
                }
            }
        }
    
    
        private Dictionary<object, object> ReadResources(string classKey, CultureInfo requestedCulture)
        {
            var resourceManager = new ResourceManager("Resources." + classKey, Assembly.Load("App_GlobalResources"));
            using (var resourceSet = resourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true))
            {
                return resourceSet.Cast<DictionaryEntry>().ToDictionary(x => x.Key, x => resourceManager.GetObject((string)x.Key, requestedCulture));
            }
        }