Reputation: 1401
Is there any convenient way to serialize a reference to a string stored in a Resources.resx file (in multiple languages). I want to access it later (after the application may have been restarted) and display it in the currently active language.
Another use case would be to pass the "resource entry" to some method, e.g. to display an error message (in the currently active language) and at the same time log the message in english (so that we can debug it).
One point to keep in mind is that we don't have only a single Resource.resx file (in which case we could simply store the Key and use the ResourceManager
instance), but a large number of them in a composite application.
There are multiple use cases: One purpose is to avoid unnecessary code duplication. It is much more convenient to write something like ShowMessage(messageKey)
(which displays the message and logs it) than to write
ShowMessage(Resources.ResourceManager.GetString("Key", CultureInfo.CurrentCulture));
Log(Resources.ResourceManager.GetString("Key", CultureInfo.InvariantCulture));
This would also be useful to have some localized exception (so that the component does not have to know anything about the ShowMessage method).
In my case, I have some serializable CNC macro where I want to have some localizable message step (where the user has to do some manual action before continue). The language may be different when configuring the macro and when executing it.
Upvotes: 1
Views: 229
Reputation: 116794
You could consider some variation on the Observer Pattern, say Third-party Connect, that uses events to show and log messages. It involves extracting the following into a low-level shared DLL used by all your assemblies:
public class UIMessageEventArgs : EventArgs
{
public string Key { get; private set; }
public Func<CultureInfo, string> GetString { get; private set; }
public UIMessageEventArgs(string key, Func<CultureInfo, string> getString)
{
if (key == null || getString == null)
throw new ArgumentNullException();
this.Key = key;
this.GetString = getString;
}
}
public interface IUIMessageService
{
event EventHandler<UIMessageEventArgs> OnMessage;
void ShowMessage(object sender, string key, Func<CultureInfo, string> getString);
}
public sealed class UIMessageService : IUIMessageService
{
static UIMessageService() { instance = new UIMessageService(); }
static UIMessageService instance;
public static UIMessageService Instance { get { return instance; } }
UIMessageService() { }
#region IUIMessageService Members
public event EventHandler<UIMessageEventArgs> OnMessage;
public void ShowMessage(object sender, string key, Func<CultureInfo, string> getString)
{
if (getString == null)
throw new ArgumentNullException("getString");
if (key == null)
throw new ArgumentNullException("key");
var onMessage = OnMessage;
if (onMessage != null)
onMessage(sender, new UIMessageEventArgs(key, getString));
}
#endregion
}
public static class UIMessageExtensions
{
public static void ShowMessage(this ResourceManager resourceManager, string key)
{
if (resourceManager == null)
throw new ArgumentNullException("resourceManager");
if (key == null)
throw new ArgumentNullException("key");
UIMessageService.Instance.ShowMessage(resourceManager, key, c => resourceManager.GetString(key, c));
}
}
I made the message service a singleton since I suspect all of your listeners will be singletons.
Then in your CNC code, you would just call:
Resources.ResourceManager.ShowMessage("Key");
In addition in c# 6.0 you should be able to use nameof
instead of the hardcoded property name string:
Resources.ResourceManager.ShowMessage(nameof(Resources.Key));
By the way, if you're implementing CAD/CAM related macro functionality, you might consider logging the key string rather than the invariant message - then add the invariant message to the macro as a comment. That way macros can't get accidentally invalidated by changes (spelling fixes) to message text even in the invariant language.
If at some point you need to be able to record responses from the user into the macro that optionally (at the desire of the macro author) break for an interactive response, you can extend the UIMessageService
model to allow delegates for returning a user response by message key to be injected.
Upvotes: 1