RickStrahl / Westwind.Globalization

Database driven resource localization for .NET applications
543 stars 135 forks source link

Calling DbRes.T() inside an IResourceSetValueConverter causes loop #57

Closed brianlocke closed 8 years ago

brianlocke commented 8 years ago

I have created an IResourceSetValueConverter class that replaces tokens inside the resourceValue. Some of those tokens are Keys to a resource and therefore need to be replaced with the correct resource value. Currently when you call DbRes.T() inside the Convert method the Convert get's called again with the original string.

Pseudo code:

//Resources in Localization Db
en MessageText = "My favorite color is @(Color)";
fr MessageText = "Ma couleur préférée est le @(Color)";
en Red = "Red";
fr Red = "Rouge";

// first call to DbRes.T()
var message = DbRes.T("MessageText", "Resources", "fr");
// custom IResourceSetValueConverter
CustomResourceSetValueConverter.Convert(object resourceValue, string key)
{
    var replaceableParam = ParseTextForParams(resourceValue as string);
    // this will cause a loop back into 
    var frenchColor = DbRes.T(replaceableParam, "Resources","fr");
    return resourceValue.Replace(replaceableParam,frenchColor);
}
RickStrahl commented 8 years ago

Yes that makes sense, given that the converter gets applied to any value that gets translated.

Not to be snarky, but what do you expect the behavior to be? You're using a high level API from a low level API feature.

I don't see how this could be addressed in a meaningful way.

The workaround for this is to directly access the ResourceManager and get the raw, unprocessed value.

brianlocke commented 8 years ago

Thank you for your note Rick. No snarky-ness required :) I thought that the call to DbRes.T() inside the convert would follow the same code path as any other call outside the .Convert() method. I may not have explained my situation well enough. Assuming the custom IResourceSetValueConverter is in place and breakpoint set on first line of the code.

  1. Call DbRes.T("MessageText","Resources","fr")
  2. Breakpoint hit: The resourceValue inside .Convert properly contains "Ma couleur préférée est le @(Color)"
  3. Inside the .Convert() method look up what "Color" is set for this instance, it returns "Red"
  4. Inside the .Convert() method call DbRes.T("Red","Resources","fr")
  5. Breakpoint hit: The resourceValue inside .Convert contains "Ma couleur préférée est le @(Color)", I expected it to contain "Rouge"

If this is expected behaviour then that's fine. It just didn't seem like it would have been to me. Thanks again!

RickStrahl commented 8 years ago

@brianlocke The problem is that if the converter is applied, DbRes.T() uses that converter so the call is recursive and blows the stack. I don't see a way that this can be resolved if Converters are to work inside of a call to DbRes.T() (or any of the other ResourceProvider/ResourceManager) calls.

I think this is a bit of an edge case - it's not likely that most 'conversions' would call into another translation.

brianlocke commented 8 years ago

Thank you @RickStrahl , we'll pursue an alternative process.