Internationalization of Haskell programs using Haskell data types

From HaskellWiki
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.