Comments (13)
const Component = () => {
useLingui();
return <div>{t`Always updates after switching locales`}</div>;
}
This is supported and working, and even was in the docs some time ago. But this was deleted because we don't want to populate this approach. Problem with this snippet that t
and useLingui
are not directly connected to each other, and not clean for developers that they are related.
Also if you use SSR rendering i highly discourage you from using any global instances of i18n, here i explained why.
useLingui()
simply "subscribe" current component for updates when locale is changed. Without it component using t
will not re-render on language switch.
Anyway, for migration purpose using this snippet should be fine.
Other option to consider, if you are working on a web application, consider doing full reload of the app on the language switch. It's small cost of user inconvenience but huge simplification of the code and development process. This way you will be able to use t
without any additional hooks.
from js-lingui.
Another approach that we're now trying. I haven't tested this specific block of code, but it's the essence of what we're doing. It seems to work for our project because everything is client-side.
Adapted from the react example https://lingui.dev/tutorials/react#setup
import React from "react";
import { createRoot } from "react-dom/client";
import { i18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react";
import { messages } from "./locales/en/messages";
import Inbox from "./Inbox";
i18n.load("en", messages);
i18n.activate("en");
const App = () => (
<I18nProvider i18n={i18n}>
<InnerApp />
</I18nProvider>
);
const InnerApp = () => {
const { i18n } = useLingui();
return (
// re-render the app whenever the locale changes
<React.Fragment key={i18n.locale}>
<Inbox />
</React.Fragment>
);
}
const root = createRoot(document.getElementById('root'));
root.render(<App />);
from js-lingui.
The current design here for a reason. Indeed, the design proposed by you is better and I even investigated to possibility to do something like that before. However, there are technical restrictions on the babel-macro side and also this kind of transpilation opens a wide variety of usages user's could do with these functions which we could not know ahead of time and it would be a big maintenance burden to handle all possible cases in transpilation.
The current flow is much simpler, we take 1 existing node and replacing to another one. To achieve what you're proposing you need replace multiple related to each other nodes and traverse AST back and forth which is waay more complicated process.
from js-lingui.
I had similar thoughts about this today and while I was trying the different suggested approaches, I noticed that this
const Component = () => {
useLingui();
return <div>{t`Always updates after switching locales`}</div>;
}
effectively behaves the same way as
const Component = () => {
const { i18n } = useLingui();
return <div>{t(i18n)`Always updates after switching locales`}</div>
}
I assume this is an unexpected/unsupported behavior?
I haven't dug too deep into the lingui source yet but I assume it's because useLingui()
is updating the i18n reference used by the macro below it with what it gets from React Context?
I don't think I'll use that approach in the long term, but we just migrated from i18next and with 300+ files to update it might be a quick and useful temporary fix while figuring out a better long term strategy.
I'm currently trying to see if there's any way to guarantee that i18n
is a global singleton shared across our monorepo, rather than needing to inject it in every t``.
from js-lingui.
Thanks for the detailed explanation.
We actually opted for a full reload after switching locales like you suggested and it's been working great for our requirements!
from js-lingui.
Yes, that would also work. That was actually a default behavior in lingui < 4
from js-lingui.
Wait but what happens if I do this:
import { t } from '@lingui/macro';
import { useLingui } from '@lingui/react';
() => {
const { i18n } = useLingui();
const text = t`Text`;
const other = i18n._(....);
}
from looking at the macro code, i expect this:
import { i18n } from '@lingui/core';
import { useLingui } from '@lingui/react';
() => {
// name clashes with import from core?
const { i18n } = useLingui();
const text = i18n._(...);
const other = i18n._(....);
}
technically the i18n
instances from the import
and the useLingui
should clash, but from looking at the output js code, it looks like babel doesn't do the import and just uses the instance from useLingui?
Does that means you can technically just do this?
import { t } from '@lingui/macro';
import { useLingui } from '@lingui/react';
() => {
const { i18n } = useLingui();
t`Text`;
}
EDIT: https://www.trickster.dev/post/javascript-ast-manipulation-with-babel-untangling-scope-confusion/ says babel uses innermost scope reference when such clashes appear.
Though you still have problem with memoization probably...
from js-lingui.
I'm thinking you can probably do this
import { useLingui } from '@lingui/macro';
() => {
const { _ } = useLingui();
let a = _`Text`;
let b = React.useMemo(() => { return _`B` }, [_]);
}
// transforms into
import { useLingui } from '@lingui/react';
() => {
const { _ } = useLingui();
let a = _(...descriptor...);
let b = React.useMemo(() => { return _(...descriptor...) }, [_]);
}
by using scope.getBinding('_')
in the macro and then traversing it's referencePaths
, if there is a taggedtemplate call, replace it with callexpression and descriptor, and if it's an arrayexpression leave it. other uses should throw the reportUnsupportedSyntax. I'm trying to write it but can't seem to be able to run the project locally :/
from js-lingui.
Thanks for digging into it, firstly we are a bit restricted with what babel-macro allow us to do. Secondly we also have SWC plugin which replicate functionality and we should keep them in sync and SWC's plugins API doesn't replicate babel's API especially in part of scopes and references.
I don't say this is not possible, I just say this would open a Pandora's box of weird cases. Also, you need to consider that lingui supports recursive macro expanding, such as:
t`Hello ${plural(count, {single, plural})}`
Any way, if you are willing to try, I can assist you in discord.
from js-lingui.
Yeah I had a decent attempt that worked the way I mentioned but nesting was an issue. check it here: https://github.com/dan-dr/js-lingui/tree/feat/improved-react-hook-syntax
I'll give it up for now, and might go with the wrapping fragment since we are only client side. feel free to close or keep open for more ideas.
from js-lingui.
Well, i picked it up when you finished and was able to make it work.
from js-lingui.
@dan-dr could you try on your project? Here is how to run it on your local project
from js-lingui.
published as https://github.com/lingui/js-lingui/releases/tag/v4.8.0-next.0
from js-lingui.
Related Issues (20)
- Lingui doesn't extract msg within a msg HOT 2
- lingui extract-experimental empty space after {} HOT 2
- Error when aliasing Trans from '@lingui/react' in presence of macro Trans from '@lingui/macro' HOT 2
- `Nextjs` `swc` plugin example not working HOT 3
- Macro: t inside t causing ReferenceError: t is not defined HOT 3
- why not working plural macro? please help me...
- [SIMPLE PATCH READY] Simple hack for compatibility with Turbopack (NextJS) HOT 2
- Missing auto-generated `id` for `<Trans>` macro when using Typescript HOT 4
- ERROR in ./node_modules/@lingui/macro/dist/index.mjs 347:24 Module parse failed HOT 7
- a special message cant compile. HOT 1
- `lingui` can be null HOT 2
- Compile messages to JSON HOT 5
- Support Gatsby HOT 2
- Cannot find type definition file for './node_modules/@lingui/macro/global'. HOT 2
- Next.js tutorial HOT 3
- The `catalogsMergePath` option is missing in the documentation
- Support backup messages HOT 3
- Extract removes manual comments from po files HOT 1
- React Fragment (`<>`) inside `<Plural>` is not working HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from js-lingui.