Internationalization of Haskell programs using Haskell data types
From HaskellWiki
(Difference between revisions)
(Attribute this page to Felipe Lessa) |
|||
| Line 8: | Line 8: | ||
<haskell> | <haskell> | ||
| - | + | data Message = | |
| - | + | Hello | |
| - | + | | WhatsYourName | |
| - | + | | MyNameIs String | |
| - | + | | Ihave_apples Int | |
| - | + | | GoodBye | |
</haskell> | </haskell> | ||
| Line 20: | Line 20: | ||
<haskell> | <haskell> | ||
| - | + | 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!" | |
</haskell> | </haskell> | ||
| Line 43: | Line 43: | ||
<haskell> | <haskell> | ||
| - | + | 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 | |
</haskell> | </haskell> | ||
| Line 60: | Line 60: | ||
<haskell> | <haskell> | ||
| - | + | putStrLn $ r Hello | |
| - | + | putStrLn $ r WhatsYourName | |
| - | + | name <- getLine | |
| - | + | putStrLn $ r (MyNameIs "Alice") | |
| - | + | putStrLn $ r (Ihave_apples $ length name `mod` 4) | |
| - | + | putStrLn $ r GoodBye | |
</haskell> | </haskell> | ||
Revision as of 13:20, 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
r = render ["fr", "pt"]
r
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.
