Coder Social home page Coder Social logo

Comments (26)

thekip avatar thekip commented on June 14, 2024 5

An update here:

Extracted message id incorrect when Trans children has plain text follow JSX element, space is losted

I created a separate discussion, please add your ideas there.

Dependency tree related files (AboutText.tsx/Developers.tsx) do not extracted in reproduction, but Switcher.tsx did

This one is fixed in #1867 separate test case was added

from js-lingui.

thekip avatar thekip commented on June 14, 2024 2

Hi @semoal i see following tasks:

  1. Move macro step to each file before it would be processed by esbuild. (Right now babel with macro applied at the last step together with extractor plugin on the whole bundle). This could be done quite easily by writing esbuild plugin or taking one from existing.
  2. [Optional] Instead of applying babel and babel's macro version on each file, it's better to apply SWC + lingui-plugin. I expect a noticeable time overhead if point 1 would be implemented, using SWC instead of babel should cut the time. Unfortunately, this requires changes in lingui-swc plugin, since it doesn't create /*i18n*/ comments which are required by extractor.
  3. In some discord discussions someone reported that esbuild trying to resolve scss file, I don't remember how it is implemented now, but i suppose we should mark as "external" every non js/js-like file for simplicity.

I think this 3 is essential to at least unblock following adoption of the extractor.

From my side, i can help with SWC Rust plugin, and can explain how extractor works now.

After basic functionality become stable we can do performance optimizations:

  1. [Multithreading] Run extraction process on each bundle in the separate worker
  2. Move new extractor to separate package (to avoid people download and install esbuild & swc if they don't use it)

from js-lingui.

thekip avatar thekip commented on June 14, 2024 1

So use extract-experimental in production seems not a good idea recently.

Yes, it was created as PoC, and actually there not match attention to it, so i could not get enough feedback to make it production ready.

On the other hand, how about the first question: Space is losted when plain text follow JSX element under Trans.

I didn't investigate it, but i think the problem is similar, when code is processed by esbuild it gets reprinted and space might be dropped.

from js-lingui.

thekip avatar thekip commented on June 14, 2024 1

Actually, some spaces are deleted intentionally. You can read unit-tests to understand the cases. The issue would be if the final line would be different between what left by macro in the code and what was extracted to catalog.

from js-lingui.

thekip avatar thekip commented on June 14, 2024 1

I considered that solution in the beginning, even look into that exact library. Solution with esbuild i like more because:

  1. it's doing tree shaking, more chances that catalog will not contain unnecessary strings. If your project uses tons of barrel files (index.{ts,js} with re-exports) this deps tree resolution become useless without tree-shaking.
  2. it's much faster
  3. it's much easier to use, setup and maintenance.

I still think we need to continue with esbuild. The problems mentioned in this issue are fixable, i just don't have a time for that currently.

from js-lingui.

semoal avatar semoal commented on June 14, 2024 1

How far @thekip are we of converting this feature in something stable? Probably if you detail which tasks are pending I can help on my free time :) We noticed that our catalogs are getting large and this splitting by page would be amazing

from js-lingui.

thekip avatar thekip commented on June 14, 2024 1

Extracted message id incorrect when Trans children has plain text follow JSX element, space is losted

Fixed: #1882

from js-lingui.

thekip avatar thekip commented on June 14, 2024 1

Interesting, thanks for report, that probably related to useLingui and this refactoring I will take a look.

from js-lingui.

thekip avatar thekip commented on June 14, 2024

Well, i've found a problem why some files not get processed by extractor. Unfirtunately it's not easy to fix, because it's need to change literally everthying in how this is processed now.

The simple explanation of the process now:

  1. Files bundled together with esbuild, JSX is preserved
  2. Regular JS extractor is applied to the bundles
    1. Macro applied to whole bundle
    2. Extractor extract from all usages as it was written without macro

The problem here is that esbuild while bundling doing a lot of work related to module imports. It renames, deduplicate and etc. Macro is able to understand renamed imports, but macro is also responsible of turning macro input into runtime import. And here where problems appears. Macro is not smart enough to analyze what import already inserted in the file and in what order (the esbuild could generate very complicated setups, because what actually bundlers do)

So after macro expannding some imports got deleted and extractor did not recognize these nodes as belonging to the Lingui
Here is the output result after intermediate steps:

Esbuild bundle
// src/pages/index.page.tsx
import { Plural as Plural2, t as t2, Trans as Trans3 } from "@lingui/macro";
import path from "path";
import Head from "next/head";

// src/components/AboutText.tsx
import { Trans } from "@lingui/macro";
function AboutText() {
  return <p>
    <Trans>Hello, world</Trans>
    <br />
    <Trans id="message.next-explanation">Next.js is an open-source React front-end development web framework that enables functionality such as server-side rendering and generating static websites for React based web applications. It is a production-ready framework that allows developers to quickly create static and dynamic JAMstack websites and is used widely by many large companies.</Trans>
  </p>;
}

// src/components/Developers.tsx
import { useState } from "react";
import { Trans as Trans2, Plural } from "@lingui/macro";
function Developers() {
  const [selected, setSelected] = useState("1");
  return <div>
    <p><Trans2>Plural Test: How many developers?</Trans2></p>
    <div style={{ display: "flex", justifyContent: "space-evenly" }}>
      <select
        value={selected}
        onChange={(evt) => setSelected(evt.target.value)}
      >
        <option value="1">1</option>
        <option value="2">2</option>
      </select>
      <p><Plural value={selected} one="Developer" other="Developers" /></p>
    </div>
  </div>;
}

// src/components/Switcher.tsx
import { useRouter } from "next/router";
import { useState as useState2 } from "react";
import { msg } from "@lingui/macro";
import { useLingui } from "@lingui/react";
var languages = {
  en: msg`English`,
  sr: msg`Serbian`,
  es: msg`Spanish`
};
function Switcher() {
  const router = useRouter();
  const { i18n: i18n2 } = useLingui();
  const [locale, setLocale] = useState2(
    router.locale.split("-")[0]
  );
  function handleChange(event) {
    const locale2 = event.target.value;
    setLocale(locale2);
    router.push(router.pathname, router.pathname, { locale: locale2 });
  }
  return <select value={locale} onChange={handleChange}>{Object.keys(languages).map((locale2) => {
    return <option value={locale2} key={locale2}>{i18n2._(languages[locale2])}</option>;
  })}</select>;
}

// src/pages/index.page.tsx
import styles from "../styles/Index.module.css";

// src/utils.ts
import { i18n } from "@lingui/core";
import { useRouter as useRouter2 } from "next/router";
import { useEffect, useState as useState3 } from "react";
async function loadCatalog(locale, pathname) {
  if (pathname === "_error") {
    return {};
  }
  const catalog = await import(`@lingui/loader!./locales/src/pages/${pathname}.page/${locale}.po`);
  return catalog.messages;
}

// src/pages/index.page.tsx
import { useLingui as useLingui2 } from "@lingui/react";
var getStaticProps = async (ctx) => {
  const fileName = __filename;
  const cwd = process.cwd();
  const { locale } = ctx;
  const pathname = path.relative(cwd, fileName).replace(".next/server/pages/", "").replace(".js", "");
  const translation = await loadCatalog(locale || "en", pathname);
  return {
    props: {
      translation
    }
  };
};
var Index = () => {
  useLingui2();
  return <div className={styles.container}>
    <Head>
      {
        /*
         The Next Head component is not being rendered in the React
         component tree and React Context is not being passed down to the components placed in the <Head>.
         That means we cannot use the <Trans> component here and instead have to use `t` macro.
        */
      }
      <title>{t2`Translation Demo`}</title>
      <link rel="icon" href="/favicon.ico" />
    </Head>
    <main className={styles.main}>
      <Switcher />
      <h1 className={styles.title}><Trans3>
        {"Welcome to "}
        <a href="https://nextjs.org">Next.js!</a>
      </Trans3></h1>
      <h2><Trans3>Plain text</Trans3></h2>
      <h2>{t2`Plain text`}</h2>
      <h2><Trans3>
        <a href="https://nextjs.org">Next.js</a>
        {" say hi."}
      </Trans3></h2>
      <h2><Trans3>
        {"Wonderful framework "}
        <a href="https://nextjs.org">Next.js</a>
        {" say hi."}
      </Trans3></h2>
      <h2><Trans3>
        {"Wonderful framework "}
        <a href="https://nextjs.org">Next.js</a>
        {" say hi. And "}
        <a href="https://nextjs.org">Next.js</a>
        {" say hi."}
      </Trans3></h2>
      <div className={styles.description}><AboutText /></div>
      <Developers />
      <div>
        <Plural2 value={1} one="# Person" other="# Persons" />
        <br />
        <Plural2 value={2} one="# Person" other="# Persons" />
      </div>
    </main>
  </div>;
};
var index_page_default = Index;
export {
  index_page_default as default,
  getStaticProps
};
Bundle after Macro
import path from "path";
    import Head from "next/head";
    
    // src/components/Developers.tsx
    import { useState } from "react";
    function Developers() {
      const [selected, setSelected] = useState("1");
      return <div>
          <p>
            <Trans id={"jryo3h"} message={"Plural Test: How many developers?"} />
          </p>
          <div style={{
          display: "flex",
          justifyContent: "space-evenly"
        }}>
            <select value={selected} onChange={evt => setSelected(evt.target.value)}>
              <option value="1">1</option>
              <option value="2">2</option>
            </select>
            <p>
              <Trans id={"y0Og8v"} message={"{selected, plural, one {Developer} other {Developers}}"} values={{
              selected: selected
            }} />
            </p>
          </div>
        </div>;
    }
    
    // src/components/Switcher.tsx
    import { useRouter } from "next/router";
    import { useState as useState2 } from "react";
    import { useLingui, Trans } from "@lingui/react";
    var languages = {
      en:
      /*i18n*/
      {
        id: "lYGfRP",
        message: "English"
      },
      sr:
      /*i18n*/
      {
        id: "9aBtdW",
        message: "Serbian"
      },
      es:
      /*i18n*/
      {
        id: "65A04M",
        message: "Spanish"
      }
    };
    function Switcher() {
      const router = useRouter();
      const {
        i18n: i18n2
      } = useLingui();
      const [locale, setLocale] = useState2(router.locale.split("-")[0]);
      function handleChange(event) {
        const locale2 = event.target.value;
        setLocale(locale2);
        router.push(router.pathname, router.pathname, {
          locale: locale2
        });
      }
      return <select value={locale} onChange={handleChange}>
          {Object.keys(languages).map(locale2 => {
          return <option value={locale2} key={locale2}>
                {i18n2._(languages[locale2])}
              </option>;
        })}
        </select>;
    }
    
    // src/pages/index.page.tsx
    import styles from "../styles/Index.module.css";
    
    // src/utils.ts
    import { i18n } from "@lingui/core";
    import { useRouter as useRouter2 } from "next/router";
    import { useEffect, useState as useState3 } from "react";
    async function loadCatalog(locale, pathname) {
      if (pathname === "_error") {
        return {};
      }
      const catalog = await import(`@lingui/loader!./locales/src/pages/${pathname}.page/${locale}.po`);
      return catalog.messages;
    }
    
    // src/pages/index.page.tsx
    import { useLingui as useLingui2 } from "@lingui/react";
    var getStaticProps = async ctx => {
      const fileName = __filename;
      const cwd = process.cwd();
      const {
        locale
      } = ctx;
      const pathname = path.relative(cwd, fileName).replace(".next/server/pages/", "").replace(".js", "");
      const translation = await loadCatalog(locale || "en", pathname);
      return {
        props: {
          translation
        }
      };
    };
    var Index = () => {
      useLingui2();
      return <div className={styles.container}>
          <Head>
            {/*
             The Next Head component is not being rendered in the React
             component tree and React Context is not being passed down to the components placed in the <Head>.
             That means we cannot use the <Trans> component here and instead have to use `t` macro.
             */}
            <title>{i18n._(
            /*i18n*/
            {
              id: "HjmF2U",
              message: "Translation Demo"
            })}</title>
            <link rel="icon" href="/favicon.ico" />
          </Head>
          <main className={styles.main}>
            <Switcher />
            <h1 className={styles.title}>
              <Trans id={"QpzMsa"} message={"Welcome to <0>Next.js!</0>"} components={{
              0: <a href="https://nextjs.org" />
            }} />
            </h1>
            <h2>
              <Trans id={"pOo4Aa"} message={"Plain text"} />
            </h2>
            <h2>{i18n._(
            /*i18n*/
            {
              id: "pOo4Aa",
              message: "Plain text"
            })}</h2>
            <h2>
              <Trans id={"L7eJFB"} message={"<0>Next.js</0>say hi."} components={{
              0: <a href="https://nextjs.org" />
            }} />
            </h2>
            <h2>
              <Trans id={"4rdBWT"} message={"Wonderful framework <0>Next.js</0>say hi."} components={{
              0: <a href="https://nextjs.org" />
            }} />
            </h2>
            <h2>
              <Trans id={"mQ2tsK"} message={"Wonderful framework <0>Next.js</0>say hi. And <1>Next.js</1>say hi."} components={{
              0: <a href="https://nextjs.org" />,
              1: <a href="https://nextjs.org" />
            }} />
            </h2>
            <div className={styles.description}>
              <AboutText />
            </div>
            <Developers />
            <div>
              <Trans id={"9C7Ncf"} message={"{0, plural, one {# Person} other {# Persons}}"} values={{
              0: 1
            }} />
              <br />
              <Trans id={"9C7Ncf"} message={"{0, plural, one {# Person} other {# Persons}}"} values={{
              0: 2
            }} />
            </div>
          </main>
        </div>;
    };
    var index_page_default = Index;
    export { index_page_default as default, getStaticProps };

Note how code of src/components/Developers.tsx appears without actual runtime imports. The imports somehwere below in the listing, but not in that scope of visibility. That the reason why extractor didn't pick up them.

Solution which i'm actually thinking of is to change order of processing in the following way:

  1. Write a plugin for esbuild which would invoke SWC + Rust version of Macro for each file before they get processed by esbuild.
  2. get the bundles
  3. feed them to js extractor (no macro processing happend on the final bundles)

That makes process more safe, because macro would process untouched files and would be more future-safe.
From other side this defenetely will increase time needed for processing.

Other option could be to implement a separate AST transformation which would hoist all lingui imports to the very top of the file.

from js-lingui.

thekip avatar thekip commented on June 14, 2024

continuing developing an idea:

SWC plugin unfortunately was not designed to work in extractor pipeline. It always work in a "production" mode means always remove non-essential properties which actually used by extractor. So some additional work would be required here.
But to prove the theory and make a PoC babel version could be used. I'm expecting it to be quite slow, unfortunately.

About hoisting imports - this could fix this exact case and could break in some other, so i would rather skip this option.

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

It seems so hard to process, but in our big project seems not find out this question. I just find it when I create the reproduction 😂 So use extract-experimental in production seems not a good idea recently.

On the other hand, how about the first question: Space is losted when plain text follow JSX element under Trans.

BTW, Esbuild bundle related code format is broken.

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

@thekip Is there any plan to refactor the PoC to make it fully usable?

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

Space is losted when plain text follow JSX element under Trans.

The issue also happens to lingui extract somewhere, it's wired.

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

It seems so hard to process, but in our big project seems not find out this question. I just find it when I create the reproduction 😂 So use extract-experimental in production seems not a good idea recently.

On the other hand, how about the first question: Space is losted when plain text follow JSX element under Trans.

BTW, Esbuild bundle related code format is broken.

How about make extractor extract id directly regardless of whether module imports?

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

@thekip I found a another solution, use dependency-tree to get all of entries dependencies, then extract all of the dependencies by AST, no esbuild required.

How about this idea?

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

@thekip Thanks for your great work, I will try lingui extract-experimental tomorrow, and alse waiting for #1882

from js-lingui.

yunsii avatar yunsii commented on June 14, 2024

@thekip Unfortunately, with 4.8.0-next.1, lingui extract-experimental does not works with calling currying function directly, like below:

  const result = curringFoo()()
  console.log('curringFoo', result)

Throw error:

SyntaxError: /tmp/js-lingui-extract-cEKHmj/src/pages/index.page.jsx: Unsupported macro usage. Please check the examples at https://lingui.dev/ref/macro#examples-of-js-macros.
 If you think this is a bug, fill in an issue at https://github.com/lingui/js-lingui/issues

 Error: Cannot read properties of undefined (reading 'isExpression')
  101 | var Index = () => {
  102 |   useLingui2();
> 103 |   const result = curringFoo()();
      |                  ^^^^^^^^^^^^^^
  104 |   console.log("curringFoo", result);
  105 |   return <div className={styles.container}>
  106 |     <Head>
    at File.buildCodeFrameError (/home/my/projects/lingui-examples-nextjs-swc-1797/node_modules/.pnpm/@[email protected]/node_modules/@babel/core/lib/transformation/file/file.js:205:12)
    at NodePath.buildCodeFrameError (/home/my/projects/lingui-examples-nextjs-swc-1797/node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/index.js:101:21)

Reproduction: https://github.com/yunsii/lingui-examples-nextjs-swc-1797/blob/0949ea46481695df7d24056efe98c98dbef6e691/src/pages/index.page.tsx#L39-L40

But it works after I try to call currying function step by step like this:

  const curryingBar = curringFoo()
  const result = curryingBar()
  console.log('curringFoo', result)

from js-lingui.

chrischen avatar chrischen commented on June 14, 2024

I use .mjs files but in imports I omit the file extension such as import foo from "./bar"; and extract-eperimental will give 'Could not resolve "./bar"' errors.

from js-lingui.

thekip avatar thekip commented on June 14, 2024

https://esbuild.github.io/api/#resolve-extensions

// lingui.config.ts

 experimental: {
    extractor: {
      /// ...
      resolveEsbuildOptions: (options: import('esbuild').BuildOptions) => {
        options.resolveExtensions = ['.ts', '.js', '.jsx', '.tsx', '.mjs'];
        return options;
      }
    },
  },

from js-lingui.

chrischen avatar chrischen commented on June 14, 2024

It's extracting messages from some of the detected pages but for some reason this one it fails. There is no Event.jsx (just an Event.mjs file). It's the same as the other files which are being extracted. Getting rid of the Event.mjs file removes the error and the other files still extract fine so it must be something within my Event.mjs file (changing the name doesn't do anything).

Cannot process file ../../../../var/folders/x3/yd9k6w0x2b1b9z5j6grkmll80000gp/T/js-lingui-extract-91fcwL/src/components/pages/Event.jsx /var/folders/x3/yd9k6w0x2b1b9z5j6grkmll80000gp/T/js-lingui-extract-91fcwL/src/components/pages/Event.jsx: Cannot read properties of undefined (reading 'name')
TypeError: /var/folders/x3/yd9k6w0x2b1b9z5j6grkmll80000gp/T/js-lingui-extract-91fcwL/src/components/pages/Event.jsx: Cannot read properties of undefined (reading 'name')

I also would like to take the opportunity to propose an alternate strategy to build-time resolution of dependencies. Currently I use Relay, and I have to compose data requirements from smaller components up until the final page component where it collects all the data requirements. But Relay doesn't auto-detect the data requirements at the page level, but rather has the developer statically define the data dependencies of the sub-components for every level of composed component.

For example a UserProfilePage component may compose of UserName, UserEmail, etc, and UserName and UserEmail define the data requirements it needs, and UserProfilePage you define (via GraphQL fragments) the sum of the data requirements of its constituent components.

I attempted a similar strategy with Lingui where each component file defines its own loadMessages function which will load the message bundle given the locale, and then call the lingui api to load it and merge the messages, and return this as a promise. So for example UserName and UserEmail indicate that they need to load some ../../locales/en/User[Name/Email].ts file and merge the messages into the Lingui context. The UserProfilePage component then composes the requirements of these two child components, and then when the page route is loaded it executes all its loadMessage functions (provided as an array of Promises). The UserProfilePage render function then uses React Suspense to wait for the message bundles to load first.

This actually works fine with current Lingui as is. I just tell the Lingui extractor to split the message bundles into one file per component. The only problem is that there are duplicate translations in the .po files. I don't think it's an issue that there are duplicate entries in the compiled .ts files, but duplicate entries in .po files means it's tough to translate without deduplication.

Is there a way to have it generate a merged .po file for a translator to use, and then during compile separate that back into individual per-component .ts files? If not, what do you think of supporting this feature to support component-based bundle loading?

from js-lingui.

thekip avatar thekip commented on June 14, 2024

Getting rid of the Event.mjs file removes the error and the other files still extract fine so it must be something within my Event.mjs file (changing the name doesn't do anything).

There is something in the bundle itself, if you can share it (maybe privately) i will fix it.

Regarding your strategy - that's sounds interesting, I think that could be an option for some people. Would be nice if you can share it with community.

I also use relay on my project, and i understand what you're talking about. However, I'm not sure that this approach would suit all devlopers. Relay, thanks to graphql language and fragment masking (and types if you use TS) make developer experience on very high level, unfortunately achieve the same experience with lingui would be problematic.
Without that support, working with your strategy would lead to a lot of user-errors on the subsequent iterations. What if you forgot to add a dependency into a parent component? (in relay you realize this quickly, thanks to types and masking). What if you delete a component, but forgot to delete if from dependency? (relay has an eslint plugin which analyzes graphql fragment and code and show an error in this case)

I don't think it's an issue that there are duplicate entries in the compiled .ts files, but duplicate entries in .po files means it's tough to translate without deduplication.

Any TMS will help you with this. Deduplicating should happen on the level of TMS, not on the level of individual files.

The same challenge would be with experimental extractor as well, messages might be duplicated between pages.

from js-lingui.

chrischen avatar chrischen commented on June 14, 2024

Yes I agree the problem would arise where we forget to call some loadMessages() of a child component and the best case the translation never shows or worst case it doesn't render and permanently Suspends.

Actually here is the file. It is generated by the ReScript compiler so it's not hand written JS.

// Generated by ReScript, PLEASE EDIT WITH CARE

import * as RelayEnv from "../../entry/RelayEnv.mjs";
import * as EventRsvps from "../organisms/EventRsvps.mjs";
import * as Core__Option from "@rescript/core/src/Core__Option.mjs";
import * as Core from "@linaria/core";
import * as RelayRuntime from "relay-runtime";
import * as ViewerRsvpStatus from "../organisms/ViewerRsvpStatus.mjs";
import * as ReactRouterDom from "react-router-dom";
import * as JsxRuntime from "react/jsx-runtime";
import * as EventQuery_graphql from "../../__generated__/EventQuery_graphql.mjs";
import * as RescriptRelay_Query from "rescript-relay/src/RescriptRelay_Query.mjs";
import * as AppContext from "../layouts/appContext";
import * as RescriptRelay_Mutation from "rescript-relay/src/RescriptRelay_Mutation.mjs";
import * as EventJoinMutation_graphql from "../../__generated__/EventJoinMutation_graphql.mjs";
import * as EventLeaveMutation_graphql from "../../__generated__/EventLeaveMutation_graphql.mjs";

import { css, cx } from '@linaria/core'
;

import { t } from '@lingui/macro'
;

var convertVariables = EventQuery_graphql.Internal.convertVariables;

var convertResponse = EventQuery_graphql.Internal.convertResponse;

var convertWrapRawResponse = EventQuery_graphql.Internal.convertWrapRawResponse;

var use = RescriptRelay_Query.useQuery(convertVariables, EventQuery_graphql.node, convertResponse);

var useLoader = RescriptRelay_Query.useLoader(convertVariables, EventQuery_graphql.node, (function (prim) {
        return prim;
      }));

var usePreloaded = RescriptRelay_Query.usePreloaded(EventQuery_graphql.node, convertResponse, (function (prim) {
        return prim;
      }));

var $$fetch = RescriptRelay_Query.$$fetch(EventQuery_graphql.node, convertResponse, convertVariables);

var fetchPromised = RescriptRelay_Query.fetchPromised(EventQuery_graphql.node, convertResponse, convertVariables);

var retain = RescriptRelay_Query.retain(EventQuery_graphql.node, convertVariables);

var EventQuery = {
  Operation: undefined,
  Types: undefined,
  convertVariables: convertVariables,
  convertResponse: convertResponse,
  convertWrapRawResponse: convertWrapRawResponse,
  use: use,
  useLoader: useLoader,
  usePreloaded: usePreloaded,
  $$fetch: $$fetch,
  fetchPromised: fetchPromised,
  retain: retain
};

var convertVariables$1 = EventJoinMutation_graphql.Internal.convertVariables;

var convertResponse$1 = EventJoinMutation_graphql.Internal.convertResponse;

var convertWrapRawResponse$1 = EventJoinMutation_graphql.Internal.convertWrapRawResponse;

var commitMutation = RescriptRelay_Mutation.commitMutation(convertVariables$1, EventJoinMutation_graphql.node, convertResponse$1, convertWrapRawResponse$1);

var use$1 = RescriptRelay_Mutation.useMutation(convertVariables$1, EventJoinMutation_graphql.node, convertResponse$1, convertWrapRawResponse$1);

var EventJoinMutation = {
  Operation: undefined,
  Types: undefined,
  convertVariables: convertVariables$1,
  convertResponse: convertResponse$1,
  convertWrapRawResponse: convertWrapRawResponse$1,
  commitMutation: commitMutation,
  use: use$1
};

var convertVariables$2 = EventLeaveMutation_graphql.Internal.convertVariables;

var convertResponse$2 = EventLeaveMutation_graphql.Internal.convertResponse;

var convertWrapRawResponse$2 = EventLeaveMutation_graphql.Internal.convertWrapRawResponse;

var commitMutation$1 = RescriptRelay_Mutation.commitMutation(convertVariables$2, EventLeaveMutation_graphql.node, convertResponse$2, convertWrapRawResponse$2);

var use$2 = RescriptRelay_Mutation.useMutation(convertVariables$2, EventLeaveMutation_graphql.node, convertResponse$2, convertWrapRawResponse$2);

var EventLeaveMutation = {
  Operation: undefined,
  Types: undefined,
  convertVariables: convertVariables$2,
  convertResponse: convertResponse$2,
  convertWrapRawResponse: convertWrapRawResponse$2,
  commitMutation: commitMutation$1,
  use: use$2
};

var sessionContext = AppContext.SessionContext;

function $$Event(props) {
  var query = ReactRouterDom.useLoaderData();
  var match = usePreloaded(query.data);
  var match$1 = use$2(undefined);
  var commitMutationLeave = match$1[0];
  var match$2 = use$1(undefined);
  var commitMutationJoin = match$2[0];
  return Core__Option.getOr(Core__Option.map(match.event, (function ($$event) {
                    var __id = $$event.__id;
                    var onJoin = function (param) {
                      var connectionId = RelayRuntime.ConnectionHandler.getConnectionID(__id, "EventRsvps_event_rsvps", undefined);
                      commitMutationJoin({
                            connections: [connectionId],
                            id: __id
                          }, undefined, undefined, undefined, undefined, undefined, undefined);
                    };
                    var onLeave = function (param) {
                      var connectionId = RelayRuntime.ConnectionHandler.getConnectionID(__id, "EventRsvps_event_rsvps", undefined);
                      commitMutationLeave({
                            connections: [connectionId],
                            id: $$event.__id
                          }, undefined, undefined, undefined, undefined, undefined, undefined);
                    };
                    return JsxRuntime.jsx(ReactRouterDom.Await, {
                                children: JsxRuntime.jsxs("div", {
                                      children: [
                                        JsxRuntime.jsxs("h1", {
                                              children: [
                                                (t`Event:`),
                                                " ",
                                                Core__Option.getOr(Core__Option.map($$event.title, (function (prim) {
                                                            return prim;
                                                          })), null)
                                              ]
                                            }),
                                        JsxRuntime.jsx("div", {
                                              className: Core.cx("grid", "grid-cols-1", "gap-y-10", "sm:grid-cols-2", "gap-x-6", "lg:grid-cols-3", "xl:gap-x-8")
                                            }),
                                        JsxRuntime.jsx(ViewerRsvpStatus.make, {
                                              onJoin: onJoin,
                                              onLeave: onLeave,
                                              joined: true
                                            }),
                                        JsxRuntime.jsx(EventRsvps.make, {
                                              event: $$event.fragmentRefs
                                            })
                                      ],
                                      className: "bg-white"
                                    }),
                                resolve: query.messages,
                                errorElement: "Error loading"
                              });
                  })), JsxRuntime.jsx("div", {
                  children: "Event Doesn't Exist"
                }));
}

var LoaderArgs = {};

function loader(param) {
  var params = param.params;
  var url = new URL(param.request.url);
  Core__Option.getOr(params.lang, "en");
  var after = url.searchParams.get("after");
  var before = url.searchParams.get("before");
  return ReactRouterDom.defer({
              data: Core__Option.map(RelayEnv.getRelayEnv(param.context, import.meta.env.SSR), (function (env) {
                      return EventQuery_graphql.load(env, {
                                  after: after,
                                  before: before,
                                  eventId: params.eventId,
                                  first: 20
                                }, "store-or-network", undefined, undefined);
                    }))
            });
}

var make = $$Event;

var $$default = $$Event;

var Component = $$Event;

export {
  EventQuery ,
  EventJoinMutation ,
  EventLeaveMutation ,
  sessionContext ,
  make ,
  $$default ,
  $$default as default,
  Component ,
  LoaderArgs ,
  loader ,
}
/*  Not a pure module */

from js-lingui.

thekip avatar thekip commented on June 14, 2024

Thanks for the reply, you need to send this file "Cannot process file ../../../../var/folders/x3/yd9k6w0x2b1b9z5j6grkmll80000gp/T/js-lingui-extract-91fcwL/src/components/pages/Event.jsx /var/folders/x3/yd9k6w0x2b1b9z5j6grkmll80000gp/T/js-lingui-extract-91fcwL/src/components/pages/Event.jsx: Cannot read properties of undefined (reading 'name')"

This would be the bundle crated from Event.mjs.

from js-lingui.

chrischen avatar chrischen commented on June 14, 2024

That file doesn't exist, and there are no reference to .jsx or .tsx. The other files that extract fine are compiled via the same process. I can send those if you'd like. JSX is not used, and neither is TSX. I am pretty much working exclusively with the non-JSX react files like that .mjs file using function calls. That's why I am confused why it's trying to pull the Event.jsx file and only in that case.

from js-lingui.

thekip avatar thekip commented on June 14, 2024

It's because this file is created by underlying esbuild and stored in temporary folder. It's created with jsx extension. It does not exists because cli was able to clean up it even in case of error.

Would you be minded to patch the cli sources in node_modules and repeat?

You need in this file @lingui/cli/dist/lingui-extract-experimental.js delete this line:

    // cleanup temp directory
    await promises_1.default.rm(tempDir, { recursive: true, force: true });

from js-lingui.

thekip avatar thekip commented on June 14, 2024

@chrischen by the way, if you are trying to feed code generated by rescript to lingui extractor and this code looks like that what you posted, lingui extractor would not be able to extract strings from JSX elements such as <Trans> because actual jsx is already traspiled to function calls. I'm not familiar with rescript, but if there is an option to preserve JSX, that would help.

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.