Closed diegolacarta closed 3 years ago
Hey @diegolacarta, what version of Lingui do you have?
"@lingui/cli": "2.7.2", "@lingui/loader": "2.7.2", "@lingui/macro": "2.7.2", "@lingui/react": "2.7.2",
Could you please also post your Babel config? Do you have babel-plugin-macros
enabled?
{
"env": {
"local": {
"presets": ["@babel/preset-react", "@lingui/babel-preset-react"],
"plugins": [
["@babel/plugin-syntax-dynamic-import"],
["macros"],
[
"emotion",
{
"sourceMap": true,
"autoLabel": true
}
],
[
"react-intl",
{
"messagesDir": "./i18n/messages/",
"extractSourceLocation": true
}
]
]
}
}
}
react-intl in there just while transitioning away from it
That looks good. Could you also please show how babel transforms the file with i18n? babel src/file.with.i18n.js
Finally, does extract work for Trans
imported from @lingui/macro
package?
There's also an example repo with js-macros (no React): https://github.com/lingui/js-lingui/tree/master/examples/vanilla-js Maybe it would help you find the root cause.
That looks good. Could you also please show how babel transforms the file with i18n?
babel src/file.with.i18n.js
Finally, does extract work for
Trans
imported from@lingui/macro
package?
I'm using typescript, following the setup from https://github.com/lingui/js-lingui/blob/master/docs/guides/typescript.rst
I could debug at which point babel plugin is not doing what it should, or if you could point me into where to look that'd help
Trans doesn't work when imported from @lingui/macro:
<Trans>random text</Trans>
...
> Missing message ID, skipping.
> <Trans>random text</Trans>
Right, so now we now the macros doesn't work.
It would be great to see how transpiled source code looks like. Unfortunately I don't use Typescript, but maybe you run TS before Babel?
Also not even this works:
import { setupI18n } from '@lingui/core';
import { t } from '@lingui/macro';
const i18n = setupI18n()
i18n._(t`Hello`)
This is the final code after building with webpack:
Original:
import {setupI18n} from '@lingui/core'
import {t} from '@lingui/macro'
const i18n = setupI18n()
i18n._(t`Hello`)
Transpiled:
! function(e) {
function r(r) {
for (var n, i, l = r[0], f = r[1], c = r[2], a = 0, s = []; a < l.length; a++) i = l[a], o[i] && s.push(o[i][0]), o[i] = 0;
for (n in f) Object.prototype.hasOwnProperty.call(f, n) && (e[n] = f[n]);
for (p && p(r); s.length;) s.shift()();
return u.push.apply(u, c || []), t()
}
function t() {
for (var e, r = 0; r < u.length; r++) {
for (var t = u[r], n = !0, l = 1; l < t.length; l++) {
var f = t[l];
0 !== o[f] && (n = !1)
}
n && (u.splice(r--, 1), e = i(i.s = t[0]))
}
return e
}
var n = {},
o = {
0: 0
},
u = [];
function i(r) {
if (n[r]) return n[r].exports;
var t = n[r] = {
i: r,
l: !1,
exports: {}
};
return e[r].call(t.exports, t, t.exports, i), t.l = !0, t.exports
}
i.m = e, i.c = n, i.d = function(e, r, t) {
i.o(e, r) || Object.defineProperty(e, r, {
enumerable: !0,
get: t
})
}, i.r = function(e) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value: !0
})
}, i.t = function(e, r) {
if (1 & r && (e = i(e)), 8 & r) return e;
if (4 & r && "object" == typeof e && e && e.__esModule) return e;
var t = Object.create(null);
if (i.r(t), Object.defineProperty(t, "default", {
enumerable: !0,
value: e
}), 2 & r && "string" != typeof e)
for (var n in e) i.d(t, n, function(r) {
return e[r]
}.bind(null, n));
return t
}, i.n = function(e) {
var r = e && e.__esModule ? function() {
return e.default
} : function() {
return e
};
return i.d(r, "a", r), r
}, i.o = function(e, r) {
return Object.prototype.hasOwnProperty.call(e, r)
}, i.p = "\x3c!-- server-replace:PUBLIC_PATH --\x3e/";
var l = window.webpackJsonp = window.webpackJsonp || [],
f = l.push.bind(l);
l.push = r, l = l.slice();
for (var c = 0; c < l.length; c++) r(l[c]);
var p = f;
u.push([39, 1]), t()
}({
39: function(e, r, t) {
e.exports = t(40)
},
40: function(e, r, t) {
"use strict";
t.r(r);
var n = t(38);
Object(n.setupI18n)()._({
id: "Hello"
})
}
});
I just tried changing my .linguirc to:
{
"localeDir": "src/locales/",
"srcPathDirs": ["src/"],
"format": "po",
"extractBabelOptions": {
"plugins": ["@babel/plugin-syntax-dynamic-import", "macros"]
}
}
Adding "macros" it now extracts the message with both \<Trans/> from marcos, and i18n._(t`...`), but doesn't translate it
and then finally adding: "presets": ["@babel/preset-react", "@lingui/babel-preset-react"],
to .linguirc seems to make everything work as expected.
I thought it would pick up my .babelrc from the project
Interesting. What's your project structure? Do you have .babelrc
right next to the package.json
? And how do you run the lingui extract
command?
yes, .babelrc is at same level as package.json, and I run lingui extract via npm script: npm run extract-locales
Could you please share minimal example so I can take a look? It should work as you described, pick the config from .babelrc
will try to reproduce when I find some time
I'm having the same issue with lingui extract
not picking up strings from i18n._(t`...`)
. I'm importing t
from @lingui/react
, since my project is on React Native and macros don't work (babel-plugin-macros
tries to import Node standard modules path
, os
and fs
when I import Trans
from @lingui/macros
, should it actually work?). The docs don't mention anything about using lingui without macros though, is it possible?
Using Trans
from @lingui/react
works just fine though. Strings get extracted, catalogs are compiled and no errors are thrown during runtime.
Any help is much appreciated. π
EDIT: Actually, t
is not part of @lingui/react
is it? π It seems the whole problem is simply that macros aren't working, so of course I can't use t
, and strings using it aren't being extracted.
I'm facing similar issue. The whole extraction behaves very weird/doesn't work.
Versions:
$ yarn list --depth 0 --pattern @lingui
yarn list v1.13.0
ββ @lingui/babel-plugin-extract-messages@2.8.3
ββ @lingui/babel-plugin-transform-js@2.8.3
ββ @lingui/babel-plugin-transform-react@2.8.3
ββ @lingui/cli@2.8.3
ββ @lingui/conf@2.8.3
ββ @lingui/core@2.8.3
ββ @lingui/macro@2.8.3
ββ @lingui/react@2.8.3
config:
const config = {
compileNamespace: 'es',
format: 'minimal',
localeDir: 'public/locale',
srcPathDirs: ['src'],
};
module.exports = config;
import React from 'react'
import {Trans} from '@lingui/macro'
// Missing message ID, skipping. <Trans>Continue</Trans>
const App = () => <div><h1>hello</h2><button><Trans>Continue</Trans></button></div>
// Works -> {
"continue": ""
}
const App = () => <div><h1>hello</h2><button><Trans id="continue">Continue</Trans></button></div>
Plural
doesn't work with id
import React from 'react';
import { Plural } from '@lingui/macro';
const App = () => {
return (
<div>
/* WORKS ->
"{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}": "{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}"
*/
<Plural
one="At least # lower-case letter"
other="At least # lower-case letters"
value={count}
/>
/* doesn't!
it even removes valid translation when run with --clean flag
*/
<Plural
id="validator.lowerCase"
one="At least # lower-case letter"
other="At least # lower-case letters"
value={count}
/>
</div>
);
};
What's super weird is that once I add id
to Plural
, then I run lignui extract --clean
,
->
{
-{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}": "{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}
+
}
after that, once I remove id
from plural and run lignui extract
again, it won't work anymore and generates nothing within messages.json
.
Hey @Hotell, what's your babel config? It seems you're mixing macros with plugins. You should use either one and not mix them together.
Ideally please create a repository with minimal example so we can debug the issue quickly.
what's your babel config?
const presets = [
[
'@babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 2,
// Do not transform modules to CJS
modules: IS_TEST ? 'commonjs' : false,
loose: true,
},
],
'@babel/preset-react',
'@babel/preset-typescript'
]
/** @type {import('babel').BabelConfigOptions['plugins']} */
const plugins = [
'@babel/plugin-syntax-dynamic-import',
['@babel/plugin-proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-object-rest-spread', { loose: true }],
'macros',
]
It seems you're mixing macros with plugins. You should use either one and not mix them together.
I'm not sure I follow
Also
Plural
gets caught when used from @lingui/react
Trans
from @lingui/macro
is used for plural it is caught within extraction as well <Trans id={ '{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}' } />
Ideally please create a repository with minimal example so we can debug the issue quickly.
I wished I'd have time for that hah. That's a non trivial request when taking into consideration the size of the project...
Also Plural gets caught when used from @lingui/react
If you use macros, definitely don't import Plural
from @lingui/react
.
In LinguiJS 2.x (current version), there're two ways how to transform components into ICU MessageFormat - plugins and macros:
Plugins:
@lingui/babel-plugin-transform-{js,react}
to .babelrc
Trans
, Plural
and other components from @lingui/react
Macros:
macros
to .babelrc
Trans
and other components from @lingui/macro
It seems you're using the second option, macros
. I just misinterpreted the dependencies.
I wished I'd have time for that hah. That's a non trivial request when taking into consideration the size of the project...
Well, the problem is somewhere in your configuration. If you look into examples
, you'll find working projects. The only way to figure out the problem is create a repository with one file, your babel config and install LinguiJS dependencies. If you don't have time, then I can't help you, sorry.
I'm using @lingui/macro
with v2 solely. It doesn't work with Plural
-> strangely enough id does when Trans
"low level" ICU is used directly <Trans id={ '{count, plural, one {At least # lower-case letter} other {At least # lower-case letters}}' } />
I'm gonna try to use v3 and get back here with results ( if there will be any )
In the meantime I appreciate your time and help βοΈ.
Cheers
Unfortunately, the v3 isn't production ready yet :/ See #334
I'll try to setup the repo this evening. I'm suspicious that it's either Typescript related (LinguiJS uses TypeScript 2.x, not Babel preset) or related to some babel plugins.
Unfortunately, the v3 isn't production ready yet :/ See #334
I'll try to setup the repo this evening. I'm suspicious that it's either Typescript related (LinguiJS uses TypeScript 2.x, not Babel preset) or related to some babel plugins.
I appreciate your efforts Tomas, but it's open source... In my experience it should be consumer responsibility to provide demo which simulates described "bug", not the authors. Our time as maintainers is very precious. So please don't waste your time on creating repro. I'll do it, when I find some time today...
cheers π
I know, youβre right. Iβm just open-source junkie - when I see a problem I canβt resist solving it. If I werenβt super busy at work right now, I would already start working on it ;)
Let me know if I can further help or clarify something.
Cheers On 26 Jun 2019, 16:01 +0200, Martin Hochel notifications@github.com, wrote:
Unfortunately, the v3 isn't production ready yet :/ See #334 I'll try to setup the repo this evening. I'm suspicious that it's either Typescript related (LinguiJS uses TypeScript 2.x, not Babel preset) or related to some babel plugins. I appreciate your efforts Tomas, but it's open source... In my experience it should be consumer responsibility to provide demo which simulates described "bug", not the authors. Our time as maintainers is very precious. So please don't waste your time on creating repro. I'll do it, when I find some time today... cheers π β You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.
Hmm so, I've converted weback js/flow/react example to typescript with latest versions of deps. Looks like works there (attached) Check Form
within Children.tsx
.
Everything works, hmm. Looks like I don't have @lingui/babel-plugin-transform-{js,react}
within dependencies at work (as it's not properly stated in the docs ?)
webpack-react-typescript.tar.gz
Iβm just open-source junkie - when I see a problem I canβt resist solving it I know, been there, don't that. don't do that :D
so after adding "@lingui/babel-preset-react": "2.8.3",
Plural
macro works.
Ups so I found the real culprit.
lingui
CLI doesn't work within monorepo...
It won't find root babel.config.js
. That's why it was behaving so strange all along...
No idea how to solve this situation...
What lingui cli needs to support is:
babelOptions: {
rootMode: 'upward',
},
HA! so actually that's supported already :D π
const config = {
extractBabelOptions: {
rootMode: 'upward',
}
}
Great, I'm glad you've figured it out.
So what's the summary? You have a monorepo, each package has it's own .babelrc
or they all use the root babel.config.js
? I'm just asking so I can include it in docs.
Cheers π
Yes, one babel.config.js
within root.
-> lingui.config.js
within root
-> lingui.config.js
per package(app) which extends/overrides from root
βοΈ
Hey @Hotell,
Just to confirm, did you make this work in a monorepo, in which Components are being translated?
I'd love to replicate what you did and when I get it working, I'll help @tricoder42 with the documentation.
I'm currently facing a similar problem with monorepos, I can get everything to work except Lingui, and it's crucial to the developer's experience.
Hey @Hotell,
Just to confirm, did you make this work in a monorepo, in which Components are being translated?
I'd love to replicate what you did and when I get it working, I'll help @tricoder42 with the documentation.
I'm currently facing a similar problem with monorepos, I can get everything to work except Lingui, and it's crucial to the developer's experience.
I have the same problem, any solution for monorepos?
I was able to get the extraction working in a monorepo setup.
We have multiple applications and shared common-ui
component library built with rollup.js.
In our case the problem was that we were configuring babel plugins directly through rollup rather than .babelrc
I was puzzled about how lignui actually works and then realized it uses .babelrc
so once I had that (using macros
plugin) the extraction worked.
Now there's a bigger / more interesting problem remaining. The component library will have its own catalog and it's unclear what's the right way to get that loaded.
Each app has a global provider:
<I18nProvider
language={i18nStore.language}
catalogs={i18nStore.catalogs}>
<MainContainer />
</I18nProvider>
But then somewhere deeper in MainContainer
we use a component that comes with its own catalog.
This adapte picks up the language provided by the upper provider and replaces the catalog with the internal one. Perhaps merging the catalog (or a way to provide fallback catalogs) would be better, just in case the shared components are wrapping components from outside (which get their catalog overriden)
export const withI18nAdapter = <P extends any>(
Component: React.ComponentType<P>
) =>
withI18n()((_props: P & withI18nProps) => {
const language = _props.i18n?.language ?? 'en';
return (
<I18nProvider language={language} catalogs={catalogs}>
<Component {...(_props as P)} />
</I18nProvider>
);
})
Then, when exporting the components
const ComponentI18n = withI18nAdapter(Component);
export { ComponentI18n as Component };
Hi Cosmin @clehene ,
did you get this to work somehow? i have the same situation. component library in monorepo. not sure how to get it to work. thanks, Cezar ps: @tricoder42 any input on this?
Hey @cezarneaga. Yes we built an adapter. Likely suboptimal, but it works. We can contribute it as a helper to lingui-js. Meanwhile I'm posting the code here
import { I18nProvider, withI18n, withI18nProps } from '@lingui/react';
import * as React from 'react';
import catalogRo from '../locales/ro/messages.js';
import catalogEn from '../locales/en/messages.js';
/**
*
* Similar to Lingui JS `withI18n` but wraps component with an i18n adapter
* that:
* * picks the `language` parameter from the provided `i18n` instance
* * changes the i18n catalog to the wrapped component's (internal) one
*
* embed-ui provider(lang1, catalog1) ->
* adapter => new provider(lang1, catalog2)
*
* TODO use defaults if instance not provided (we'll fail with undefined otherwise
* TODO load catalog dynamically
* TODO merge catalog message instead of override?
*
* @param Component to wrap
*/
export const withI18nAdapter: <P extends object>(
Component: React.ComponentType<P>
) => React.ComponentClass<
Pick<P & withI18nProps, Exclude<keyof P, keyof withI18nProps>>
> = <P extends object>(Component: React.ComponentType<P>) =>
withI18n()((props: P & withI18nProps) => {
const language = props.i18n?.language ?? 'en';
return (
<I18nProvider language={language} catalogs={catalogs}>
<Component {...(props as P)} />
</I18nProvider>
);
});
const catalogs = { ro: catalogRo, en: catalogEn };
And then in index.tsx
import { ActionSet } from './components/ActionSet';
const ActionSetI18n = withI18nAdapter(ActionSet);
export { ActionSetI18n as ActionSet };
New version has been released. Please check if the problem persist in the new version.
Hey @cezarneaga. Yes we built an adapter. Likely suboptimal, but it works. We can contribute it as a helper to lingui-js. Meanwhile I'm posting the code here
Thanks! would like to try the v3 and see if this is still needed.
Is the new behavior documented somewhere? I'd like to track that and change our code if that works.
@cezarneaga does 3 work properly? Can we remove the adapter?
@cezarneaga does 3 work properly? Can we remove the adapter?
On v3.x, practically you don't need withI18n for anything, macros work out of the box for example:
t`some translate`
and if you need i18n instance, you can directly import it from core
import { i18n } from "@lingui/core"
I'll try to find some time tomorrow to build a sample mono-repo with lingui 3 and multiple catalogs ππ»
That's great. How does it work with shared components libraries that contain catalogs?
In our case we have
There are going to be different instances / catalogs. How do these get reconciled?
That's great. How does it work with shared components libraries that contain catalogs?
In our case we have
- ui-1 - catalog-ui-1
- ui-2 - catalog-ui-2
- shared-components - catalog-shared-components
There are going to be different instances / catalogs. How do these get reconciled?
They get merged by locale internally, you have more information in lingui website on configuration section.
Tomorrow I'll expand this a lit
No messages get extracted when using:
They get extracted when using it like:
They also get extracted as expected when using a react component:
any ideas?