tl;dr: A version of elm/html
geared towards translation.
- ✅ Avoid using untranslated strings in places that should be translated.
- ✅ Avoid the need to pass around a global context to every view function.
⚠️ Defering the translation step to a single place may negatively affect performance. I haven't yet tested this package in production or any performance critical rendering scenario.
This package helps you write HTML when your application is going to be translated into multiple languages.
It does this by exposing almost exactly the same interface as elm/html
but with an additional userText
parameter and functions to convert between the 2 packages:
-- elm/html
Html.Html msg
-- elm-i18n/translatable-html
Translatable.Html.Html userText msg
-- elm/html
Html.Attributes.Attribute msg
-- elm-i18n/translatable-html
Translatable.Html.Attributes.Attribute userText msg
The idea is that if you have a custom type for your untranslated source strings (e.g. Translatable
), this package helps you enforce that only that custom type can be used in places that should be translated (e.g. Html.text
or Html.Attributes.title
) and plain strings cannot be used.
As well as parameterising the Html
and Attribute
type, it also defers translation so it can be applied in a single step. This means that you no longer need to pass around a global context to nearly every view function that contains the configuration necessary to turn an untranslated string into a translated one (i.e. the users current language and the dictionary of translated strings).
import Html
type alias GlobalContext =
{ translateConfig : TranslateConfig }
view : GlobalContext -> Html.Html msg
view globalContext =
Html.div []
[ view1 globalContext
, view2 globalContext
, view3 globalContext
]
view1 : GlobalContext -> Html.Html msg
view1 { translateConfig } =
"Foo"
|> translatable
|> translate translateConfig
|> Html.text
view2 : GlobalContext -> Html.Html msg
view2 { translateConfig } =
"Bar"
|> translatable
|> translate translateConfig
|> Html.text
view3 : GlobalContext -> Html.Html msg
view3 { translateConfig } =
"Baz"
|> translatable
|> translate translateConfig
|> Html.text
type Translatable
= Translatable String
translatable : String -> Translatable
translatable =
Translatable
translate : TranslateConfig -> Translatable -> String
translate translateConfig (Translatable userText) =
userText
import Html
import Translatable.Html
type alias GlobalContext =
{ translateConfig : TranslateConfig }
view : GlobalContext -> Html.Html msg
view { translateConfig } =
Translatable.Html.toHtml (translate translateConfig) <|
Translatable.Html.div []
[ view1
, view2
, view3
]
view1 : Translatable.Html.Html Translatable msg
view1 =
"Foo"
|> translatable
|> Translatable.Html.text
view2 : Translatable.Html.Html Translatable msg
view2 =
"Bar"
|> translatable
|> Translatable.Html.text
view3 : Translatable.Html.Html Translatable msg
view3 =
"Baz"
|> translatable
|> Translatable.Html.text
type Translatable
= Translatable String
translatable : String -> Translatable
translatable =
Translatable
translate : TranslateConfig -> Translatable -> String
translate translateConfig (Translatable userText) =
userText
A more detailed example app showing how I recommend using this package can be found in the ./example
directory.
As mentioned above, using this package over elm/html
may have a negative impact on performance.
Using Translatable.Html.Lazy
may be a way to mitigate the problem.
There are some benchmarks comparing this package to elm/html
in the ./benchmarks
directory.
elm/html
exposes 8 lazy functions; due to the way lazy workstranslatable-html
can only expose 6 lazy functions as 2 of these parameters are used internally.