Giter Club home page Giter Club logo

Comments (13)

thekip avatar thekip commented on May 24, 2024 1
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.

wentokay avatar wentokay commented on May 24, 2024 1

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.

thekip avatar thekip commented on May 24, 2024

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.

wentokay avatar wentokay commented on May 24, 2024

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.

wentokay avatar wentokay commented on May 24, 2024

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.

thekip avatar thekip commented on May 24, 2024

Yes, that would also work. That was actually a default behavior in lingui < 4

from js-lingui.

dan-dr avatar dan-dr commented on May 24, 2024

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.

dan-dr avatar dan-dr commented on May 24, 2024

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.

thekip avatar thekip commented on May 24, 2024

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.

dan-dr avatar dan-dr commented on May 24, 2024

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.

thekip avatar thekip commented on May 24, 2024

Well, i picked it up when you finished and was able to make it work.

from js-lingui.

thekip avatar thekip commented on May 24, 2024

@dan-dr could you try on your project? Here is how to run it on your local project

#1859

from js-lingui.

thekip avatar thekip commented on May 24, 2024

published as https://github.com/lingui/js-lingui/releases/tag/v4.8.0-next.0

from js-lingui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.