Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for runtime translations #305
Add support for runtime translations #305
Changes from 9 commits
a26f0b9
fa94a8e
63aea14
1aca9b3
32c1339
5fb99e1
35dfb30
6991fb9
853fec5
904219f
17d8397
cb5aabb
8eb0bce
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually leave it as responsibility of the runtime backend to call interpolation, specially now that the interpolation module is public API. This will give more flexibility too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also do that for the plural module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case no because I can’t think of them having different plural rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why would one change the interpolation module on a per-message basis? In the current way they can already replace on a per-translator basis.
If we require the repo to implement that, this would mean that a change from one interpolator to another now would need to be done in two different places (in the translator where
use Gettext
is called) and in the repo itself (or at least by passing as a parameter on the repo configuraiton.I think that would be more confusing, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would vote that the interpolation is done outside the implementation. Ther reason for this is, that nothing is preventing me from interpolating values inside the implementation as well. This way you can do whatever you want inside the implementation and we will make sure that interpolation is handled if there is bindings remaining in the message.
As for the pluralalization: It should normally always be the same for a given locale and is a bit complicated to get right. I would therefore:
@callback get_plural_forms(locale()) :: String.t()
Gettext.Plural.init/1
with thelocale
andplural_forms_header
set to the result of the callback to get theGettext.Plural.plural_info
Gettext.Plural.plural/2
with theplural_info
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I see there are two "philosophies" here and the path we choose I guess should be similar for both the plural forms and interpolation cases:
Options
Leave most of the implementation to the repo
In that case, we should:
n
to the repo and let it handle the plural_form partImplement "sane defaults"
For the interpolation part, I guess I agree with @maennchen: they can interpolate on their side even if we interpolate again here.
For the plural part, I guess we could just have an optional callback as he suggested. However we probably want to pass more info to that, something like:
repo.plural_info(locale, %{domain: domain, plural_mod: plural_mod})
. The reason for includingdomain
is that it might be the case where in the same locale we need different nplurals like the chinese example given in #343 (comment)This mean we could do:
Some thoughts
Two scenarios I see for runtime translations are:
.po
files using something like s3fs or SergeFor the first case, letting the implementation decide on the plural form should be not an issue since such solution would already require some knowledge of how
.po
files work (since they need to parse it and because the plural forms can change when re-syncing the files). But this is a slightly more advanced use case and can probably be solved by implementingplural_info
.For the second case, passing the
plural_form
would make so an unexperienced implementer have a direct mapping between theGettext.Repo
callback signature and anEcto.Schema
avoiding them having to think too much on how to convertn
intoplural_form
so they can easily implement something like:Which is pretty simple and easy to implement without digging too deep into how Gettext work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josevalim @whatyouhide sorry for the tag, whenever you had time could you give your thoughts on the matter? I can then make the changes depending on what you folks prefer.
(I'm tagging because it could not be clear that we would like your opinion and not just a discussion between me and @maennchen, sorry for the notification)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really not sure here. I agree on the point that we want to handle interpolation anyways in Gettext, and implementers of a Gettext repo can do whatever they want, including interpolating. As for the locale, how does it relate to d55aeb0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So to keep it simple, d55aeb0 didn't directly affected this PR but created a gap in feature parity between runtime and compile-time.
Before, the runtime version was computing the plural_forms based the plural module and sending it to the repo without a chance of the repo choosing it's plural form. To give a clearer use case:
To allow for that, I first thought about just sending
count
to the runtime repo and letting it handle the plural decision however it wishes. However, because plural form rules can be complicated @maennchen suggested to me that we should compute plural forms using the plural module defined but allow for an optional callback to get plural information.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that the name "repo" makes sense here. Should we call this something like
Gettext.TranslationFetcher
? After all, the documentation says that this is a "behaviour for modules that can fetch Gettext translations".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, good point. I don't think Repo is completely bad though, as fetching a translation will fetch from a place where the transltions are "stored", a "translation repository". However,
TranslationFetcher
orMessageFetcher
could reveal better the intention of retrievingmsgstr
/translation
.Summing up, aesthetic-wise I think
Repo
is nicer but maybe it is not clear enough. I'd be down to whatever you prefer.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also put in the fact that it is runtime fetching into the name as well. If we for example ever allow a compiled strategy that reads
.mo
files, we could come up with another compile time strategy, which would for sure have a different set of callbacks than the runtime ones have.=>
Gettext.RuntimeTranslationFetcher
?