Internationali[s|z]ation (I18n) seems to be a deceptively complex problemfiction.
I have never had to consider the option of generating application translations as a pre-build phase of an application (for example,science fiction-i18n) or dynamically loaded (e.g.elm-i18 next) when working with i18n onrailsoPhoenix. Honestly, I still don't know what is "better" in the context of Elm. But I know I want to have runtime switchable languages via a dropdown, so creating a sample page with dynamically loaded translations will be the main focus of this blog post.
I have usedtachyonsa lot lately about the style and how he plays with Elm, so here's what we're going to do:
- recreate tachyonsDocumentation page for the Frame-Centered Title component.in elms
- Add a custom language switch dropdown to the page
- Provide some translations for the page onJSONFormat and allow dropdown to change language
- Save the selected language in
memoria local
so that any selected language is persisted across page refreshes and across sessions. - Explore generating Elm modules from JSON translation files to give translations some type safety
(If you want to go ahead and see the end result, feel free to clone mineexample elm-i18n
Repo)
Let's start!
Update (December 21, 2018)
The version of Elm used in this post is 0.18. I still stand by the general points of the post, but some of the code is now deprecated. He
Maestro
Branch ofexample elm-i18n
Repohas been updated to Elm 0.19. So if you go ahead and run into issues, try matching them there with the updated codebase.The complete original 0.18 codebase used in this post can be found at0,18 ramarest
Bootstrap a new Elm application
Create Elm Appwill help us start our app, so install it with:
npminstall - GRAMScrear-elm-app
Then generate a new application and initialize it.npm
(using the default fields provided for the generatedpackage.json
file is fine) and install tachyons:
create-elm-app elm-i18n-exampleCDelm-i18n-examplenpm initnpminstalltachyons
Next, to import tachyons into the project, modify the generatedindex.js
file looks like this:
src/index.js
matter "tachyons"matter "./principal.css"matter { First of all } outside "./Main.ulm"until application container = document.getElementById("root")And(application container) { First of all.embed(application container)}
Well if you runLaunch elm app
,http://localhost:3000/It should open automatically and you should see a familiar splash screen letting you know that your Elm app is working.
Before we really get started, let's clean up some of the generated code given to us by the Create Elm app:
- We do not need
src/principal.css
since the tachyons take care of the hairstyle - So this app will not use service workers
src/registerServiceWorker.js
can be removed - We won't be using the Elm logo from the splash screen, so it can be removed, along with any references to it.
src/Main.elm
So run the following command and make the following changes:
rmsrc/main.css src/registerServiceWorker.js public/logo.svg
src/index.js
matter "tachyons"matter { First of all } outside "./Main.ulm"// ...
src/Main.elm
-- ...vista : Model -> HTML Newsvista Model = division [] [ h1 [] [ Text "Your Elm app is working!" ] ]
You should now have a very basic looking (but buildable) page, so let's lighten it up a bit!
Rebuild the Tachyon documentation page
Using the sample code in theFull screen centered title pageAs a guide (but with some minor adjustments), change theMajor. Science fiction
Module definitions, import statements, andvista
Function to rebuild the page:
src/Main.elm
Module First of all expose (first of all)matter HTML expose (HTML, Article, division, h1, first of all_, Text)matter HTML.Attribute expose (Class)-- ...vista : Model -> HTML Newsvista Model = permission classes = [ "bg-dunkelrosa" , "overflow tank" , "sans serif" , "Weiss" ] |> line.to connect "" |> Class In first of all_ [ classes ] [ Content ]Content : HTML NewsContent = permission ArticleClasses = [ "dt" , "vh-100" , "w-100" ] |> line.to connect "" |> Class divclases = [ "dtc" , "ph3 ph4-l" , "CT" , "v-means" ] |> line.to connect "" |> Class In Article [ ArticleClasses ] [ division [ divclases ] [ titular ] ]titular : HTML Newstitular = permission classes = [ "f6 f2m" , "f-subtitle-l" , "fw6" , "CT" ] |> line.to connect "" |> Class In h1 [ classes ] [ Text "Vertically centering things in CSS is easy!" ]
I think it's easier to scan and maintain the Tachyon classes in lists like this, but it also has the side effect of making the function definitions very long, so here we've split the content into three different smaller functions.
The use of utility-based CSS frameworks like tachyons andtailwindIt can seem daunting at first, with all the mnemonics you seem to have to memorize, so I always keep themThe tachyon style table.Open it in a browser tab for quick reference, and if this is your first look at tachyons, I recommend doing the same.
In either case, your page should now look like the following screenshot:
If not, check your codeDieRebuild page 1-tachyons-doc
Zweigmy codebase to see if anything is missing.
Add language dropdown
Right now the language dropdown is populated with placeholder values and you can't change the language, but what we want from the menu at the end is:
- The current language should be displayed in the menu by default
- If you click on the menu it should open up and display all the other available languagesapart fromthe current language
- When you hover over a menu item, it should be highlighted somehow
- Clicking on a menu item should change the current language of the app (more on this later)
- If you click anywhere else on the page while the menu is open, the menu should close
Most of these requirements sound like they're better served in their own module, so let's come up with a nameLanguageDropdown.elm
, and start rendering only the current language selection so that we get the correct positioning of the menu.
current selection
src/LanguageDropdown.elm
Module language dropdown menu expose (vista)matter HTML expose (HTML, division, li, PAG, equipment, Text, ul)matter HTML.Attribute expose (Class)vista : HTML Newsvista = permission classes = [ "Center" , "f3" , "to fold" , "h3" , "Element Center" , "justify-end" , "w-90" ] |> line.to connect "" |> Class In division [ classes ] [ current selection ]current selection : HTML Newscurrent selection = permission classes = [ "b-white" , "licensed in letters" , "br2" , "pa2" , "Pointer" , "CT" , "w4" ] |> line.to connect "" |> Class caretClasses = [ "absolute" , "ml2" ] |> line.to connect "" |> Class In PAG [ classes ] [ equipment [] [ Text "English" ] , equipment [ caretClasses ] [ Text "▾" ] ]
Next, we need to import the language dropdown code into theFirst of all
module, as well as easily customize the styles invista
Function, since there is now more to the page than just the message:
src/Main.elm
-- ...matter language dropdown menu-- ...vista : Model -> HTML Newsvista Model = permission classes = [ "bg-dunkelrosa" , "overflow tank" , "pt3" , "sans serif" , "vh-100" , "Weiss" ] |> line.to connect "" |> Class In first of all_ [ classes ] [ language dropdown menu.vista , Content ]Content : HTML NewsContent = permission ArticleClasses = [ "dt" , "vh-75" , "w-100" ] |> line.to connect "" |> Class -- ... In -- ...
Now your page should look like this:
The "menu" here (yes, currently it's only onePAG
tag) currently doesn't do anything, but at least we can confirm that it seems to be in a good place on the page. Now we're actually giving you onedrop down list
under thecurrent selection
!
Language dropdown list
src/LanguageDropdown.elm
vista : HTML Newsvista = permission -- ... In division [ classes ] [ current selection , drop down list ]-- ...drop down list : HTML Newsdrop down list = permission classes = [ "absolute" , "b-white" , "Bed and breakfast" , "Degree in Law" , "brother" , "br-down" , "br2" , "Element Center" , "List" , "mt5 , "pl0" , "Pointer" , "pr0" , "pt1" , "CT" , "top-0" , "w4" ] |> line.to connect "" |> Class selectable languages = [ "Italian", "Japanese" ] In ul [ classes ] (List.Map DropdownListItem selectable languages)DropdownListItem : line -> HTML NewsDropdownListItem Language = permission classes = [ "hover-bg-blanco" , "Hover-Dunkelrosa" , "ph1" , "PV2" , "pt0" , "w-100" ] |> line.to connect "" |> Class In li [ classes ] [ equipment [] [ Text Language ] ]
That leads to:
- For the dropdown list, we insert an HTML unordered list (
ul
) directly belowPAG
label that simulates opening a menu. - When we hover over a menu item, we can see which item is currently selected.
- Selectable languages currently have strings as placeholders, but we'll change this later when we introduce the concept of language in the app.
So now we know what the menu looks like when it's open, but we need it to respond to mouse clicks to open and close the dropdown list (read: turn the list on and off), so let's do that now.
Show and hide available languages
The app needs to be able to track whether to show or hide the dropdown and be able to track menu and page clicks, so it sounds like we'll need the following:
- A boolean flag to tell the application if this is the case
showAvailable languages
O no - An update
News
this toggles the visibility of the dropdown list; let's call itShow available languages
- An update
News
This will hide the dropdown menu when it is open but a click is being tracked elsewhere on the page. let's call itCloseAvailable languages
We start by updating theNews
join type. BothMajor. Science fiction
YLanguageDropdown.elm
need access toNews
, so let's extract it into its own module:
src/Msj.elm
Module News expose (News(..))type News = CloseAvailable languages | Show available languages
Next excerptModel
and theinside
function disabledFirst of all
in a new onemodel.olmo
Module, make sure the dropdown is hidden by default:
src/model.elm
Module Model expose (Model, inside)matter News expose (News)type alias Model = { showAvailable languages : bool }inside : ( Model, Before News )inside = ( { showAvailable languages = INCORRECT }, Before.none )
Now we have to updateMajor. Science fiction
YLanguageDropdown.elm
to import these modules and then write handling code for themNews
it's in theUpdate
Function:
src/Main.elm
-- ...matter Model expose (Model)matter News expose (News(CloseAvailable languages, Show available languages))Update : News -> Model -> ( Model, Before News )Update News Model = Fall News Von CloseAvailable languages -> ( { Model | showAvailable languages = INCORRECT }, Before.none ) Show available languages -> ( { Model | showAvailable languages = no Model.showAvailable languages } , Before.none )-- ...first of all : program Never Model Newsfirst of all = HTML.program { vista = vista , inside = Model.inside , Update = Update , subscriptions = always Sub.none }
Soylanguage dropdown menu
, since we are going to send type messages nowNews
, all feature notes withHTML message
needs to be updatedHTML message
. We will also make use of that.vista
functionModel
Parameters on the dropdown to determine what to show and how the dropdown should be styled on opening and closing:
src/LanguageDropdown.elm
-- ...matter HTML.events expose (on click)matter Model expose (Model)matter News expose (News(Show available languages))vista : Model -> HTML Newsvista Model = permission -- ... In division [ classes ] [ current selection Model , drop down list Model ]current selection : Model -> HTML Newscurrent selection Model = permission show classes = And Model.showAvailable languages So [ "br--up" ] Anders [] classes = [ -- ... ] ++ show classes |> line.to connect "" |> Class -- ... In PAG [ classes, on click Show available languages ] [ -- ... ]drop down list : Model -> HTML Newsdrop down list Model = permission show classes = And Model.showAvailable languages So [ "to fold", "columna flexible" ] Anders [ "dn" ] classes = [ -- ... ] ++ show classes |> line.to connect "" |> Class -- ... In -- ...DropdownListItem : line -> HTML News-- ...
Once you've made the above changes, you should be able to click the dropdown menu to open and close it and show and hide the available languages. However, if you open the menu and then click anywhere else, the menu remains open.
To close it (and actually use thatCloseAvailable languages
message), we have to use thatelm mouse packand a subscription to mouse clicks.
Subscribe to mouse clicks
Install the Elm Mouse package:
elm bundleinstall -yLong Elm/Mouse
then create onesubscriptions
Function in Elm that listens for mouse clickssoloIf the dropdown is open and a click is detected, a message will be sent.CloseAvailable languages
News:
src/Main.elm
-- ...matter Maus-- ...subscriptions : Model -> Sub Newssubscriptions Model = And Model.showAvailable languages So Maus.clicks (\_ -> CloseAvailable languages) Anders Sub.nonefirst of all : program Never Model Newsfirst of all = HTML.ProgrammMitFlags { vista = vista , inside = Model.inside , Update = Update , subscriptions = subscriptions }
Now if you click on the dropdown and then click somewhere else, the menu will close as expected.
If the app doesn't behave as expected so far, check your code againstDieAdd 2 language dropdown menu
Zweigmy codebase to see if anything is missing.
Now it's time to give your app the concept of a language to switch to and replace those placeholder values with actual data!
change of language
It's time to put some translations in the app and for that we will useelm-i18 next, WithHTTP en ElmPackage, so let's start installing:
elm bundleinstall -yChristophP/elm-i18nextalm-Packetinstall -yelm-lang/http
First, let's provide some translation JSON files for the English, Italian, and Japanese on-screen message. A... createpublic/local/
directory and add the following files under it:
public/locale/translations.en.json
{ "CentroVerticalInCssIsSimple": "Centering things vertically in CSS is easy!"}
public/locale/translations.it.json
{ "CentroVerticalInCssIsSimple": "Centering vertically with CSS is easy!"}
public/local/translations.ja.json
{ "CentroVerticalInCssIsSimple": "CSS vertical centering is easy!"}
Next we create onetranslations
Module where we define the type of a language and provide a helper function to convert a string language code to a language:
src/Translations.elm
Module translations expose (Language(..), getLnFromCode)type Language = In | ES | YgetLnFromCode : line -> LanguagegetLnFromCode Code = Fall Code Von "In" -> In "Es" -> ES "Y" -> Y _ -> In
Excellent! Now we have to add some new ones.News
Types for:
- Get the translations of the JSON files
- change language
src/Msj.elm
Module News expose (News(..))matter Http expose (Error)matter I18Weiter expose (translations)matter translations expose (Language)type News = change language Language | CloseAvailable languages | Get Translations (Result Error translations) | Show available languages
Now we need a way to get the translations of the JSON files and return the result via theGet Translations
message, so let's create that in a new module calledBefore
:
src/Cmd.elm
Module Before expose (look up translations)matter I18Weitermatter News expose (News(Get Translations))matter translations expose (Language)look up translations : Language -> Before Newslook up translations Language = Language |> aUrlTranslations |> I18Weiter.look up translations Get TranslationsaUrlTranslations : Language -> lineaUrlTranslations Language = permission translationlanguage = Language |> Chain |> line.reduce In "/locale/translations". ++ translationlanguage ++ ".json"
Now himModel
should know whatcurrent language
the application is to determine whattranslations
should be loaded, so let's add that information and call thatCmd.fetchTranslations Es
Command to immediately get the translations corresponding to English, which we will also set as the default language:
src/model.elm
Module Model expose (Model, inside)matter Beforematter I18Weiter expose (translations)matter News expose (News)matter translations expose (Language(In))type alias Model = { current language : Language , showAvailable languages : bool , translations : translations }inside : ( Model, Before News )inside = ( { current language = In , showAvailable languages = INCORRECT , translations = I18Weiter.initial translations } , Before.look up translations In )
Next we have to deal with the newchange language
YGet Translations
news in theUpdate
Function:
- If the language is changed, as well as the change
current language
, we need to get the translations for that language the same way we did ininside
function - If fetching the translations is successful, we display the new translations; otherwise, we just ignore any bugs for now, as we wouldn't expect to get translations for a language we didn't create ourselves.
src/Main.elm
-- ...matter Beforematter News expose ( News ( change language , CloseAvailable languages , Get Translations , Show available languages ) )---...Update : News -> Model -> ( Model, Before News )Update News Model = Fall News Von -- ... change language Language -> ( { Model | current language = Language } , Before.look up translations Language ) Get Translations (OK translations) -> ( { Model | translations = translations }, Before.none ) Get Translations (err News) -> ( Model, Before.none )
At this point, the app should be back to a point where everything is recompiled, but on the surface there's no change as the language display is still made up of static values, so let's change that.
First we create oneLanguage
Module that has some helper functions to generate the string value for a language (for example "English" should always be displayed as "English" regardless of the current language) and maintain a static list of available languages for us to display in the Menu dropdown. Unfortunately, there is no way to get a list of type values of a type (for example,[And, that, yes]
of theLanguage
type), so it must be a separate definition:
src/language.elm
Module Language expose (Available languages, langToString)matter translations expose (Language(In, ES, Y))Available languages : List LanguageAvailable languages = [ In, ES, Y ]langToString : Language -> linelangToString Language = Fall Language Von In -> "English" ES -> "Italian" Y -> "Japanese"
Now that we have our language data set, let's go back to the view code and move down the page to start viewing. First, let's display the correct information in the dropdown for both the current language and the other languages available in the dropdown:
src/LanguageDropdown.elm
-- ...matter Languagematter News expose (News(change language, Show available languages))matter translations expose (Language)-- ...current selection : Model -> HTML Newscurrent selection Model = permission -- ... In PAG [ classes, on click Show available languages ] [ equipment [] [ Text (Language.langToString Model.current language) ] , equipment [ caretClasses ] [ Text "▾" ] ]drop down list : Model -> HTML Newsdrop down list Model = permission -- ... selectable languages = List.Filter (\Language -> Language /= Model.current language) Language.Available languages In ul [ classes ] (List.Map DropdownListItem selectable languages)DropdownListItem : Language -> HTML NewsDropdownListItem Language = permission -- ... In li [ classes, on click (change language Language) ] [ equipment [] [ Text (Language.langToString Language) ] ]
At this point, if you select a new language from the dropdown, you'll see the current language indicator change in the menu, and if you open the elm debugger, you'll see the application language isStrictly speakingchange, and translations for the languageSonloaded in the application:
Excellent! Now let's make this translated message display on the page by telling the content which translations to display:
src/Main.elm
-- ...matter translations expose (Language)-- ...vista : Model -> HTML Newsvista Model = permission -- ... In first of all_ [ classes ] [ language dropdown menu.vista Model , Content Model.translations ]Content : translations -> HTML NewsContent translations = permission -- ... In Article [ ArticleClasses ] [ division [ divclases ] [ titular translations ] ]titular : translations -> HTML Newstitular translations = permission -- ... In h1 [ classes ] [ Text (I18Weiter.T translations "VerticalCenterInCssIsSimple") ]
And now when you change the language, you should see the message displayed in that language:
Fantastic! That covers the core functionality of language switching, but we can do more. However, before you continue, if you are unable to switch languages, you should re-verify your codeDie3-Add language change
Zweigmy base code.
detect user language
Currently, the app's default language is English at launch, but it would be nice if we at least tried to configure the app to initially display in the user's preferred language. To get around the idea of a “preferred language” (becauseThis is not universal across browsers.), we consider it as the language of the browser used. How do we do that? In javascript we can use:
browser.language
-
navigator.userIdioma
(for Internet Explorer)
So, let's get this information from Javascript and pass it to Elm as a flag:
src/index.js
matter "tachyons"matter { First of all } outside "./Main.ulm"until application container = document.getElementById("root")And(application container) { First of all.embed(application container, { Language: getLanguage() })}function getLanguage() { go back Browser.Language || Browser.language of the user}
Our application currently cannot accept javascript flags, so let's change our program type toProgrammMitFlags
For this to happen:
src/Main.elm
-- ...matter Model expose (banderas, Model)-- ...first of all : program banderas Model Newsfirst of all = HTML.ProgrammMitFlags { vista = vista , inside = Model.inside , Update = Update , subscriptions = subscriptions }
Next we define what type of flags we accept in theModel
module and since we don't trust the information passed by javascript, we decode the flag to make sure we get a string.
src/model.elm
Module Model expose (banderas, Model, inside)-- ...matter json.decode and decode expose (Wert)matter Languagetype alias banderas = { Language : Wert }-- ...inside : banderas -> ( Model, Before News )inside banderas = permission Language = banderas.Language |> decode.decode value decode.line |> Language.longFromFlag In ( { current language = Language , showAvailable languages = INCORRECT , translations = I18Weiter.initial translations } , Before.look up translations Language )
Finally, we create theidioma.langFromFlag
Function that returns a language if the decoding goes well and a default language if it doesn't:
src/language.elm
Module Language expose (Available languages, longFromFlag, langToString)-- ...longFromFlag : Result line line -> LanguagelongFromFlag Language = Fall Language Von OK Language -> translations.getLnFromCode Language err _ -> In
If your browser language is English, you won't notice any changes from these additions, but if you change your browser language to Italian or Japanese and then refresh the page, you'll see the app launch in that language.
For Chrome, you can change the language settings by opening browser settings, opening advanced settings...
...Find the language settings, then select a language to move to the top of the list:
Does the default language not change? Check your code againstDie4-detect the language of the user
Zweigmy base code.
Now it's nice to have a default language, but if you change the language and then refresh the page, the app reverts to the language set in the browser. Many people want to read content in a different language than their system settings and it would be nice to be able to save your language preference for this app. So, let's use the browser one thenmemoria local
to help us do just that.
Save language settings
To send data from elm to javascript we need to use itElm-Ports. All port functions return acommand message
, so let's add the function to save a language setting in theBefore
module and change it to aport-how
:
src/Cmd.elm
Puerto Module Before expose (look up translations, StoreSprache)-- ...Puerto storeLanguageInLocalStorage : line -> Before News-- ...StoreSprache : Language -> Before NewsStoreSprache Language = Language |> Chain |> line.reduce |> storeLanguageInLocalStorage
here we create oneStoreSprache
Command function that a assumesLanguage
write, type and send it to JavascriptstoreLanguageInLocalStorage
Port. There is currently no code on the javascript side that subscribes to messages from this port, so let's do it next:
src/index.js
// ...And(application container) { until application = First of all.embed(application container, { Language: getLanguage() }) application.ports.storeLanguageInLocalStorage.subscribe to((Language) => { memoria local.setItem("elm-i18n sample language", Language) })}// ...
There is no particular reason behind the "elm-i18n-example-language" key; It could have had any name, but it's best to make it as unique as possible, since many different applications are likely to use it.memoria local
.
Ok, we have configured the path to javascript, now we need to make sure that the command is executed every time the language is changed (i.e. thechange language
message is sent), so let's make this addition to thatUpdate
Function:
src/Main.elm
-- ...Update : News -> Model -> ( Model, Before News )Update News Model = Fall News Von change language Language -> ( { Model | current language = Language } , Before.Carry [ Before.look up translations Language , Before.StoreSprache Language ] ) -- ...
Hechange language
Branch ofUpdate
The feature has gotten a bit busier and needs to be usedcommand batch
to send commands to retrieve new language translations and save the user's language preference.
You should now be able to change the language and save it.memoria local
. Open the Javascript console in your browser's developer tools to confirm this with the following command:localStorage.getItem("elm-i18n sample language")
Success! However, there is a small problem: when you refresh the browser, the application still reverts to the default language, English. We need to have our javascript code to get the languagememoria local
(if applicable) and pass it in as the Elm language flag, so let's do this:
src/index.js
// ...function getLanguage() { go back memoria local.gets the object("elm-i18n sample language") || Browser.Language || Browser.language of the user}
Now when you change the language and refresh the page, the app should still show you the language you originally selected! If not, check your codeDieMemory language preference 5
Zweigmy base code.
At this point, our site is almost complete. However, there are still some potential issues that might be worth investigating further:
- When updating the page, the translation key "verticalCenteringInCssIsEasy" may blink briefly before the translation appears. This is particularly noticeable with the Japanese translation. Perhaps the translations are loading too slowly…?
- If you accidentally make a typo while requesting a translation by pressing a button in a view (eg.
I18Next.t Übersetzungen "this key does not exist"
), then no error is thrown - the key is just displayed on the page, which might not be what you want. - If you inadvertently fail to provide a translation for a particular key for a known available language, or make a typographical error in the translation file (for example, the
translations.ja.json
file or change its key name), then again no error is thrown and the requested key is displayed unchanged on the page.
Elm programmers are spoiled by the fact that the Elm compiler is always looking over its shoulder, helping us avoid such bugs. If you are sure that you solve the described problems manually or if they are not important to you, then everything is fine and you do not need to continue. But if you want Elm to keep a better eye on your i18n development, what are your options?
Type-safe translations
Since we have our translation files as JSON, we canelm i18n generationto generate onetranslations
Module containing a function for each translation in the JSON files. So let's try it.
Install it with the following command:
npminstall - GRAMSelm-i18n-gen
create a new onetranslations
Module for the application with the following command:
elm-i18n-gen public/locale src/Translations.elm
and when you open ittranslations
module you should see:
src/Translations.elm
Module translations expose (..)type Language = In | ES | YgetLnFromCode : line -> LanguagegetLnFromCode Code = Fall Code Von "In" -> In "Es" -> ES "Y" -> Y _ -> InVerticalCenterInCssIsSimple : Language -> lineVerticalCenterInCssIsSimple language = Fall language Von In -> "Vertically centering things in CSS is easy!" ES -> "Vertical centering with CSS is easy!" Y -> "Vertical centering with CSS is easy! "
We only have one translation key in our JSON files, soelm-i18n-gen
created just one feature for us that covers translations for all of our languages. You can also see here that I adoptedelm-i18n-gen
The naming conventions specific toLanguage
, YgetLnFromCode
in advance, and intentionally put this information in thetranslations
module knowing that it will be overwritten when the newtranslations
the file was generated (... I think mineChekhov's gunstuck...).
Anyway, now that we have our function, let's use it in the view:
src/Main.elm
-- ...matter translations expose (Language)-- ...vista : Model -> HTML Newsvista Model = permission -- ... In first of all_ [ classes ] [ language dropdown menu.vista Model , Content Model.current language ]Content : Language -> HTML NewsContent Language = permission -- ... In Article [ ArticleClasses ] [ division [ divclases ] [ titular Language ] ]titular : Language -> HTML Newstitular Language = permission -- ... In h1 [ classes ] [ Text (translations.VerticalCenterInCssIsSimple Language) ]
The implications of this change are as follows:
- It is no longer necessary to search for the translations and, therefore, neither
Get Translations
News
, Dielook up translations
function in theBefore
module, whichtranslations
entrance inModel
, and any trace of theI18Weiter
YHttp
Packages can now be safely removed. - Consequently, the problem of displaying a translation key before the translation is loaded has disappeared since now we only call one function.
- Elm generates a compile error if a translation is not provided for all languages.
Those are some pretty cool perks! I'm not sure if there are any downsides to this, other than maybe there is a single module with potentially hundreds of functions for a large JSON translation file. But I guess the maintenance overhead for this module would be the same for the JSON file. Please let me know if I'm wrong about this!
VerDie6 types of safe translations
Zweigmy codebase to see the final form of the app with all redundant code removed.
Diploma
Even after all this, I'm still not sure what to think about an ideal solution for I18n on Elm. I plan to use the methods outlined in this blog post for now, but if you have better ways of doing things (I'd love to see a real example of an app that does thescience fiction-i18npackage), please let me know!