Skip to content
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

Merged
merged 19 commits into from
Sep 10, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/webpack-react-macros/src/App.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import * as React from "react"

import { I18nProvider, i18nMark } from "@lingui/react"
import { Trans } from "@lingui/react.macro"
import { I18nProvider } from "@lingui/react"
import { t, Trans } from "@lingui/macro"

import NeverUpdate from "./Usecases/NeverUpdate"
import Children from "./Usecases/Children"
import ElementAttributes from "./Usecases/ElementAttributes"
import Formats from "./Usecases/Formats"

const languages = {
en: i18nMark("English"),
cs: i18nMark("Czech"),
fr: i18nMark("French")
en: t`English`,
cs: t`Czech`,
fr: t`French`
}

export default class App extends React.Component {
Expand Down
2 changes: 1 addition & 1 deletion examples/webpack-react-macros/src/Usecases/Children.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import * as React from "react"
import { Trans, Select, Plural } from "@lingui/react.macro"
import { Trans, Select, Plural } from "@lingui/macro"

type ChildrenPropTypes = {
name?: string,
Expand Down
42 changes: 21 additions & 21 deletions examples/webpack-react-macros/src/Usecases/ElementAttributes.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
// @flow
import * as React from "react"
import { withI18n } from "@lingui/react"
import { Trans } from "@lingui/react.macro"
import { t } from "@lingui/js.macro"
import { I18n } from "@lingui/react"
import { t, Trans } from "@lingui/macro"

type ElementAttributesProps = {
i18n: Object
}

class ElementAttributes extends React.Component<ElementAttributesProps> {
export default class ElementAttributes extends React.Component<
ElementAttributesProps
> {
props: ElementAttributesProps

render() {
const { i18n } = this.props
const articleName = "Scientific Journal"
const closeLabel = t`Close`

return (
<div>
<Trans>
<a
className="expression"
href="/article"
title={t`Full content of ${articleName}`}
>
Article
</a>
</Trans>
<button className="variable" aria-label={closeLabel}>
X
</button>
</div>
<I18n>
{({ i18n }) => (
<div>
<a
className="expression"
href="/article"
title={i18n._(t`Full content of ${articleName}`)}
Copy link
Contributor

@danielkcz danielkcz Sep 10, 2018

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}`)

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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 :)

Copy link
Contributor Author

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.

>
<Trans>Article</Trans>
</a>
<button className="variable" aria-label={i18n._(closeLabel)}>
X
</button>
</div>
)}
</I18n>
)
}
}

export default withI18n()(ElementAttributes)
2 changes: 1 addition & 1 deletion examples/webpack-react-macros/src/Usecases/Formats.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react"
import { Trans, NumberFormat, DateFormat } from "@lingui/react.macro"
import { Trans, NumberFormat, DateFormat } from "@lingui/macro"

export default class Formats extends React.Component {
render() {
Expand Down
8 changes: 5 additions & 3 deletions examples/webpack-react-macros/src/Usecases/PureComponent.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
import * as React from "react"
import { withI18n } from "@lingui/react"
import { t } from "@lingui/js.macro"
import { t } from "@lingui/macro"

type PureComponentTestProps = {
children?: any,
Expand Down Expand Up @@ -35,7 +35,7 @@ const CorrectUpdate = withI18n()(

render() {
const { i18n, value } = this.props
return <span className="valid">{t`The value is: ${value}`}</span>
return <span className="valid">{i18n._(t`The value is: ${value}`)}</span>
}
}
)
Expand All @@ -46,7 +46,9 @@ const SkippedUpdate = withI18n({ withHash: false })(

render() {
const { i18n, value } = this.props
return <span className="invalid">{t`The value is: ${value}`}</span>
return (
<span className="invalid">{i18n._(t`The value is: ${value}`)}</span>
)
}
}
)
Expand Down
1,032 changes: 540 additions & 492 deletions examples/webpack-react-macros/src/Usecases/__snapshots__/Children.test.js.snap

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,125 +2,137 @@

exports[`Formats should render 1`] = `
<Component
language="en"
language=en
>
<I18nProvider
catalogs={
Object {
"en": Object {},
en: Object {},
}
}
defaultRender={null}
language="en"
language=en
>
<Formats>
<div>
<ul>
<li>
<withI18n
className="percent"
id="The answer is {answer,number,percent}"
<WithI18n
className=percent
id=The answer is {answer,number,percent}
values={
Object {
"answer": 0.42,
answer: 0.42,
}
}
>
<Trans
className="percent"
i18n={
I18n {
"_activeLanguageData": Object {
"plurals": [Function],
},
"_activeMessages": Object {},
"_catalogs": Object {
"en": Object {
"languageData": Object {},
"messages": Object {},
<I18n
update={true}
withHash={true}
>
<Trans
className=percent
i18n={
I18n {
_activeLanguageData: Object {
plurals: [Function],
},
_activeMessages: Object {},
_catalogs: Object {
en: Object {
languageData: Object {},
messages: Object {},
},
},
_dev: Object {
compile: [Function],
loadLanguageData: [Function],
},
},
"_dev": Object {
"compile": [Function],
"loadLanguageData": [Function],
},
"_language": "en",
"_locales": undefined,
"plural": [Function],
"select": [Function],
"selectOrdinal": [Function],
"t": [Function],
_language: en,
_locales: undefined,
_missing: undefined,
plural: [Function],
select: [Function],
selectOrdinal: [Function],
t: [Function],
}
}
}
i18nHash={null}
id="The answer is {answer,number,percent}"
values={
Object {
"answer": 0.42,
i18nHash={null}
id=The answer is {answer,number,percent}
values={
Object {
answer: 0.42,
}
}
}
>
<Render
className="percent"
value="The answer is 42%"
>
The answer is 42%
</Render>
</Trans>
</withI18n>
<Render
className=percent
value=The answer is 42%
>
The answer is 42%
</Render>
</Trans>
</I18n>
</WithI18n>
</li>
<li>
<withI18n
className="date"
id="Today is {now,date}"
<WithI18n
className=date
id=Today is {now,date}
values={
Object {
"now": 2017-04-05T11:14:00.000Z,
now: 2017-04-05T11:14:00.000Z,
}
}
>
<Trans
className="date"
i18n={
I18n {
"_activeLanguageData": Object {
"plurals": [Function],
},
"_activeMessages": Object {},
"_catalogs": Object {
"en": Object {
"languageData": Object {},
"messages": Object {},
<I18n
update={true}
withHash={true}
>
<Trans
className=date
i18n={
I18n {
_activeLanguageData: Object {
plurals: [Function],
},
_activeMessages: Object {},
_catalogs: Object {
en: Object {
languageData: Object {},
messages: Object {},
},
},
_dev: Object {
compile: [Function],
loadLanguageData: [Function],
},
},
"_dev": Object {
"compile": [Function],
"loadLanguageData": [Function],
},
"_language": "en",
"_locales": undefined,
"plural": [Function],
"select": [Function],
"selectOrdinal": [Function],
"t": [Function],
_language: en,
_locales: undefined,
_missing: undefined,
plural: [Function],
select: [Function],
selectOrdinal: [Function],
t: [Function],
}
}
}
i18nHash={null}
id="Today is {now,date}"
values={
Object {
"now": 2017-04-05T11:14:00.000Z,
i18nHash={null}
id=Today is {now,date}
values={
Object {
now: 2017-04-05T11:14:00.000Z,
}
}
}
>
<Render
className="date"
value="Today is 4/5/2017"
>
Today is 4/5/2017
</Render>
</Trans>
</withI18n>
<Render
className=date
value=Today is 4/5/2017
>
Today is 4/5/2017
</Render>
</Trans>
</I18n>
</WithI18n>
</li>
</ul>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-plugin-extract-messages/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export default function({ types: t }) {

const props = attrs.reduce((acc, item) => {
const key = item.name.name
if (key === "id" || key === "defaults") {
if (key === "id" || key === "defaults" || key === "description") {
if (item.value.value) {
acc[key] = item.value.value
} else if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ Object {
],
},
msg.hello: Object {
description: Description,
origin: Array [
Array [
packages/babel-plugin-extract-messages/test/fixtures/jsx/all.js,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Trans } from "@lingui/react"
;<span id="ignore" />
;<Trans /> // this should be ignored
;<Trans defaults="Missing ID" /> // this should be ignored
;<Trans id={"msg.hello"} />
;<Trans id={"msg.hello"} description="Description" />
;<Trans id="msg.default" defaults="Hello World" />
;<Trans id="msg.default" defaults="Hello World" />
;<Trans id="Hi, my name is <0>{name}</0>" values={{ count }} />
Expand Down
Loading