Skip to content

Generates Elm types and functions from i18n key/value JSON files

License

Notifications You must be signed in to change notification settings

dragonwasrobot/i18n-to-elm

Repository files navigation

i18n to Elm

Status

Generates Elm types and functions from i18n key/value JSON files.

The tool is meant as an aid if you are using a centralized service to handle the translation of your i18n resources but then need to import the i18n keys/values into your Elm application in a type-safe way.

Note: If you like code that generates code, you might like my other project which turns JSON-schema specs into Elm types+decoders+encoders.

Installation

This project requires that you already have elixir and its build tool mix installed. This can either be done with asdf, using the included .tool-versions file, or however you and your operating system prefers to install applications.

  • Clone this repository: git clone [email protected]:dragonwasrobot/i18n-to-elm.git
  • Build an executable: MIX_ENV=prod mix build
  • An executable, i18n2elm, has now been created in your current working directory.

Usage

Run ./i18n2elm for usage instructions.

The executable expects one or more json files with the naming scheme: <language code>_<COUNTRY CODE>.json, e.g. en_US.json or da_DK.json, and that each json file is a simple dictionary of i18n keys and values, for example:

{
    "Hello": "Hej, {0}. Leder du efter {1}?",
    "Next" : "Næste",
    "No": "Nej",
    "Previous": "Forrige",
    "Yes": "Ja"
}

A complete example of input and output code can be found in the examples folder.

Example

If we supply i18n2elm with the folder examples/input-i18n-json, containing the two JSON files, da_DK.json:

{
    "Hello": "Hej, {0}. Leder du efter {1}?",
    "Next" : "Næste",
    "No": "Nej",
    "Previous": "Forrige",
    "Yes": "Ja"
}

and en_US.json:

{
    "Hello": "Hello, {0}. Is it {1} you are looking for?",
    "Next" : "Next",
    "No": "No",
    "Previous": "Previous",
    "Yes": "Yes"
}

it produces the following Elm files, Translations/DaDk.elm:

module Translations.DaDk exposing (daDkTranslations)

import Translations.Ids exposing (TranslationId(..))


daDkTranslations : TranslationId -> String
daDkTranslations tid =
    case tid of
        TidHello hole0 hole1 ->
            "Hej, " ++ hole0 ++ ". Leder du efter " ++ hole1 ++ "?"

        TidNext ->
            "Næste"

        TidNo ->
            "Nej"

        TidPrevious ->
            "Forrige"

        TidYes ->
            "Ja"

and Translations/EnUs.elm:

module Translations.EnUs exposing (enUsTranslations)

import Translations.Ids exposing (TranslationId(..))


enUsTranslations : TranslationId -> String
enUsTranslations tid =
    case tid of
        TidHello hole0 hole1 ->
            "Hello, " ++ hole0 ++ ". Is it " ++ hole1 ++ " you are looking for?"

        TidNext ->
            "Next"

        TidNo ->
            "No"

        TidPrevious ->
            "Previous"

        TidYes ->
            "Yes"

and Translations/Ids.elm:

module Translations.Ids exposing (TranslationId(..))


type TranslationId
    = TidHello String String
    | TidNext
    | TidNo
    | TidPrevious
    | TidYes

and finally Translations/Util.elm:

module Translations.Util exposing (parseLanguage, translate, Language(..))

import Translations.Ids exposing (TranslationId)
import Translations.DaDk exposing (daDkTranslations)
import Translations.EnUs exposing (enUsTranslations)


type Language
    = DA_DK
    | EN_US


parseLanguage : String -> Result String Language
parseLanguage candidate =
    case candidate of
        "da_DK" ->
            Ok DA_DK

        "en_US" ->
            Ok EN_US

        _ ->
            Err <| "Unknown language: '" ++ candidate ++ "'"


translate : Language -> TranslationId -> String
translate language translationId =
    let
        translateFun =
            case language of
                DA_DK ->
                    daDkTranslations

                EN_US ->
                    enUsTranslations
    in
        translateFun translationId

which contains:

  • The Danish translations as a function, daDkTranslations,
  • the English translations as a function, enUsTranslations,
  • all the translation IDs as a union type, TranslationId,
  • a union type capturing all available languages, Language,
  • a function to parse a string into a Language, parseLanguage, and
  • a function to translate a TranslationId for a given Language into a concrete String value.