{"id":307,"date":"2009-05-04T13:02:21","date_gmt":"2009-05-04T13:02:21","guid":{"rendered":"https:\/\/blogs.mathworks.com\/desktop\/2009\/05\/04\/internationalization-of-guis\/"},"modified":"2018-01-08T14:27:07","modified_gmt":"2018-01-08T19:27:07","slug":"internationalization-of-guis","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/community\/2009\/05\/04\/internationalization-of-guis\/","title":{"rendered":"Internationalization of GUIs"},"content":{"rendered":"<p>Recently, Mario asked on the MATLAB newsgroup about how to provide a localized version of his GUI made in GUIDE. This is an interesting problem with no official, but many worthwhile solutions.<\/p>\n<p>Right now depending on where you live you can purchase MATLAB either in English or Japanese:<\/p>\n<div align=\"center\">\n<a  href=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/side_by_side_large.png\"><img decoding=\"async\" border=\"0\" src=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/side_by_side.png\" alt=\"English and Japanese MATLAB side by side\"><\/a>\n<\/div>\n<p>The translated strings that ship with MATLAB come compiled and bundled up, and we&#8217;re not able to extend our translation mechanisms into a tool that would be useable for MATLAB customers. This means we have to think of other ways for providing localizeable GUIs. Here&#8217;s an example GUI that I quickly whipped up using a few easily translateable nouns. I apologize ahead of time, the buttons will only work if you have the image processing toolbox as I took some of my favorite images from its demos. However, the language changing menu works without any toolboxes. There&#8217;s a lot more code than you&#8217;re used to seeing on this blog, so I&#8217;ve provided a zip file with all the examples at the end.<\/p>\n<div align=\"center\"><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/french_gui.png\" alt=\"The translate GUI\"><\/div>\n<p>Below I present four of many possible strategies to create an internationalizeable MATLAB GUI. For each of these strategies the actual GUI code (the <tt>translateDemo.fig<\/tt> and <tt>translateDemo.m<\/tt> files) remain unchanged. The difference happens in the dispatch function <tt>getLabel.m<\/tt>, which is called from the following function by the menu callbacks. Note that menu labels have a different property to set than the <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/index.html?\/access\/helpdesk\/help\/releases\/R2009a\/techdoc\/ref\/uicontrol.html\"><tt>uicontrol<\/tt><\/a>s. I&#8217;ll leave it as an exercise for you to simplify this function using the <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/index.html?\/access\/helpdesk\/help\/releases\/R2009a\/techdoc\/ref\/uicontrol_props.html&#038;https:\/\/www.mathworks.com\/access\/helpdesk\/help\/releases\/R2009a\/techdoc\/infotool\/hgprop\/uicontrol_propnames.html#UserData\"><tt>UserData<\/tt><\/a> or <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/index.html?\/access\/helpdesk\/help\/releases\/R2009a\/techdoc\/ref\/uicontrol_props.html&#038;https:\/\/www.mathworks.com\/access\/helpdesk\/help\/releases\/R2009a\/techdoc\/infotool\/hgprop\/uicontrol_propnames.html#Tag\"><tt>Tag<\/tt><\/a> properties.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> setLanguage(lang)\r\n<span style=\"color: #228B22\">% find the label or string for each of the uicontrols for a given language<\/span>\r\n<span style=\"color: #228B22\">% and set it.<\/span>\r\nh = guidata(gcf);\r\nset(h.language, <span style=\"color: #A020F0\">'Label'<\/span>,  getLabel(lang, <span style=\"color: #A020F0\">'language'<\/span>));\r\nset(h.english,  <span style=\"color: #A020F0\">'Label'<\/span>,  getLabel(lang, <span style=\"color: #A020F0\">'english'<\/span>));\r\nset(h.french,   <span style=\"color: #A020F0\">'Label'<\/span>,  getLabel(lang, <span style=\"color: #A020F0\">'french'<\/span>));\r\nset(h.german,   <span style=\"color: #A020F0\">'Label'<\/span>,  getLabel(lang, <span style=\"color: #A020F0\">'german'<\/span>));\r\nset(h.peppers,  <span style=\"color: #A020F0\">'String'<\/span>, getLabel(lang, <span style=\"color: #A020F0\">'peppers'<\/span>));\r\nset(h.children, <span style=\"color: #A020F0\">'String'<\/span>, getLabel(lang, <span style=\"color: #A020F0\">'children'<\/span>));\r\nset(h.canoe,    <span style=\"color: #A020F0\">'String'<\/span>, getLabel(lang, <span style=\"color: #A020F0\">'canoe'<\/span>));<\/pre>\n<p><strong>Using MATLAB classes<\/strong><br \/>\nThe first method makes use of constant properties in MATLAB class objects, allowing us to define the strings using the same pattern as one class file per language. Note that the keys for all of the languages are in English. It doesn&#8217;t matter what the keys actually are, as long as they are consistent. As you can see from my getLabel function, I&#8217;m taking advantage of the default <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/ref\/subsref.html\"><tt>subsref<\/tt><\/a> to access a class property dynamically. I think it&#8217;s a neat trick. <\/p>\n<p><i><tt>getLabel.m<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> xlatedString = getLabel(lang, label)\r\nxlatedString = <span style=\"color: #A020F0\">'???'<\/span>;\r\n<span style=\"color: #0000FF\">switch<\/span> lang\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'en'<\/span>\r\n        xlatedString = EnglishStrings.(label);\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'de'<\/span>\r\n        xlatedString = GermanStrings.(label);\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'fr'<\/span>\r\n        xlatedString = FrenchStrings.(label);\r\n<span style=\"color: #0000FF\">end<\/span><\/pre>\n<p>The following is my class with the English labels. The French and German ones follow the same pattern.<br \/>\n<i><tt>EnglishStrings.m<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">classdef<\/span> EnglishStrings\r\n    <span style=\"color: #0000FF\">properties<\/span> (Constant)\r\n        language = <span style=\"color: #A020F0\">'Language'<\/span>;\r\n        english = <span style=\"color: #A020F0\">'English'<\/span>;\r\n        french = <span style=\"color: #A020F0\">'French'<\/span>;\r\n        german = <span style=\"color: #A020F0\">'German'<\/span>;\r\n        canoe = <span style=\"color: #A020F0\">'Canoe'<\/span>;\r\n        children = <span style=\"color: #A020F0\">'Children'<\/span>;\r\n        peppers = <span style=\"color: #A020F0\">'Peppers'<\/span>;\r\n    <span style=\"color: #0000FF\">end<\/span>\r\n<span style=\"color: #0000FF\">end<\/span><\/pre>\n<p>The advantage of this method is that it takes the MATLAB search path out of the equation. If you can run the GUI code, you can get to the class objects&#8211;the file locations do not need to be hard coded.<br \/>\n<strong>Using XML<\/strong><br \/>\nHard coding the strings in class files may be a little a clunky or not fit into your workflow. The next method makes use of XML files, but you can use whatever combination of files and I\/O methods to read them you&#8217;d like: plain text files (with <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/ref\/fread.html\"><tt>fread<\/tt><\/a>), Microsoft Excel files (with <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/ref\/xlsread.html\"><tt>xlsread<\/tt><\/a>), or even using a <tt>containers.Map<\/tt> and saving\/loading .MAT files!<br \/>\n<i><tt>getLabel.m<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> xlatedString = getLabel(lang, label)\r\n\r\nxlatedString = <span style=\"color: #A020F0\">'???'<\/span>;\r\n<span style=\"color: #0000FF\">switch<\/span> lang\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'en'<\/span>\r\n        xmlfile = <span style=\"color: #A020F0\">'english.xml'<\/span>;\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'de'<\/span>\r\n        xmlfile = <span style=\"color: #A020F0\">'german.xml'<\/span>;\r\n    <span style=\"color: #0000FF\">case<\/span> <span style=\"color: #A020F0\">'fr'<\/span>\r\n        xmlfile = <span style=\"color: #A020F0\">'french.xml'<\/span>;\r\n<span style=\"color: #0000FF\">end<\/span>\r\n\r\n<span style=\"color: #0000FF\">try<\/span>\r\n    xDoc = xmlread(xmlfile);\r\n    root = xDoc.getDocumentElement;\r\n    strings = root.getElementsByTagName(<span style=\"color: #A020F0\">'string'<\/span>);\r\n    <span style=\"color: #0000FF\">for<\/span> i=0:strings.getLength - 1\r\n        <span style=\"color: #0000FF\">if<\/span> strcmp(strings.item(i).getAttribute(<span style=\"color: #A020F0\">'id'<\/span>), label)\r\n            <span style=\"color: #228B22\">%translate from java string to MATLAB string<\/span>\r\n            xlatedString = char(strings.item(i).getTextContent);\r\n        <span style=\"color: #0000FF\">end<\/span>\r\n    <span style=\"color: #0000FF\">end<\/span>\r\n<span style=\"color: #0000FF\">catch<\/span> <span style=\"color: #228B22\">%#ok&lt;CTCH&gt;<\/span>\r\n    <span style=\"color: #228B22\">%ignore any read errors and use '???'<\/span>\r\n<span style=\"color: #0000FF\">end<\/span><\/pre>\n<p><i><tt>french.xml<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">\r\n&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;strings&gt;\r\n    &lt;string id=\"language\"&gt;Langue&lt;\/string&gt;\r\n    &lt;string id=\"english\"&gt;Anglais&lt;\/string&gt;\r\n    &lt;string id=\"french\"&gt;Fran\u00e7ais&lt;\/string&gt;\r\n    &lt;string id=\"german\"&gt;Allemand&lt;\/string&gt;\r\n    &lt;string id=\"canoe\"&gt;Cano\u00eb&lt;\/string&gt;\r\n    &lt;string id=\"children\"&gt;Enfants&lt;\/string&gt;\r\n    &lt;string id=\"peppers\"&gt;Poivrons&lt;\/string&gt;\r\n&lt;\/strings&gt;\r\n<\/pre>\n<p><strong>Using a Java Resource Bundle<\/strong><br \/>\nJava provides a built-in mechanism for storing strings and choosing them based upon locale called a <a href=\"http:\/\/java.sun.com\/javase\/6\/docs\/api\/java\/util\/ResourceBundle.html\"><tt>ResourceBundle<\/tt><\/a>. We can take advantage of <tt>java.util<\/tt> classes from MATLAB so this method uses Java&#8217;s solution for our MATLAB GUI. Remember to convert the <tt>java.lang.String<\/tt> returned from the bundle using the MATLAB <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009a\/techdoc\/ref\/char.html\"><tt>char<\/tt><\/a> function.<br \/>\n<i><tt>getLabel.m<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> xlatedString = getLabel(lang, label)\r\n<span style=\"color: #228B22\">%using the java resource bundle<\/span>\r\nxlatedString = <span style=\"color: #A020F0\">'???'<\/span>;\r\n<span style=\"color: #0000FF\">try<\/span>\r\n    file = java.io.File([<span style=\"color: #A020F0\">'strings_'<\/span> lang <span style=\"color: #A020F0\">'.properties'<\/span>]);\r\n    inputStream = java.io.FileInputStream(file);\r\n    resourceBundle = java.util.PropertyResourceBundle(inputStream);\r\n    xlatedString = char(resourceBundle.getString(label));\r\n<span style=\"color: #0000FF\">catch<\/span> <span style=\"color: #228B22\">%#ok&lt;CTCH&gt;<\/span>\r\n    <span style=\"color: #228B22\">%ignore any read errors and use '???'<\/span>\r\n<span style=\"color: #0000FF\">end<\/span><\/pre>\n<p><i><tt>strings_de.properties<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">\r\nlanguage=Sprache\r\nenglish=Englisch\r\nfrench=Franz\u00f6sisch\r\ngerman=Deutsch\r\ncanoe=Kanu\r\nchildren=Kinder\r\npeppers=Paprikas\r\n<\/pre>\n<p>The Java ResourceBundle mechanism comes with the ability to automatically select the right file based upon the locale information and filename. To take advantage of that, we&#8217;d have to discuss how MATLAB and the ClassLoader interact&#8230;a topic for a different post.<br \/>\n<strong>Google Translation Services<\/strong><\/p>\n<div align=\"center\"><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/spanish_gui.png\" alt=\"The translate GUI with Spanish added\"><\/div>\n<p>Thanks to smart people at Google, you can get live translation to\/from nearly any language. For this version of the GUI, I&#8217;ve added Spanish, Finnish, Filipino, and Turkish to the menu for almost no extra work. All the strings are translated live through <a href=\"http:\/\/code.google.com\/apis\/ajaxlanguage\/documentation\/\">Google&#8217;s translation API<\/a>. I won&#8217;t interpret their <a href=\"http:\/\/code.google.com\/apis\/ajaxlanguage\/terms.html\">Terms of Service<\/a> for you, but if you do decide to use their services, play nice: it&#8217;s a great service they&#8217;re giving away for free.<\/p>\n<p><i><tt>getLabel.m<\/tt><\/i><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> xlatedString = getLabel(lang, label)\r\nxlatedString = <span style=\"color: #A020F0\">'???'<\/span>;\r\n<span style=\"color: #0000FF\">try<\/span>\r\n    url = <span style=\"color: #A020F0\">'http:\/\/ajax.googleapis.com\/ajax\/services\/language\/translate'<\/span>;\r\n    <span style=\"color: #228B22\">%'en' (English) is the base language<\/span>\r\n    page = urlread(url,<span style=\"color: #A020F0\">'get'<\/span>,{<span style=\"color: #A020F0\">'v'<\/span>,<span style=\"color: #A020F0\">'1.0'<\/span>,<span style=\"color: #A020F0\">'q'<\/span>,label,<span style=\"color: #A020F0\">'langpair'<\/span>,[<span style=\"color: #A020F0\">'en|'<\/span> lang]});\r\n    pattern = <span style=\"color: #A020F0\">'(?&lt;=\"translatedText\":\")(.+?)(?=\")'<\/span>;\r\n    xlatedString = regexp(page,pattern,<span style=\"color: #A020F0\">'match'<\/span>,<span style=\"color: #A020F0\">'once'<\/span>);\r\n<span style=\"color: #0000FF\">catch<\/span> <span style=\"color: #228B22\">%#ok&lt;CTCH&gt;<\/span>\r\n    <span style=\"color: #228B22\">%ignore any read errors and use '???'<\/span>\r\n<span style=\"color: #0000FF\">end<\/span><\/pre>\n<p>To make this nicer, I should probably look up the stored English strings instead of using my object labels for the translation (i.e. this doesn&#8217;t work for a phrase and doesn&#8217;t do the correct capitalization). Also, this code can be cleaned up a little using Fran\u00e7ois Glineur&#8217;s <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/23393--another--json-parser\">JSON Parser<\/a> from the MATLAB file exchange.<\/p>\n<p>The real power here, I think is that you can provide a localized UI without having to develop a competency in that language. Of course the real question is whether or not it is better to provide no translation or a translation that could be wrong and confusing.<\/p>\n<p><strong>Determining Language Automatically<\/strong><br \/>\nMost modern operating systems know something about the user&#8217;s environment such as the location and language. Java is able to get this information from the system and thus you can get it from MATLAB:<br \/>\n<code lang=\"java\">java.util.Locale.getDefault().getLanguage()<\/code><br \/>\nThis returns the cute little two-letter language code that is consistent with the ones I&#8217;ve been using, and so we can stick this in the <tt>openingFcn<\/tt> function and have out GUI automatically detect the language and choose the appropriate strings.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">function<\/span> translateDemo_OpeningFcn(hObject, eventdata, handles, varargin)\r\n<span style=\"color: #228B22\">% This function has no output args, see OutputFcn.<\/span>\r\n<span style=\"color: #228B22\">% hObject    handle to figure<\/span>\r\n<span style=\"color: #228B22\">% eventdata  reserved - to be defined in a future version of MATLAB<\/span>\r\n<span style=\"color: #228B22\">% handles    structure with handles and user data (see GUIDATA)<\/span>\r\n<span style=\"color: #228B22\">% varargin   command line arguments to translateDemo (see VARARGIN)<\/span>\r\n\r\n<span style=\"color: #228B22\">% Choose default command line output for translateDemo<\/span>\r\nhandles.output = hObject;\r\n\r\n<span style=\"color: #228B22\">% Update handles structure<\/span>\r\nguidata(hObject, handles);\r\n\r\n<span style=\"color: #228B22\">%default to the peppers<\/span>\r\npeppers_Callback(handles.peppers, [], handles);\r\nsetLanguage(char(java.util.Locale.getDefault().getLanguage()))\r\n<\/pre>\n<p>A web search should reveal how to change the language settings for your particular OS. Here&#8217;s how to do it for Windows XP, and the result of making my machine think I understand Finnish:<\/p>\n<div align=\"center\">\n<a  href=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/finnish_settings_large.png\"><img decoding=\"async\" border=\"0\" src=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/finnish_settings.png\" alt=\"Windows XP Finnish language settings\"><\/a><br \/>\n<a  href=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/finnish_gui_large.png\"><img decoding=\"async\" border=\"0\" src=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/finnish_gui.png\" alt=\"demo GUI in Finnish\"><\/a>\n<\/div>\n<p>I&#8217;d like to close this post asking my high school teachers, colleagues in France and Germany, and Aur\u00e9lien to forgive me for any embarrasing translation mistakes. Bon Chance!<\/p>\n<p>You can download the demo code <a  href=\"https:\/\/blogs.mathworks.com\/images\/desktop\/michael_katz_internationalization_of_guis\/translate_gui_demo.zip\">right-clicking here<\/a> and doing a Save As. I will also put them on the MATLAB file exchange and link them once they are up.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently, Mario asked on the MATLAB newsgroup about how to provide a localized version of his GUI made in GUIDE. This is an interesting problem with no official, but many worthwhile solutions.<br \/>\nRight&#8230; <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/community\/2009\/05\/04\/internationalization-of-guis\/\">read more >><\/a><\/p>\n","protected":false},"author":38,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[36,17],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/posts\/307"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/comments?post=307"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/posts\/307\/revisions"}],"predecessor-version":[{"id":5048,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/posts\/307\/revisions\/5048"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/media?parent=307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/categories?post=307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/community\/wp-json\/wp\/v2\/tags?post=307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}