I want to make my plugin as multilingual. As I watched in some tutorials how to do it in C# that all of them doing this in Windows Forms by using string.resx, string.tr.resx, string.de.resx … files for different languages.
My plugin shaped by Panel in the Eto.Forms. Structure of plugin UI like below
MainPanel
TabControl -> TabPages
Collapsible Sections in the TabPages
TextBoxes, CheckBoxes, Labels etc.. in the Sections
Is there any way to make localizable for Panel object. How can I change my Label.Text properties according to string.resx files? What is the best practices for this?
Thanks this helps, in addition which layer I should manage my language changes?
Where and how should I initialize this Localization, in the MainPanel? I mean, practically When I switch language from Menu, which layer should be effected according to this initialization?
.resx files use CultureInfo.CurrentUICulture automatically, assuming you have included all of the localized assemblies. You should not have to set this yourself (it is based on the current user’s settings), but if you do want to change it via your own UI you can set strings.Culture = new CultureInfo("en-US"); for example.
Note that your UI won’t change automatically (unless you have your own code to do this), so you’d have to re-create your UI classes again to pick up the new values.
I’ve encountered weird thing, that is when I update language by special event to take language code (en-Us, zh-CN…) I was trying to simple close panel and open again. Language changes for “Head-Up Displays” which is inheriting from DisplayConduit, but Panel inside Labels don’t change. Is there anything related to registration of Panel? Because when I open my plugin by Command typing, I register it by this code;
The event is triggered by MyPluginTabControl which is below layer when we compare with MyPluginMainPanel. Below method is my event handler which I am using it in MyPluginMainPanel;
private void MyPluginTabControl_LanguageChanged(object sender, string e)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(e);
RhinoApp.WriteLine("My Plugin language has changed...");
Panels.ClosePanel(typeof(MyPluginMainPanel).GUID);
Panels.OpenPanel(typeof(MyPluginMainPanel).GUID);
}
This method gave me to infinite loop as you can see gif;
After your suggestion, I simply show you what code I am using in the MainPanel object;
public MyPluginMainPanel(uint documentRuntimeSerialNumber)
{
DocUint = documentRuntimeSerialNumber;
// Padding around the main container
Padding = 6;
// Heads-up Display
MyPluginDisplayConduit = new MyPluginDisplayConduit();
MyPluginDisplayConduit.Enabled = true;
CreateContent();
}
private void CreateContent()
{
// ViewModel associated with a specific RhinoDoc.RuntimeSerialNumber
MyPluginViewModel = new MyPluginViewModel(DocUint, MyPluginController,
MyPluginDisplayConduit);
// Set this panels DataContext, Page... panels will inherit this
DataContext = MyPluginViewModel;
// Bind this panel's content to the view model
this.Bind(c => c.Content, MyPluginViewModel, m => m.Content);
}
private void ReloadContent()
{
MyPluginViewModel = null;
DataContext = null;
CreateContent();
}
// Event that triggers from UI
private void MyPluginTabControl_LanguageChanged(object sender, string e)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(e)
RhinoApp.WriteLine("MyPlugin language was changed...")
ReloadContent();
}
You’re setting your content from a binding on the Panel itself, which you shouldn’t add more than once. It may be getting a feedback loop from the multiple bindings you are adding (since bindings are two-way by default).
@oguzhankoral, sorry I can’t really say, I don’t know how your MyPluginViewModel works. Does it create a new UI for its content property? Typically you don’t create UI via the view model, but perhaps you have a reason for that such as changing the panel display completely based on certain conditions.
Perhaps take a look at how your MyPluginViewModel.Content property is implemented. Are you caching the UI that is created somewhere? It needs to be recreated.
@curtisw I followed the layout of Dale in the samples of rhinocommon. Maybe that structure not fits my needs. The structure of MyPluginViewModel is something like this;
internal class MyPluginViewModel : ViewModel
{
public uint DocumentRuntimeSerialNumber { get; }
public RhinoDoc Document => RhinoDoc.FromRuntimeSerialNumber(DocumentRuntimeSerialNumber);
public MyPluginViewModel(uint documentRuntimeSerialNumber, IMyPluginController myPluginController, MyPluginDisplayConduit myPluginDisplayConduit)
{
// Read-only property initialization
DocumentRuntimeSerialNumber = documentRuntimeSerialNumber;
// Panel
Content = new MyPluginTabControl(this, myPluginController, myPluginDisplayConduit);
}
private Control myPluginContent;
/// <summary>
/// Bind this to the main panel container contents, will get set by the
/// next and back buttons (I dont have next back buttons)
////------> This part seems need to change,
/// because I am using TabControl on the contrary of the Dale's example
/// </summary>
public Control Content
{
get => myPluginContent;
set
{
if (myPluginContent == value)
return;
myPluginContent = value;
RaisePropertyChanged(nameof(Content));
}
}
}
The example you are working from is for a “wizard” interface which swaps out the panels for different steps. It can certainly do the same if really needed, but I kept things as simple as possible in this sample so you can see how it works. A more simple panel layout is here, which is what I based this on.
This layout more simple and clear for me, it helps thanks a million I encounter an issue, when I change the language again and again, the UI actions (even Rhino) getting slower each time. Is there any chance to we forgot to delete previous caches?
Perhaps you are hooking into events in Rhino each time you are creating your UI or creating multiple display conduits without destroying them? Otherwise there’s nothing (in my sample) that would cause that as far as I can tell.