Issue while accessing resource file strings in Web API - c#

I have added a resource file which needs to support globalization.
In Global.asax I received the culture info.
protected void Application_BeginRequest()
{
var cul = Context.Request.Headers["culture"];
if (cul != null && !string.IsNullOrEmpty(cul))
{
var culture = new CultureInfo(cul);
//Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
}
Now I'm trying to access it as:
ResourceManager rm = new ResourceManager("Resource", System.Reflection.Assembly.GetExecutingAssembly());
string err = rm.GetString("ERROR_1");
The error I get is:
{"Could not find any resources appropriate for the specified culture or the neutral culture. Make sure \"Resource.resources\" was correctly embedded or linked into assembly \"...\" at compile time, or that all the satellite assemblies required are loadable and fully signed."} System.SystemException {System.Resources.MissingManifestResourceException}
The code and resource has same namespace.

I don't have much experience with the ResourceManager, but from the official documentation I don't think that using reflection to get the assembly is intended. It specifically mentions that the second parameter, the assembly, should be 'the assembly in which the default .resources file resides'. It later talks about setting Thread.CurrentThread.CurrentUICulture. You can find all that information on msdn: https://msdn.microsoft.com/en-us/library/system.resources.resourcemanager(v=vs.110).aspx
However, you might want to take a look at the msdn documentation on localizing asp.net web pages: https://msdn.microsoft.com/en-us/library/ms227427.aspx. It seems to have some specialized mechanisms that might be very useful to you.

Related

WPF get string from resources throws an exception

I've been trying to get a string from resources file:
var resourceManager = new ResourceManager(typeof(Properties.Settings));
var recent1 = resourceManager.GetString("recent1");
But I got an exception:
System.Resources.MissingManifestResourceException: 'Could not find any
resources appropriate for the specified culture or the neutral
culture. Make sure "ProCodeX.Properties.Settings.resources" was
correctly embedded or linked into assembly "ProCodeX" at compile time,
or that all the satellite assemblies required are loadable and fully
signed.
How do I fix it?
For retrieve string from .resx file don't no need to create the ResourceManager class instance. The template uses internal static signature for the property when adding a string to the resources. Therefore the resource can be obtained directly:
var recent = Properties.Resources.recent1;
And here's an example how do get the string by creating instance of the ResourceManager when required to obtain resource for specific culture:
ResourceManager rm = new ResourceManager("WpfApp11.Properties.Resources", typeof(Properties.Resources).Assembly);
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
var recent1 = rm.GetString("recent1");
For additional information see ResourceManager.GetString Method.

GetString always return default language resource

I have a microservice in .Net-Core that have to handle some resources in a resx file and return them based on the culture I provide with a call to an API so I will not use the culture of the current thread, but when I call the method GetString(key, culture) it always return the default language.
I have 2 resx file at the moment: resource.resx and resource.it-IT.resx if i call the api with the it-IT culture string I always get the translation in the resource.resx file and not in the resource.it-IT.resx file
The resx files are in another project called Localization
I have a generic method where I pass the Enum I have to localize and the type of the file where the localization is stored, then I compose the key of the resource and call the GetString method.
I have also tried changing the culture of the current thread with
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureName);
public static string GetDisplayName(this Enum e, Type resourceType, string cultureName)
{
var rm = new ResourceManager(resourceType);
var resourceDisplayName = rm.GetString(e.GetType().Name + "_" + e, CultureInfo.CreateSpecificCulture(cultureName));
return string.IsNullOrWhiteSpace(resourceDisplayName) ? string.Format("[[{0}]]", e) : resourceDisplayName;
}
I have investigated a bit more and in the resource manager when I inspect it I have 3 resourceSet
resource
resource.it
resource.it-IT
If I inspect inside these 3 resource set I have all my resource always in English it seems that the resource manager doesn't load the resx italian file
About your resource.resx and resource.it-IT.resx files, please check if your key is the same in both the files. If the key you are trying to access is not available, the code automatically redirects to default file (resource.resx).
This link will help complete implementation of Localization and Globalization
After reading this: NetCore Bug I managed to solve my problem, first of all I have refactored my method to this:
public static string GetDisplayName(this Enum e, Type resourceType, string cultureName)
{
var rm = new ResourceManager(resourceType.FullName, resourceType.Assembly);
var key = $"{e.GetType().Name}_{e}";
var culture = CultureInfo.CreateSpecificCulture(cultureName);
var resourceDisplayName = rm.GetString(key, culture);
return string.IsNullOrWhiteSpace(resourceDisplayName) ? string.Format("[[{0}]]", e) : resourceDisplayName;
}
Then I have removed the reference to the Localization project from the API project and only left that reference in another project that is then referenced from the API project

Unable to read culture specific values

I working on a localization project and unable to read the value by local from the resource file.
I have a sample solution as below:
1. Web API project
2. Resources Project.
- In resources project, I have 3 resource files de-DE, fr-FR, and en-US.
I am reading the resource key "Name" from the resource file, I am able to get the value from de-DE and en-US by setting culture value as below.
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR");
var name = Employees.Name;
return new string[] { name };
}
However, When I try to read the key for fr-FR local, it is giving English value.
The only difference is, the French resource file is present inside a folder and others are present at project level.
The .NET resource system is based largely on convention; it expects resource files for specific cultures to be found at very specific paths.
Employees.resx contains the neutral resources for the Employees container.
Employees.[culture].resx contains the resources for the Employees container for a specific culture.
If you have a resource file in another folder, the resource-lookup system treats it as a separate resource. fr-FR/Employees.fr-FR.resx is the French resources for the fr_FR.Employees container.
To make your resources load correctly, you just need to put them in the same folder:
Employees.resx
Employees.de-DE.resx
Employees.fr-FR.resx

ResourceLoader in shared assembly

Class Library A
Strings
en-US
Resources.resw
zh-CN
Resources.resw
Application
Views
ViewA.xaml
So I have a View, ViewA that I need to manually load localized strings from. However, whenever I do this, I receive an empty string.
I have tried:
var loader = ResourceLoader.GetForCurrentView();
var myLocalizedText = loader.GetString("Foo");
and
var loader = new ResourceLoader();
var myLocalizedText = loader.GetString("Foo");
The variable myLocalizedText is always an empty string.
I tried to reproduce your issue, however I just got ResourceMap Not Found. exception when using ResourceLoader.GetForCurrentView() or new ResourceLoader().
If we want to construct a resource loader for resources from a library package, we need use ResourceLoader.GetForCurrentView(String) method or ResourceLoader.ResourceLoader(String) constructor. Here the String is the resource identifier of the ResourceMap that the new resource loader uses for unqualified resource references.
Components or library files are typically added into a subfolder of the package they are included in during the build process, similar to their string resources. Their resource identifier usually takes the following form:
ClassLibraryOrAssemblyName/ResourceFileName/StringName
So for your case, we can use following code to load localized strings:
var loader = ResourceLoader.GetForCurrentView("ClassLibraryA/Resources");
var myLocalizedText = loader.GetString("Foo");
For more information, please see: Loading strings from libraries or controls and scenario 6 in Application resources and localization sample.
Besides, please note that for a UWP app, it's better to use GetForCurrentView(String) method:
[ResourceLoader(String) may be altered or unavailable for releases after Windows 8.1. Instead, use GetForCurrentView(String).]
Also if you want to add Chinese language, you'd better use zh-Hans instead of zh-CN:
Include script when there is no suppress script value defined for the language. See the IANA subtag registry for language tag details. For example, use zh-Hant, zh-Hant-TW, or zh-Hans, and not zh-CN or zh-TW.
For more information see: Qualify resources with their language.

How to use ResourceManager in a "website" mode?

I am trying here to do a manual translation for the application I am working with. (There is already a working LocalizationModule but it's working dodgy, so I can't use <asp:Localize /> tags.
Normally with ResourceManager you are supposed to be using it as Namespace.Folder.Resourcename (in an application). Currently I am translating an existing asp.net "website" (not web application so no namespace here....).
The resources are located into a folder name "Locales/resources" which contains "fr-ca.resx" and "en-us.resx".
So I used a code with something like this :
public static string T(string search)
{
System.Resources.ResourceManager resMan = new System.Resources.ResourceManager( "Locales", System.Reflection.Assembly.GetExecutingAssembly(), null );
var text = resMan.GetString(search, System.Threading.Thread.CurrentThread.CurrentCulture);
if (text == null)
return "null";
else if (text == string.Empty)
return "empty";
else
return text;
}
and inside the page I have something like this <%= Locale.T("T_HOME") %>
When I refresh I have this :
Could not find any resources
appropriate for the specified culture
or the neutral culture. Make sure
"Locales.resources" was correctly
embedded or linked into assembly
"App_Code.9yopn1f7" at compile time,
or that all the satellite assemblies
required are loadable and fully
signed. Description: An unhandled
exception occurred during the
execution of the current web request.
Please review the stack trace for more
information about the error and where
it originated in the code.
Exception Details:
System.Resources.MissingManifestResourceException:
Could not find any resources
appropriate for the specified culture
or the neutral culture. Make sure
"Locales.resources" was correctly
embedded or linked into assembly
"App_Code.9yopn1f7" at compile time,
or that all the satellite assemblies
required are loadable and fully
signed.
Source Error:
Line 14:
System.Resources.ResourceManager
resMan = new
System.Resources.ResourceManager(
"Locales",
System.Reflection.Assembly.GetExecutingAssembly(),
null ); Line 15: Line 16: var
text = resMan.GetString(search,
System.Threading.Thread.CurrentThread.CurrentCulture);
Line 17: Line 18: if (text == null)
Source File:
c:\inetpub\vhosts\galerieocarre.com\subdomains\dev\httpdocs\App_Code\Locale.cs
Line: 16
I even tried to load the resource with Locales.fr-ca or only fr-ca nothing quite work here.
Marvin Smit's solution is great if you do not have access to the HTTPContext
const string ASSEMBLY_NAME = "App_GlobalResources";
const string RESOURCE_NAME = "Resources.MetaTagResource";
const string RESOURCE_MANAGER = "ResourceManager";
Assembly assembly = Assembly.Load(ASSEMBLY_NAME);
Type type = assembly.GetType(RESOURCE_NAME);
PropertyInfo propertyInfo = type.GetProperty(RESOURCE_MANAGER);
ResourceManager resourceManager = propertyInfo.GetValue(null, new object[] { }) as ResourceManager;
resourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true);
But if you have access to the HTTPContext just use HttpContext.GetGlobalResourceObject
string title = HttpContext.GetGlobalResourceObject("MetaTagResource", "Title").ToString();
string keywords = HttpContext.GetGlobalResourceObject("MetaTagResource", "keywords").ToString();
string description = HttpContext.GetGlobalResourceObject("MetaTagResource", "Description").ToString();
Maybe you are just looking for The System.Web.Page's base GetLocalResourceObject(),?
see http://msdn.microsoft.com/en-us/library/ms153597.aspx
When using resources in ASP.Net, you will see a specialized compiler being used (custom Tool property) on the .resx files (ResXCodeGen)
Bottom line of this is that your resources are compiled into a class. The name of this class is the name you should use when you want to address the resources in there.
The name of the class is generated as follows:
{project namespace}{folder structure}{filename}.resx (.resx is NOT part of the generated name)
Since you mentioned your resx file is located in a directory name "Locales/resources", the name you would have to use is (assuming the resx file is called 'locales.resx')
"locales.resources.locales"
The addition of the language and locale, like the "uk-en" is added by the resource manager, loading the appropriate assembly based on the Culture that is specified when creating an instance of the ResourceManager. If none is given, the Thread.CurrentCulture is used. You should not use the language/locale extensions yourself, leave it to the resource manager to deal with that.
If you are not sure how the resources class will end up, you can always look at the MSIL or use reflector to determine the name of the resource class in the actual deployed assembly.
;-- Added after comments where placed -------
I also looked at some other code i had arround;
Have you tried the Reflection on App_GlobalResources approach?
1: You load the "App_GlobalResources" library while in the context of the website (in a HttpHandler, Aspx, Ascx, etc). =>
Assembly.Load("App_GlobalResources");
2: Walk through the available types in there and grab the "ResourceManager" property from each type.=>
PropertyInfo pi = type.GetProperty("ResourceManager");
resManager = pi.GetValue(null, new object[] { }) as ResourceManager;
3: If it had one, get the ResourceSet you want => resManager.GetResourceSet(englishCulture, true, true);
Hope this helps.
this is not c# but you can easily convert it into it
I have in the app_localResources directory with 2 files
myPage.aspx.resx
myPage.aspx.fr-ca.resx
and I use it like this in my .aspx page
<asp:Label ID="lAddress1" runat="server" Text="<%$ Resources: lAddress1 %>"></asp:Label>
this is how I manage it on mine
'using LCID from
Public Enum elang
En = &H1009 'en-CA http://www.microsoft.com/resources/msdn/goglobal/default.mspx?submitted=1009&OS=Windows%202003%20%20Service%20Pack%201
Fr = &HC0C 'fr-CA http://www.microsoft.com/resources/msdn/goglobal/default.mspx?submitted=0C0C&OS=Windows%202003%20%20Service%20Pack%201
End Enum
'strongly typed value in session
Private _lang As elang = elang.En
Public Property lang() As elang
Get
Return _lang
End Get
Set(ByVal value As elang)
_lang = value
End Set
End Property
and in every page I got
Protected Overrides Sub InitializeCulture()
If Not Me.IsPostBack Then
Threading.Thread.CurrentThread.CurrentUICulture = New Globalization.CultureInfo(Sess.lang)
Threading.Thread.CurrentThread.CurrentCulture = Globalization.CultureInfo.CreateSpecificCulture(Threading.Thread.CurrentThread.CurrentUICulture.Name)
End If
MyBase.InitializeCulture()
End Sub
when I want to use the resourcemanager I create a global resources file at the root level the I use it like this
Dim rm = New System.Resources.ResourceManager("Resources.MyPage", Reflection.Assembly.Load("App_GlobalResources"))
Edit
In case of a Web Site project, read this walkthrough of Microsoft.
I'm afraid you can't use the ResourceMagager in a Website project, because it requires a namespace / assembly where the resources are located.

Categories

Resources