I would like to use resourcefiles to get some text.These resourcefiles will be in dll.It's nothing todo with localization just in case you ask.
I want to have the ability to choose which rexfile to use based on a configsettings.
Sample
MyCompany.RexFiles.dll
RexFileA
RexFileB
RexFileC
My question
Given that in a config file I have a settings that decide which rexfile to use eg CurrentRexfile="RexFileB"
How can I default to right rexFile depending on the configSettings.
Any suggestions
You can use the ResourceManager Class to retrieve resources:
System.Reflection.Assembly myAssembly = this.GetType().Assembly;
string rexFile = ConfigurationManager.AppSettings["CuurentRexfile"];
System.Reflection.Assembly otherAssembly = System.Reflection.Assembly.Load(rexFile);
System.Resources.ResourceManager resManager = new System.Resources.ResourceManager("ResourceNamespace.myResources", otherAssembly);
string test = resManager.GetString("resourceString");
more read here
I have a library project (SamplePlugin) that is meant to be used as an MEF module and loaded at runtime. Recently, I decided to support internationalization. To that end, I created Properties/Resource.resx and respective Properties/Resource.xx-yy.resx for each supported locale. I then added string resources with locale specific translations to each resource file. However at runtime, I cannot seem to get the culture-correct resource. Here is the relavent code:
Loading the module:
var di = new DirectoryInfo("Plugins/");
var dlls = di.GetFileSystemInfos("*.dll", SearchOption.AllDirectories);
var catalog = new AggregateCatalog();
foreach (var fi in dlls)
{
var ac = new AssemblyCatalog(Assembly.LoadFile(fi.FullName));
catalog.Catalogs.Add(ac);
}
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
Method inside of MEF module (SamplePlugin):
string GetFrenchString()
{
var resourceManager = new ResourceManager(
"SamplePlugin.Properties.Resources",
System.Reflection.Assembly.GetExecutingAssembly());
var culture = new System.Globalization.CultureInfo("fr-FR");
return (string)resourceManager.GetObject("SampleText", culture);
}
File structure of the compiled application:
app.exe
Plugins/SamplePlugin/SamplePlugin.dll
Plugins/SamplePlugin/zh-CN/SamplePlugin.resources.dll
Plugins/SamplePlugin/de-DE/SamplePlugin.resources.dll
Plugins/SamplePlugin/fr-FR/SamplePlugin.resources.dll
...
When I run GetFrenchString() I get "Sample Text" (from resource.resx) instead of "exemple de texte" (from resource.fr-FR.resx). I actually found similar question but the poster answered his own question and provided very little detail in both his question and answer.
Additional details:
The access modifiers of all my resource files are "public"
I'm trying to get localization working in my application. I have my ui resource files, named "ui.resx" and "ui.de.resx" in my solution. However, something in my implementation is incorrect, and I'm stumped.
ResourceManager res_man;
CultureInfo culture;
string exception;
private void myForm_Load(object sender, EventArgs e)
{
culture = CultureInfo.CreateSpecificCulture("de");
res_man = new ResourceManager("MyApp.ui.resx", typeof(myForm).Assembly);
doTheThing();
}
private void doTheThing()
{
try
{
BTN_save.text = ui.SAVE;
//Do code here
}
catch(Exception e)
{
exception = e.toString();
}
}
When I run the program, it errors out and exception reads:
"Exception: System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "ui.resx.resources" was correctly embedded or linked into assembly "myProgram" at compile time, or that all the satellite assemblies required are loadable and fully signed."
You should use the full name (with namespace) of your class as first parameter lik:
var resman= new ResourceManager("Sample.Resources", typeof(Resources).Assembly);
To know what name you should use, open ui.cs under the ui.resx node and look at the namespace of the class and the class name and use them as shown above.
Pay attention that you should not pass "MyApp.ui.resx", instead pass "MyApp.ui"
Then you can simply use the manager to get a resource for specific culture like this:
var str = resman.GetString("YourResourceKey", culture);
Note:
Another thing you should notice, there is more simple way to read culture specific resources. You can simply set :
var culture= ...
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
After setting culture, wherever you use for example MyApp.Ui.Key the value of the Key specific to that culture will be used.
I have an application that manage IIS Application instances so I am looking for a kind of GIUD to identify each applications. This GUID must be created when the application is deployed in IIS and must be persistent to IIS/Windows updates/restarts.
I did not need the use of Microsoft.Web.Administration: I want a simple way, for each IIS application, it returns its unique ID (by a method called within it).
Here is an example of what I'm looking for and I'd like to have an unique id returned by this.????? :
public class MvcApplication : System.Web.HttpApplication
{
string myUniqueID {
get { return this.?????; }
}
}
Thanks for help.
HostingEnvironment.ApplicationID
https://msdn.microsoft.com/en-us/library/system.web.hosting.hostingenvironment.applicationid(v=vs.110).aspx
I had to do something similar.
Read the web.config file for a HostId setting. Preferably split your configuration file into two, with one config file that is local to the install, and doesn't get replaced upon upgrading to a new version of the website.
If the HostId value doesn't exist in the web.config, call Guid.NewGuid() to generate a new value.
Save the new value to the web config, preferably in the local section/file.
Return the value.
Here is some psuedo-code:
public Guid HostId
{
get
{
var result = GetSetting(ConfigFileLocalSettingList.HostId).TryToGuid();
if (result == null)
{
result = Guid.NewGuid();
SetSetting(ConfigFileLocalSettingList.HostId, result.ToString());
Save();
}
return result.Value;
}
}
You can use the assembly GUID for this purpose: In AssemblyInfo.cs, you can find
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("307E39B9-2C41-40CF-B29F-84C8BBCD6519")]
To read this value, you can use:
public static string AssemblyGUID
{
get {
var assembly = Assembly.GetExecutingAssembly();
var attribute = (System.Runtime.InteropServices.GuidAttribute)assembly.GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), true)[0];
var GUID = attribute.Value;
return GUID;
}
}
which is taken from another SO answer (you can find it here).
And if it is required, Visual Studio allows you to create a new GUID via menu Tools -> Create GUID - if you need a different one.
Or in C# you simply use
var newGuid=(Guid.NewGuid()).ToString();
Console.WriteLine(newGuid);
to create a new GUID.
I'm designing a multilingual application using .resx files.
I have a few files like GlobalStrings.resx, GlobalStrings.es.resx, GlobalStrings.en.resx, etc.
When I want to use this, I just need to set Thread.CurrentThread.CurrentCulture.
The problem:
I have a combobox with all the available languages, but I'm loading this manually:
comboLanguage.Items.Add(CultureInfo.GetCultureInfo("en"));
comboLanguage.Items.Add(CultureInfo.GetCultureInfo("es"));
I've tried with
cmbLanguage.Items.AddRange(CultureInfo.GetCultures(CultureTypes.UserCustomCulture));
without any success. Also tried with all the elements in CultureTypes, but I'm only getting a big list with a lot more languages that I'm not using, or an empty list.
Is there any way to get only the supported languages?
You can programatically list the cultures available in your application
// Pass the class name of your resources as a parameter e.g. MyResources for MyResources.resx
ResourceManager rm = new ResourceManager(typeof(MyResources));
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
try
{
ResourceSet rs = rm.GetResourceSet(culture, true, false);
// or ResourceSet rs = rm.GetResourceSet(new CultureInfo(culture.TwoLetterISOLanguageName), true, false);
string isSupported = (rs == null) ? " is not supported" : " is supported";
Console.WriteLine(culture + isSupported);
}
catch (CultureNotFoundException exc)
{
Console.WriteLine(culture + " is not available on the machine or is an invalid culture identifier.");
}
}
based on answer by #hans-holzbart but fixed to not return the InvariantCulture too and wrapped into a reusable method:
public static IEnumerable<CultureInfo> GetAvailableCultures()
{
List<CultureInfo> result = new List<CultureInfo>();
ResourceManager rm = new ResourceManager(typeof(Resources));
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
try
{
if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work
ResourceSet rs = rm.GetResourceSet(culture, true, false);
if (rs != null)
result.Add(culture);
}
catch (CultureNotFoundException)
{
//NOP
}
}
return result;
}
using that method, you can get a list of strings to add to some ComboBox with the following:
public static ObservableCollection<string> GetAvailableLanguages()
{
var languages = new ObservableCollection<string>();
var cultures = GetAvailableCultures();
foreach (CultureInfo culture in cultures)
languages.Add(culture.NativeName + " (" + culture.EnglishName + " [" + culture.TwoLetterISOLanguageName + "])");
return languages;
}
This would be one of solution on basis of following statement:
Each satellite assembly for a specific language is named the same but lies in a sub-folder named after the specific culture e.g. fr or fr-CA.
public IEnumerable<CultureInfo> GetSupportedCulture()
{
//Get all culture
CultureInfo[] culture = CultureInfo.GetCultures(CultureTypes.AllCultures);
//Find the location where application installed.
string exeLocation = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
//Return all culture for which satellite folder found with culture code.
return culture.Where(cultureInfo => Directory.Exists(Path.Combine(exeLocation, cultureInfo.Name)));
}
I'm not sure about getting the languages, maybe you can scan your installation folder for dll-files, but setting your language to an unsupported language should not be a problem.
.NET will fallback to the culture neutral resources if no culture specific files can be found so you can safely select unsupported languages.
As long as you control the application yourself you could just store the available languages in a application setting somewhere. Just a comma-separated string with the culture names should suffice: "en, es"
Using what Rune Grimstad said I end up with this:
string executablePath = Path.GetDirectoryName(Application.ExecutablePath);
string[] directories = Directory.GetDirectories(executablePath);
foreach (string s in directories)
{
try
{
DirectoryInfo langDirectory = new DirectoryInfo(s);
cmbLanguage.Items.Add(CultureInfo.GetCultureInfo(langDirectory.Name));
}
catch (Exception)
{
}
}
or another way
int pathLenght = executablePath.Length + 1;
foreach (string s in directories)
{
try
{
cmbLanguage.Items.Add(CultureInfo.GetCultureInfo(s.Remove(0, pathLenght)));
}
catch (Exception)
{
}
}
I still don't think that this is a good idea ...
A generic answer where the resource type to search is specified. Uses reflection but is cached.
Usage:
List<string> comboBoxEntries = CommonUtil.CulturesOfResource<GlobalStrings>()
.Select(cultureInfo => cultureInfo.NativeName)
.ToList();
Implementation (Utility Class):
static ConcurrentDictionary<Type, List<CultureInfo>> __resourceCultures = new ConcurrentDictionary<Type, List<CultureInfo>>();
/// <summary>
/// Return the list of cultures that is supported by a Resource Assembly (usually collection of resx files).
/// </summary>
static public List<CultureInfo> CulturesOfResource<T>()
{
return __resourceCultures.GetOrAdd(typeof(T), (t) =>
{
ResourceManager manager = new ResourceManager(t);
return CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(c => !c.Equals(CultureInfo.InvariantCulture) &&
manager.GetResourceSet(c, true, false) != null)
.ToList();
});
}
It may suffer the same issue with the accepted answer in that all the language resources will probably be loaded.
#"Ankush Madankar" presents an interesting starting point but it has two problems:
1) Finds also resource folders for resources of refrenced assemblies
2) Doesn find the resource for the base assembly language
I won't try to solve issue 2) but for issue 1) the code should be
public List<CultureInfo> GetSupportedCultures()
{
CultureInfo[] culture = CultureInfo.GetCultures(CultureTypes.AllCultures);
// get the assembly
Assembly assembly = Assembly.GetExecutingAssembly();
//Find the location of the assembly
string assemblyLocation =
Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(assembly.CodeBase).Path));
//Find the file anme of the assembly
string resourceFilename = Path.GetFileNameWithoutExtension(assembly.Location) + ".resources.dll";
//Return all culture for which satellite folder found with culture code.
return culture.Where(cultureInfo =>
assemblyLocation != null &&
Directory.Exists(Path.Combine(assemblyLocation, cultureInfo.Name)) &&
File.Exists(Path.Combine(assemblyLocation, cultureInfo.Name, resourceFilename))
).ToList();
}
1. Gets the set of languages that are preferred by the user, in order of preference:
Windows.System.UserProfile.GlobalizationPreferences.Languages;
2. Gets or sets the language qualifier for this context (application):
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Languages;
Both are List<string>.