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.
Related
I have a web application project. I generated the DLL and import it in another project. I implemented VirtualPathProvider.
I followed this web site: http://support.microsoft.com/kb/910441/en-us?spid=8940&sid=global, and everything works until I add another site master.
I added site_export.master and changed its Build Action to Embedded Resource.
I changed my page to use the new site master.
GetManifestResourceStream() returns null when I load site_export.master.
I call GetManifestResourceNames() to check if site_export.master exists in the DLL and it does. It's in the list. All of the name spaces match. I didn't list the name space out here.
Why can't GetManifestResourceStream() load my new site_export.master? It loads site.master just fine. I know my DLL is loaded because I can see other files in the DLL.
Remember the following issues...
Step 1. Build action set to embedded resource see
C#’s GetManifestResourceStream Gotcha
Step 2. Use namespace.resourcename see GetManifestResourceStream() returns null ?
Actually, this method returns null if a private resource in another assembly is accessed and the caller does not have ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag.
Side-hint. To make sure you're in the right assembly and with right name: dump and evaluate all the resources available in your target assembly
string[] names = assembly.GetManifestResourceNames();
(in my case, I misused a namespace from another assembly)
I did this to make it work:
Step 1: Select the resource (CRDF.xsl in my case) and right click > Properties.
Set Build Action to "EmbeddedResource" and Logical Name to name of your choice, e.g. CRDFXSL.
Step 2 : Change your Source code like this:
Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();
xslStream = _assembly.GetManifestResourceStream("CRDFXSL");
_xmlReader = XmlReader.Create(xslStream);
Thus everything went smoooooooth..
Hint and Caution:
If the "Assembly name" and "Default namespace" does not match in the project file then also GetManifestResourceStream would return null. GetManifestResourceNames still returns the names of assemblies but during loading the manifest would not work.
Try this:
Dim ctx As Windows.ApplicationModel.Resources.Core.ResourceContext = New Windows.ApplicationModel.Resources.Core.ResourceContext()
ctx.Languages = {Globalization.CultureInfo.CurrentUICulture.Name}
Dim rmap As Windows.ApplicationModel.Resources.Core.ResourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap
Dim res = rmap.GetValue("Assets/sample.png", ctx)
Dim resFile = Await res.GetValueAsFileAsync
The Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap list all resources.
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.
Spending hours on this. Thinking my thought process might be off..
I wanted to create one point of entry for language translation across different libraries and applications.
What I did was the following:
Created New Class Library Project called Translations
At Root Level Added New Item - MyStrings.en-US.resx file
Populated resx file
resx - Access Modifier set to Public
At Root Level of Translations Project Added New Item Class - Translator
Added Property
public class Translator
{
private ResourceManager _translationManager;
public ResourceManager TranslationManager
{
get
{
if (_translationManager == null)
{
_translationManager = new ResourceManager("MyStrings", this.GetType().Assembly);
}
return _translationManager;
}
}
}
In WebSite (not web project but website) Added Reference to Translations Project
In the code behind declared
private Translator _translate;
public Translator Translate
{
get
{
if (_translate == null)
{
_translate = new Translator();
}
return _translate;
}
}
then in a LINQ statement
Title = TranslationManager.GetString(appsAvailable.Value.ResourceKey, CurrentCulture)
ResourceKey does have a value
CurrentCulture = en-US
And I am getting this error
Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure "MyStrings.resources" was correctly
embedded or linked into assembly "Translations" at compile time, or
that all the satellite assemblies required are loadable and fully
signed.
When I look at my bin/obj/debug folder I am seeing this Translations.MyStrings.en-US.resources
which is not the name it is looking for. I have tried to modify the "basename" for the manager from "MyStrings" to 'Translations.MyStrings" but I get a similar error stating "Translations.MyStrings.resources" can't be found. I have also tried just saying okay forget the culture right now let's access it "Translations.MyStrings.en-US" as the base name. and it says it still can not find it.
Any ideas of where I am going wrong? I am thinking it needs to be copied somewhere so the software finds it but don't know where it goes? Or am I trying to do something that it is not meant to do?
Your help is greatly appreciated!
Just download MAT (Multilingual App Toolkit) for Visual Studio. https://marketplace.visualstudio.com/items?itemName=MultilingualAppToolkit.MultilingualAppToolkit-18308
This is the way to go to translate and maintain your projects in Visual Studio ;-)
https://blogs.msdn.microsoft.com/matdev/
I'm trying to move an image and a style sheet from a user control to embedded resources in the assembly. I have used Reflector to see that the image and .css file are embedded in the assembly, but when I try to access them using the URL created by ClientScript.GetWebResourceUrl(), the resource is not found. I'm stumped.
Assembly default namespace:
TestWebApp
The paths to the files (marked as BuildAction: Embedded Resource) are
TestWebApp/Resources/CSS/PaymentHistory.css
TestWebApp/Resources/Images/loading.gif
And so my resources are registered as:
[assembly: WebResource("TestWebApp.Resources.CSS.PaymentHistory.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("TestWebApp.Resources.Images.loading.gif", "image/gif")]
User Control (in the same assembly) that accesses the resources :
TestWebApp.UserControls.PaymentHistory
To simplify, I'm currently just trying to reference the image and not the stylesheet. In my user control's Page_Load, I set the ImageUrl of an Image control to the resource URL:
image1.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "TestWebApp.Resources.Images.loading.gif");
At runtime, everything appears to work without errors but it renders a broken image. Here is the rendered image source:
<img style="border-width:0px;" src="/WebResource.axd?d=8fC_1tLPjrUCxmFc_Q2MKY0-pHAak-sTWkpLLV3D56H_c08LujXC63ia2PNICE65_i-Q4JqprAigLpbrXG-rIAr6ePO4HHcdQKgdd3szlThv2gizxOJLJsPRNe-b_M6ApTwPsH_5oZAuONTN0cumOTRr1nA1&t=635133745137507721" id="ph1_image1">
If I navigate to that URL in my browser, I get a 404, The resource cannot be found. What am I doing wrong?
EDIT:
There must be something fundamental I'm not understanding and/or I'm doing something really stupid. Here is a simple VS 2010 example. I have followed all of the required steps I'm aware of to embed JScript1.js and access it via WebResource.axd, but it gets the error.
In the Default.aspx.cs file of your example project, change this.GetType() to typeof(_Default):
Page.ClientScript.RegisterClientScriptInclude("JScript1",
Page.ClientScript.GetWebResourceUrl(typeof(_Default), "EmbeddedResources.JScript1.js"));
Similarly, in the PaymentHistory.ascx.cs file, change this.GetType() to typeof(PaymentHistory):
image1.ImageUrl = Page.ClientScript.GetWebResourceUrl(
typeof(PaymentHistory), "TestWebApp.Resources.Images.loading.gif");
Explanation: GetWebResourceUrl looks at the type argument to determine which assembly contains the embedded resource. Specifying this.GetType() as the type is incorrect because, in an .aspx or .ascx code-behind class, this.GetType() refers not to that class but rather to the derived class that gets dynamically generated from the .aspx or .ascx markup. This derived class resides in a separate assembly, so GetWebResourceUrl can't find the embedded resource.
Is the resource in a separate project or in the same project as your User Control? If separate you have to substitute this.GetType() with an object's GetType() function that resides in the separate project.
If in the same project, just do Page.GetType(), because you want a reference to the page and not the user control
First of all, the type that you are passing to the GetWebResourceUrl call (or to the RegisterClientScriptResource I show below) is actually there to point to which assembly contains your resource. The problem is that "this.GetType()" is returning a type that is not in the current executing assembly (as strange as that may be).
The following 2 lines demonstrate the issue.
Response.Write(this.GetType().Assembly.FullName + "<br>");
Response.Write(Assembly.GetExecutingAssembly().FullName + "<br>");
The first line returns the name of a "App_Web_??????" assembly. The second returns the expected "EmbeddedResources" assembly.
In the call below, I just pass in the first type I get back from the executing assembly and the call works.
Page.ClientScript.RegisterClientScriptResource(Assembly.GetExecutingAssembly().GetTypes()[0], names[0]);
this.GetType() actually returns a type that the web server creates that inherits from your type. That is why typeof(_Default) would also work to designate the correct assembly.
Here you can see a code in Vb.NET that uses the Reflection library to detect the current Assembly Name and the current NameSpace.
If you concatenate the namespace with embedded image name, you can use the command Page.clientScript.GetWebResourceURL to generate a link for image as you see in first function
In second function, you see a loop in all of resources name until find the complete name of embedded resouce.
Friend Class ReadResources
' Get our assembly.
Private Shared executingAssembly As System.Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
' Get our namespace.
Private Shared myNamespace As String = executingAssembly.GetName().Name.ToString()
''' <summary>
''' Generate resource link
''' </summary>
Friend Shared Function GetResourceLink(ByVal ref As String,
ByVal obj As Object,
ByVal page As Web.UI.Page) As String
Dim out As String = Nothing
out = Page.ClientScript.GetWebResourceUrl(obj.GetType, myNamespace & "." & ref)
If out Is Nothing OrElse out.Length <= 0 Then
out = FindResource(ref, obj)
End If
Return out
End Function
Friend Shared Function FindResource(ByVal reference As String,
ByVal obj As Object) As String
Dim out As String = ""
For Each embedded In obj.GetType().Assembly.GetManifestResourceNames()
If embedded.Contains(reference) Then
out = embedded
Exit For
End If
Next
Return out
End Function
End Class
I have a web application project. I generated the DLL and import it in another project. I implemented VirtualPathProvider.
I followed this web site: http://support.microsoft.com/kb/910441/en-us?spid=8940&sid=global, and everything works until I add another site master.
I added site_export.master and changed its Build Action to Embedded Resource.
I changed my page to use the new site master.
GetManifestResourceStream() returns null when I load site_export.master.
I call GetManifestResourceNames() to check if site_export.master exists in the DLL and it does. It's in the list. All of the name spaces match. I didn't list the name space out here.
Why can't GetManifestResourceStream() load my new site_export.master? It loads site.master just fine. I know my DLL is loaded because I can see other files in the DLL.
Remember the following issues...
Step 1. Build action set to embedded resource see
C#’s GetManifestResourceStream Gotcha
Step 2. Use namespace.resourcename see GetManifestResourceStream() returns null ?
Actually, this method returns null if a private resource in another assembly is accessed and the caller does not have ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag.
Side-hint. To make sure you're in the right assembly and with right name: dump and evaluate all the resources available in your target assembly
string[] names = assembly.GetManifestResourceNames();
(in my case, I misused a namespace from another assembly)
I did this to make it work:
Step 1: Select the resource (CRDF.xsl in my case) and right click > Properties.
Set Build Action to "EmbeddedResource" and Logical Name to name of your choice, e.g. CRDFXSL.
Step 2 : Change your Source code like this:
Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();
xslStream = _assembly.GetManifestResourceStream("CRDFXSL");
_xmlReader = XmlReader.Create(xslStream);
Thus everything went smoooooooth..
Hint and Caution:
If the "Assembly name" and "Default namespace" does not match in the project file then also GetManifestResourceStream would return null. GetManifestResourceNames still returns the names of assemblies but during loading the manifest would not work.
Try this:
Dim ctx As Windows.ApplicationModel.Resources.Core.ResourceContext = New Windows.ApplicationModel.Resources.Core.ResourceContext()
ctx.Languages = {Globalization.CultureInfo.CurrentUICulture.Name}
Dim rmap As Windows.ApplicationModel.Resources.Core.ResourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap
Dim res = rmap.GetValue("Assets/sample.png", ctx)
Dim resFile = Await res.GetValueAsFileAsync
The Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap list all resources.