I found some threads about changing the localization of windows forms but nothing about doing the same for ribbons or other UI elements of Excel.
My.Application.SetCulture
is not avaialbe in my VS 2013 (don't know why).
1 Answers
it took me a while to accept the boundaries of VSTO but I coded an acceptable workaround. But first the limitation I came across
Office applications can't change culture while running. This can be seen if one uses the Microsoft Office Language tool to change the user interface language.
You'll always get a message that the change cannot take place until the Office apps are closed and restarted. (Source)Sound reasonable, at least I haven't found any entry what disagrees and all MSDN entries I found mentioning setting local before startup of the AddIn only
It seems there isn't any collection of ribbon objects. That means you cannot iterate trough all your ribbons in case you have multiple ones (depending of OS or situation). Since you cannot use multiple ribbons simultaneously anyway (but you can chose which to display at run time) There might by something closed to it for Outlook AddIns according to this MSDN entry.
You cannot change the language of a single tab make it refresh all containing controls. You have to do it one by one on each layer Tab->Group->Items
Finally my code. I have two separate classes, one for relocalize any open forms and one for the AddIn. Both are basically loop through all objects in the forms and all tabs of specific ribbon and change the language resource for each of them.
It works surprisingly well after all those constrains I came across. The only thing what I don't understand is, why I have to pass the reference to the ribbon to the class cs_RuntimeLocalizer4OfficeUI
as Microsoft.Office.Tools.Ribbon.RibbonBase
type?
RIBBON
private void Bt_LocalDE_Click(object sender, ToolsRibbon.RibbonControlEventArgs e)
{
changeUICulture("de-DE");
}
private void Bt_LocalEN_Click(object sender, ToolsRibbon.RibbonControlEventArgs e)
{
changeUICulture("en-GB");
}
private void changeUICulture(string cultureCode)// (Control parent, CultureInfo culture) //https://stackoverflow.com/questions/11711426/proper-way-to-change-language-at-runtime
{
cs_RuntimeLocalizer4OfficeUI.ChangeCulture(this, cultureCode);
foreach (WinForms.Form OpenForm in WinForms.Application.OpenForms) //based on https://hashfactor.wordpress.com/2009/01/28/c-check-if-a-form-is-already-opened/
{
cs_RuntimeLocalizer4Forms.ChangeCulture(OpenForm, cultureCode);
}
}
}
CLASS cs_RuntimeLocalizer4OfficeUI
using OToolsRibbon = Microsoft.Office.Tools.Ribbon;
using System.Globalization;
using System.Threading;
using System.ComponentModel;
using SysDiag = System.Diagnostics;
namespace Pro_Wunderkiste4Excel
{
static class cs_RuntimeLocalizer4OfficeUI //based on https://stackoverflow.com/questions/6980888/localization-at-runtime since relocalization after startup is not possible according to https://www.gittprogram.com/question/1159277_cultureinfo-currentculture.html
{
public static void ChangeCulture(OToolsRibbon.RibbonBase ri_Ribbon, string cultureCode)
{
CultureInfo culture = CultureInfo.GetCultureInfo(cultureCode); //http://www.csharp-examples.net/culture-names/
Thread.CurrentThread.CurrentUICulture = culture;
ComponentResourceManager resources = new ComponentResourceManager(ri_Ribbon.GetType());
foreach (OToolsRibbon.RibbonTab ri_Tab in ri_Ribbon.Tabs) //based on http://www.devcomponents.com/kb2/?p=696
{
resources.ApplyResources(ri_Tab, ri_Tab.Name, culture);
foreach (OToolsRibbon.RibbonGroup ri_TabGroups in ri_Tab.Groups) //based on https://stackoverflow.com/questions/7824125/better-way-to-programmatically-lock-disable-multiple-ui-controls-on-ribbon-bar
{
resources.ApplyResources(ri_TabGroups, ri_TabGroups.Name, culture);
foreach (OToolsRibbon.RibbonControl ri_TabGroupsCtrl in ri_TabGroups.Items)
{
SysDiag.Debug.Print(ri_TabGroupsCtrl.Name);
resources.ApplyResources(ri_TabGroupsCtrl, ri_TabGroupsCtrl.Name, culture);
}
}
}
}
}
}
CLASS cs_RuntimeLocalizer4Forms
using System.Windows.Forms;
using System.Globalization;
using System.Threading;
using System.ComponentModel;
namespace Pro_Wunderkiste4Excel
{
static class cs_RuntimeLocalizer4Forms //based on https://stackoverflow.com/questions/6980888/localization-at-runtime and https://stackoverflow.com/questions/3558406/how-to-change-language-at-runtime-without-layout-troubles
{
public static void ChangeCulture(Form frm, string cultureCode)
{
CultureInfo culture = CultureInfo.GetCultureInfo(cultureCode); //http://www.csharp-examples.net/culture-names/
Thread.CurrentThread.CurrentUICulture = culture;
ComponentResourceManager resources = new ComponentResourceManager(frm.GetType());
ApplyResourceToControl(resources, frm, culture);
resources.ApplyResources(frm, "$this", culture);
}
private static void ApplyResourceToControl(ComponentResourceManager res, Control control, CultureInfo lang)
{
if (control.GetType() == typeof(MenuStrip)) // See if this is a menuStrip
{
MenuStrip strip = (MenuStrip)control;
ApplyResourceToToolStripItemCollection(strip.Items, res, lang);
}
foreach (Control c in control.Controls) // Apply to all sub-controls
{
ApplyResourceToControl(res, c, lang);
res.ApplyResources(c, c.Name, lang);
}
// Apply to self
res.ApplyResources(control, control.Name, lang);
}
private static void ApplyResourceToToolStripItemCollection(ToolStripItemCollection col, ComponentResourceManager res, CultureInfo lang)
{
for (int i = 0; i < col.Count; i++) // Apply to all sub items
{
ToolStripItem item = (ToolStripMenuItem)col[i];
if (item.GetType() == typeof(ToolStripMenuItem))
{
ToolStripMenuItem menuitem = (ToolStripMenuItem)item;
ApplyResourceToToolStripItemCollection(menuitem.DropDownItems, res, lang);
}
res.ApplyResources(item, item.Name, lang);
}
}
}
}
In case you want to set the language according the OS or Office language as described here you may interested in the Local IDs table
Another approach might working with multiple addins. One out of these does only load/unload addins which have to change their language.
-
Thanks man. I don't have this "WinForms.Application.OpenForms". How did you achieve "WinForms" object? – Jalali Shakib Jun 30 '18 at 12:22
-
can't remember, I found properly the post [Find the open forms in c# windows application](https://stackoverflow.com/questions/1108368/find-the-open-forms-in-c-sharp-windows-application). You have to add `Namespace: System.Windows.Forms` and `Assembly: System.Windows.Forms (in System.Windows.Forms.dll)` – Stefan Jul 09 '18 at 15:21