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
Related
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
I must be missing something here.
I create a brand new WPF application in VS2015. I create a resource 'String1' and set the value to 'fksdlfdskfs'.
I update the default MainWindow.xaml.cs so that the constructor has:
public MainWindow()
{
InitializeComponent();
this.Title = Properties.Resources.String1;
}
And run the application, and it works fine, my window title is fksdlfdskfs.
In the AssemblyInfo.cs file I see the below comments:
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
So I add the following into my WpfApplication5.csproj file and reload the project in VS:
<UICulture>en-US</UICulture>
And then uncommented the following line in AssemblyInfo.cs:
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
If I now go to run the application, the application no longer runs and I get the following exception on the line where I read the resource:
System.Resources.MissingManifestResourceException: Could not find any
resources appropriate for the specified culture or the neutral
culture. Make sure
"WpfApplication5.Properties.Resources.en-US.resources" was correctly
embedded or linked into assembly "WpfApplication5" at compile time, or
that all the satellite assemblies required are loadable and fully
signed.
If I change UltimateResourceFallbackLocation.Satellite to UltimateResourceFallbackLocation.MainAssembly in the AssemblyInfo.cs file, I get the following exception instead:
System.IO.IOException: Cannot locate resource 'mainwindow.xaml'
What am I doing wrong or what am I missing?
You're not forced to use code behind for localization, you can simply use x:Static markup extension to bind to static fields:
<Window
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:SandBox.Properties"
Title="{x:Static properties:Resources.TitleSandbox}">
</Window>
Just make sure your Resource file access modifier is set to Public
The error message you get typically means you do not have a Resource.en-US.resx file because [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] is here to tell your app to use en en-US resource file as default source.
Add a file named Resources.en-US.resx if you want to get rid of the error the quick way
What I personally do to localize a WPF app is :
I leave AssemblyInfo.cs as it is, which means that Resource.resx (without language id) file will be the default (which is generally en-US)
I create additional Resource.{id}.resx file next to default like this :
,
It is usually the same as Resource.resx but translated in the matching language
I force the culture at startup (typically in the App.xaml.cs) with a user settable language id so user can change application language :
// language is typically "en", "fr" and so on
var culture = new CultureInfo(language);
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
// You'll need to restart the app if you do this after application init
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.
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.
I am having an issue getting the correct resource file entries and need some help ... here is my scenario
I have a series of projects that are a part of a large reporting solution that follow this format
Plugin.****Report
Reference (folder)
DataAccessLayer (folder)
DataSets (folder)
DataWrappers (folder)
Localization (folder)
*.cs
Where * is the name of the report I am going to generate
The *.cs has an export statement so that I can pick it up using MEF (not sure if this is relevant, but thought it worth mentioning). The namespace in *.cs is CompanyName.DataShaper.Plugin.*Report. Due to the project name, and location of the files, I changed the default namespace for each project to be CompanyName.DataShaper.Plugin.*Report (it was just Plugin.*Report before my change).
Now for the problem .. inside of *.cs I am instantiating a ResourceManager. That looks like this ...
_resourceManager =
new ResourceManager("CompanyName.DataShaper.Plugin.*Report.Localization.*Report",
Assembly.GetExecutingAssembly());
inside my resx designer file I have the following ...
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CompanyName.DataShaper.Plugin.*Report.Localization.*Report", typeof(*Report).Assembly);
resourceMan = temp;
}
return resourceMan;
}
My call to the resource manager looks like this ...
string resourceString = _resourceManager.GetString(resourceKey, _currrentCultureInfo);
where _currentCultureInfo is a a correct CultureInfo object.
I have 4 different resx files in my Localization folder for each project, (****Report.resx, ****Report.fr-ca.resx, ****Report.en-gb.resx, ****Report.de-de.resx).
When I make the call to the resource manager, I always get the entry from the .resx ... never any of the other language files, regardless of the CultureInfo object I pass into the call. What have I messed up?
--> Quick update to my original question, but this does appear to be MEF related. I instantiated my class the old fashioned way (new *Report()) and made the localization call and it works fine
OK, I figured this out .. I am getting the .resx file because it is truly embedded into the main assembly. The other files are getting built into separate dlls for each language, I then need to copy them into the same folder that I build my aggregate container from, my resource manager then sees all languages.