Internationalization of Haskell programs using Haskell data types

From HaskellWiki
Revision as of 12:47, 3 October 2011 by YitzGale (talk | contribs) (Attribute this page to Felipe Lessa)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

You can use Haskell data types for internationalization. The following example is adapted from a haskell-cafe mailing list post by Felipe Lessa.

The idea is to have a data type with all your messages, like

 data Message =
   Hello |
   WhatsYourName |
   MyNameIs String |
   Ihave_apples Int
   GoodBye

For each of your supported languages, you provide a rendering function (they may be in separate source files):

 render_en_US :: Message -> String
 render_en_US Hello = "Hello!"
 render_en_US WhatsYourName = "What's your name?"
 render_en_US (MyNameIs name) = "My name is " ++ name ++ "."
 render_en_US (Ihave_apples 0) = "I don't have any apples."
 render_en_US (Ihave_apples 1) = "I have one apple."
 render_en_US (Ihave_apples n) = "I have " ++ n ++ " apples."
 render_en_US GoodBye = "Good bye!"

 render_pt_BR :: Message -> String
 render_pt_BR Hello = "Olá!"
 render_pt_BR WhatsYourName = "Como você se chama?"
 render_pt_BR (MyNameIs name) = "Eu me chamo " ++ name ++ "."
 render_pt_BR (Ihave_apples 0) = "Não tenho nenhuma maçã."
 render_pt_BR (Ihave_apples 1) = "Tenho uma maçã."
 render_pt_BR (Ihave_apples 2) = "Tenho uma maçã."
 render_pt_BR (Ihave_apples n) = "Tenho " ++ show n ++ " maçãs."
 render_pt_BR GoodBye = "Tchau!"

Given those functions, you can construct something like

 type Lang = String

 render :: [Lang] -> Message -> String
 render ("pt"   :_) = render_pt_BR
 render ("pt_BR":_) = render_pt_BR
 render ("en"   :_) = render_en_US
 render ("en_US":_) = render_en_US
 render (_:xs) = render xs
 render _ = render_en_US

So r = render ["fr", "pt"] will do the right thing. You just need to pass this r around in your code.

Using is easy and clear:

 putStrLn $ r Hello
 putStrLn $ r WhatsYourName
 name <- getLine
 putStrLn $ r MyNameIs "Alice"
 putStrLn $ r (Ihave_apples $ length name `mod` 4)
 putStrLn $ r GoodBye

This approach is used for internationalization in the Yesod web framework, except that instead of one big data type, some type classes are used.