Difference between revisions of "Internationalization of Haskell programs using Haskell data types"
Jump to navigation
Jump to search
(Attribute this page to Felipe Lessa) |
m |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 8: | Line 8: | ||
<haskell> |
<haskell> |
||
− | + | data Message = |
|
− | + | Hello |
|
− | WhatsYourName |
+ | | WhatsYourName |
− | MyNameIs String |
+ | | MyNameIs String |
− | Ihave_apples Int |
+ | | Ihave_apples Int |
− | GoodBye |
+ | | 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> |
||
This approach is used for internationalization |
This approach is used for internationalization |
||
in the |
in the |
||
− | [http://www.yesodweb.com/ Yesod web framework], |
+ | [http://www.yesodweb.com/book/internationalization Yesod web framework], |
except that instead of one big data type, |
except that instead of one big data type, |
||
[http://hackage.haskell.org/packages/archive/yesod-core/0.9.2/doc/html/Yesod-Message.html some type classes] |
[http://hackage.haskell.org/packages/archive/yesod-core/0.9.2/doc/html/Yesod-Message.html some type classes] |
||
are used. |
are used. |
||
+ | |||
+ | [[Category:Code]] |
Latest revision as of 03:41, 14 August 2021
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.