Last active
July 26, 2020 06:36
-
-
Save sebleblanc/6bee5a64b6618c49a336b5f682caad51 to your computer and use it in GitHub Desktop.
Bilingual (tri-, quadrilingual…) strings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I had to deal with bilingual strings from an XML API (Canadian weather | |
website) in a short script that I wrote. I wanted a way to handle | |
those that was lightweight and simple. | |
First we define a sum type for languages that we support. Thanks to | |
this type, we can ensure through exhaustive pattern matching that we | |
have always included all supported languages in a string. It is so | |
simple to implement that it remains simple while still making use of | |
the safeties of the type system. | |
> data Lang = English | French -- | Spanish | Japanese … | |
The following type synonym will make type signatures clearer: | |
> type Translated a = Lang -> a | |
Next is a helper function. Its definition depends on the `Lang` | |
type. With several languages, it might get repetitive. Also, it needs | |
all possible translations to be included, but keep in mind that this | |
is a quick and dirty solution meant for two or three languages at | |
once. In a pinch, you may always pass `undefined` as one of the | |
translated strings, but you would have to know elsewhere if the | |
string is missing, or else you will get a `Prelude.undefined | |
exception: | |
> biling :: String -> String -> Translated String | |
> biling e _ English = e | |
> biling _ f French = f | |
It is invoked like so: | |
> let greeting = biling "Hello" "Bonjour" | |
To retrieve a translated string, one only has to pass the language to | |
the translated string, as it is after all just a function awaiting a | |
parameter. In the following snippet, the first line yields "Hello", | |
while the second yields "Bonjour": | |
> greeting English | |
> greeting French | |
If you want an alternative where you can expand to more languages | |
later, the following will demonstrate a method of doing it. | |
First we declare a default language code. We chose English. | |
> instance Default Lang where def = English | |
Once this is set, we add a catch all case that will defer to the default | |
language. | |
> greeting English = "Hello" | |
> greeting French = "Bonjour" | |
> greeting _ = greeting def | |
The compiler will warn you of redundant pattern matching, but it is | |
better than a non-exhaustive pattern error. | |
When you are ready to support an additional language, you only have to | |
add it to the sum type. Your program will still compile, deferring to | |
the default language when a translation is not provided. | |
> data Lang = English | French | Italian |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment