{"id":6583,"date":"2007-03-08T15:46:00","date_gmt":"2007-03-08T15:46:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/03\/08\/making-your-vb-code-ready-to-go-global-matt-gertz\/"},"modified":"2024-07-05T14:50:31","modified_gmt":"2024-07-05T21:50:31","slug":"making-your-vb-code-ready-to-go-global-matt-gertz","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/making-your-vb-code-ready-to-go-global-matt-gertz\/","title":{"rendered":"Making your VB code ready to go global (Matt Gertz)"},"content":{"rendered":"<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Greetings, all!<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">I\u2019m Matt Gertz, the Dev Manager for Visual Basic team.<span>&nbsp; <\/span>I\u2019ve been on the team for a bit over 12 years, via the Blackbird\/Visual InterDev side of the product, and in that time have been a dev on various features (mostly IDE-related), dev lead of deployment, dev lead of compiler, and box lead before my current responsibilities as DM.<span>&nbsp; <\/span>I\u2019ve been somewhat remiss in not having posted to this blog before, being content to hang out on the VB IDE Forum, but it\u2019s my intent to correct that situation and to throw out a few thoughts here and there.<span>&nbsp; <\/span>Many of our clever folk here have been writing about some of the exciting new features upcoming for VB9 (such as Scott\u2019s excellent series on extension methods), so rather than stealing a measure from them, I\u2019m going to instead focus on things that you can do with Visual Basic right now.<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Going global<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Many of the questions I\u2019ve been asked by customers over the years revolve around the concept of globalization \u2013 making your code work in different languages \u2013 so I\u2019m going to write about this today.<span>&nbsp; <\/span>I\u2019m actually fairly passionate this subject \u2013 if there was such a thing as a Unicode groupie, that might well describe me.<span>&nbsp; <\/span>A lot of this enthusiasm comes from years of development on code that needs to go international.<span>&nbsp; <\/span>In Ye Olde Days, this was frankly very hard to do, but fortunately, using Visual Basic &amp; .NET, making your code ready for a global audience is far simpler than it used to be.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Consider the following (admittedly contrived) code:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Sub<\/span> test(<span>ByVal<\/span> value <span>As<\/span> <span>Double<\/span>)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> s <span>As<\/span> <span>String<\/span> = value.ToString<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> positionOfDot = InStr(s, <span>&#8220;.&#8221;<\/span>)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> positionOfDot &gt; 0 <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(<span>&#8220;The number &#8220;<\/span> &amp; s.Substring(positionOfDot) _<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span>&amp; <span>&#8221; is the decimal portion.&#8221;<\/span>)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Else<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(<span>&#8220;There is no decimal portion.&#8221;<\/span>)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">This code will work fine in English (although there are certainly better ways to get the decimal portion of a number &#8212; please don&#8217;t do it this way for real&nbsp;<span><span>J<\/span><\/span>).<span>&nbsp; <\/span>However, there are several problems with the code if you want to take it global, problems which I\u2019m sure many folks will have spotted:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font face=\"Calibri\" size=\"3\">(1)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">Many cultures don\u2019t use \u201c.\u201d as a decimal separator \u2013 many cultures use (for example) a comma.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font face=\"Calibri\" size=\"3\">(2)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">The output strings are hard-coded to English \u2013 you\u2019d have to change the code for each language.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font face=\"Calibri\" size=\"3\">(3)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">The first output string assumes an English grammar ordering \u2013 some languages might need the argument at the end or the beginning, not in the middle.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">So , some of you might be thinking, \u201cWhat\u2019s so wrong about 2 and 3?<span>&nbsp; <\/span>I\u2019m going to have to translate the strings anyway if I go global, right?\u201d<span>&nbsp; <\/span>Sure, but you don\u2019t want to have to touch your code files unless necessary, and you sure don\u2019t want to have different code paths for different languages \u2013 it will make your supportability nightmarish for any given version of your application.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Fortunately, there are solutions:<\/font><\/p>\n<p class=\"MsoListParagraph\"><span><span><font face=\"Calibri\" size=\"3\">(1)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">When dealing with cultural information, rely on the System.Globalization namespace.<span>&nbsp; <\/span>For example, instead of hard-coding the \u201c.\u201d, you can instead call the following code:<\/font><\/p>\n<p class=\"MsoNormal\"><span>Imports<\/span><span> System.Globalization<\/span><\/p>\n<p class=\"MsoNormal\"><span>(\u2026)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> c <span>As<\/span> <span>String<\/span> = _<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span>CultureInfo.CurrentUICulture.NumberFormat.CurrencyDecimalSeparator<\/span><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><font face=\"Calibri\" size=\"3\">to get the decimal separator for the current culture \u2013 in the contrived example above, you\u2019d then use the result as your search string instead of \u201c.\u201d.<span>&nbsp; <\/span>There are many, many pieces of information you can pull out of the CurrentUICulture, and you can even determine information about other cultures as well from System.Globalization.<span>&nbsp; <\/span>I\u2019ve attached a ZIP file to this post which gives examples of the cool things you can do with that namespace.&nbsp; (The example also leverages the Encoding class in the System.Text namespace to show how you can translate your strings&nbsp;from UTF-8 to Unicode to DBCS, something you might need to do in global code.)<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font face=\"Calibri\" size=\"3\">(2)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">Move your strings to your project\u2019s resources.<span>&nbsp; <\/span>This is pretty darn simple in VS2005.<span>&nbsp; <\/span>Simply right-click the project and choose \u201cProperties,\u201d and then navigate to the \u201cResources\u201d page.<span>&nbsp; <\/span>Add your strings to the resource table (each string will need a name as well as its text value), and then in code, simply type \u201c<\/font><span>My<\/span><span>.Resources.MyResourceName\u201d <\/span><font face=\"Calibri\" size=\"3\">to use the string. <span>&nbsp;<\/span>Later, when you need to change the string to a different language, you simply update your resources rather than your code.<span>&nbsp; <\/span>The resource manager also can hold icons, images, and even whole text files that you might be using in your UI.<span>&nbsp; <\/span>(If you\u2019re not using VS2005, then check out my attached example to see how to access the resources without \u201cMy\u201d &#8212; I wrote that code before the \u201cMy\u201d functionality was available, and simply threw my resources into a handy resx file.)<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font face=\"Calibri\" size=\"3\">(3)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">Use replacement characters in strings rather than concatenating pieces of strings together when writing full grammatical sentences.<span>&nbsp; <\/span>Trust me; this will make your life a lot easier when localizing your code. <span>&nbsp;&nbsp;<\/span>In the resources, make your string resource (let\u2019s name it \u201cMyOutput\u201d) something like:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><font face=\"Calibri\" size=\"3\">\u201cThe number {0} is the decimal portion.\u201d<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>And then the call becomes:<\/font><\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(<span>String<\/span>.Format(<span>My<\/span>.Resources.MyOutput, _<\/span><\/p>\n<p class=\"MsoNormal\"><span>s.Substring(positionOfDot))<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<blockquote>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Now, your localization team won\u2019t need to touch your code to change the grammar of the sentence \u2013 they can just move around the \u201c{0}\u201d in the resource string when translating.<\/font><\/font><\/span><\/p>\n<\/blockquote>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\"><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\"><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">The resources on your forms can also be automatically managed from the resource manager, making it similarly easy to update the default strings in your controls.<span>&nbsp; <\/span>Simply change the \u201cLocalizable\u201d property of the form to \u201cTrue,\u201d and your form\u2019s strings will no longer be hard-coded in InitializeComponent, but will now be stored instead in {form\u2019s name}.resx (you may have to choose \u201cShow All Files\u201d to see that file).<span>&nbsp; <\/span>Those resources are kept separate from the code resources (which are stored in Resources.resx), so you would need to translate both when going global.<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\">The downside of everything I\u2019ve just mentioned is that you still need to rebuild your product for each language after translating the resources \u2013 the code isn\u2019t changed, but the resources have, so compilation is necessary.<span>&nbsp; <\/span>To get around this and to avoid all possibility of code binaries being different from language to language, you can create separate assemblies for your resources and refer to them from your main project, leveraging the assembly\u2019s ability to identify its culture.<span>&nbsp; <\/span>I\u2019m not going to go into it since there\u2019s information already about this on the net if you\u2019re interested \u2013 <\/font><a href=\"http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/cpguide\/html\/cpconLocalizingResources.asp\"><font face=\"Calibri\" size=\"3\">here\u2019s one<\/font><\/a><font size=\"3\"><font face=\"Calibri\">, for example.<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">One big win in using VB from a global point of view is that everything is Unicode \u2013 you don\u2019t have to do anything special to support the wide variety of characters out there.<span>&nbsp; <\/span>Even the editor supports Unicode, so you can have a wide variety of (for example) variable names.<span>&nbsp; <\/span>However, I should point out that we do not support Unicode characters greater than &amp;H00FFFF, the so-called \u201csurrogate character\u201d combinations, as variable names.<span>&nbsp; <\/span>(If you don\u2019t know what a \u201csurrogate character\u201d is\u2026 well, that\u2019s a topic for another time.)<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Hopefully you will find this information on globalization useful \u2013 please feel free to comment or ask questions, and I\u2019ll do my best to follow up.<span>&nbsp; The book &#8220;Developing International Software&#8221; from Microsoft Press is also a very good reference on how we deal with globalization issues here.&nbsp; The fully comprehensive &#8220;Unicode Standard 5.0&#8221; volume from The Unicode Consortium is also a handy thing to have around for specific questions on Unicode usage (and it also makes a great booster seat for kids when they&#8217;re sitting at a high table) &#8212; if it&#8217;s outside your budget, you can read it online at <a href=\"http:\/\/www.unicode.org\/\">www.unicode.org<\/a>.<\/span><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Going forward, my plan for my blog entries is to walk through a fairly complex card game I wrote last year, in order to point out some of the other very useful functionality in Visual Basic 2005 that you might not know as much about.<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Until next time,<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">&#8211;Matt&#8211;*<\/font><\/font><\/span><\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Components.PostAttachments\/00\/01\/83\/93\/81\/VB-Globalization-usage.zip\">VB-Globalization-usage.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Greetings, all! I\u2019m Matt Gertz, the Dev Manager for Visual Basic team.&nbsp; I\u2019ve been on the team for a bit over 12 years, via the Blackbird\/Visual InterDev side of the product, and in that time have been a dev on various features (mostly IDE-related), dev lead of deployment, dev lead of compiler, and box lead [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22,195],"tags":[62,71,101,165],"class_list":["post-6583","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matt-gertz","category-visual-basic","tag-encoding","tag-globalization","tag-matt-gertz","tag-vb2005"],"acf":[],"blog_post_summary":"<p>Greetings, all! I\u2019m Matt Gertz, the Dev Manager for Visual Basic team.&nbsp; I\u2019ve been on the team for a bit over 12 years, via the Blackbird\/Visual InterDev side of the product, and in that time have been a dev on various features (mostly IDE-related), dev lead of deployment, dev lead of compiler, and box lead [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6583","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=6583"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6583\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=6583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=6583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=6583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}