2
\$\begingroup\$

I wrote the following code to get the translated string from Resource Manager. The method GetTranslatedString is called more than 50 times in my project.

  public static string GetTranslatedString(string input, string culture)
    {
        if (string.IsNullOrEmpty(input)) return input;
        string retInput = input;
        CultureInfo cultureInfo = new CultureInfo(culture);
        ResourceManager rm = new ResourceManager("Globalization.XYZ", Assembly.GetExecutingAssembly());

        var entry = rm.GetResourceSet(cultureInfo, true, true)
            .OfType<DictionaryEntry>()
            .FirstOrDefault(e => e.Key.ToString().Equals(input, StringComparison.InvariantCultureIgnoreCase));
        if (entry.Value == null) return retInput;
        return entry.Value.ToString();

    }

But I feel it's not perfect code because the ResourceManager class gets new instances many times and since I'm calling GetTranslatedString many times I am sure it will impact on performance.

Second major problem is, I am using reflection inside this code. and it's a costly operation.

It would helpful if I could get review on this.

\$\endgroup\$
1
  • \$\begingroup\$ updated the post, if there is no translation I am returning the input back. \$\endgroup\$
    – kudlatiger
    Commented Oct 9, 2015 at 15:52

1 Answer 1

2
\$\begingroup\$
public static string GetTranslatedString(string input, string culture)
{
    if (string.IsNullOrEmpty(input)) return input;
    string retInput = input;
    CultureInfo cultureInfo = new CultureInfo(culture);
    ResourceManager rm = new ResourceManager("Tesla.TSS.Globalization.SchedulingSystem", Assembly.GetExecutingAssembly());

    var entry = rm.GetResourceSet(cultureInfo, true, true)
        .OfType<DictionaryEntry>()
        .FirstOrDefault(e => e.Key.ToString().Equals(input, StringComparison.InvariantCultureIgnoreCase));
    if (entry.Value == null) return retInput;
    return entry.Value.ToString();

}  

Because the resources of your application won't change during runtime, the easiest way would be to once get the whole items and store them in a dictionary. Then your application can use the dictionary to retrieve the translated strings.

I would like to suggest to make this a little bit more flexible, so you could use it in other projects too.

At first the method which will retrieve the Dictionary<string,string> from the ResourceManager

public static Dictionary<string, string> GetTranslations(CultureInfo cultureInfo, string baseName, Assembly assembly)
{
    ResourceManager rm = new ResourceManager(baseName, assembly);

    using (ResourceSet rs = rm.GetResourceSet(cultureInfo, true, true))
    {
        return rs.OfType<DictionaryEntry>()
                 .ToDictionary(r => r.Key.ToString(),
                      r => r.Value.ToString());
    }
}

as you can see, this can be called independent from your current project.

Now let us add an overloaded method which takes the culture as a string like so

public static Dictionary<string, string> GetTranslations(string culture, string baseName, Assembly assembly)
{
    CultureInfo cultureInfo = new CultureInfo(culture);
    return GetTranslations(cultureInfo, baseName, assembly);
}

In your project you can call it now like

Dictionary<string,string> translations = GetTranslations(culture, "Tesla.TSS.Globalization.SchedulingSystem", Assembly.GetExecutingAssembly());

and you could query this to get the translated strings.

You could have a method ChangeLanguage(string culture) like so

private string currentCultureName = "en-Us";
private void ChangeLanguage(string culture)
{
    if (string.IsNullOrWhiteSpace(culture)) 
    {
        currentCultureName = CultureInfo.CurrentUICulture.Name;
    }
    else
    {
        currentCultureName = culture;
    }

    translations = GetTranslations(culture, "Tesla.TSS.Globalization.SchedulingSystem", Assembly.GetExecutingAssembly());
}  

to change the current dictionary.

Your former GetTranslatedString() method should then live as a class method (not static) inside your project and should look like so

public string GetTranslatedString(string input, string culture)
{

    if (input == null) { throw new ArgumentNullException("input"); }

    if (string.IsNullOrWhiteSpace(input)) { return input; }

    if (currentCultureName != culture)
    {
        ChangeLanguage(culture);
    }

    string translation;
    if (translations.TryGetValue(input, out translation))
    {
        return translation;
    }

    return input;
} 

As you can see I have change quite a few things like

  • adding braces {} although they are optional for single line if statements, but they will make the code less error prone.

  • for a passed in input which is null this will throw an ArgumentNullException which is much better than just returning the null.

  • for the passed in culture I didn't add a null check, because if the ChangeLanguage() method will be called with a null value the name of the CurrentUICulture will be used.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you. I am implementing it. sounds good. keep you posted \$\endgroup\$
    – kudlatiger
    Commented Oct 9, 2015 at 19:10
  • \$\begingroup\$ I am just doing sample project for my school academic. your way of reviewing helped a lot, we all students learned a lot in this answer. Thank you with respect Heslacher. \$\endgroup\$
    – kudlatiger
    Commented Oct 9, 2015 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.