I'm converting a project to use a satellite assembly.
I created a new class library (named "Resources"). All of the default resources are at the root level *.resx
.
Then there is a folder for each culture.
"en/"
with *.en.resx
en-GB/
with *.en-GB.resx
I changed the .resx files Access Modifier
to "Public" and changed these settings.
BuildAction: EmbeddedResource
CopyToOutputDirectory: CopyAlways
I made sure the .resx
designers *.Designer.cs
use the "Resources" namespace.
I added the Class library to an ASP.NET MVC app and in global.asax.cs
I have the culture being set as needed.
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
I tried adding the al.exe
and Resgen.exe
commands to the post-build event in the Resources class library.
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\Resgen.exe" en-GB/MyResourceFile.en-GB.resx "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\al.exe" /t:lib /embed:en-GB/MyResourceFile.en-GB.resources /culture:en-gb /out:Resources.resources.dll
Looking inside the MVC apps bin/
folder there are folders for each language with 3 files:
MyResources.en-GB.Designer.cs, MyResources.en-GB.resx, Resources.resources.dll
The root level only has Resources.dll
and Resources.resources.dll
but the default language works fine. The second *.resources.dll
is due to the post-build event.
When I change the CurrentUICulture it doesn't change the UI language. Before moving the resources out of the App_GlobalResources/
to an external assembly it worked fine (Razor example).
@Resources.MyResources.StringIdentifier
Looking at the Resource .dlls
using .NET Reflector these are the differences.
Satellite Resources: (Project: Resources)
Resources.en_GB.MyResources.en-GB.resources
App_GlobalResources: (Project MVCApp)
Namespace.MVCApp.App_GlobalResources.MyResources.en-GB.resources
Edit:
After setting the CurrentCulture and UICulture in the global.asax.cs
, I tested manually retrieving a ResourceManager
which actually worked and retrieved strings in the expected language.
System.Resources.ResourceManager gStrings =
new System.Resources.ResourceManager("Resources.MyResources", System.Reflection.Assembly.Load("Resources")); // Resources=Project Name
string test = gStrings.GetString("TestString"); // WORKS IN GLOBAL.ASAX.CS!!!
I tried the same test in an MVC Controller, but it doesn't work. So the only place the ResourceManager can be retrieved is the Global.asax.cs.
Oddly enough the same test at the UI level in razor would only return the default cultures text! The cultureInfo is correct, but the ResourceManager only returns the default language in the ASP.NET MVC Razor UI. (This is strictly for testing)
@{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentUICulture;
System.Resources.ResourceManager gStrings =
new System.Resources.ResourceManager("Resources.MyResource", System.Reflection.Assembly.Load("Resources"));
string s = gStrings.GetString("Test"); // DOESN'T WORK IN UI
}
TLDR version:
Converting from Resources (.resx) from App_GlobalResources to satellite assemblies.
The issue at hand.
I can manually call a ResourceManager for the satellite assembly, using the CurrentUICulture language in global.asax
and it works as expected, however the same test fails from the UI side and fails in a MVC controller.
The default language works fine, so why doesn't the UI switch languages?
If have recently set up a project where the internaltionalization works correctly more or less like you describe.
https://github.com/Jacco/Perpetuality
I switch the language per HTTP request in OnAuthorize in the controller I use as base:
using Perpetuality.Data;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Perpetuality.Controllers
{
public partial class BaseController : Controller
{
private CultureInfo GetCultureInfo(AuthorizationContext filterContext)
{
switch ((string)filterContext.RouteData.Values["language"])
{
case "nl":
return CultureInfo.CreateSpecificCulture("nl-NL");
case "en":
return CultureInfo.CreateSpecificCulture("en-US");
case "pt":
return CultureInfo.CreateSpecificCulture("pt-PT");
case "de":
return CultureInfo.CreateSpecificCulture("de-DE");
case "es":
return CultureInfo.CreateSpecificCulture("es-ES");
case "fr":
return CultureInfo.CreateSpecificCulture("fr-FR");
case "it":
return CultureInfo.CreateSpecificCulture("it-IT");
case "jp":
return CultureInfo.CreateSpecificCulture("ja-JP");
default:
return CultureInfo.CreateSpecificCulture("en-US");
}
}
protected override void OnAuthorization(AuthorizationContext filterContext)
{
Thread.CurrentThread.CurrentCulture = GetCultureInfo(filterContext);
Thread.CurrentThread.CurrentUICulture = GetCultureInfo(filterContext);
base.OnAuthorization(filterContext);
}
}
}
In my project the RESX files are specified differently than in yours:
BuildAction: EmbeddedResource
CopyToOutputDirectory: DoNotCopy
In my vies I access the strings like this:
@Resources.Home.Index.FacebookButtonCaption
I did setup nothing post or pre build.
In my project the language is always on the url. That was a user can switch language if no appropriate language was initially chosen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With