Trying to wrap my head around smart strings

So I’m trying to get smart formatting to work and found this thread that seems to be doing the same thing I’m trying to do. Basically I’m just doing this (for testing purposes obviously), which is the same as in the linked thread:

Dictionary<string, string> dict = new Dictionary<string, string>();
dict["test"] = "testing";
localizedString.GetLocalizedString(dict);

And using a string like this:
Start game {test}

But get errors that I could not format the string

FormattingException: Error parsing format string: Could not evaluate the selector "test" at 12
Start game {test}
------------^
UnityEngine.Localization.SmartFormat.SmartFormatter.FormatError

I don’t know if I have to change something in the localization settings (I Haven’t touched anything aside from setting ‘parse error action’ to ‘throw error’), or if I’m sending the dictionary wrong. The output I’m looking to acheive is Start game testing based on this input. What am I doing wrong?

Hi,
Do you have a Dictionary Source added to the Smart String settings?

I did a quick test project and it works for me, its attached.

6942341–816128–SmartExample.zip (64.7 KB)

Yes I do (see attached image). So I removed the localization settings and created a new one, but that did not work either. I edited the ‘No translation found message’ just to make sure that it’s applied properly and sure enough, the message there is changed, so I know that the localization settings actually updates/changes.

I guess I’ll start with a test project too tonight and see if I can reproduce your behaviour instead. I don’t think it should be a unity version issue, but what version did you do this on? I’m on 2020.1.0f1.

6944045--816410--localizationSmartStringDictionarySource.png

Alright, so I got around to test this some more and I found the problem.

I actually hooked up to the StringChanged event too

Dictionary<string, string> dict = new Dictionary<string, string>();
dict["test"] = "testing";
localizedString.GetLocalizedString(dict);           
localizedString.StringChanged += LocalizedString_StringChanged;

When I’ve hooked up to this event (I use it to apply the text to my text object), it does a call to LocalizedString.RefreshString(). The call stack was of help here, where it tells me that the ‘AutomaticLoadingCompleted(…)’ calls this function and sends an empty list of arguments. I’m not entirely sure why the arguments are not set yet though because it’s sent into the localizedString when calling GetLocalizedString(…). If I do set the arguments directly, it works though.

Dictionary<string, string> dict = new Dictionary<string, string>();
dict["test"] = "testing";

// set the arguments directly and it works
localizedString.Arguments = new object[] { dict };

localizedString.GetLocalizedString(dict);           
localizedString.StringChanged += LocalizedString_StringChanged;

Maybe I can work around not using the StringChanged event, I can look into it, or maybe I can live with setting the arguments directly too

Ah I think I understand. GetLocalizedString and StringChanged event are 2 different ways to get the Localized value, they don’t work together.
GetLocalizedString calls directly in to the StringDatabase and returns the loading operation, it won’t trigger the StringChanged event. When you add a subscriber to StringChanged then that will trigger the loading operation using the provided arguments in the property. So you don’t need to use GetLocalizedString at all here.

It does make sense that you may want to use it this way though. I’ll see if we can improve it.

1 Like

Well, if you say I can just skip getlocalizedstring and set the arguments directly then I think I’ll just do that. I did not know they were not really compatible. Thanks for your help and explanation, now it’s time to use the feature :slight_smile:

1 Like