-
Notifications
You must be signed in to change notification settings - Fork 378
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
RFC-001 - Macros #318
RFC-001 - Macros #318
Conversation
Codecov Report
@@ Coverage Diff @@
## master #318 +/- ##
==========================================
+ Coverage 95.52% 95.86% +0.34%
==========================================
Files 43 49 +6
Lines 1140 1379 +239
==========================================
+ Hits 1089 1322 +233
- Misses 51 57 +6
Continue to review full report at Codecov.
|
<a | ||
className="expression" | ||
href="/article" | ||
title={i18n._(t`Full content of ${articleName}`)} |
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.
Is it really an improvement considering how it was looking before? :) Was the previous approach working? I am not sure, haven't used that. Also, I think that in gitter we were talking about a variant like that which would be much nicer imo.
i18n(t`Full content of ${articleName}`)
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.
You mean i18n.t
over i18n._(t
? It's necessary to move to macros... I don't think there's a way to have a object property to be a macro.
Other way would be convert it to i18n._
directly, but for that we would need i18n
in scope, which wouldn't be used otherwise and linter would complain.
This approach is very flexible, but the only drawback is how it looks :/ But you really get used to it. I wrote vanilla-js
example and it was so great.
i18n(t
is planned, I just have to figure out how to create callable object. I already started working on it but then figure out this is not the core of the problem and can be done later. Both i18n._(..)
and i18n(...)
will be supported anyway until v3.
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.
And yeah, the previous approach had several problems, especially when plugins were misconfigured. It doesn't allow you to use this.props.i18n.t
, because only i18n.t
worked. You couldn't use it with i18n.use
method, which switches language locally (i18n.use('cs')._(t...)
). And also for lazy messages you had to use different API, i18nMark
. Now there's the same API for all messages, lazy/immediate translations, with/without IDs.
As I said, I like everything about it except how it looks... but I believe it won't be such a problem once we have i18n(t...)
API.
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.
Well, a "callable object" is just a function with additional properties/methods attached directly to it. There is nothing wrong about that in my opinion and it will make it much easier to use and look at :)
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.
Cool! I believe there's nothing wrong with it as well, but it felt a bit hackish :) I'm halfway through with implementation, which I saved in different branch. I'll finalize it soon.
@FredyC I've added checklist to PR description, so it's clear what's missing. I would like to release an early version asap, so I can play with it and get some feedback. |
@tricoder42 Right ... I am a bit preoccupied for the next couple of days, but I will try to have a look occasionally. |
@FredyC Making https://stackoverflow.com/questions/12656079/constructor-for-callable-object-in-javascript After fiddling a bit, I come up with this solution: import { setupI18n as legacySetupI18n, I18n as legacyI18n } from "@lingui/core"
export function setupI18n(params = {}) {
const i18n = legacySetupI18n(params)
function _() {
return i18n._.apply(i18n, arguments)
}
// this is unsupported by flow
_.__proto__ = i18n
return _
} The only problem is that the line I would appreciate any help here :) |
I don't think you need to care about prototype at all. Instead of having function setupI18n(params = {}) {
let _language: string
let _locales: ?Locales
// all other private properties
// this is instead of a current `constructor`
function i18n() {
if (process.env.NODE_ENV !== "production") {
this.t = t
this.select = select
this.plural = plural(this)
this.selectOrdinal = selectOrdinal(this)
}
}
Object.assign(i18n, {
get availableLanguages(): Array<string> {
return Object.keys(this._catalogs)
}
get language(): string {
return this._language
}
get locales(): ?Locales {
return this._locales
}
// etc...
})
return i18n
} |
35f34fe
to
b8691d3
Compare
Yeah, but you're not creating a callable object. What you have is a pattern to create an object with some method on contructor (you should assign properties to i18n.prototype, btw). What we need is a function and somehow assign a i18n object to function's prototype. That way the function is callable, but "inherits" properties/methods from i18n object. I've just moved proto assignment to external file to make Flow happy and added flow types in recent commit: b8691d3. It works. I tried few variation, but this is the only one which works. Not sure if there's a better way, but suggestions welcome :) |
b8691d3
to
7562f39
Compare
Alright, I reverted this commit and moved it to https://github.com/lingui/js-lingui/tree/rfc/001-macros-callable-i18n branch... It's more complex than expected and it need to think through. EDIT: integration tests failed, because language switching doesn't work. Not sure if it's caused by mixing ES6 classes with classical prototypal inheritance, or by setting prototype of a Function. |
Let's ship the pig and see how it works 🤞 |
I don't think you are right about this. Even if you look at the Flow doc I've linked, they are creating callable object like this. It's the exact same approach I've drafted above. function add(x, y) {
return x + y;
}
add.bar = "hello world"; Yes, every function can be a constructor, you can call it with I don't think I am going to use this "pig" just yet, because it's too ugly to have in the code :) |
I have to review it again. These things just give me a headache. And common, it's not that bad :) |
I guess this is a limitation of macros, they are nice and all, but with reliability on actual imports, it makes it much verbose. But would it be too bad to have a separate optional babel plugin that could convert current |
We'll see. I would like to have just a one way how to do these things, otherwise it's gonna be harder to maintain |
Implementation of RFC-001.
Resolves #298
Resolves #258
Resolves #197
Work in progress:
In next batch:
i18n(...)
API as a shortcut fori18n._(...)