How to do extreme branding / internationalization in .NET.

We are planning a fairly large application.

-We want to internationalize our application for 30 countries.

- In most countries, 1 to 6 different brands are available.

-What combination of a certain language, such as 'de', and a brand like XXX, may appear several times, so we need another identifier to get something unique:

"locale_brand_siteorigin" 

Therefore, we have a .resx file:

configurations. de.burgerking.px10 .resx

Bold is a unique identifier.

At runtime, we create:

 var rm = new ResourceManager("MyNamespace.Configurations.UniqueIdentifier",Assembly.GetExecuting()); 

Depending on our business logic, we can create the aforementioned ResourceManager.

Finally, we get 180 + resx files with all combinations of a unique identifier.

Do you know what is the best way to do this kind of branding?

4 years ago, someone asked this question, but no one answered:

Industry Standard for Application Branding

UPDATE

I also want to expand my question asking for a solution showing the benefits of using the cultureandregioninfobuilder class to create these many custom cultures.

https://msdn.microsoft.com/en-us/library/system.globalization.cultureandregioninfobuilder(v=vs.110).aspx

+6
source share
2 answers

I would not recommend using .resx files for such a huge project. When a website is translated into many languages, usually many people are involved in managing copying, translation, etc. These people will not be able to edit .resx files because they are technically embedded in the application code. This means that your developers will have to constantly update resources every time there is a change ... a real nightmare for everyone.

I recently created a database driven system for SumoSoft.Cms . All lines can be controlled through the admin panel, and in the code that you use:

 @CmsMethods.StringContent("ContentSection_Name", "Fallback_Value") 

This helper queries the database looking for an object of type "ContentSection", which is structured more or less as follows:

 public class ContentSection { public string Name { get; set; } public ICollection<ContentSectionLocalizedString> LocalizedStrings { get; set; } } 

Each localized line contains a link to a specific Country and the "Content" property, so all Helpers do this to select the one that matches the current culture of the stream.

+2
source

Turning around at @ FrancescoLorenzetti84, one of the ways I've done this in the past to simplify support is to wrap the database retrieval in the ResourceString class so you can do something like:

 private static readonly ResourceString res = "The value"; 

and then refer to this in code. Behind the scene, the ResourceString class does the job. Here is an example of this:

 namespace ResString { public interface IResourceResolver { string Resolve(string key, string defaultValue); } public class ResourceString { public ResourceString(string value) { this.defaultValue = value; GetOwner(); } public string Value { get { if (!resolved) Resolve(); return value; } } public override string ToString() { return Value; } public static implicit operator string(ResourceString rhs) { return rhs.Value; } public static implicit operator ResourceString(string rhs) { return new ResourceString(rhs); } protected virtual void Resolve() { if (Resolver != null) { if (key == null) key = GetKey(); value = Resolver.Resolve(key, defaultValue); } else { value = defaultValue; } resolved = true; } [MethodImpl(MethodImplOptions.NoInlining)] protected virtual void GetOwner() { StackTrace trace = new StackTrace(); StackFrame frame = null; int i = 1; while (i < trace.FrameCount && (owner == null || typeof(ResourceString).IsAssignableFrom(owner))) { frame = trace.GetFrame(i); MethodBase meth = frame.GetMethod(); owner = meth.DeclaringType; i++; } } protected virtual string GetKey() { string result = owner.FullName; FieldInfo field = owner.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(f => typeof(ResourceString).IsAssignableFrom(f.FieldType) && f.GetValue(null) == this ).FirstOrDefault(); if (field != null) result += "." + field.Name; return result; } public static IResourceResolver Resolver { get; set; } private string defaultValue; private string value; private bool resolved; private string key; private Type owner; } } 

And an example program:

 namespace ResString { class Program { /// <summary> /// Description for the first resource. /// </summary> private static readonly ResourceString firstRes = "First"; /// <summary> /// Description for the second resource. /// </summary> private static readonly ResourceString secondRes = "Second"; /// <summary> /// Description for the format string. /// </summary> private static readonly ResourceString format = "{0} {1}"; static void Main(string[] args) { ResourceString.Resolver = new French(); Console.WriteLine(String.Format(format, firstRes, secondRes)); } private class French : IResourceResolver { public string Resolve(string key, string defaultValue) { switch (key) { case "ResString.Program.firstRes": return "Premier"; case "ResString.Program.secondRes": return "Deuxième"; case "ResString.Program.format": return "{1} {0}"; } return defaultValue; } } } } 

If you run this, it will output: Deuxième Premier

Comment on the purpose of the Resolver, and you will receive: First second

Anywhere you would use a string in the user interface, use a declared ResourceString instead.

Changing the recognizer after the string values ​​have been resolved will not change their value, since the values ​​are retrieved only once. Of course, you will need to write a real resolver that pulls from the database.

Then you need a utility to run through the compiled classes and pull out ResourceString declarations and put the key and default values ​​in the database or text file so that they can be translated. This should also go through the generated XML help files for each assembly and pull out the comment for ResourceString declarations so that the translator has some context to work with. Key announcements also provide context, as you can easily group assets by user interface class.

Add this to your build script, make sure it is updated regularly.

You can use the same approach with images, etc.

+1
source

All Articles