zoukankan      html  css  js  c++  java
  • Globalization and Localization

    Globalization of Windows Applications in 20 Minutes Using C#

    By rajesh-lal | 1 Sep 2006
    Describes the essential features required to enable multiple languages in a Windows application using resource files.
    Is your email address OK? You are signed up for our newsletters but your email address has not been reconfirmed in a long time. To make this warning go away please click here to have a confirmation email sent so we can confirm your email address and continue sending you your newsletters. Alternatively, you can update your subscriptions.

    Globalization of Windows Application in 20 Minutes

    Prelude

    There was once a time when multiple language support for a Windows application used to be a three to six months call, but with the advent of .NET, not anymore. Here is a 20 minutes crash course for globalization / localization of a Windows application. I think you'll find it as useful as I do.

    Globalization, in simple terms, means enabling an application so that it works in different nationals, similar to how a global company operates in different countries. For a Windows application, globalization means it is intended for worldwide distribution. There are two aspects of globalization:

    • Internationalization: Enabling the application to be used without language or culture barriers, i.e., language and culture information comes from a resource rather than being hard coded in the application.
    • Localization: Translating and enabling the product for a specific locale. Based on a resource file, the application is translated into a language and culture.

    Target

    • Modular design: Code Once Use Everywhere (COUE), this is the prime feature which is needed when you globalize an application. All anyone should do is convert any user interface output/message box /labels text etc., to something like frmMain.RM.GetString("10001"). No culture information or resource manager initialization need to be done again in forms or anywhere else.
    • Default language: Saving and retrieving the default language selected by the user in the Registry.
    • Features: How to take care of date/time, multiple forms, images etc.
    • Reusability: Minimum effort when you add a new form to the application.
    • Extensibility: Support for multiple languages like French, Spanish, and English, using resource files for each.

    To hold your interest, here is how it looks:

    Time starts now

    The first thing we need will be three resource files for three languages English, French, and Spanish. I have used Google translate here[^] to accomplish this:

    1. English file name: resource.en-US.txt.
    2. Spanish file name: resource.es-ES.txt.
    3. French file name: resource.fr-FR.txt.

    Using the Resource generator (Resgen) in the Visual Studio .NET 2003 Command Prompt, we will create three resource files which can be understood by the application, here is how:

    We are done with the resource files which will be used by the application and will look something like this (below) with the extension .resources for each text file:

    Put these three .resources files in a Resource folder in the executable path.

    Functionality

    First run

    When the application runs for the first time, we check for the Registry entry language of the application in [HKEY_CURRENT_USER\SOFTWARE\CODE PROJECT\GLOBALIZATION SAMPLE], and returns "en-US" if there is no entry yet. This value is set for the string strCulture of the application.

    GetStringRegistryValue in the RegistryAccess class helps us get this:

     Collapse
    static public string GetStringRegistryValue(string key, string defaultValue)
    {
        RegistryKey rkCompany;
        RegistryKey rkApplication;
        rkCompany = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, 
                    false).OpenSubKey(COMPANY_NAME, false);
        if( rkCompany != null )
        {
            rkApplication = rkCompany.OpenSubKey(APPLICATION_NAME, true);
            if( rkApplication != null )
            {
                foreach(string sKey in rkApplication.GetValueNames())
                {
                    if( sKey == key )
                    {
                    return (string)rkApplication.GetValue(sKey);
                    }
                }
            }
        }
        return defaultValue;
    }

    Globalize application

    Once we have the strCulture, we call the GlobalizeApp function:

     Collapse
    // Resource path
    private string strResourcesPath= Application.StartupPath + "/Resources";
    // string to store current culture which is comon in all the forms
    private string strCulture= "en-US";
    //resourcemanager which retrivesthe strings
    //from the resource files
    private static ResourceManager rm;
    
    private void GlobalizeApp()
    {
        SetCulture();
        SetResource();
        SetUIChanges();
    }
    private void SetCulture()
    {
        CultureInfo objCI = new CultureInfo(strCulture);
        Thread.CurrentThread.CurrentCulture = objCI;
        Thread.CurrentThread.CurrentUICulture = objCI;
        
    }
    private void SetResource()
    {
        rm = ResourceManager.CreateFileBasedResourceManager
            ("resource", strResourcesPath, null);
    
    }
    private void SetUIChanges()
    {
        ...
    }

    The GlobalizeApp function sets the culture information of the current thread, sets the Resource manager to the respective resource file, andSetUIChnages does all the user interface translations.

    Modular design: Code Once Use Everywhere

    This, as I said already, is an important feature because when an application expands or grows with time, you should be ready to change a new string with just one statement replacement. For this, I have created a public resource manager in frmMain:

     Collapse
    public static ResourceManager RM
    { 
      get 
      { 
       return rm ; 
       } 
    }

    So, when the main form loads, you set the culture and the resource file information to the public resource manager. And, in the new added form or anywhere you add a message box or label, you can call the resource manager like this:

     Collapse
    this.Text = frmMain.RM.GetString("0006");
    label1.Text = frmMain.RM.GetString("0008");

    Translations

    SetUIChanges describes how the translations are done:

    • Texts are directly translated from the resource file
    • Images have to be taken care for using multiple images
    • DateTime etc., which are Windows specific does not need to be translated at all (isn't that cool?)

    The code-behind

     Collapse
    private void SetUIChanges()
    {
        if (String.Compare(strCulture,"en-US")==0)
        { 
            picTop.Image = picE.Image;
        }
    
        if (String.Compare(strCulture,"es-ES")==0)
        { 
            picTop.Image = picS.Image;
        }
    
        if (String.Compare(strCulture,"fr-FR")==0)
        { 
            picTop.Image = picF.Image;
        }
        label1.Text=rm.GetString("0001");
        label2.Text=rm.GetString("0002");
        label3.Text=rm.GetString("0003");
        btnSubmit.Text=rm.GetString("0004");
        btnCancel.Text=rm.GetString("0005");
        this.Text = rm.GetString("0000");
        lblselect.Text = rm.GetString("0009");
    
        lbltime.Text = DateTime.Now.ToLongDateString().ToString(); 
    }

    For images, I have used three hidden PictureBox controls as shown below:

    Saving the default culture in the Registry

    The code-behind:

     Collapse
    static public void SetStringRegistryValue(string key, string stringValue)
    {
        RegistryKey rkSoftware;
        RegistryKey rkCompany;
        RegistryKey rkApplication;
    
        rkSoftware = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, true);
        rkCompany = rkSoftware.CreateSubKey(COMPANY_NAME);
        if( rkCompany != null )
        {
            rkApplication = rkCompany.CreateSubKey(APPLICATION_NAME);
            if( rkApplication != null )
            {
                rkApplication.SetValue(key, stringValue);
            }
        }
    }

    Acknowledgement

    My humble acknowledgement to my boss who gave me a 6 days deadline, for globalization of an application we have been working on for a year.

    What's wrong with the .Resx approach

    i got a number of emails asking why not use the .resx approach for each form. Well, here are a few of the reasons. I prefer a single resource file compared to multiple .resx files for each form for three simple reasons:

    1. Maintainability:
    2. Assuming you are taking the .resx files approach:

      Take a simple scenario. By mistake, you have a wrong translation for the "Submit" button, say for the German language. The original translation is "Einreichen", but you initially missed the last n and now, you have "Einreiche" instead of "Einreichen" for Submit buttons throughout your application.

      What you can do to resolve this:

      1. You have to go to each form and change the resource file of the form.
      2. Compile the EXE again, creating the German DLL, and redistribute the whole EXE with setup including the new DLL.

      On the other hand, if you use a single resource file as in this article, "Submit" buttons in all the forms translate into something likeResourceManager.GetString("101").

      If the translation is wrong, just-

      1. Update the initial German text file.
      2. Resgen it and create a resource file.
      3. Overwrite your existing resource file with the updated resource file.

      You are done. Redistribution needs just the lightweight resource file and your EXE will automatically update the Submit buttons everywhere.

    3. Extensibility:
    4. If you have to add another language, say Latino, with the .resx file approach, you have to go to each form and create a resx file for Latino, and compile and create a Latino DLL.

      With the Single Resource file approach, you just have to create another text file with the Latino translation as shown in the example above, Resgen it, and add a menu option for Latino, and you are done. You can have a Latino menu option even earlier, and add the resource file later; you won't even need to re-compile.

    5. Dynamic UI changes:
    6. With resource files, you can have a dropdown menu instead of the radio button in the example, and change the complete UI on the fly to whichever language you fancy. With the .resx and DLL approach, you have to start the application with that localized DLL.

      I think you might be able to dynamically change the UI, but it will be a much more complicated process.

      Another not that important reason is, the Resource file approach creates lightweight .Resources files whereas .resx creates a DLL for each language.

      If you want to go by the standard approach, you can definitely get better results, but will not be as fast as this approach.

    And thanks

    For coming so far. I hope this 20 minutes was worth it, and give me your comments/ suggestion to improve this.

    In action (French)

    Article history

    • August 20 2006: First published.
    • September 01 2006: Added comparison with .Resx approach.

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    rajesh-lal


    Software Developer (Senior)
    Nokia Inc.
    United States United States

    Member
    Senior Engineer at Nokia Inc. Mountain View

    Author of the following books

    1. 
    Creating Vista Gadgets using HTML, CSS, & JavaScript (website). 
    2. 
    Beginning Smartphone Web Development (website)
    3. 
    Developing Web Widget with HTML, CSS, JSON and AJAX (website)



    Globalization and localization demystified in ASP.NET 2.0

    By Vivek Thakur | 30 Sep 2006
    This article explains how to globalize an ASP.NET 2.0 website, step by step, with a practical example.
    Is your email address OK? You are signed up for our newsletters but your email address has not been reconfirmed in a long time. To make this warning go away please click here to have a confirmation email sent so we can confirm your email address and continue sending you your newsletters. Alternatively, you can update your subscriptions.

    Introduction

    Globalization and localization are two important processes which every developer should be aware of while creating global products or applications. Though there are many articles which explain the subject well, I did not find a single resource which explains all important concepts regarding globalization/localization, practically and comprehensively. This article aims to provide practical step-by-step approach to globalizing a web application in ASP.NET 2.0.

    Background Theory

    Globalization is defined as the process of developing a program or an application so that it is usable across multiple cultures and regions, irrespective of the language and regional differences. For example, you have made a small inventory management program and you live in a region where English is the main language, assume England. Now, if you want to sell your program in a different country, let’s say Germany, then you need to make sure that your program displays and takes input in German language.

    Localization is the process of creating content, input, and output data, in a region specific culture and language. Culture will decide date display settings (like, mm/dd/yyyy or dd/mm/yyyy), currency display formats etc. Now, the process by which we can make sure that our program will be localized is known as Internationalization or Globalization. In simpler terms, Globalization can be defined as the set of activities which will ensure that our program will run in regions with different languages and cultures.

    So, globalization is related to intrinsic code changes to support such changes like using Resource files etc. Whereas, localization is the process of using a particular culture and regional info so that the program uses the local languages and culture. This means translating strings into a particular local language. This covers putting language specific strings in the resource files. Globalization starts in the main construction phase along with the code development. Localization generally comes later.

    Globalizing an ASP.NET 2.0 Website

    Let’s start with a simple example. For the purposes of explaining localization and keeping things simple, I have created a new website in ASP.NET and C#, called TestSite (source code of the example is included in this article). I have added a Master Page and a default page. This default page has a TextBoxand a Calendar control. The TextBox control has a double number which will represent currency, and we will see how the currency format varies as user selects different languages. The default page looks like this when I run the application:

    Default.JPG

    I have published the test web application, and you can see the functional version here.

    Cultures and Locale

    Now, before we move ahead, let me throw some light on cultures and locale.

    Languages also depend upon the geographical location. For example, French is spoken in France as well as Canada (besides many other countries). But linguistically speaking, Canadian French is quite different from French spoken in France. Similarly, there are linguistic differences between US English and British English. Therefore, the language needs to be associated with the particular region where it is spoken, and this is done by using locale (language + location).

    For example: fr is the code for French language. fr-FR means French language in France. So, fr specifies only the language whereas fr-FR is the locale. Similarly, fr-CA defines another locale implying French language and culture in Canada. If we use only fr, it implies a neutral culture (i.e., location neutral).

    How do we define or change the current culture?

    There are two properties of the CultureInfo class in the .NET FCL (Framework Class Library) which we can set using the overloaded constructor of the class, and then we can use the class to change the culture of the currently executing thread:

    • UICulture: gets/sets the user interface culture for the currently executing thread. This property helps the runtime to load the resource strings from a specific resource file (which we will see later). This property can take neutral cultures as well as locales. For example:
    •  Collapse
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr”);

      Or,

       Collapse
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr-CA”);
    • Culture: gets/sets the region specific culture and formats of currency, dates etc. This needs language as well as location (locale).
    •  Collapse
      Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr-A”); //correct as 
          ///we have given locale 
      Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr”); //wrong, will
                                                                 // not work

    Sometimes we need a culture which does not belong to any language or locale, which is invariant of any region/language. For this, we have theCultureInfo.InvariantCulture property. It is used during the internal system processes which need to be culture independent, or to store data which does not need to be displayed directly to the end user.

    Both UICulture and Culture properties can be defined in the Web.Config file under the <GLOBALIZATION>property. They can also be specified at page level. But we don’t want to hard-code these values, and would like to set them dynamically instead. As seen above, we could also get/set these values from the code using the Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICultureproperties. So, we will use these properties in our application.

    Switching Locale

    Coming back to our application, we need a way to switch the locale. There are two approaches regarding this:

    1. Use the browser settings: In IE, the user can change the culture by going to Internet Options->General->Languages. For this to work, we need to set both the Culture and the UICulture to auto and enableClientBasedCulture = true as:
    2.  Collapse
      <GLOBALIZATION culture="auto" uiculture="auto" enableClientBasedCulture="”true”" />
    3. User specified settings: We can give an option for the user to specify and change the culture and the language at runtime. This is the recommended approach, as sometimes the browser itself may not have the user specific culture set (for example, a French tourist might be surfing net in India). Also, sometimes changing Language settings via the browser is blocked.

    Going by the second recommended approach, I have created a section on the top (inside a Panel control) in the Master Page where I have a drop-down with these language options which let the users choose a particular locale. For illustration purposes, I have the option of only four languages to choose from: Hindi, US English, British English, and French.

    For my application to be globalized, I want that whenever the user selects a locale from the language, the following should happen:

    1. All content should be localized: This means that all strings and text should be displayed in the chosen language and locale.
    2. Each control’s caption/content should also show text in local language.
    3. Date and currency formatting should occur according to the chosen locale.
    4. All messages displayed to the user should be in the local language.

    To achieve the above goals, the first thing you need to make sure is to take out content from the code and put it in separate resource files, which are simple XML files in .NET with a .resx extension.

    Since this content will vary from language to language, we will have resource files for every culture. Each such file has Name and Value fields (like a Dictionary). Below are the sample entries in two resources, assuming we have to enter a string “Welcome”:

    1. Add a new resource file, and name it as TestSiteResource.resx (you can use any name), and open it in the VS editor. Enter “Banner” in the Name field, and “Test Website for Localization” in the value field. This resource file is the default for American English.
    2. Add another resource file, and name it as TestSiteResources.fr-FR.resx. This file is for French language strings. Add “Banner” in the Name field, and “Examinez le site Web pour le comportement de localisation” in the Value field.
    3. If you want to add Canadian French resources, then you need to create another resource file by the name of TestSiteResources.fr-CA.resx. The middle part of this name defines the locale, and this should be the same as specified by the UICulture property.

    4. These files would be saved in the App_GlobalResources folder in ASP.NET 2.0.

    Tip/Trick: If you want that only certain pages show localized strings, you can restrict the localization behavior throughout the application by putting resource files in the App_LocalDirectory folder. This will make localization page specific and not application wide. The naming should be like (assuming you want to localize only a page named MyPage.aspx):

    • MyPage.aspx.resx: this is the default resource file for MyPage.aspx.
    • MyPage.aspx.fr-FR.resx: this will be used when the culture changes to French, but only MyPage.aspx in the application would be localized.

    All the above .resx files would be compiled into assemblies at runtime. These assemblies are known by the name of “satellite assemblies”, and have strongly typed wrappers for the .resx files. So, we don’t need to worry about creating resource assemblies ourselves in ASP.NET 2.0. These assemblies are placed in separate folders (by the name of the locale) under the /bin folder, after you have published your website:

    BinResFiles.JPG

    For non ASP.NET applications, we need to use two tools:

    1. Resource file generator: resgen.exe
    2. Assembly linker (al.exe)

    There is lot of detailed information on how to use these tools, on MSDN, and the user can refer to these links:

    Now that we have created the resource files for different cultures and languages, we need a way to load them at runtime when the user changes culture dynamically. Fortunately, implementing this in ASP.NET 2.0 is quite easy. See the code below:

     Collapse
    String welcome = Resources.TestSiteResources.Welcome;

    In this line of code, we are using the Resources namespace which was created automatically by ASP.NET when it compiled the resource files into satellite assemblies, and we used the TestSiteResources class, with the same name as the resource file we created. We then accessed theWelcome property which will give the actual text from the resource file based on the current culture. If we want to localize the text of the Label controllblWelcome, we can set the same using these methods, in ASP.NET 2.0:

    1. Implicit localization: Here, we specify the new meta tags in the control definition and let ASP.NET get the value from the resource files based on the resourcekey attribute:
    2.  Collapse
      <asp:Label id=lblWelcome meta:resourcekey="lblWelcome" 
                 Text="Welcome" runat="server">
      </asp:Label>

      For this to work, we need to have page specific resource files in the /App_LocalDirectory folder. Implicit localization helps trim down the size of the global resource files, and helps in better overall resource management. Use it when you have largely page specific content.

      You do not need to do anything manually to set these implicit localization properties. Just open your web page in the Design mode, go to Tools->Generate Local Resources. This will automatically create a resource file for your page. You only need to set the values (Control.Property) of different fields for each control in the resource file editor in Visual Studio 2005.

    3. Explicit localization: This works when we have Global resource files. Here, we use Expressions to set the values from the resource files, as:
    4.  Collapse
      <asp:Label id=lblWelcome Text="<%$Resources:TestSiteResources, Welcome %>" 
                 runat="server"></asp:Label>

      We can set this using the VS IDE. Select the Label control, go to the Properties window, select Expressions->Text. Then, choose Resourcesfrom the drop down and enter the class name (TestSiteResources, for this example) and the Resource key (Banner). This is the recommended way to localize the UI controls on a page.

      Sample screenshot

    5. Programmatically accessing strongly typed resource classes as:
    6.  Collapse
      lblWelcome.Text = Resources.TestSiteResources.Welcome;

      This will work, but then it needs to be coded for every control in the page. So, use #2 for all the controls, and use this method to access resource strings for other content, if needed. Also, note that controls like the Calendar control have localization in-built. As soon as the UICulture andCulture of the current thread changes, it shows localized content by itself, thanks to ASP.NET!

    Incorporating Globalization

    In my website, after creating resource files and putting some localized data, I first start using the explicit localization to set the text of the controls such asLabels in my website so that they get their values from the resource files. Since there are four languages, I have created four resource files besides a fifth fallback resource file (with no locale name).

    s1.JPG

    Notice that the resource files have the locale as their middle names, so I need to set the UICulture to the same named locale in order for ASP.NET to access these resource files.

    But the problem is: how should I change the culture dynamically on the postback event? Fortunately, ASP.NET provides a method in the Page class to override: InitializeCulture(). This method executes very early in the page lifecycle (much before any control is generated), and here we can set the UICulture and Culture of the current thread.

    Since this method is in the Page class and I do not want to repeat the same code for each web page, I created a BasePage class, and all the aspxpages in my application derive from this BasePage class. But, I faced another problem now. Let me explain:

    Going back to the UI design: I had a MasterPage and a Header user control in it (inside a ContentPlaceHolder). I had a default page associated with that MasterPage. The entire site had to be localized dynamically. So, in the header, there was a dropdown from where the user could select a language/culture. In the BasePage’s InitilializeCulture method, I had to get the value of the item the user selected from the drop down, but since it was not initialized as yet (since InitializeCulture() is called much earlier in the page life cycle), I cannot access any control's value. The answer: use the Form collection (from the Response object). Here is the code:

     Collapse
    ///<SUMMARY>
    /// The name of the culture selection dropdown list in the common header. 
    /// We need to use this name as we don't have any other
    /// control property as the control (dropdown) itself is not initialized yet.
    /// So we use the "nested" dropdown name through which we will get the 
    /// dropdown's value from the Request.Form[] collection.
    /// </SUMMARY>
    public const string LanguageDropDownID = "ctl00$cphHeader$Header1$ddlLanguage"; 
    /// <SUMMARY>
    /// The name of the PostBack event target field in a posted form. You can use
    /// this to see which control triggered a PostBack: 
    /// Request.Form[PostBackEventTarget] .
    /// </SUMMARY>
       public const string PostBackEventTarget = "__EVENTTARGET";

    See how I am using the "parentControl:ChildControl" method to access the control from the Form collection. You can access any nested control generated by ASP.NET by adopting this convention. Using this value of the selected item from the Form collection, I set the culture in a switchcase statement, as:

     Collapse
        /// <SUMMARY>
        /// Overriding the InitializeCulture method to set the user selected
        /// option in the current thread. Note that this method is called much
        /// earlier in the Page lifecycle and we don't have access to any controls
        /// in this stage, so have to use Form collection.
        /// </SUMMARY>
        protected override void InitializeCulture()
        {
          ///<remarks><REMARKS>
          ///Check if PostBack occured. Cannot use IsPostBack in this method
          ///as this property is not set yet.
          ///</remarks>
            if (Request[PostBackEventTarget] != null)
            {
                string controlID = Request[PostBackEventTarget];
    
                if (controlID.Equals(LanguageDropDownID))
                {
                string selectedValue = 
                       Request.Form[Request[PostBackEventTarget]].ToString();
    
                switch (selectedValue)
                {
                    case "0": SetCulture("hi-IN", "hi-IN");
                        break;
                    case "1": SetCulture("en-US", "en-US");
                        break;
                    case "2": SetCulture("en-GB", "en-GB");
                        break;
                    case "3": SetCulture("fr-FR", "fr-FR");
                        break;
                    default: break;
                }
            }
          }
            ///<remarks>
            ///Get the culture from the session if the control is tranferred to a
            ///new page in the same application.
            ///</remarks>
            if (Session["MyUICulture"] != null && Session["MyCulture"] != null)
            {
                Thread.CurrentThread.CurrentUICulture = (CultureInfo)Session["MyUICulture"];
                Thread.CurrentThread.CurrentCulture = (CultureInfo)Session["MyCulture"];
            }
            base.InitializeCulture();
        }
        /// <Summary>
        /// Sets the current UICulture and CurrentCulture based on
        /// the arguments
        /// </Summary>
        /// <PARAM name="name"></PARAM>
        /// <PARAM name="locale"></PARAM>
        protected void SetCulture(string name, string locale)
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(name);
            Thread.CurrentThread.CurrentCulture = new CultureInfo(locale);
            ///<remarks>
            ///Saving the current thread's culture set by the User in the Session
            ///so that it can be used across the pages in the current application.
            ///</remarks>
            Session["MyUICulture"] = Thread.CurrentThread.CurrentUICulture;
            Session["MyCulture"] = Thread.CurrentThread.CurrentCulture;
        }

    So the user will see the content in his/her selected language. We need to save the culture selected in a Session or a Cookie variable because if the user moves to some other page in the same application, the thread's culture information would be lost as the new Page class will instantiate from the beginning (HTTP is stateless!). Cookies can be used if you do not want to lose the current thread's Culture on the user's Session expiry. Once we have pulled out all content from the web application, set the Culture and UICulture based on the user choice, and usedResources.TestWebSite.XXXPropertyName, we are ready with our globalization framework. Now, the only thing left is the adding of resource specific data in the resource files. For each culture, we need to have a separate (and appropriately named) resource file. This process is localization. In myweb.config file, I have used the following properties:

     Collapse
    <globalization responseEncoding"=utf-8” requestEncoding="utf-8” 
                   fileEncoding="utf-8" />

    Note the encoding attributes: utf-8 (8 bit Unicode Transformation Format) is used since it is variable length character encoding and can represent languages such as Greek, Arabic etc., besides it is ASCII compatible too. For more info on UTF-8 encoding, see this link.

    Also, an important point to note is that though we can have the resource files in raw XML form on the deployment server (so that the user can edit them without re-compiling the entire site), the application will re-start if we make any modification in the resource files. This can hamper the performance of the deployed application.

    dir Attribute for Language Direction

    Many times, we also need to set the direction of the localized text (which is set using the dir attribute of the <html> or the <body> tag). This is necessary because some languages are read from right-to-left (RTL), e.g., Arabic, instead of the standard left-to-right (LTR) like Hindi and English. This can be achieved quite easily by setting the dir attribute to the appropriate value from the .resx file.

    First, create a Direction (you can use any name) field in all your resource files, setting its property to RTL or LTR based on individual resource files. For Arabic, the value of this field would be RTL, and for Hindi it would be LTR. Then, set the same in the dir attribute of the <body> tag as:

     Collapse
    <body runat="server" dir="> 
    <%$ Resources: TestSiteResources, Direction %>"

    This will set the right direction as the value will come from the resource file based on the current thread's culture.

    Using a Database for Localization

    We have seen how to localize the text of the controls and the presentation in the UI. But what about the content stored in a database? This content also needs to be localized, but since it is stored in a DB, we cannot use resource files for the same. We need to create new tables for the same.

    Suppose I have a table which stores user comments. The table structure is:

    T1.JPG

    Now, we want the Comments and the Name fields to be displayed in localized text. But we can’t store all the different language versions of these fields in this same table as it will not be normalized (since there are other fields which don’t need to be localized but will be repeated). Hence, we need to re-organize the table structure and create another table which will hold the localized version of these two fields. First, we need to remove these two fields from this table and create a new table as:

    T2.JPG

    Here, we have added a new field as CultureID, which is equivalent to LCID, or the Locale Identifier, an integer which indicates a particular culture. We can add culture specific localized data as:

    T3.JPG

    Now, we can use SQL queries with CultureID (LCID) as one of the parameters to get the localized content. We can also provide a user interface to enter localized data into such tables so that the content can be created in an interactive way.

    Summary

    I have tried to cover some important aspects of implementing Globalization in ASP.NET 2.0, and we saw that it is easy and simple, but there are a few important points to note:

    1. Do not rely on the web browser’s settings. Give a link on the application (may be in the header) so that the users can select their choice of language by clicking it.
    2. Use Resource files to separate Presentation related data in the GUI. Resource fallback is the approach used by ASP.NET when it is unable to find the resource file for a particular culture. It will first go to the neutral resource file, and then the default or fallback resource file (TestSiteResource.resx).
    3. Use database tables for data or content stored in a DB. You need to create separate tables to store localized content.
    4. If you use sn.exe to create a strong name of your main application assembly, then you need to use the private key from the same set of key pair (generated by sn.exe) to sign your satellite assemblies as well. Strong named assemblies require that satellite assemblies should also be strongly named.

    Though I tried my best to cover important topics, in case I missed something, I would appreciate if readers can send in their suggestions on the same.

    Happy globalizing!

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    Vivek Thakur


    Web Developer

    India India

    Member
    Vivek Thakur is the admin and moderator of the popular ASP.NET community http://www.codeasp.net (CodeAsp.Net).

    All his articles can be found at:

    http://www.codeasp.net/people/vivek_iit#prArticles

    Join the premiere ASP.NET community for free today:

    http://www.codeasp.net/register

    For questions/comments, do post them in http://www.codeasp.net/forums so that I can answer to each of them.

    Architecture FAQ for Localization and Globalization Part 1

    Architecture FAQ for Localization and Globalization Part 1
    Is your email address OK? You are signed up for our newsletters but your email address has not been reconfirmed in a long time. To make this warning go away please click here to have a confirmation email sent so we can confirm your email address and continue sending you your newsletters. Alternatively, you can update your subscriptions.

    Introduction

    When we see around, architectures mainly discuss about loose coupling , scalability , performance etc etc. Many architecture forget one of the important aspects in software is making application globalized. Depending on project some application would not really want to have multi-language based websites , but i am sure many will. So in this article we will go through a series of FAQ which will give you a quick start on making application multi-language based.

    Lately i have been writing and recording videos heavily on design patterns , UML and many architectural stuff you can visit http://www.questpond.com for design pattern and UML videos.

    You can read my previous articles on design patterns and UML in the below links:-

    Part 1 – Design patterns Factory, Abstract factory, builder, prototype, shallow and deep copy, and singleton and command patterns

    SoftArchInter1.aspx  

    Part 2 – Design patterns Interpreter, Iterator, Mediator, Memento and observer patterns

    SoftArch2.aspx 

    Part 3 – Design patterns State, Stratergy, Visitor, Adapter and fly weight pattern

    SoftArch3.aspx 

    Part 4 Design patterns Bridge, Composite, Decorator, Facade, COR, Proxy and template pattern

    SoftArch4.aspx

    Loosely coupled architecture using

    IOCDI.aspx 

    You can download by architecture interview question book from 

    http://www.questpond.com/softArchi.zip.zip  

     

     What is Unicode & Why was it introduced?


    In order to understand the concept of Unicode we need to move little back and understand ANSI code. ASCII (ask key) stands for American Standard Code for Information Interchange. In ASCII format, every character is represented by one byte (i.e. 8 bits). So in short we can have 256 characters (2^8). Before UNICODE came in to picture programmers used code page to represent characters in different languages. Code page is a different interpretation of ASCII set. Code pages keep 128 characters for English and the rest 128 characters are tailored for a specific language. 
    Below is a pictorial representation of the same.

     

    Figure 14.1:- Code page in action


    There are following disadvantages of the CODE page approach:-
    • Some languages like Chinese have more than 5000 characters, which is difficult to represent only with 128-character set.
    • Only two languages can be supported at a one time. As said in the previous note you can use 128 for English and the rest 128 for the other language.
    • The end client should have the code page.
    • Code Representation change according to Operating system and Language used. That means a character can be represented in different numbers depending on operating system.
    For all the above problems, UNICODE was introduced. UNICODE represents characters with 2 bytes. So if its two bytes that means 18 bits. You can now have 2^16 characters i.e. 65536 characters. That is a huge number you can include any language in the world. Further if you use surrogates you can have additional 1 million characters...Hmm that can include type of language including historian characters.
    ASCII representation varied according to operating system and language. However, in UNICODE it assigns a unique letter for every character irrespective of Language or operating system, which makes programmers life much easier while developing international compatible applications.
     

     Does .NET support UNICODE and how do you know it supports?


    Yes, .NET definitely supports UNICODE. Try to see size of (char), you will see 2 bytes. Char type data type stores only one character, which needs only 8 bits, but because .NET has to support UNICODE, it uses 16 bits to store the same.
     

     What is the difference between localization and globalization?


    Below are the definition is which is taken from the Microsoft glossary. 
    Globalization: -It is the process of developing a program core whose features and code design are not solely based on a single language or locale. 
    Localization: - The process of adapting a program for a specific local market, which includes translating the user interface, resizing dialog boxes, customizing features (if necessary), and testing results to ensure that the program still works.
    You can visualize globalization as more of architecture decisions. While localization is adapting your content to local market. Globalization phase occurs before localization phase.
     

     What architecture decisions you should consider while planning for international software’s?


    Note: - Many programmers think its only converting the text from one language to other. It’s a very wrong assumption that just by translating strings from one language to other language the software is localized. Interviewer will definitely get disappointed by such an answer. So let’s try to visualize what are the design considerations to be taken when we design software globally.


    • Avoid hard coding of strings in the project. Any display right from labels to error messages read it from a resource file.
    • Length of the string is also of prime importance. It’s a noted fact that when we translate English language in to other language the words increase by minimum 30 to 40 %. For instance you can see from the below figure how the Hindi text has increased as compared to English text.
     

    Figure 14.2: - Text length increase


    So all your labels, message boxes should design in such a way that the text size mismatched gets adjusted. Do not crowd all your fields on one screen you will definitely end with the text length issue. Leave some room for expansion.
    • Decimal separator varies from locale to locale. For instance 25, 12.80 in the United States are 25.12,80 in Greece or Germany. Yes, you guessed right the decimal separator in Europe is a "," (Comma).
    • Calendar changes from country to country. Definitely, Gregorian calendar is the most used. However, there are some other calendars like Hebrew, Islamic, Chinese etc. All these calendars have huge differences. For instance, Nepal follows Nepali Calendar, which is 56.7 years ahead of Gregorian calendar. So according to cultural settings user can expect the dates accordingly.
    • Sort order is affected by language. You can see from the figure below Hindi and English languages have different sorting order.
     

    Figure 14.3: - Different sorting order according to locale


    • Time varies from locale to locale. For instance, an 8 PM in India is 20:00 in Europe. In Europe, there is not concept of AM and PM.
    • If you are using built-in fonts, use the resource file to bundle the same. You can load the fonts from the resource file rather than telling the user explicitly to install the fonts in his PC.
    • Keyboards layout changes according locale and region. So be careful while designing the short cut keys. The function keys are mostly present in all key boards. Probably you can consider the function keys for short cut keys. Below is a sample Hindi key board. If you define CTRL + V as a short cut for paste functionality it can create confusion for Hindi users on the below key board.
     

    Figure 14.4: - Localized Hindi keyboard


    Courtesy: - Image taken from http://www-306.ibm.com/


    So you can see from the above points that making software adapt to global culture is not only related to string translation. It is much beyond that.
     

     How do we get the current culture of the environment in windows and ASP.NET?


    “CultureInfo.CurrentCulture” displays the current culture of the environment. For instance if you are running Hindi it will display “hi-IN”. Please note one thing in mind “Current Culture” will only give you the culture on which your application is running. Therefore, if it is a windows application this will work fine. However, in ASP.NET 2.0 we need to know what culture the end user has. 
    For a real international website, different users can log in with different culture. For instance, you can see from the given figure below different users are logging in with different regional settings. Client browser sends the information in the request headers to the server. For instance, a Korean user will send “KO” in the request headers to server. We can get the value using the” Request.UserLanguages”. 
     

    Figure 14.5: - Different users logging in from different countries


    Regional settings are defined on the user’s browser as shown below. Click on Tools – Internet options – Languages. You can then add languages in the language preference box. Using "Move up" and "Move down”, you can define the priority of the languages. In the below figure we have four languages defined with “Hindi” language set at the top priority. ” Request.UserLanguages” returns an array of string with the sorted order defined in your language preference tab of the browser.
     

    Figure 14.6: - Setting language preferences in browser


    Below is the code snippet, which shows how we can display the user languages. The first figure is the code snippet, which shows how to use “Request.UserLanguages”. The second figure shows the output for the same.
     

    Figure 14.7: - Request.UserLanguages in action

     

    Figure 14.8: - Output from Request.UserLanguages


    One of the things to be noted is “q” value. “q” stands for quality factor. In the above figure, the quality factor means the following:-
    "I prefer Hindi, but will accept English US (with 80% comprehension) or Greek (with 50% comprehension) or French (with 30 % comprehension)."
    Just for Non-English speakers meaning of Comprehension. 
    It is the process of understanding and constructing meaning from a piece of text.
    The comprehension is from the perspective of the end user. It says the end browser user will understand with this much comprehension for that language. For instance in the above example the end browser under stands English comprehension of 80 %.
    Note: - You can find the sample to display the user languages in “Globalization” folder. Run “DisplayAllLanguageSettings.aspx” and see the output. Just to mention the source is coded in VS.NET 2005 so if you try to open it using VS.NET 2003 you can get errors.
     

     Which are the important namespaces during localization and globalization?


    There are two most important namespaces:-
    • ‘System.Globalization’ – This namespace contains classes that define culture-related information, including the language, the country/region, the calendars in use, the format patterns for dates, currency and numbers, and the sort order for strings.
    • ‘System.Resources’ – This namespace provides classes and interfaces that allow developers to create, store, and manage various culture-specific resources used in an application. With this namespace, you can read a resource file and display it accordingly to the user’s culture.
     

     What are resource files and how do we generate resource files?


    Resource files are files, which contain program resources. Many programmers think resource files for only storing strings. However, you can also store bitmaps, icons, fonts, wav files in to resource files.
    In order to generate resource file you need click on tools – generate local resource as shown in the figure below. Do not forget to keep page in designer view or else you will not see the option. Once you generate the resource file you will see the resx file generated in the solution explorer.
     

    Figure 14.9: - Generating resource files using IDE
     

    If you see the resource file it will basically have a key and the value for the key.
     

     

    Figure 14.10: - Resource file in action


    If you see the above figure, the key is basically the object name. You can see the Label1 has some value stored in the resource file.
     

     Can resource file be in any other format other than resx extensions?


    Yes, they can be in .txt format in name and value pairs. For instance below is a simple .txt file with values.
    Lbluserid = User Id
    LblPassword = Password
    CmdSubmitPassword = Submit
     

     How is resource files actually used in project?


     How can we use Culture Auto in project?


    Note: - Hmmm we have talked so much theoretically its time to see something practically in action. Let’s make small project to understand how we can implement the same. In Globalization folder you can run the “LoginScreen.aspx” to see it practically. Below goes the explanation.


    We will make a simple login screen, which we will try to use for English as well as Greek. The login screen will display English settings when an English user logs in and Greek Settingswhen a Greek user logs in. So below are the steps to start with.
     

    Figure 14.11: - Culture Auto in action


    In the above figure, you can see the login page. You can find the same in CD as named “LoginScreen.aspx”. It is a simple page with two labels and two text boxes. Now the labels values i.e. “User ID” and “Password” should be changed according to regional settings set on the browser. So below are the steps for the same:-
    • Make two resource files as shown below one for Greece and other for English. There are three values defined for “Userid”, “Password” and the main title of the page. The other important thing to note is the naming convention of the files. You need to tag the naming convention with the language code. You can see from the below figure the resource files naming convention is divided in two three parts File name, Language code and resource file extension. In this sample, we will demonstrate for English and Greek language so we tagged the file with “el” language code.
     

    Figure 14.12: - Resource file naming conventions


    Below are the two resource files defined?
     

    Figure 14.13: - Greek and English resource files


    • Once you have defined your resource files we need to define two attributes “UICulture=Auto” and “Culture=Auto”. See the above figure “Culture Auto in Action”.
    • Final step you also need to define resource key at the UI object level. You can see a sample of the same in figure “Culture Auto in Action”.
     

    Figure 14.14: - Login screen according to settings


    Compile the project, run, and see the output after changing regional settings for both languages. You should see different outputs as shown in the above figure. With out a single line of code everything works…. That is the magic of “UICulture=Auto” attribute.
     

    Note: - You can the get the above source code in “Globalization” folder. See for “LoginScreen.aspx” page.


    Note: - In the further section we will be answering three questions in one go.
     

     

    References

     

    Hanselman has given list of containers useful link to visit. 

    http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx 


    http://msdn.microsoft.com/en-us/magazine/cc163739.aspx 

    http://msdn.microsoft.com/en-us/library/cc707905.aspx 

    http://www.devx.com/Java/Article/27583/0/page/2 
     

    Other Interview question PDF's

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    Shivprasad koirala


    Architect
    http://www.questpond.com
    India India

    Member
    I am a Microsoft MVP for ASP/ASP.NEt and currently a CEO of a small E-learning company in India. We are very much active in making training videos , writing books and corporate trainings. You can visit about my organization at http://www.questpond.com and also enjoy the videos uploaded for Design pattern, FPA , UML ,Share Point,WCF,WPF,WWF,LINQ, Project and lot. I am also actively involved in RFC which is a financial open source madei in C#. It has modules like accounting , invoicing , purchase , stock
  • 相关阅读:
    Python爬虫 -- 抓取电影天堂8分以上电影
    Kotlin & Vertx 构建web服务
    js promise 风格编程
    Java Config 下的Spring Test方式
    (转)SpringSecurity扩展User类,获取Session
    maven 打包 xml文件
    EL表达式的操作符
    mysql 去除空格
    spring security
    GoogleApis 屏蔽
  • 原文地址:https://www.cnblogs.com/anorthwolf/p/1806686.html
Copyright © 2011-2022 走看看