Repository navigation
Replies: 1 comment
|
In v6 you can drop Babel entirely for this: Packages npm i @lingui/core
npm i -D @lingui/cli @lingui/conf @lingui/native-tools
import { defineConfig } from "@lingui/conf"
import { createSwcExtractor } from "@lingui/native-tools"
export default defineConfig({
sourceLocale: "en",
locales: ["en", "nl"],
catalogs: [{ path: "<rootDir>/src/locales/{locale}/messages", include: ["src"] }],
extractors: [createSwcExtractor()], // native extractor, no Babel
compileNamespace: "es", // ESM catalogs, see note below
})Messages and i18n instances For a queue worker I'd use // src/messages.ts
import { msg, plural } from "@lingui/core/macro"
export const newMessageTitle = (name: string) => msg`New message from ${name}`
export const unreadBody = (count: number) =>
msg`You have ${plural(count, { one: "# unread message", other: "# unread messages" })}`// src/i18n.ts
import { setupI18n, type I18n } from "@lingui/core"
import { messages as en } from "./locales/en/messages.mjs"
import { messages as nl } from "./locales/nl/messages.mjs"
const instances: Record<string, I18n> = {
en: setupI18n({ locale: "en", messages: { en } }),
nl: setupI18n({ locale: "nl", messages: { nl } }),
}
export const i18nFor = (locale: string) => instances[locale] ?? instances.en!// in the job handler
const i18n = i18nFor(job.locale)
const title = i18n._(newMessageTitle(job.from))
const body = i18n._(unreadBody(job.unread))
Option A: no build step, a Node loader hook // register.mjs
import { register } from "node:module"
register("./lingui-hooks.mjs", import.meta.url)// lingui-hooks.mjs
import { readFile } from "node:fs/promises"
import { fileURLToPath } from "node:url"
import { transform } from "@lingui/native-tools"
export async function load(url, context, nextLoad) {
if (!url.startsWith("file:") || url.includes("/node_modules/") || !/\.[cm]?[jt]sx?$/.test(url)) {
return nextLoad(url, context)
}
const filename = fileURLToPath(url)
const source = await readFile(filename, "utf8")
if (!/@lingui\/[\w-]+\/macro/.test(source)) return nextLoad(url, context)
// also strips TypeScript, so the result is plain JS
const { code } = await transform(source, filename, { sourceMaps: "inline" })
return { format: "module", source: code, shortCircuit: true }
}node --import ./register.mjs src/worker.ts
Option B: a build step with esbuild // build.mjs
import { build } from "esbuild"
import { readFile } from "node:fs/promises"
import { transform } from "@lingui/native-tools"
await build({
entryPoints: ["src/worker.ts"],
bundle: true,
platform: "node",
format: "esm",
packages: "external",
outfile: "dist/worker.js",
plugins: [{
name: "lingui-macro",
setup(b) {
b.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async ({ path }) => {
const source = await readFile(path, "utf8")
if (!/@lingui\/[\w-]+\/macro/.test(source)) return undefined
const { code } = await transform(source, path, { sourceMaps: "inline" })
return { contents: code, loader: "js" }
})
},
}],
})Build with Two things that tripped me up
|
Uh oh!
There was an error while loading. Please reload this page.
We have a simple node project that we use to send push notifications. This is basically a worker process consuming a queue, and sending out HTTP calls to google/apple with the message we want to display on the user's phone.
Obviously we want this translated.
Obviously we want this with Lingui.
Obviously we want the macro syntax.
We got it to work with babel, but it is very fragile (v5 -> v6 update was painful).
What is the best practices to use Lingui in a bare bones setup? Do the maintainers want to support this (or at least document some best practices around this).
Open for discussion, and see how you solved it.
All reactions