Upgrade to Pro — share decks privately, control downloads, hide ads and more …

i18n in Elm - Treat localized text as constants

i18n in Elm - Treat localized text as constants

A presentation explaining the concept and techniques used in https://github.com/iosphere/elm-i18n. This also includes a brief look at other techniques for translations and internationalizations in Elm.

Felix Lamouroux

June 10, 2017
Tweet

Other Decks in Programming

Transcript

  1. i18n in Elm Treat localized text as constants Felix Lamouroux,

    iosphere GmbH © Felix Lamouroux, iosphere GmbH, 2017 1
  2. Two approaches to internationalization (i18n) Switching languages at 1. Runtime

    2. Compile time © Felix Lamouroux, iosphere GmbH, 2017 2
  3. Basic Setup Elm App Model Keep user's language in model

    Rose!a Stone Translation function Pass through Provide the language to any function requiring localized text Monolithic build One build for all languages: all.js © Felix Lamouroux, iosphere GmbH, 2017 4
  4. Example 1 type Language = English | Norwegian type TranslationId

    = Login | WelcomeBack {name : String} {-| Get a translated string for the given language. -} translate : Language -> TranslationId -> String {-| ... provide user's language to view functions. -} view : Language -> Html Msg 1 See Elm i18n and Type Safety By Amitai Burstein gizra.com/content/elm-i18n-type-safety © Felix Lamouroux, iosphere GmbH, 2017 5
  5. Main drawback: monolithic versions Monolithic builds ➜ Monolithic versions Lockstep

    Each version must fully support all languages. Larger builds All supported languages are downloaded on clients. © Felix Lamouroux, iosphere GmbH, 2017 6
  6. Translation.json: elm-taco Load translations dynamically via JSON 1. Not type-safe

    2. No guarantee that all translations are complete © Felix Lamouroux, iosphere GmbH, 2017 7
  7. Setup using iosphere/elm-i18n 1. One build per language: en.js and

    no.js2 2. Use functions & constants for localized strings 3. Serve localized builds 2 Issue #2 © Felix Lamouroux, iosphere GmbH, 2017 9
  8. Organizing localized strings /src/ ├─ Main.elm # (e.g. imports Translation.Main)

    └─ View.elm # (e.g. imports Translation.View) /Translation/ ├─ En/ │ ├─ Main.elm # (module Translation.Main) │ └─ View.elm # (module Translation.View) └─ No/ ├─ Main.elm # (module Translation.Main) └─ View.elm # (module Translation.View) © Felix Lamouroux, iosphere GmbH, 2017 10
  9. Organizing localized strings /src/ ├─ Main.elm # (e.g. imports Translation.Main)

    ├─ View.elm # (e.g. imports Translation.View) └─>Translation # (linked to e.g. /Translation/No/) /Translation/ ├─ En/ │ ├─ Main.elm # (module Translation.Main) │ └─ View.elm # (module Translation.View) └─ No/ ├─ Main.elm # (module Translation.Main) └─ View.elm # (module Translation.View) © Felix Lamouroux, iosphere GmbH, 2017 11
  10. Organizing localized strings /src/ ├─ Main.elm # (e.g. imports Translation.Main)

    ├─ View.elm # (e.g. imports Translation.View) └─>Translation # (linked to e.g. /Translation/En/) /Translation/ ├─ En/ │ ├─ Main.elm # (module Translation.Main) │ └─ View.elm # (module Translation.View) └─ No/ ├─ Main.elm # (module Translation.Main) └─ View.elm # (module Translation.View) © Felix Lamouroux, iosphere GmbH, 2017 12
  11. Example: Translation/No/Main.elm module Translation.Main exposing ( ..) {-| A short

    greeting. -} greeting : String greeting = "Hei!" {-| A personalized greeting. Use placeholder `name`. -} greetingWithName : String -> String greetingWithName name = "God dag, " ++ name © Felix Lamouroux, iosphere GmbH, 2017 13
  12. Example: Translation/En/Main.elm module Translation.Main exposing ( ..) {-| A short

    greeting. -} greeting : String greeting = "Hello" {-| A personalized greeting. Use placeholder `name`. -} greetingWithName : String -> String greetingWithName name = "Welcome back, " ++ name © Felix Lamouroux, iosphere GmbH, 2017 14
  13. Switching languages — Switch working copy of your app to

    English: elm-i18n-switch -l En — Compile Norwegian and English versions to dist/no.js and dist/en.js: elm-i18n-switch -l No --output dist elm-i18n-switch -l En --output dist — Serve appropriate build on your website (e.g. en.html). © Felix Lamouroux, iosphere GmbH, 2017 15
  14. Export Elm code to CSV Extract strings from your Elm

    code to a CSV file. elm-i18n-generator --format CSV --root example/Translation --language No --export © Felix Lamouroux, iosphere GmbH, 2017 17
  15. Example: CSV export — All modules are exported into one

    long CSV file. — CSV can be converted back to Elm code. Module Key Comment Supported Placeholders Translation Translation.Main greeting A short greeting. -/- Hei! Translation.Main greetingWithNa me A personalized greeting. Use placeholder name. name God dag, {{name}} © Felix Lamouroux, iosphere GmbH, 2017 18
  16. Example: PO export3 — All modules are exported into one

    long PO string file. — PO file can be converted back to Elm code. #. A short greeting. msgid "Translation.Main.greeting" msgstr "Hei!" #. A personalized greeting. Use placeholder `name`. #. i18n: placeholders: name msgid "Translation.Main.greetingWithName" msgstr "God dag, %(name)s" 3 The Format of PO Files © Felix Lamouroux, iosphere GmbH, 2017 19
  17. Import Elm string constants and functions from PO — Create

    Elm modules from PO/CSV exports: elm-i18n-generator --format PO --language De --import export.po © Felix Lamouroux, iosphere GmbH, 2017 20
  18. Main drawback: no runtime language switching — Reload to switch

    language — Restore state of app/session But: You are doing it wrong if many users switch language ➜ Make an educated guess about the user's preferred language © Felix Lamouroux, iosphere GmbH, 2017 21
  19. Simple view functions and code — Full type safety —

    Auto-completion by the IDE — Your Elm app can be language agnostic import Translation.Main as Translation view : Html Msg view = div [] [ text (Translation.greeting "Richard") ] © Felix Lamouroux, iosphere GmbH, 2017 23
  20. Phased rollout Quick Develop new features in your own language

    Phased Rollout new features to some languages first Safe Incomplete translations do not compile © Felix Lamouroux, iosphere GmbH, 2017 24
  21. Be!er testing Create a pseudo language for testing Avoid changing

    tests when wording changes Setup: Translation/Test/Main.elm elm-i18n-switch -l Test elm-test © Felix Lamouroux, iosphere GmbH, 2017 25
  22. Work with professional translators Be!er collaboration Work with translators in

    a known convenient formats Add new languages Setup new languages without changes to existing files © Felix Lamouroux, iosphere GmbH, 2017 26
  23. Contributions welcome — Add support for JSON/XLIFF/... import & export

    — Add support for plurals4 — Alternative build option: runtime language switching5 5 Issue #2 4 Issue #1 © Felix Lamouroux, iosphere GmbH, 2017 27
  24. Contact me — Elm Slack: felix — Twitter: @felixlamouroux —

    Website: iosphere.de — Repository: github.com/iosphere/elm-i18n © Felix Lamouroux, iosphere GmbH, 2017 30