|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
You are kidding right?When it comes time to make an application language independent is the time all the sales people cheer and developers hide. To a salesman localized software means more markets and more sales, to a developer it equals a mind-numbing list of problems. One of the main problems is that software is generally never designed from the ground up to include support for changing the language. Not building from the ground up with this support means that every single piece of code that represents language to the user (buttons, menus, images, prompts, help, text) must be found and altered to support language independence. This problem multiplies exponentially when you deal with applications that have hundreds of thousands lines of code, which have been poured over and modified constantly by different developers. Web based E-Commerce applications present the same aforementioned problem, but brings currency issues into the picture. For each language supported all functionality dealing with currency must be located and modified to support each languages currency denomination. The currency has to be stored in a way that is easily transferable between all the languages supported whether the user is viewing it in US dollars the stored value must be able to be converted to Pesos , Franks , or Pounds. The other thing to keep in mind is that currency exchange rates are not static, they change. Object Orientation to the RescueFrom whatever side you are from (sales or development) you can now see the issues that are present. If the targeted application was not built with localization in mind there is twice the amount of work to do. If on the other hand the target application is in design phase we can lay out a plan of action for localization. Object Oriented Programming (OOP) is a means to encapsulate programming code into pre-defined execution and data. Instead of having a huge list of functions and variables we can use OOP to take developing large scale (or small) applications easy to understand and implement. A simple real-world example of object orientation is basic business structure. Although in small businesses the president knows everyone, what they are supposed to be doing, how they should do it, on a large scale this is not possible. Breaking this company down object oriented style we can see the following: Object Employee Object Manager Object Vice President Object President: Each object has its own properties (attributes) and methods (actions): Object Employee Skill (property) Pay (property) Responsibilities (property) Execute (method) Object Manager Skill (property) Pay (property) Responsibilities (property) Execute (method) Collection of Employee Objects (employees he is responsible for) Object Vice President Skill (property) Pay (property) Responsibilities (property) Execute (method) Collection of Manager Objects (managers he is responsible for) Object President: Skill (property) Pay (property) Responsibilities (property) Execute (method) Collection of Vice President Objects (Vice Presidents he is responsible for) The whole company can now be represented in the following object: Object Company: Incoming (property) Outgoing (property) President Object (property) Collection of Vice President Objects (property) Collection of Manager Objects (property) Collection of Employee Objects (property) By using Object Orientation (OO) we can execute actions without even knowing who is involved or how it works. An example is if a President wishes to hand out bonus checks and he has 3000 employees it would be next to impossible for him to evaluate performance on all the employees and hand out the appropriate bonus checks. By using OO the president simply hands the order over to his Vice President who then passes it on to each manager underneath them which finally gets down to the employee level. So without knowing anything about the employees or managers a president can do this: Company -> President -> ExecuteBonusCheckPayments() And all the employees get appropriate bonus checks. Moving back to our application we can use OOP to maximize development and implementation of language and currency independence. By removing the need for a developer to know or care what language the application is using we simplify their development and maximize use of their time to functionality. Although implementation of localization is a hefty job, once the preliminary pieces of code are in place developers will not need to address it much if at all. I will be focussing on an ASP E-Commerce application but the theory can easily be transported to any development environment. Data RepresentationData representation is for developers and translators. A client using localized software will never see or need to see how data is represented. Basically data representation is the way we will represent localized data in our code. The base language for our data representation will be English. Once the application is created developers will be referencing the data representation of text rather than the actual text, translators will be referencing the text and ignoring the data representation. Lets take a button that will need to be localized. The button displays the word "Help" on it, but being localized the word "HELP" in Spanish is "Socorro". Our data representation is dr_txt_HELP. In English: dr_txt_HELP = "Help" In Spanish: dr_txt_HELP = "Socorro" Now our developers could care less what language the help button is in because in the code all they will ever use is the dr_txt_HELP. This data representation can be used for images as well. In English: dr_img_HELP = "Help.jpg" In Spanish: dr_img_HELP = "Socorro.jpg" As you can see this data representation gives us the best of both worlds in programming and translation. The more languages you support the easier it will be for a translator to look at a text file and translate to the target language. After the data representation has been defined developers do not have to care which language the application is being viewed in. IncludesBy now we have a clear idea on how data will be represented, now we need to define how that data is incorporated into an application. We will use include files and object orientation to achieve the desired functionality. At the highest level we need to know which language we will be displaying, this will be accomplished with a single variable called USING_LANGUAGE. Each language supported will have an associated value which would be contained in a supported languages file. Example of our supported languages file: LANUGAGE_ENGLISH = 0 LANGUAGE_SPANISH = 1 LANGUAGE_FRENCH = 2 LANGUAGE_CUBAN = 3 The supported languages file would be included on every page in the web application. Optimization is of concern when dealing with passing script on the server side so I am going to split each language dependent include into a separate file and place them in separate directories. This will prevent each pages performance from being hurt by a huge amount of if/then/else statements. Our directory structure will be as follows: (root)
(language files)
(localized)
So if we are adding the home page the directory would look like this: (root)
home.asp
(language files)
I_supported_languages.asp
I_home.asp
(localized)
I_home_english.asp
I_home_spanish.asp
I_home_french.asp
I_home_cuban.asp
The home.asp in the root is the actual page which will include I_supported_languages.asp and the I_home.asp in the "language files" directory. The I_home.asp in the "language files" directory will include the appropriate localized file based on our USING_LANGUAGE variable. Lets take a look at what is inside the I_home.asp file: Listing of I_home.asp: <%if USING_LANGUAGE = "LANUGAGE_ENGLISH" then%> <!--#INCLUDE FILE=" localized /I_home_english.asp" --> <%elseif USING_LANGUAGE = "LANGUAGE_SPANISH" then%> <!--#INCLUDE FILE=" localized /I_home_spanish.asp" --> <%elseif USING_LANGUAGE = "LANGUAGE_FRENCH" then%> <!--#INCLUDE FILE=" localized /I_home_french.asp" --> <%elseif USING_LANGUAGE = "LANGUAGE_CUBAN" then%> <!--#INCLUDE FILE=" localized /I_home_cuban.asp" --> By looking at the above listing we can see that if before we include the I_home.asp we set the USING_LANGUAGE variable to LANUGAGE_ENGLISH it directs I_home.asp to include the I_home_english.asp file. What does that do you ask? Lets take a look inside the I_home_english.asp file and find out: Listing of I_home_english.asp: <% ‘ English Data Representations for home.asp dr_txt_PAGETITLE = "Welcome to MyStore.com" dr_txt.ABOUT = "MyStore.com is the ecommerce site of the century. " &_ "You will find that we have only the best goods and services." dr_txt.SENDEMAIL = "Send Us Some Email" %> By including the above listed file we can now access the data representations instead of the actual text. I mentioned before that our base language would be english, hence why the variables are in english. By looking at theactual home.asp page you will see how all this comes together. Listing of home.asp: <!--#INCLUDE FILE=" language files / I_supported_languages.asp" --> <% USING_LANGUAGE = "LANUGAGE_ENGLISH" %> <!--#INCLUDE FILE=" language files / I_home.asp" --> <center> <b> <%=dr_txt_PAGETITLE%> </b> <br> <%= dr_txt.ABOUT %> <br> <a HREF=mailto://president@aol.com><%=dr_txt.SENDEMAIL %></a> The output if viewed through a browser would look like this:
It is a very simple page, but demonstrates that the developer no longer needs to care what language the text is in. By changing the USING_LANGUAGE variable the page is immediately changed to the corresponding language. To add a new language all we need to do is send out the I_home_english.asp page (which is all text) and have a translator modify the text after the "=" sign, and then add the appropriate language title in the supported languages file. You may be wondering at this point why not just create the page in the desired language. The reason is that a web based application typically has a lot of code on a page, if we had 5 pages representing the different languages then when developers made a change to the code on one page, they would have to go change the code in all 5 pages. This also brings up an important issue of when to get files translated. Only when a page is completed and ready to be published should translation take place. Any time before this point and you will be facing a constant battle of un-translated items. Now that we can display our pages in any language we need to tackle two more issues. CurrencyThe previous section introduced our method for addressing text and image objects in a language independent manner. We will now deal with currency conversion. Object Orientation will provide us with the means to deal with currency as a language independent data representation. We need to create an object that will take our base denomination US Dollars in pennies, and convert it to the desired currency. One issue to address is that someone might be viewing a page in Spanish, but is going to buy the item in US Dollars. We address this by creating a new variable called USING_CURRENCY, which will tell our application which currency the client wishes to view. Currency exchange rates and conversion are better handled by a third party therefore I propose using Cloanto Currency Server. Cloanto Currency Server ($995) provides a daily update source of currency exchange rates, and interfaced with ASP provides us with a way to convert our US pennies (product, shipping costs) to all denominations Cloanto Currency Server supports - here is a long list (source: www.cloanto.com):
Implementing a conversion routine ourselves would be non-productive and more than likely cost much more than the $995.00 than Cloanto charges. As I mentioned before we will be using the USING_CURRENCY variable to define which conversion is required. We will create an asp-scripted object to buffer the actual implementation of currency conversion. When we are done to get the value of any currency we should be able to do the following: // Include the supported languages file <!--#INCLUDE FILE=" language files / I_supported_languages.asp" --> // Set the language to English <% USING_LANGUAGE = "LANUGAGE_ENGLISH" %> // Set our target currency to be Tanzanian shillings <% USING_CURRENCY = "TZS" %> <center> Us Dollars: $10.00 Tanzanian shillings: <%=localCurrency.ConvertFromUS(1000)%> Take note of the line "<%=local_Currency(1000)%>" we are taking $10.00 in pennies and sending it to a function called ConvertFromUS in an object called localCurrency. The result should be the Tanzanian shillings representation of $10.00. We use pennies for currency in our code because pennies can reflect a whole or partial dollar amount without using decimal places (which speeds up calculations). Creating the localCurrency ObjectIn the previous section we used an imaginary object called "localCurrency" to convert us pennies into any denomination we want. Now we will create the localCurrency Object. Outline: LocalCurrency
// Methods
ConvertFromUS (method)
// Properties
m_sCurrencyCode (string based representation of the destination
denomination EX: "TZS")
m_objCloanto (Cloanto Conversion Object)
By creating this object and then calling the ConvertFromUS method developers no longer need to care what currency the client is viewing. Another benefit to putting this into an object is that if the method of conversion changes from using Cloanto developers only need to change the implementation of this object and nothing else. An example is that 50 pages use the LocalCurrency object to do their currency conversions. If our company decides that we will use WidgetCompanies solution instead of Cloanto a developer only needs to modify the implementation of ConvertFromUS (which is located in a single file), and the functionality is passed along to all 50 pages without ever having to touch them. We will create and contain the LocalCurrency object inside of our I_supported_languages.asp file. This way whenever that file is included we know we have language and currency independence at our fingertips. When the LocalCurrency object is created it will be passed the three letter currency code. There are all kinds of other functionality that could be added to the localCurrency object, but for now our single method is sufficient. Database TextUp to this point we have address a large chunk of localizing a web application. All of our pages and currency now have the ability to be viewed in different languages. The last problem to solve is that E-Commerce has a lot of text stored in a database. Product names, descriptions, store names, informational text, are all stored in a database. How do we localize database entries? We only need to concern ourselves with text that will be viewed by end users, but that still leaves us with a significant problem. The solution is to be able to tell which languages a particular record supports and then pulling the specific language field out of the database. If a particular record does not support the desired language we will have to default to the language it does support. This is easy if we are pulling known records out of a database but becomes tricky when dealing with something as dynamic as a product search. You do not want to have to look at each item when querying a database having thousands (or more) of records, this would be slow and not applicable to a web environment when many users may be hitting the database at the same time. We will make a trade off between size and speed. For each entry in a recordset that has viewable text we will actually multiple entries equal to the number of languages being supported. To clarify this we will create a table representation of supported languages. This table will mostly used for reference and administration. Supported languages table: Lanugage : (string representation of language)
LanguageID : (ID of the language)
If we look at our previous implementation of page-based localization we used the following variables to describe the desired language: LANGUAGE_ENGLISH = 0 LANGUAGE_SPANISH = 1 LANGUAGE_FRENCH = 2 LANGUAGE_CUBAN = 3 We now put those values into our Supported languages table: Language: English LanguageID: 0 Language: Spanish LanguageID: 1 Language: French LanguageID: 2 Language: Cuban LanguageID: 3 Now that we have a reference to what languages the entire application supports we need to drill down into a specific recordset to see how it is used. Let’s use a very simple Product table for an example: Product Table (not localized) ProductID : (ID of product) ProductName : (String Representation of products name) Price_retail : (retail Price in pennies) Description : (string representation of product description) Notes : (string representation of additional product notes) An example of a Product Entry would be: ProductID: 55 ProductName: SuperSlingShot5000 Price_retail: 1000 Description: Introducing the SuperSlingShot5000, the finest slingshot you could ever own. Can propel an acorn over 200 yards. Notes: Not recommended for children under the age of 15 Since we are only concerned about text that will be presented to the end user we will not be touching the ProductID, Price_retail, or ProductName fields. The product name could theoretically be considered for localization but I do not think it applies. To localize this entry we first need to specify which languages this entry supports by adding a languages_supported string field. Our modified table now has the following structure: ProductID : (ID of product) ProductName : (String Representation of products name) Price_retail : (retail Price in pennies) Description : (string representation of product description) Notes : (string representation of additional product notes) Languages_supported : (list of languages supported separated by commas) We will use a string list of supported language IDs seperated by commas: ProductID: 55 ProductName: SuperSlingShot5000 Price_retail: 1000 Description: Introducing the SuperSlingShot5000, the finest slingshot You could ever own. Can propel an acorn over 200 yards. Notes: Not recommended for children under the age of 15 Languages_supported 0 If we supported English and Spanish the Languages_Supported field would look like this: Languages_supported 0,1 We now have to add localized fields equal to the number of languages being supported by the entire application. Even though we are only supporting English at this point in our table, the entire application supports 4 languages. Here is the final structure of our example table: ProductID : (ID of product) ProductName : (String Representation of products name) Price_retail : (retail Price in pennies) Description0 : (string representation of product description) Description1 : (string representation of product description) Description2 : (string representation of product description) Description3 : (string representation of product description) Notes0 : (string representation of additional product notes) Notes1 : (string representation of additional product notes) Notes2 : (string representation of additional product notes) Notes3 : (string representation of additional product notes) Languages_supported : (list of languages supported separated by commas) Each field now has the language ID appended to the end. Now we can get any field in any supported language. What if our recordset only supports English and the entire application supports four different languages? This problem is solved when the record is generated. No matter how many languages the record will eventually support we will take whatever language the record is created with and stuff it into all the language fields. So if we only support English in this record the Description0-3 will all contain English. Duplicating data may seem wasteful but remember we are trading speed for size. With the above method we can query an entire database in English by pulling out Description0 or Spanish with Description1, we do not need to verify if each entry is compliant. Putting It All TogetherA lot of ground was covered in this document but now we will put it all together. By using a variable called USING_LANGUAGE we now have the ability to change the language in which a page is viewed. By using a variable called USING_CURRENCY we can change the denomination currency is viewed. Since we have localized our entire database we can now use the same variable (USING_LANGUAGE - already defined on each page) to know which fields to pull out. By starting from the ground-up we have built the foundation for seamless integration of new languages and currency into our application. Making a trade on the database side for speed over size, using a third-party solution for currency exchanges, and our use of ‘language includes’ maximizes development time and application speed. I can not overstate the importance of attention to detail when planning for localization of an application. Everyone involved in the project from sales to developers need to communicate and understand each other’s responsibilities and time frames. Only by working as a team will a project as massive as an E-Commerce site be successfully localized and launched.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||