Best practices for global resources in c# - c#

When we want to make our application for all users(speak different languages),We need a global technology.
In C# we use ResourceManager as follow:
using System;
using System.Reflection;
using System.Resources;
public class Example
{
public static void Main()
{
// Retrieve the resource.
ResourceManager rm = new ResourceManager("ExampleResources" ,
typeof(Example).Assembly);
string greeting = rm.GetString("Greeting");
Console.Write("Enter your name: ");
string name = Console.ReadLine();
Console.WriteLine("{0} {1}!", greeting, name);
}
}
// The example produces output similar to the following:
// Enter your name: John
// Hello John!
The assembly have two or more language resources:
Assembly
|--Assembly.en-us.resx
|--Assembly.zh-cn.resx
Then we archive to change the resource by changing thread cultureinfo to use different resource.
If the application have a lot of dll(assembly) files.
I want to have a single point(one resource file for one language) for the application,
Is there a good solution for my idea?
Before I just change the View(eg.Winform or UserControl)'s Language to implement different UI for corresponding language.

Just build the internationalization in C# using the way you described. But as last step of the build process, you can run Fody.Costura.
This will take all the different dlls and pack them into your application so that you only have a single .exe file with everything included.
The benefit is that you can use the C# internationalization frameworks as intended without any hacks, but you still get a single exe you can deliver to your customers.

I find the C# internationalization frameworks very lacking, so I normally
make one assembly for resources and reference from the other projects. The resource files I generate from some tool (DB, excel, textfile) and keep both the source data and the resource files under version control.
MyApp.sln
ResourceProject.csproj
Resources.resx
Resources.ru.resx
Resources.de.resx
Resource.cs
Core.csproj
UI.csproj
The resource class can load all the different assemblies
namespace MyApp.Resources
{
public static class Resource
{
private static ResourceManager manager;
static Resource()
{
manager = new ResourceManager("MyApp.Resources", Assembly.GetAssembly(typeof(Resource)));
}
public static string GetString(string key, string culture)
{
return GetString(key, new CultureInfo(culture));
}
public static string GetString(string key, CultureInfo culture)
{
return manager.GetString(key, culture);
}
}
}
This simple class can be extended in various ways. In the calling assemblies you can have utility classes that will call based on the current UI culture or thread culture depending on the situation.
Note that this completely sidesteps any built-in WinForms or WPF i18N methods.
For GUI:s you can make a utility that recursively translates whole forms. The lookup itself can/should be extended with warnings for missing keys, fallback arguments, prefixes/namespaces if you have thousands of keys and so on.

Related

Retrieve <Version> tag written in csproj file from dll [duplicate]

I am trying to get the executing assembly version in C# 3.0 using the following code:
var assemblyFullName = Assembly.GetExecutingAssembly().FullName;
var version = assemblyFullName .Split(',')[1].Split('=')[1];
Is there another proper way of doing so?
Two options... regardless of application type you can always invoke:
Assembly.GetExecutingAssembly().GetName().Version
If a Windows Forms application, you can always access via application if looking specifically for product version.
Application.ProductVersion
Using GetExecutingAssembly for an assembly reference is not always an option. As such, I personally find it useful to create a static helper class in projects where I may need to reference the underlying assembly or assembly version:
// A sample assembly reference class that would exist in the `Core` project.
public static class CoreAssembly
{
public static readonly Assembly Reference = typeof(CoreAssembly).Assembly;
public static readonly Version Version = Reference.GetName().Version;
}
Then I can cleanly reference CoreAssembly.Version in my code as required.
In MSDN, Assembly.GetExecutingAssembly Method, is remark about method "getexecutingassembly", that for performance reasons, you should call this method only when you do not know at design time what assembly is currently executing.
The recommended way to retrieve an Assembly object that represents the current assembly is to use the Type.Assembly property of a type found in the assembly.
The following example illustrates:
using System;
using System.Reflection;
public class Example
{
public static void Main()
{
Console.WriteLine("The version of the currently executing assembly is: {0}",
typeof(Example).Assembly.GetName().Version);
}
}
/* This example produces output similar to the following:
The version of the currently executing assembly is: 1.1.0.0
Of course this is very similar to the answer with helper class "public static class CoreAssembly", but, if you know at least one type of executing assembly, it isn't mandatory to create a helper class, and it saves your time.
using System.Reflection;
{
string version = Assembly.GetEntryAssembly().GetName().Version.ToString();
}
Remarks from MSDN http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getentryassembly%28v=vs.110%29.aspx:
The GetEntryAssembly method can return null when a managed assembly has been loaded from an unmanaged application. For example, if an unmanaged application creates an instance of a COM component written in C#, a call to the GetEntryAssembly method from the C# component returns null, because the entry point for the process was unmanaged code rather than a managed assembly.
Product Version may be preferred if you're using versioning via GitVersion or other versioning software.
To get this from within your class library you can call System.Diagnostics.FileVersionInfo.ProductVersion:
using System.Diagnostics;
using System.Reflection;
//...
var assemblyLocation = Assembly.GetExecutingAssembly().Location;
var productVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion
This should do:
Assembly assem = Assembly.GetExecutingAssembly();
AssemblyName aName = assem.GetName();
return aName.Version.ToString();
I finally settled on typeof(MyClass).GetTypeInfo().Assembly.GetName().Version for a netstandard1.6 app. All of the other proposed answers presented a partial solution. This is the only thing that got me exactly what I needed.
Sourced from a combination of places:
https://msdn.microsoft.com/en-us/library/x4cw969y(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/2exyydhb(v=vs.110).aspx

Using Resource files for things other than language

I am working on an MVC application that is effectively a piece of middleware to provide admin and reporting on an external BPM solution.
The users of the system aren't all for the same business function and may refer to fields as different things (e.g. division A calls a client a Client but division B calls them a Prospect). Is there a way I could have resource files for
Resources.divA.resx
Resources.divB.resx
Resources.divC.resx
From my googling, it appears it can only be used for localization.
You can use the ResourceManager class to help with this.
When you add some resources to a project, the IDE automatically adds a Resources.Designer.cs file to the project to manage the resources. The generated code looks something like this:
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AssemblyName.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
This uses the ResourceManager constructor that looks up resources based on a combination of a root name and the current locale.
You can write similar code yourself, but compute a root name based on whether the the resources are for division A, B or C. So you would call it something like "AssemblyName.Resources.divA" instead of "AssemblyName.Properties.Resources".
You can then also have specific versions for each other supported language and they will be automatically loaded (if present) for the current culture. This is how it works for the IDE-managed resources.

How to create at runtime a .NET exe file assembly from already compiled classes

I need to create executable file assembly at runtime. My main goal is to compile types from the actual Project (.dll) performing compilation task, without using strings keeping the code that needs to be compiled to the output exe file. Maintaining those strings during code development/refactoring would be a nightmare. As shown in the example below, when I refactor class CodeToCompile, I also need to remember to change string codeToCompile in RuntimeCompiler.Compile() method:
using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
namespace RuntimeCompiler
{
public class Compiler
{
public void Compile()
{
string codeToCompile =
#"public class CodeToCompile
{
public static void Main(string[] args)
{
Console.ReadLine();
}
}";
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
CompilerParameters parameters = new CompilerParameters
{
GenerateExecutable = true,
OutputAssembly = "Generated.exe"
};
CompilerResults results = icc.CompileAssemblyFromSource(parameters, codeToCompile);
}
}
public class CodeToCompile
{
public static void Main(string[] args)
{
Console.ReadLine();
}
}
}
What I would like to achive is changing the string with code that needs to be compiled to reference of the type that needs to be compiled into .exe assembly.
string codeToCompile = "..."; //CodeToCompile source code
CompilerResults results = icc.CompileAssemblyFromSource(parameters, codeToCompile);
CompilerResults results = icc.CompileAssemblyFromSource(parameters, typeof(CodeToCompile));
Any ideas what would be the best way to achieve this?
I have easily found information how to dynamically compile C# code from string using System.CodeDom.Compiler namespace, as shown above. Thus any method to get a runtime object uncompiled code as a string would do the job. My research in this direction did not give me solution and I strongly doubt that it is possible to do in an easy way.
My second idea is to use mechanism to "move" compiled type from the running assembly to a newly created one, but unfortunately I also haven't found any solution to do this task.
...without using strings keeping the code that needs to be compiled to output exe file. Maintaining those strings during code development/refactoring would be a nightmare...
My advice here is to look into .NET Globalization
Globalization involves designing and developing a world-ready app that supports localized interfaces and regional data for users in multiple cultures...The handling of characters and strings is a central focus of globalization, because each culture or region may use different characters and character sets and sort them differently. More...
An alternative to CodeDom.Compiler is .NET's Reflection Emit:
...the System.Reflection.Emit namespace that allow a compiler or tool to emit metadata and Microsoft intermediate language (MSIL) at run time and optionally generate a portable executable (PE) file on disk. Script engines and compilers are the primary users of this namespace. More...

How can I get correct string localization when running my unit tests?

I have a project that needs to support French and English. I put all strings into resource files. When I debug the program in Visual Studio, I can successfully view the program in French. However, when I run the tests for the program, the program reverts to English. I added the French resource dll file to the deployment. This allows me to debug individual unit tests in French, but when I click Test -> Debug -> All Tests in Solution, the program runs in English.
I tried to add [DeploymentItem(#"..\bin\x86\Release\fr", "fr-FR")] to one of the tests also, but this didn't help. Does anyone have any suggestions on how to fix this? Thanks!
I wrap language tests in a using statement like this:
[Test]
public void Loads_correct_labels_from_language()
{
using(new LanguageSwitchContext("fr"))
{
var okayString = MyResources.Okay_Button;
Assert.Equals("your localized string here", okayString);
}
}
public class LanguageSwitchContext : IDisposable
{
public CultureInfo PreviousLanguage { get; private set; }
public LanguageSwitchContext(CultureInfo culture)
{
PreviousLanguage = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
}
public LanguageSwitchContext(string language)
{
//create culture from language
}
public void Dispose()
{
System.Threading.CurrentThread.CurrentCulture = PreviousCulture;
}
}
There are two potential issues here:
When your tests are run, CurrentUICulture may not be set to the language you wish to test
The satellite assemblies (only French in your example) may not be deployed in the unit test environment. When ResourceManager doesn't find a matching satellite assembly for a UI culture, it defaults to the base language embedded in the project's DLL itself (and so you get English, assuming that's your base language).
For 1. you can make sure to set System.Threading.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR"); in your test or at your test class's initialization.
For 2. the use of a DeploymentItemAttribute like you mentioned should work. Do verify that the satellite assembly deployed when your successfully run your app in French does get copied with the same name and in the same subfolder in your test's deployment. It's probably something more like [DeploymentItem(#"bin\fr-FR", "fr-FR")]

Resources per version

I know it is possible to store localized versions of resources to be retrieved by the application.
I would like to use a similar principle and to store different versions of data into a resource file/assembly, then use the version as the key to retrieve this data. Is this possible? Is this a common technique?
The data I will be storing is UI Control data identifications.
So for example I would have multiple resources available per version:
Version 1.0 btnID = "thisButton1"
Version 2.0 btnID = "thisButton2"
The application would determine automatically which resource to pick up based on the version currently being used.
You can create a custom class that will wrap the access to the resources and load the correct resource file internally. Assuming you have chosen to name your resource file Resources.1.0.0.0.resources, you can do the following:
public class ResourceReader
{
private static ResourceManager _resourceManager = new ResourceManager(
"Resources." + System.Reflection.Assembly
.GetExecutingAssembly()
.GetName()
.Version.ToString(),
Assembly.GetExecutingAssembly());
// If you have resource property btnID, you can expose it like this:
public static string BtnID
{
get
{
return _resourceManager.GetString("btnID");
}
}
// you can add other properties for every value in the resource file.
}
All you need to do is to know the exact version of your application and to ensure such resource file exists. This can be cumbersome if you have enabled automatic versioning in the assembly info (by using 1.0.* for instance). Of course, you may choose not to use the entire version, but only the major or major and minor version numbers.

Categories

Resources