WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

.NET Localization, Part 4: Localizing Units
Pages: 1, 2

Bringing It All Together: the Utility Class

We now can write a utility class that programmers can use on the server side when displaying data on a page or saving data from a page. These utility classes play a role to tailor the OO classes available to suit the immediate problem at hand. The primary need here is, as stated, to read values from screens and save them in the database, and vice versa. Please note that the sample code shown for this example is pseudo code.




public class UnitConverter
{
  // Support for reading from screens
  public static IMeasure createImperialWeight(double value, 
                            WeightUnit intendedImperialUnit)
  {
    // region -> imperial:
    return new Weight(value,intendedImperialUnit);

    // region -> metric
    Weight  metricWeight = new Weight(value,
                  intendedImperialUnit.getEquivalentUnit());

    return metricWeight.getAs(intendedImperialUnit);
  }

  //.. Other measures

  // Support for writing to screens
  public static Imeasure convertFromImperial(Imeasure measure)
  {
    //region ->imperial
    return measure;
   
    // region -> metric
    return measure.getAs(measure.getUnit().getEquivalentUnit());
  }
} // end of UnitConverter static class

Reading From an Entry Field

Let us begin with the assumption that all units are internally maintained on the application server and in the database as imperial. We are trying to read a weight field from the screen. The user has entered a number 57 as weight. The code for reading that weight on the server side is as follows:


//static function
Weight w = Converter.CreateImperialWeight(57, //value entered 
                                  //expected weight unit. 
                                  //Will allow Kgs or 
                                  //Pounds on the user side      
                                  Units.Pound.self); 
  

The intention of the CreateImperialWeight is to read a weight unit in pounds, irrespective of the locale in which the Web browser is being operated. If you were to see the Web site in a metric locale, it would have read 57 kgs, and 57 Lbs if it were an imperial region. The function will internally take this into account and always return an object of type Weight, the unit of which would point to an object of type Pound. All quantity conversions will take place internally, returning proper pound quantity.

Let us examine w, the Weight variable:


// Created weight will be in pounds
assert(w.getUnit().name() == Units.Pound.self.getName());

Meaning, if we examine the Unit object that belongs to the Weight measure, we will learn that it will be of type Pounds. To know the double value in pounds, do the following:


// Get the value to store in db
double wValueInPounds = w.getValue();

Let us see how we can get the value w in tons:


//Get value in tons
double wValueInTons = w.getValueAs(Units.Ton.self);

To get the value in tons, simply use the getValueAs function on the Weight measure object by specifying the target unit as Ton. getValueAs takes a unit and returns the converted double value in that target unit.

If we want the target measure as an object instead, we can use getAs on the measure:


Weight wValueInTons = w.getAs(Units.Ton.self);

Writing to an Entry Field

Let us shift focus to printing a field on the screen. Assume we read this value from a database.


// Create a Length measure using imperial
Length lengthFromDB = new Length(100,   // value read from db
                     Units.Miles.self); // value in miles

// Obtain a length measure in the target Unit irrespective of the region
Length lengthOnTheScreen = 
               UnitConverter.convertFromImperial(lengthFromDB );

convertFromImperial will take an imperial unit and return a region-dependent measure. In the above example, if the region is imperial, then the returned unit is the same. If it is metric, then it will be in kilometers. How does this function know it is kilometers, when all we said was Miles? A Unit class definition (as it was presented above) includes an equivalent unit setting for each of the units in the other system. So, a mile will point to a kilometer and a kilometer will point to a mile as comparable measures. Here is a code segment that gives you a variety of values that you can put on the screen:


// will be in miles or kilometers depending on the user locale
double lengthOnTheScreenValue = lengthOnTheScreen.getValue(); 
  
// Ex: Km.
string lenghtOnTheScreenShortLabel = 
                  lengthOnTheScreen.getUnit().getShortLabel(); 

// Ex: Kilometers           
string lenghtOnTheScreenLongLabel = 
                  lengthOnTheScreen.getUnit().getLongLabel(); 

Converting Between Units

Also, we can convert units from one to another.


Length    len1InCm = new Length(100,Units.Cm.self);    
Length    len1InMeters = len1InCm.getAs(Units.Meters.self);
assert(len1InCm == len1InMeters)

Conclusion

The solution to the problem demonstrates how well OO principles come to the rescue of internationalization. This is because once abstracted, objects have the ability to suit the locale due to their polymorphic nature. This is OO 101. You can even extend these measures by defining manipulation operators such as addition, subtraction, etc. We see the following advantages in the suggested approach:

  1. Unit conversions are type safe.
  2. IDE will prompt you for the defined units so far in the system. This finite set of units is a good compromise between complete openness and ease of use.
  3. It is trivial to convert from one unit to another.
  4. This suits the internationalization issue quite well.

Nevertheless, there are areas that are not explored in this short article, such as precision, for instance. Not much thought was given to a page that contains mixed mode units: metric and imperial. Also, getting the labels from resource files will be necessary for localizing labels.

Additional Localization References