-
Notifications
You must be signed in to change notification settings - Fork 397
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
improvement: Context #1281
improvement: Context #1281
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
As @nmorel said, it fixes the primary issue without changing the logic & structure already in place. I think it would be better to focus on this here, and if some changes should be made, tailor this in another PR. |
One thing I forgot to add, I'm not used to ramda 😅 |
Will review this afternoon guys, thanks for the hard work! |
@semoal is something in that PR what stops it from being merged? |
@andrii-bodnar I prefer to get feedback on the PR first before putting any more work on current branch. |
@andrii-bodnar @nmorel I reviewed the code in general it looks good to me. Here are my thoughts (doesn't mean you have to do this, just want to rise an opinion):
Example from other i18n project docs which I've found helpful:
But actually i want to rise a bigger discussion here, read at the end of the comment.
Discussion:Implementation offered in this PR is ok just as quick workaround for such essential feature as context. And this is fine. Part of this was already discussed here, I want to summarize. Current lingui implementation has a flaw: you have your original message in the bundle at least 2 times + 1 translation. This PR would also add even more kilobytes because for each msg which should have a context you would have context explicitly written in the bundle + in the msg catalog. A much better option would be generating a "stable" ID based on the msg + context as hash with fixed length.
And lookups in runtime would be much simpler. Hash would be calculated at build time by macros + compile time for catalogs. So macros instead of const message = t({
context: 'My context',
message: `Hello`
})
// ↓ ↓ ↓ ↓ ↓ ↓
import { i18n } from "@lingui/core"
const message = i18n._(/*i18n*/{
context: 'My context',
id: `Hello`
}) Would generate: import { i18n } from "@lingui/core"
const message = i18n._(/*i18n*/{
id: "<hash(message + context)>",
message: `Hello`, // only for development purpose, would be dropped in production
}) Compile catalog command would also calculate hashes from msg + context on the fly. However, there are amounts of users who use a lib without a macros. I don't know who they are and what were the reasons behind this decision. I think if you don't use a macro, you lose everything what making lingui awesome. Without a macro there are better alternatives with more stars and bigger community. So I think we should concentrate on one thing and do it well instead of supporting multiple different usages. This optional status of the macro and necessity of implementing all existing features in 2 modes adds additional complexity to the project and prevents the possibility of implementing some really cool features because we always should think about "runtime" users. Anyway, it would be great to know how many of users don't use a macro and how painful would be dropping support of the non-macro usage. @andrii-bodnar what do you think? We can discuss dropping non-macro usage separately somewhere. Depending on this, we can later decide a what to do with this PR. PS this proposal with build-time id generation still can be used without dropping non-macro users, but it would require 2 runtimes, 2 sets of tests and confusing setup options, that's why I want to avoid it. And avoid generating hashes at runtime as well. |
I read test snapshots carefully one more time and the following came up. If we bring "a default" context as was proposed, this brings "nested" structures to these catalog formats: Lingui (Raw) and Simple JSON catalog formats If we do that, we also need to provide an upgrade path for the users. This should be relatively simple. So I would say context feature not really compatible with supported JSON formats. Also generating a "hashed" id as proposed by me would definitely break simple JSON format flow, because key would no longer be an original string. That's another questions to discuss. |
Very well summarized on the structure. This PR was careful to not bring any breaking changes and only use what was previously attempted (but not finished) on context support. That's why there is no default context that would change the all structure to add one level in depth for everyone, not only context users. I totally agree that a better way to handle the internal structure (and json format) would be with key as hash. So instead of having 2 breaking changes in a row, I think it would be better to skip the default context improvement and immediately jump on all flat with key as hash. |
For the default context, it's possible I think to introduce it without breaking change. |
@nmorel could you elaborate on this more? |
If I take examples from here, we will have this with the current PR :
#: src/App.js:3
# Comment for translators
msgid "messageId"
msgstr "Translated Message"
#: src/App.js:4
# Comment for translators
msgctxt "messageCtxt"
msgid "messageId"
msgstr "Translated Message with ctxt"
{
"messageId": "Translated Message",
"messageCtxt": {
"messageId": "Translated Message with ctxt"
}
}
{
"messageId": {
"translation": "Translated message",
"defaults": "Default message",
"description": "Comment for translators",
"origin": [["src/App.js", 3]]
},
"messageCtxt": {
"messageId": {
"translation": "Translated Message with ctxt",
"defaults": "Default message",
"description": "Comment for translators",
"origin": [["src/App.js", 4]]
},
}
} We can keep this format and only introduce the default context internally with a structure like this : {
"<user context or default context>": {
"<message id>": {
"translation": "<message translation>",
"defaults": "<default message>",
"description": "<comments>",
"origin": [<origin1>, <origin2>]
}
}
} When parsing po files, if there is no context, we set the default context to the message. {
"messageCtxt": {
"__isContext__": true,
"messageId": {
"translation": "Translated Message with ctxt",
"defaults": "Default message",
"description": "Comment for translators",
"origin": [["src/App.js", 4]]
},
}
} When converting the internal structure to po/json/raw files, it won't be too hard to remove the default context. With this, we keep the format intact (except for message with context) and in lingui code, the structure is the same. But if you want to introduce the hash solution soon, is it really necessary ? 🙂 |
@nmorel @thekip thanks a lot for your involvement here! I'm still learning the Lingui and it's a bit hard to make decisions about the concerns above. @Martin005 maybe you will have some thoughts? Anyway, we'd like to introduce this feature in the nearest release. It's important to keep it backward compatible and not to provide any breaking changes for now. Could you please guys briefly summarize what is currently blocking this PR? And a small general question - what's the difference between |
@andrii-bodnar the problem here if we release current implementation we would be forced to maintain it as it is right now. But the current approach has many flaws and will limit us in the implementing of new features. So instead of making a release right now and returning to this question again and again in future we propose to implement it properly from the begining and probably ship it as version 4.
This is a common for i18n process to have both. They might be called differently, f ex. meaning / description or context / comment as in Lingui. The purpose of context is provide few different translation for one source message:
Unlike context, comment don't affect message id generation, and used just as an additional information for the translator. |
Just to throw another stone here: it seems better to do things right, with a v4, if the v4 is really coming soon. But if it is coming soon, then there is no worries about supporting the v3, so the argument about being forced to maintain it turn void. So ship it quick and iterate would be better and non blocking. On the contrary if the v4 is not coming soon, then it is also better to ship it now in v3 (maybe with the changes @nmorel explain above). TLDR; in both cases I think it is better for users to ship it now. |
Suppressed by #1440 |
Hello 👋
@JSteunou and I needed the context to work for our company so we tried to fix the different issues we encountered with the current implementation.
We tried to follow the same "schema" for the internal structure and limit the changes.
It works (closes #1198) but it has some flaws.
For an example of the structure, for this file, it gives the following on extraction :
With this, we no longer have a flat structure and context add another level.
We now have at the same level a key that can represent a message id or a context.
At various location, I added a test to know which one I'm manipulating.
If a user needs to translate the words
origin
ortranslation
with a context, it breaks.This structure also add lots of complexity.
Before we fix the remaining issues, what do you think ?
Should we change something ?
Some solutions we thought about but wanted your impressions first :
For a complete example, I updated one of the repository example (the ^3.14.1 version references a local version I built).