Closed adrianbunea closed 2 years ago
Hi there, thanks for opening this issue.
Hmm, YAML format. That's quite new use case. Originally this lib was created around the need for using JSON translations files.
Your the first one who's aksed about YAML but I can see how yaml is a nice format and I'm willing to consider adding this if it makes sense overall and doesn't bloat this lib too much.
Here's some thoughts in my head
elm/*
(not a must, but nice and makes maintenance easier). Given Elm Dead code elimination this wouldn't be a cost though for users that aren't using the yaml decoder.Unfortunately I cannot attach an yml
file, Github won't let me.
here is how it looks though:
en:
questions:
food:
favorite_food: 'What is your favorite food?'
hungry: 'Are you hungry?'
when_is_dinner: 'When is dinner?'
reuse_example1: &reuse 'This can be reused in other places'
reuse_example2: *reuse
YAML allows reusing translations using & and *, according to this https://stackoverflow.com/questions/8466223/reuse-a-block-of-code-in-yaml
I was wondering if there's a more generic to provide a tree decoder that let's the user pass decoders for strings and objects respectively but not make the user implement the entire tree decoder logic. Does this make sense to you?
I think I understand your point, I was thinking of a way for your main decoder to allow providing smaller decoders for its primitives: string
, int
, List
, Dict
etc. and that way I could provide the decoders from the YAML library to your main decoder.
Thanks for sharing the yaml example.
Yeah, what you said about passing primitive decoders is pretty close to what I meant. Expect the primitives can only be for dict/object
or string
. That's how the Tree
is defined https://package.elm-lang.org/packages/ChristophP/elm-i18next/latest/I18Next#Tree
I checked the only yaml package in elm that I know https://github.com/terezka/yaml. I think a string
would be easily doable but I couldn't find a dict
or keyValuePairs
decoder in the package. Although there are two PRs open that aim to add those. do you have an idea about how you would parse your yaml into a tree structure consisting of key-value pairs and strings (on the leaves of the tree) with the functions that are currently supported by that package or another yaml package you may know of?
The YAML library you posted was the only one I knew about until I looked around. This one looks dead, but one of the guys that posted a PR published their own fork, here and it has more tools at its disposal. Using it I made this Ellie app to try the decoding capabilities. P.S. To my absolute amazement, the references are also being decoded correctly :exploding_head:
Ah, nice that someone forked and extended it. Also cool it parses thoses references correctly.
Alright then I will give it a try to expose a generic decoder that can work with the yaml string and dict decoders.
Will let you when I got some results.
Hi, any news on this?
Hi @adrianbunea , I'm sorry I was busy with other stuff. Thanks for reminding me. Will look into it tonight. Will post a status in the next few days as soon as I got something.
@adrianbunea I've thought about this for a while now and also got stuck a few times. Here are the options I tried to explore. I'd like to get your feedback on this.
elm/json
for it but I quickly found that that would fail when decoding anything other than JSON.elm/json
by using Strings and elm/parser
. But when I looked at https://package.elm-lang.org/packages/MaybeJustJames/yaml/latest/Yaml-Decode I noticed they also use their own Decode type, so Parser
is not a common denominator between ChristophP/elm-i18next
and that package.Translations
. But you already mentioned that having to do that, would take away much of the usefulness of this library and I pretty much agree.yamlTreeDecoder : Yaml.Decoder I18Next.Tree
yamlTreeDecoder =
Yaml.oneOf
[ Yam.string |> Yaml.map I18Next.string
, Yaml.lazy |>
(\_ -> Yaml.dict yamlTreeDecoder |> Yaml.map I18Next.object)
]
This is very similar to the json implementation in this lib https://github.com/ChristophP/elm-i18next/blob/4.2.0/src/I18Next.elm#L153-L159 and only a couple of lines. The decoder yields a I18Next.Tree
value.
Now this is just one step away from being able to be converted to a full Translations
value.
yamlTranslationsDecoder : Yaml.Decoder I18Next.Translations
yamlTranlsationsDecoder =
Yaml.dict yamlTreeDecoder |> Yaml.map (Dict.toList >> I18Next.fromTree)
What do you think of that? Would that be a viable solution? I would even consider adding documentation on how to do this and exposing another variant of the fromTree
function to reduce the last step to this:
yamlTranslationsDecoder : Yaml.Decoder I18Next.Translations
yamlTranlsationsDecoder =
Yaml.dict yamlTreeDecoder |> Yaml.map I18Next.fromDictTree
What are you thoughts on the points and the proposed solution? If you have any ideas that would make a generic decoder possible after all please let me know.
So, you propose to have a recipe for the YAML formats documented in the README? It sounds like an acceptable solution for now. I was thinking the problem was the library's coupling to the Elm Json Decode library, but it seems to be a core library of Elm and a sensible default so I can't really complain. These being said, point 3 is still not completely satisfied, some of the useful stuff provided by the library are left unused like this, but this might be the sacrifice that needs to be made.
If this is what you meant, then I think it would be useful to have recipes for other formats other than JSON, and people could add to the list as other formats need support.
With a change in perspective, I could see elm-i18-next
as a format agnostic library, with the main utility being the I18Next.string
, I18Next.object
and I18Next.fromTree
to create any Decoder necessary. The JSON built-in decoder would just be a sensible default provided by the library.
As a side note, I am still considering a possible solution to provide a configuration to the main Decoder, in the form of a Record with fields not just for the primitives, but for the map
, lazy
and oneOf
functions as well. And the library would just use those. Of course, this might prove impossible once we actually try it.
I am also curious what you would think of a Fork of this Repo that handles YAML instead of JSON instead?
Hi @adrianbunea ,
If this is what you meant, then I think it would be useful to have recipes for other formats other than JSON, and people could add to the list as other formats need support.
Yes something like a recipe is pretty much what I had in mind.
As a side note, I am still considering a possible solution to provide a configuration to the main Decoder, in the form of a Record with fields not just for the primitives, but for the map, lazy and oneOf functions as well. And the library would just use those. Of course, this might prove impossible once we actually try it.
Yes, let me know please if you find a way to make that work. My attempts didn'y go anywhere because I couldn't find a way to make Decoder
part generic in Decoder something
. Not sure if that's even possible in Elm.
I am also curious what you would think of a Fork of this Repo that handles YAML instead of JSON instead?
I that helps you that would definitely be an option. However, forking the entire package might not even be necessary. For example maybe it would just be enought to write a package which provides a decoder which turns YAML into Translations
. All the other functions in this lib could be reused. What do you think of that?
Recipes, or another package that adds the extra functionality would both work for me, I think the extra package might be a cleaner solution. But I cannot tell you which direction to take the package you created, in the end it is your call, all I can do is give my opinion, that I lean toward the extra package that people can opt for if they need to.
I'm closing this one. I think the best way would be to have a separate package that exposes the Yaml decoder by whoever wants to maintain it.
Hi. I'm curious how I could use this package if the translations were provided as YAML? I think there would be a few ways and I don't know which is the best.
On the user side:
Tree
and use it to generateTranslations
usingfromTree
. This is a pretty roundabout way and I think it would miss out on some of the benefits of using your library (your decoder).On the package side: