Why you should use a wrapper around resource language file and how to clean up the mess if you didn’t

I had recent experience developing a Xamarin application and we needed to make the application to be multi language, we decided to use AppResources and put all the localization strings in .resx file.  And everything was perfect during the development before we got the final language strings.

resource_handler

There were many fields that needed to be filled dynamically according to the logged in user and his personal preferences. For example one of the strings could look like this:

“Lorem ipsum dolor sit amet <username>, consectetur adipiscing elit, <address> sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex <phone> ea commodo consequat.”

So when the logged in user was Jordan Atanasovski, the special place holders needed to be replaced with that user data and the message should be displayed like this:

“Lorem ipsum dolor sit amet Jordan Atanasovski, consectetur adipiscing elit, “Programming Street 1000, DotJord” sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex 0500-jordan-atanasovski ea commodo consequat.”

So there is a solution contained from two steps:

  • Creating a wrapper class
  • Replace all the code where you’ve used AppResources

The easy part: Creating the wrapper class

For this example, I’ll demonstrate implementation of very simple reusable wrapper class to solve this problem.

public static class ResourceHandler
{
private static Dictionary<string, string> _resoruceValues;
static ResourceHandler()
{
_resoruceValues = new Dictionary<string, string>();
}

public static void SetResourceValues(Dictionary<string, string> resourceValues)
{
_resoruceValues = resourceValues;
}
public static string Format(string input)
{
var ret = input;
foreach (var resoruceValue in _resoruceValues)
{
ret = ret.Replace(resoruceValue.Key, resoruceValue.Value);
}
return ret;
}
}

Check out DotNetFiddle live demo.

The hard part(if you go brute force): Replace all the code where you’ve used AppResources

After the implementation of the wrapper class we need to replace all the places where we use AppResources values(in my case 857 uses in numerous different files through the Xamarin project) and “the raw usage” like

  • AppResources.Value1
  • AppResources.Value2
  • AppResources.Value3 etc.

Should become:

  • ResourceHandler.Format(AppResources.Value1)
  • ResourceHandler.Format(AppResources.Value2)
  • ResourceHandler.Format(AppResources.Value3) etc.

Even the thought of replacing all the appearances brute force gave me headaches and there was work of many days(and possible many “forgotten” strings) in front of me. And because I don’t like doing things manually every time when there is a possibility not to. Here is a regular expression that will help us to that change in just few seconds. For development of  regular expressions I use this cool tool Regulex that helps me visualize the regex.

Regulex

( * ) check the AppResources usage finder regex here.

So, using Visual Studio Find/Replace we enter the regex and replacement.

Regex: (AppResources\.[a-zA-Z0-9]+)([\.\s,;\)])
Replace: ResourceHandler.Format($1)$2

Note that you must select the change to be to the entire solution and select “Use regular expressions” find option.

FindReplaceVS

This “trick” you can use in many other similar scenarios, for example if you want to add wrapper around any other resource types or third party components.

Happy coding!

Advertisements

2 thoughts on “Why you should use a wrapper around resource language file and how to clean up the mess if you didn’t

  1. Will you agree that using a String.Format prepared string in the resource file will do the same job? Whoever tries to alter the resource can easily be informed that {0} will stands for the , {1} for the and {2} for the by putting a comment in that particular line in the resx file. In the String.Format approach you will get rid of the overhead you just introduced (applying the replace logic against each used resource text).

    Liked by 1 person

    • Hi Ivan, thank you for your comment. This is the first thing that pop into my mind but unfortunately it was too expensive to implement in my scenario. I’ll try to explain why.

      Using String.Format and prepared strings might be a good approach if you have the resource file at some earlier stage of the project and in this case was pre-delivery time :). As I’ve mentioned in this case I had 857 usages of the resource(there are over 250 strings in the resource file) and I needed to go one by one, add the appropriate formatting for each of them, which is very time consuming and of course opens possibility for creating new bugs.

      The other client requirement that I’m handling with this approach is the possibility for them to change the resource file. Consider this simple scenario if we have prepared in this format:
      “Lorem ipsum {0} Ipsum {1}”,
      If the client decides to change the string(real example, to add address) in “Lorem ipsum {0} Ipsum {1} Ipsum {2}” this will not work without intervention in the code.

      If you were suggesting replace for each usage of the AppResources with some kind of generic format(which theoretically could work), that will create a lot of “hard to debug” and spaghetti code if each of the usages
      AppResource.Value1
      AppResource.Value2
      AppResource.ValueN
      transforms into:
      string.Format(AppResource.Value1, Values.Value2, Values.Value3, Values.Value4, Values.Value5, Values.Value6, Values.Value7, Values.Value8, Values.Value9);

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s