Personal tools

Internationalization of Haskell programs using Haskell data types

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(Created page from a haskell-cafe post by Felipe Lessa)
 
(Attribute this page to Felipe Lessa)
Line 1: Line 1:
 
You can use Haskell data types for internationalization.
 
You can use Haskell data types for internationalization.
  +
The following example is adapted from a
  +
[http://www.haskell.org/pipermail/haskell-cafe/2011-September/095715.html haskell-cafe mailing list post]
  +
by Felipe Lessa.
  +
 
The idea is to have a data type
 
The idea is to have a data type
 
with all your messages, like
 
with all your messages, like

Revision as of 12:47, 3 October 2011

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.