lingui / js-lingui

🌍 📖 A readable, automated, and optimized (3 kb) internationalization for JavaScript
https://lingui.dev
MIT License
4.64k stars 382 forks source link

Astro integration #1640

Open dimonnwc3 opened 1 year ago

dimonnwc3 commented 1 year ago

is it possible to use this amazing library with https://astro.build?

timofei-iatsenko commented 1 year ago

I don't have experience with astro. You could try and report it back to community 😃

TheUltDev commented 1 year ago

@dimonnwc3 Astro builds on top of Vite, you should be able to follow the same Vite integration process:

Just follow the Lingui Vite integration and the core/macro (and possibly react) libraries should work?

dimonnwc3 commented 1 year ago

@TheUltDev thanks for suggestion. I was able to install and setup lingui with vite, but macros are not getting extracted. It seems that extractor expects js/jsx/ts/tsx files, but astro is using .astro extension. Which is a mix of a JS and JSX inside one file.

Running of astro itself, with a Trans macro inside, throws an error:

 error   Named export 'createMacro' not found. The requested module 'babel-plugin-macros' is a CommonJS module, which may not support all module.exports as named exports.
  CommonJS modules can always be imported via the default export, for example using:

  import pkg from 'babel-plugin-macros';
  const { createMacro } = pkg;
timofei-iatsenko commented 1 year ago

but astro is using .astro extension

You need to implement a custom extractor for such files. You can take vue-extractor as example https://github.com/lingui/js-lingui/blob/main/packages/extractor-vue/src/vue-extractor.ts

ws-rush commented 1 year ago

I think astro a huge problem, astro support React, vue, solid, and another frameworks components, I think it is intersting to write one astro extractor if it is possible

liolocs commented 7 months ago

I wrote a custom extractor for astro, not sure if this will work for whoever tests this but maybe a good starting point:

//astro-extractor.ts
import { transform } from "@astrojs/compiler";
import { extractor as defaultExtractor } from "@lingui/cli/api";

export const astroExtractor = {
    match(filename: string) {
        return filename.endsWith(".astro");
    },
    async extract(
        filename: string,
        code: string,
        onMessageExtracted: any,
        ctx: any
    ) {
        // transform to plain JS + Sourcemaps
        const { code: transformedCode, map } = await transform(code, {
            filename,
            sourcemap: "both",
            internalURL: "astro/runtime/server/index.js",
        });
        // reuse extractor from cli
        return defaultExtractor.extract(
            filename + ".ts",
            transformedCode,
            onMessageExtracted,
            { map, ...ctx }
        );
    },
};
//lingui.config.ts
import type { LinguiConfig } from "@lingui/conf";
import { astroExtractor } from "./astro-extractor";

const config: LinguiConfig = {
    locales: ["en", "es", "fr"],
    catalogs: [
        {
            path: "./src/locales/{locale}/messages",
            include: ["src"],
        },
    ],
    format: "po",
    compileNamespace: "es",
    extractors: [astroExtractor],
};

export default config;
voidpumpkin commented 2 months ago

@liolocs Thx a lot for the starting point.

I got simple extraction working by replacing transform with convertToTSX:

//astro-extractor.ts
import { convertToTSX } from "@astrojs/compiler";
import { extractor as defaultExtractor } from "@lingui/cli/api";

export const astroExtractor = {
  match(filename: string) {
    return filename.endsWith(".astro");
  },
  async extract(
    filename: string,
    code: string,
    onMessageExtracted: any,
    ctx: any,
  ) {
    let { code: transformedCode, map } = await convertToTSX(code);

    return defaultExtractor.extract(
      filename + ".tsx",
      transformedCode,
      onMessageExtracted,
      { map, ...ctx },
    );
  },
};

I have not tested a lot though.

andrii-bodnar commented 1 month ago

@liolocs @voidpumpkin Thanks for your interest and effort in making the custom extractor! 🚀

I think this should be a native feature of Lingui. Would you be interested in contributing a separate package similar to extractor-vue?

It would also be great to have a documentation tutorial and example project.

smnbbrv commented 1 month ago

The extractor itself is a very small issue. Astro is an ecosystem where one can use Astro itself (where the currently provided macros just do not work), React (which actually requires writing custom integration and injecting the babel plugin in) and any other framework of choice. Currently one can use lingui only with react components which is just not enough. Astro is there because more than 50% of the websites can be statically rendered as astro components and not having lingui there makes it problematic. I spent several hours finding a reliable solution for this but I failed.

If one wants to fully support Astro (at least a combination of Astro + React), the primary goal is to actually support Astro components.

To enable the whole Lingui ecosystem one needs

That's what would make it really lingui-way of doing things