From 30e5242f132a7e0aa847f45b472330f6113b0168 Mon Sep 17 00:00:00 2001 From: Sergei Slipchenko Date: Wed, 30 Jul 2025 10:15:53 +0400 Subject: [PATCH 01/19] fix: remove `VFC`, `FC` type usage (#2290) --- examples/rspack/src/react-env.d.ts | 2 +- packages/react/macro/index.d.ts | 10 ++++---- packages/react/src/I18nProvider.tsx | 6 ++--- packages/react/src/Trans.test.tsx | 40 ++++++++++++----------------- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/examples/rspack/src/react-env.d.ts b/examples/rspack/src/react-env.d.ts index ef67cc72c..022db4254 100644 --- a/examples/rspack/src/react-env.d.ts +++ b/examples/rspack/src/react-env.d.ts @@ -122,7 +122,7 @@ declare module "*.gif" { export default src; } declare module "*.svg" { - const ReactComponent: React.FC>; + const ReactComponent: (props: React.SVGProps) => React.ReactNode; const content: string; // export { ReactComponent }; diff --git a/packages/react/macro/index.d.ts b/packages/react/macro/index.d.ts index fb8e048ab..84e1587af 100644 --- a/packages/react/macro/index.d.ts +++ b/packages/react/macro/index.d.ts @@ -1,4 +1,4 @@ -import type { ReactNode, VFC, FC } from "react" +import type { ReactNode } from "react" import type { TransRenderCallbackOrComponent, I18nContext } from "@lingui/react" import type { MacroMessageDescriptor, @@ -52,7 +52,7 @@ type SelectChoiceProps = { * Hello {username}. * ``` */ -export const Trans: FC +export const Trans: (props: TransProps) => ReactNode /** * Props of Plural macro are transformed into plural format. @@ -67,7 +67,7 @@ export const Trans: FC * * ``` */ -export const Plural: VFC +export const Plural: (props: PluralChoiceProps) => ReactNode /** * Props of SelectOrdinal macro are transformed into selectOrdinal format. * @@ -86,7 +86,7 @@ export const Plural: VFC * /> * ``` */ -export const SelectOrdinal: VFC +export const SelectOrdinal: (props: PluralChoiceProps) => ReactNode /** * Props of Select macro are transformed into select format @@ -105,7 +105,7 @@ export const SelectOrdinal: VFC * /> * ``` */ -export const Select: VFC +export const Select: (props: SelectChoiceProps) => ReactNode declare function _t(descriptor: MacroMessageDescriptor): string declare function _t( diff --git a/packages/react/src/I18nProvider.tsx b/packages/react/src/I18nProvider.tsx index 4cec9b159..6491b1086 100644 --- a/packages/react/src/I18nProvider.tsx +++ b/packages/react/src/I18nProvider.tsx @@ -1,4 +1,4 @@ -import React, { ComponentType, FunctionComponent } from "react" +import React, { ComponentType } from "react" import type { I18n } from "@lingui/core" import type { TransRenderProps } from "./TransNoContext" @@ -31,11 +31,11 @@ export function useLingui(): I18nContext { return useLinguiInternal() } -export const I18nProvider: FunctionComponent = ({ +export function I18nProvider({ i18n, defaultComponent, children, -}) => { +}: I18nProviderProps) { const latestKnownLocale = React.useRef(i18n.locale) /** * We can't pass `i18n` object directly through context, because even when locale diff --git a/packages/react/src/Trans.test.tsx b/packages/react/src/Trans.test.tsx index 05e3b0a70..40aa03739 100644 --- a/packages/react/src/Trans.test.tsx +++ b/packages/react/src/Trans.test.tsx @@ -270,10 +270,10 @@ describe("Trans component", () => { }) it("should render nested elements with `asChild` pattern", () => { - const ComponentThatExpectsSingleElementChild: React.FC<{ + function ComponentThatExpectsSingleElementChild(props: { asChild: boolean children?: React.ReactElement - }> = (props) => { + }) { if (props.asChild && React.isValidElement(props.children)) { return props.children } @@ -387,9 +387,7 @@ describe("Trans component", () => { }) it("should take defaultComponent prop with a custom component", () => { - const ComponentFC: React.FunctionComponent = ( - props - ) => { + function ComponentFC(props: TransRenderProps) { return
{props.children}
} const span = render( @@ -406,9 +404,7 @@ describe("Trans component", () => { ])( "should ignore defaultComponent when `component` or `render` is null", (props) => { - const ComponentFC: React.FunctionComponent = ( - props - ) => { + function ComponentFC(props: TransRenderProps) { return
{props.children}
} const translation = render( @@ -434,9 +430,7 @@ describe("Trans component", () => { it("should render function component as simple prop", () => { const propsSpy = jest.fn() - const ComponentFC: React.FunctionComponent = ( - props - ) => { + function ComponentFC(props: TransRenderProps) { propsSpy(props) const [state] = React.useState("value") return
{state}
@@ -454,18 +448,18 @@ describe("Trans component", () => { }) describe("I18nProvider defaultComponent accepts render-like props", () => { - const DefaultComponent: React.FunctionComponent = ( - props - ) => ( - <> -
{props.children}
- {props.id &&
{props.id}
} - {props.message &&
{props.message}
} - {props.translation && ( -
{props.translation}
- )} - - ) + function DefaultComponent(props: TransRenderProps) { + return ( + <> +
{props.children}
+ {props.id &&
{props.id}
} + {props.message &&
{props.message}
} + {props.translation && ( +
{props.translation}
+ )} + + ) + } it("should render defaultComponent with Trans props", () => { const markup = render( From 489fb3a7c999632e57286369e44a0c6e77a3407b Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Wed, 30 Jul 2025 14:54:01 +0200 Subject: [PATCH 02/19] feat: full concurrency for extract / compile commands (#2299) --- .../api/__snapshots__/catalog.test.ts.snap | 80 ++++++++-------- packages/cli/src/api/catalog.ts | 7 +- .../cli/src/api/catalog/extractFromFiles.ts | 94 ++++++++++--------- packages/cli/src/api/compile.ts | 38 ++++---- packages/cli/src/lingui-compile.ts | 66 +++++++++---- packages/cli/src/lingui-extract.ts | 22 +++-- .../test/__snapshots__/compile.test.ts.snap | 11 ++- packages/cli/src/test/compile.test.ts | 8 +- .../expected/about.page.en.js | 2 +- .../expected/about.page.pl.js | 2 +- .../expected/about.page.en.js | 2 +- .../expected/about.page.pl.js | 2 +- .../test/metroTransformer.test.ts | 63 +++++++------ 13 files changed, 225 insertions(+), 172 deletions(-) diff --git a/packages/cli/src/api/__snapshots__/catalog.test.ts.snap b/packages/cli/src/api/__snapshots__/catalog.test.ts.snap index 25d128b95..75ac6131b 100644 --- a/packages/cli/src/api/__snapshots__/catalog.test.ts.snap +++ b/packages/cli/src/api/__snapshots__/catalog.test.ts.snap @@ -141,17 +141,13 @@ exports[`Catalog collect should extract messages from source files 1`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, ], context: undefined, message: undefined, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -160,6 +156,10 @@ exports[`Catalog collect should extract messages from source files 1`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], placeholders: {}, }, @@ -194,17 +194,13 @@ exports[`Catalog collect should extract only files passed on options 1`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, ], context: undefined, message: undefined, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -213,6 +209,10 @@ exports[`Catalog collect should extract only files passed on options 1`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], placeholders: {}, }, @@ -362,9 +362,9 @@ exports[`Catalog make should collect and write catalogs 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -374,10 +374,6 @@ exports[`Catalog make should collect and write catalogs 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -386,6 +382,10 @@ exports[`Catalog make should collect and write catalogs 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, @@ -429,9 +429,9 @@ exports[`Catalog make should collect and write catalogs 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -441,10 +441,6 @@ exports[`Catalog make should collect and write catalogs 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -453,6 +449,10 @@ exports[`Catalog make should collect and write catalogs 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, @@ -606,9 +606,9 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -618,10 +618,6 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -630,6 +626,10 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, @@ -757,9 +757,9 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -769,10 +769,6 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -781,6 +777,10 @@ exports[`Catalog make should merge with existing catalogs 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, @@ -849,9 +849,9 @@ exports[`Catalog make should only update the specified locale 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -861,10 +861,6 @@ exports[`Catalog make should only update the specified locale 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -873,6 +869,10 @@ exports[`Catalog make should only update the specified locale 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, @@ -922,9 +922,9 @@ exports[`Catalog makeTemplate should collect and write a template 2`] = ` }, Hello World: { comments: [ - Hello comment, Comment A, Comment A again, + Hello comment, js-lingui-explicit-id, ], context: null, @@ -934,10 +934,6 @@ exports[`Catalog makeTemplate should collect and write a template 2`] = ` }, obsolete: false, origin: [ - [ - collect/componentA/index.js, - 1, - ], [ collect/componentA/componentA.js, 2, @@ -946,6 +942,10 @@ exports[`Catalog makeTemplate should collect and write a template 2`] = ` collect/componentA/componentA.js, 3, ], + [ + collect/componentA/index.js, + 1, + ], ], translation: , }, diff --git a/packages/cli/src/api/catalog.ts b/packages/cli/src/api/catalog.ts index e0f74f591..931684238 100644 --- a/packages/cli/src/api/catalog.ts +++ b/packages/cli/src/api/catalog.ts @@ -80,9 +80,12 @@ export class Catalog { } async make(options: MakeOptions): Promise { - const nextCatalog = await this.collect({ files: options.files }) + const [nextCatalog, prevCatalogs] = await Promise.all([ + this.collect({ files: options.files }), + this.readAll(), + ]) + if (!nextCatalog) return false - const prevCatalogs = await this.readAll() const catalogs = this.merge(prevCatalogs, nextCatalog, { overwrite: options.overwrite, diff --git a/packages/cli/src/api/catalog/extractFromFiles.ts b/packages/cli/src/api/catalog/extractFromFiles.ts index 52c66efbb..a96ada891 100644 --- a/packages/cli/src/api/catalog/extractFromFiles.ts +++ b/packages/cli/src/api/catalog/extractFromFiles.ts @@ -35,56 +35,64 @@ export async function extractFromFiles( const messages: ExtractedCatalogType = {} let catalogSuccess = true - for (const filename of paths) { - const fileSuccess = await extract( - filename, - (next: ExtractedMessage) => { - if (!messages[next.id]) { - messages[next.id] = { - message: next.message, - context: next.context, - placeholders: {}, - comments: [], - origin: [], + + await Promise.all( + paths.map(async (filename) => { + const fileSuccess = await extract( + filename, + (next: ExtractedMessage) => { + if (!messages[next.id]) { + messages[next.id] = { + message: next.message, + context: next.context, + placeholders: {}, + comments: [], + origin: [], + } } - } - const prev = messages[next.id] + const prev = messages[next.id] - // there might be a case when filename was not mapped from sourcemaps - const filename = next.origin[0] - ? path.relative(config.rootDir, next.origin[0]).replace(/\\/g, "/") - : "" + // there might be a case when filename was not mapped from sourcemaps + const filename = next.origin[0] + ? path.relative(config.rootDir, next.origin[0]).replace(/\\/g, "/") + : "" - const origin: MessageOrigin = [filename, next.origin[1]] + const origin: MessageOrigin = [filename, next.origin[1]] - if (prev.message && next.message && prev.message !== next.message) { - throw new Error( - `Encountered different default translations for message ${pico.yellow( - next.id - )}` + - `\n${pico.yellow(prettyOrigin(prev.origin))} ${prev.message}` + - `\n${pico.yellow(prettyOrigin([origin]))} ${next.message}` - ) - } + if (prev.message && next.message && prev.message !== next.message) { + throw new Error( + `Encountered different default translations for message ${pico.yellow( + next.id + )}` + + `\n${pico.yellow(prettyOrigin(prev.origin))} ${prev.message}` + + `\n${pico.yellow(prettyOrigin([origin]))} ${next.message}` + ) + } - messages[next.id] = { - ...prev, - message: prev.message ?? next.message, - comments: next.comment - ? [...prev.comments, next.comment] - : prev.comments, - origin: [...prev.origin, [filename, next.origin[1]]], - placeholders: mergePlaceholders(prev.placeholders, next.placeholders), + messages[next.id] = { + ...prev, + message: prev.message ?? next.message, + comments: next.comment + ? [...prev.comments, next.comment].sort() + : prev.comments, + origin: ( + [...prev.origin, [filename, next.origin[1]]] as MessageOrigin[] + ).sort((a, b) => a[0].localeCompare(b[0])), + placeholders: mergePlaceholders( + prev.placeholders, + next.placeholders + ), + } + }, + config, + { + extractors: config.extractors as ExtractorType[], } - }, - config, - { - extractors: config.extractors as ExtractorType[], - } - ) - catalogSuccess &&= fileSuccess - } + ) + catalogSuccess &&= fileSuccess + }) + ) if (!catalogSuccess) return undefined diff --git a/packages/cli/src/api/compile.ts b/packages/cli/src/api/compile.ts index efc88ff07..ef5e03e71 100644 --- a/packages/cli/src/api/compile.ts +++ b/packages/cli/src/api/compile.ts @@ -49,24 +49,26 @@ export function createCompiledCatalog( const errors: MessageCompilationError[] = [] - const compiledMessages = Object.keys(messages).reduce<{ - [msgId: string]: CompiledMessage - }>((obj, key: string) => { - // Don't use `key` as a fallback translation in strict mode. - const translation = (messages[key] || (!strict ? key : "")) as string - - try { - obj[key] = compile(translation, shouldPseudolocalize) - } catch (e) { - errors.push({ - id: key, - source: translation, - error: e as Error, - }) - } - - return obj - }, {}) + const compiledMessages = Object.keys(messages) + .sort() + .reduce<{ + [msgId: string]: CompiledMessage + }>((obj, key: string) => { + // Don't use `key` as a fallback translation in strict mode. + const translation = (messages[key] || (!strict ? key : "")) as string + + try { + obj[key] = compile(translation, shouldPseudolocalize) + } catch (e) { + errors.push({ + id: key, + source: translation, + error: e as Error, + }) + } + + return obj + }, {}) if (namespace === "json") { return { source: JSON.stringify({ messages: compiledMessages }), errors } diff --git a/packages/cli/src/lingui-compile.ts b/packages/cli/src/lingui-compile.ts index bb2eab398..43fd97430 100644 --- a/packages/cli/src/lingui-compile.ts +++ b/packages/cli/src/lingui-compile.ts @@ -22,6 +22,8 @@ export type CliCompileOptions = { namespace?: string } +class ProgramExit extends Error {} + export async function command( config: LinguiConfigNormalized, options: CliCompileOptions @@ -30,12 +32,39 @@ export async function command( // Check config.compile.merge if catalogs for current locale are to be merged into a single compiled file const doMerge = !!config.catalogsMergePath - let mergedCatalogs = {} console.log("Compiling message catalogs…") - for (const locale of config.locales) { - for (const catalog of catalogs) { + let errored = false + + await Promise.all( + config.locales.map(async (locale) => { + try { + await compileLocale(locale, catalogs, options, config, doMerge) + } catch (err) { + if (err instanceof ProgramExit) { + errored = true + } else { + throw err + } + } + }) + ) + + return !errored +} + +async function compileLocale( + locale: string, + catalogs: Catalog[], + options: CliCompileOptions, + config: LinguiConfigNormalized, + doMerge: boolean +) { + let mergedCatalogs = {} + + await Promise.all( + catalogs.map(async (catalog) => { const { messages, missing: missingMessages } = await catalog.getTranslations(locale, { fallbackLocales: config.fallbackLocales, @@ -69,7 +98,7 @@ export async function command( ) } console.error() - return false + throw new ProgramExit() } if (doMerge) { @@ -78,26 +107,25 @@ export async function command( if ( !(await compileAndWrite(locale, config, options, catalog, messages)) ) { - return false + throw new ProgramExit() } } - } + }) + ) - if (doMerge) { - const result = await compileAndWrite( - locale, - config, - options, - await getCatalogForMerge(config), - mergedCatalogs - ) + if (doMerge) { + const result = await compileAndWrite( + locale, + config, + options, + await getCatalogForMerge(config), + mergedCatalogs + ) - if (!result) { - return false - } + if (!result) { + throw new ProgramExit() } } - return true } async function compileAndWrite( @@ -106,7 +134,7 @@ async function compileAndWrite( options: CliCompileOptions, catalogToWrite: Catalog, messages: Record -) { +): Promise { const namespace = options.typescript ? "ts" : options.namespace || config.compileNamespace diff --git a/packages/cli/src/lingui-extract.ts b/packages/cli/src/lingui-extract.ts index 746200e0f..478707dcb 100644 --- a/packages/cli/src/lingui-extract.ts +++ b/packages/cli/src/lingui-extract.ts @@ -33,18 +33,20 @@ export default async function command( const spinner = ora().start() - for (const catalog of catalogs) { - const result = await catalog.make({ - ...(options as CliExtractOptions), - orderBy: config.orderBy, - }) + await Promise.all( + catalogs.map(async (catalog) => { + const result = await catalog.make({ + ...(options as CliExtractOptions), + orderBy: config.orderBy, + }) - catalogStats[ - normalizePath(nodepath.relative(config.rootDir, catalog.path)) - ] = result || {} + catalogStats[ + normalizePath(nodepath.relative(config.rootDir, catalog.path)) + ] = result || {} - commandSuccess &&= Boolean(result) - } + commandSuccess &&= Boolean(result) + }) + ) if (commandSuccess) { spinner.succeed() diff --git a/packages/cli/src/test/__snapshots__/compile.test.ts.snap b/packages/cli/src/test/__snapshots__/compile.test.ts.snap index a8454947f..115b065b8 100644 --- a/packages/cli/src/test/__snapshots__/compile.test.ts.snap +++ b/packages/cli/src/test/__snapshots__/compile.test.ts.snap @@ -17,19 +17,22 @@ exports[`CLI Command: Compile allowEmpty = false Should show error and stop comp Error: Failed to compile catalog for locale en! Missing 1 translation(s) +Error: Failed to compile catalog for locale pl! +Missing 1 translation(s) + `; exports[`CLI Command: Compile allowEmpty = false Should show missing messages verbosely when verbose = true 1`] = ` -en ⇒ en.js Error: Failed to compile catalog for locale pl! Missing translations: mY42CM: (Hello World) 2ZeN02: (Test String) +en ⇒ en.js `; exports[`CLI Command: Compile failOnCompileError = true Should show error and stop compilation of catalog if message has compilation error 1`] = ` -Failed to compile catalog for locale en! +Failed to compile catalog for locale pl! Compilation error for 1 translation(s): @@ -42,6 +45,6 @@ Reason: Unexpected message end at line 1 col 13: These errors fail command execution because \`--strict\` option passed `; -exports[`CLI Command: Compile merge Should merge individual catalogs if catalogsMergePath specified in lingui config 1`] = `/*eslint-disable*/module.exports={messages:JSON.parse("{\\"Z3YTTJ\\":[\\"Foo Hello World\\"],\\"iWZSiH\\":[\\"Bar Hello World\\"]}")};`; +exports[`CLI Command: Compile merge Should merge individual catalogs if catalogsMergePath specified in lingui config 1`] = `/*eslint-disable*/module.exports={messages:JSON.parse("{\\"Z3YTTJ\\":[\\"Foo Hello World\\"],\\"iWZSiH\\":[\\"Bar Hello World\\"]}")};`; -exports[`CLI Command: Compile merge Should merge individual catalogs if catalogsMergePath specified in lingui config 2`] = `/*eslint-disable*/module.exports={messages:JSON.parse("{\\"Z3YTTJ\\":[\\"[PL] Foo Hello World\\"],\\"iWZSiH\\":[\\"[PL] Bar Hello World\\"]}")};`; +exports[`CLI Command: Compile merge Should merge individual catalogs if catalogsMergePath specified in lingui config 2`] = `/*eslint-disable*/module.exports={messages:JSON.parse("{\\"Z3YTTJ\\":[\\"[PL] Foo Hello World\\"],\\"iWZSiH\\":[\\"[PL] Bar Hello World\\"]}")};`; diff --git a/packages/cli/src/test/compile.test.ts b/packages/cli/src/test/compile.test.ts index 27e090422..ec4e8f15c 100644 --- a/packages/cli/src/test/compile.test.ts +++ b/packages/cli/src/test/compile.test.ts @@ -161,6 +161,10 @@ msgstr "" const rootDir = await createFixtures({ "en.po": ` msgid "Hello World" +msgstr "Hello {hello}" + `, + "pl.po": ` +msgid "Hello World" msgstr "Hello {hello" `, }) @@ -174,7 +178,7 @@ msgstr "Hello {hello" }) const actualFiles = readFsToListing(config.rootDir) - expect(actualFiles["en.js"]).toBeFalsy() + expect(actualFiles["pl.js"]).toBeFalsy() const log = getConsoleMockCalls(console.error) expect(log).toMatchSnapshot() @@ -205,7 +209,7 @@ msgstr "Hello {hello" }) } - it("Should merge individual catalogs if catalogsMergePath specified in lingui config", async () => { + it("Should merge individual catalogs if catalogsMergePath specified in lingui config", async () => { expect.assertions(4) const rootDir = await createFixtures({ diff --git a/packages/cli/test/extractor-experimental-template/expected/about.page.en.js b/packages/cli/test/extractor-experimental-template/expected/about.page.en.js index a9fc76325..7707d434d 100644 --- a/packages/cli/test/extractor-experimental-template/expected/about.page.en.js +++ b/packages/cli/test/extractor-experimental-template/expected/about.page.en.js @@ -1 +1 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"1TzdHc\":[\"aliased module message\"],\"LGGfGX\":[\"header message\"],\"8Pj7KC\":[\"JSX: about page message\"]}")}; \ No newline at end of file +/*eslint-disable*/module.exports={messages:JSON.parse("{\"1TzdHc\":[\"aliased module message\"],\"8Pj7KC\":[\"JSX: about page message\"],\"LGGfGX\":[\"header message\"],\"u5PTM8\":[\"about page message\"]}")}; \ No newline at end of file diff --git a/packages/cli/test/extractor-experimental-template/expected/about.page.pl.js b/packages/cli/test/extractor-experimental-template/expected/about.page.pl.js index a9fc76325..7707d434d 100644 --- a/packages/cli/test/extractor-experimental-template/expected/about.page.pl.js +++ b/packages/cli/test/extractor-experimental-template/expected/about.page.pl.js @@ -1 +1 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"1TzdHc\":[\"aliased module message\"],\"LGGfGX\":[\"header message\"],\"8Pj7KC\":[\"JSX: about page message\"]}")}; \ No newline at end of file +/*eslint-disable*/module.exports={messages:JSON.parse("{\"1TzdHc\":[\"aliased module message\"],\"8Pj7KC\":[\"JSX: about page message\"],\"LGGfGX\":[\"header message\"],\"u5PTM8\":[\"about page message\"]}")}; \ No newline at end of file diff --git a/packages/cli/test/extractor-experimental/expected/about.page.en.js b/packages/cli/test/extractor-experimental/expected/about.page.en.js index e2dc6c66d..6e6f211f5 100644 --- a/packages/cli/test/extractor-experimental/expected/about.page.en.js +++ b/packages/cli/test/extractor-experimental/expected/about.page.en.js @@ -1 +1 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"VmkjGB\":[\"Green\"],\"LGGfGX\":[\"header message\"]}")}; \ No newline at end of file +/*eslint-disable*/module.exports={messages:JSON.parse("{\"LGGfGX\":[\"header message\"],\"VmkjGB\":[\"Green\"],\"u5PTM8\":[\"about page message\"]}")}; \ No newline at end of file diff --git a/packages/cli/test/extractor-experimental/expected/about.page.pl.js b/packages/cli/test/extractor-experimental/expected/about.page.pl.js index b8d22c234..68eddc6f6 100644 --- a/packages/cli/test/extractor-experimental/expected/about.page.pl.js +++ b/packages/cli/test/extractor-experimental/expected/about.page.pl.js @@ -1 +1 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"VmkjGB\":[\"Green\"],\"LGGfGX\":[\"translation: header message\"],\"nPi9F1\":[\"this should be marked as obsolete\"]}")}; \ No newline at end of file +/*eslint-disable*/module.exports={messages:JSON.parse("{\"LGGfGX\":[\"translation: header message\"],\"VmkjGB\":[\"Green\"],\"nPi9F1\":[\"this should be marked as obsolete\"],\"u5PTM8\":[\"about page message\"]}")}; \ No newline at end of file diff --git a/packages/metro-transformer/test/metroTransformer.test.ts b/packages/metro-transformer/test/metroTransformer.test.ts index 40317f64f..23507dec5 100644 --- a/packages/metro-transformer/test/metroTransformer.test.ts +++ b/packages/metro-transformer/test/metroTransformer.test.ts @@ -15,41 +15,44 @@ describe("Lingui Metro transformer tests", () => { process.chdir(priorCwd) }) - it.each([ - [ - "English PO file", - "en", - `/*eslint-disable*/export const messages=JSON.parse("{\\"p1AaTM\\":[\\"Add a message to your inbox\\"],\\"dEgA5A\\":[\\"Cancel\\"]}");`, - ], - [ - "Czech PO file with fallback to English", - "cs", - `/*eslint-disable*/export const messages=JSON.parse("{\\"p1AaTM\\":[\\"Přidat zprávu do doručené pošty\\"],\\"dEgA5A\\":[\\"Cancel\\"]}");`, - ], - ])( - "should transform %s to a JS export", - async (_label, langCode, expectedSnapshot) => { - const filename = path.relative( - testProjectDir, - path.join(catalogsDir, langCode, "messages.po") - ) - const result = await transformFile({ - filename, - }) + it("should transform English PO file to a JS export", async () => { + const filename = path.relative( + testProjectDir, + path.join(catalogsDir, "en", "messages.po") + ) + const result = await transformFile({ + filename, + }) + + expect(result).toMatchInlineSnapshot( + `/*eslint-disable*/export const messages=JSON.parse("{\\"dEgA5A\\":[\\"Cancel\\"],\\"p1AaTM\\":[\\"Add a message to your inbox\\"]}");` + ) + }) + + it("should transform Czech PO file with fallback to English to a JS export", async () => { + const filename = path.relative( + testProjectDir, + path.join(catalogsDir, "cs", "messages.po") + ) + const result = await transformFile({ + filename, + }) - expect(result).toMatchInlineSnapshot(expectedSnapshot) - } - ) + expect(result).toMatchInlineSnapshot( + `/*eslint-disable*/export const messages=JSON.parse("{\\"dEgA5A\\":[\\"Cancel\\"],\\"p1AaTM\\":[\\"Přidat zprávu do doručené pošty\\"]}");` + ) + }) it("given a valid absolute path (not relative to lingui config root), transformer will turn it into path relative to lingui config and succeed", async () => { // this is not how the `transformFile` function would be called in a real project and covers an implementation detail const filename = path.join(catalogsDir, "en", "messages.po") - await expect( - transformFile({ - filename, - }) - ).resolves.toMatchInlineSnapshot( - `/*eslint-disable*/export const messages=JSON.parse("{\\"p1AaTM\\":[\\"Add a message to your inbox\\"],\\"dEgA5A\\":[\\"Cancel\\"]}");` + + const result = await transformFile({ + filename, + }) + + expect(result).toMatchInlineSnapshot( + `/*eslint-disable*/export const messages=JSON.parse("{\\"dEgA5A\\":[\\"Cancel\\"],\\"p1AaTM\\":[\\"Add a message to your inbox\\"]}");` ) }) From 83d91fe7a0ff97dd1e68837c53063582b7521a55 Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Fri, 1 Aug 2025 14:27:50 +0200 Subject: [PATCH 03/19] docs: add performance optimization docs (#2296) --- website/docs/guides/optimizing-bundle-size.md | 188 ++++++++++++++++++ website/sidebars.ts | 5 + 2 files changed, 193 insertions(+) create mode 100644 website/docs/guides/optimizing-bundle-size.md diff --git a/website/docs/guides/optimizing-bundle-size.md b/website/docs/guides/optimizing-bundle-size.md new file mode 100644 index 000000000..37b3cf22c --- /dev/null +++ b/website/docs/guides/optimizing-bundle-size.md @@ -0,0 +1,188 @@ +# Keeping Your Bundle Small: How Lingui Optimizes for Performance + +When you're building a modern app with internationalization (i18n), it's easy to end up with a bloated bundle. The more languages and messages you have, the more it can grow — fast. + +Lingui helps you avoid this by aggressively optimizing how translations are handled in your code and in production builds. But these optimizations can also surprise you if you're not aware of how they work. + +This guide walks you through: + +- How Lingui shrinks your bundle +- What tradeoffs are involved +- Why development and production behave differently +- How to avoid common pitfalls +- And how to configure Lingui to fit your workflow + +## Why does this matter? + +Imagine you have a simple message: + +```tsx +Hello world +``` + +If this message is included _as-is_ in your code and translations, you might end up with: + +- The message string `"Hello world"` in your source code +- The same string as a key in your translation catalog +- And again as a value in your default language catalog + +That's three copies of the same thing — and you'll have that for _every_ message. + +Now multiply that by hundreds of messages and a few languages, and you can see where this is going. + +## So how does Lingui fix that? + +### 1. It replaces messages with compact IDs + +When you build your app, Lingui transforms: + +```tsx +Hello world +``` + +into something like: + +```tsx + +``` + +The message is no longer part of the bundle. Instead, it's replaced by a short ID. This does two things: + +- Saves space (IDs are shorter than full strings) +- Prevents duplication (only the translation needs to exist, not the original text) + +### 2. It removes the message compiler from production + +Messages like this: + +```js +"{count, plural, one {# item} other {# items}}"; +``` + +use [ICU MessageFormat](https://formatjs.io/docs/core-concepts/icu-syntax), which needs to be _compiled_ into something the Lingui runtime can use. + +Lingui includes a message compiler for this, but it's not small. + +Instead of sending that to the browser, Lingui compiles messages **ahead of time** during your build when you compile your catalogs. That way, you don't need the compiler in production at all. + +That's why you need to always compile your catalogs, even if they are in JSON format (not `.po` files). Compilation isn't about converting file formats — it's about transforming messages into a form the runtime can execute. + +:::note +✅ Tip: If you use the `@lingui/vite-plugin`, `@lingui/loader` or `@lingui/metro-transformer`, you don't need to run `lingui compile` manually — these plugins compile your catalogs automatically when you import catalogs. +::: + +## But wait... why does everything still work in development? + +Here's the clever part: Lingui works differently in dev vs prod. + +In **development**, Lingui: + +- Keeps the original message (`Hello world`) in the bundle +- Includes the message compiler so new messages work immediately + +This makes it fast to iterate. You can add a new `` and see the string in the browser right away — even if you haven't extracted or compiled anything yet. + +In **production**, Lingui: + +- Strips out all original messages +- Removes the message compiler completely + +This means you **must** extract and compile all messages ahead of time — otherwise, Lingui won't know how to render them. + +## Common Problem: “Why am I seeing weird message IDs in production?” + +Let's say you add a new message: + +```tsx +This is a new message +``` + +Everything looks fine locally, but when you deploy, users see something like: + +```text +z3fd2 +``` + +This usually means one thing: the message wasn't extracted before building. + +When Lingui compiles your catalogs, it tries to match each message ID to a source message. If the message isn't there, there's nothing to fall back to — and the raw ID ends up in the UI. + +### ✅ Solution: Always extract before building + +Make sure your build script extracts the latest messages: + +```json +"build": "lingui extract-template && vite build" +``` + +This ensures your catalogs are in sync with your source code. + +## But what if I want to load translations dynamically? + +That's where the tradeoffs come in. + +Lingui's design is optimized for build-time static analysis. It's great for most apps, but it can get tricky if you want to: + +- Load translations from a CMS +- Support over-the-air (OTA) delivery of catalogs +- Inject new messages at runtime + +In these cases, you can't rely on precompiled catalogs alone — you'll need the **runtime message compiler** again. + +To bring it back, use: + +```ts +import { compileMessage } from "@lingui/message-utils/compileMessage"; + +i18n.setMessagesCompiler(compileMessage); +``` + +Just keep in mind that this will increase your bundle size again. + +## Configuring Lingui for your needs + +Here are a few ways to customize Lingui's behavior depending on your goals: + +### 1. I want production to behave like development + +You want to keep original messages and use runtime compilation, even in production — maybe for debugging or dynamic catalogs. + +**How to configure:** + +```ts +// Macro config +stripMessageField: false; + +// Runtime setup +i18n.setMessagesCompiler(compileMessage); +``` + +### 2. I want full consistency between dev and prod + +You want everything to be stripped in both environments. Useful for catching issues early. + +**How to configure:** + +```ts +// Macro config +stripMessageField: true; + +// Runtime setup +i18n.setMessagesCompiler(null); +``` + +### 3. I want to use default Lingui behavior + +You don't change anything. Lingui automatically strips messages in production and keeps them in development. + +Just make sure to always run `extract-template` before building. + +## Macro Configuration: A quick note + +Depending on your setup, Lingui macros can be used in different ways: + +- As a standalone **Babel plugin** +- As a [**SWC plugin**](https://github.com/lingui/swc-plugin) +- Through [**babel-plugin-macros**](https://github.com/kentcdodds/babel-plugin-macros/blob/main/other/docs/user.md#config) + +Each one configures slightly differently, so check their docs for details. diff --git a/website/sidebars.ts b/website/sidebars.ts index 412f23866..ce480e24c 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -60,6 +60,11 @@ const sidebar = [ label: "Lazy Translations", id: "guides/lazy-translations", }, + { + type: "doc", + label: "Optimizing Bundle Size", + id: "guides/optimizing-bundle-size", + }, { type: "doc", label: "Pseudolocalization", From 4131c8cab750efe9f8863215b94dcd4f986cba07 Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Fri, 1 Aug 2025 15:55:06 +0300 Subject: [PATCH 04/19] chore(deps-dev): bump Lerna from 8.1.9 to 8.2.4 (#2301) --- package.json | 2 +- yarn.lock | 279 ++++++++++++++++++++------------------------------- 2 files changed, 111 insertions(+), 170 deletions(-) diff --git a/package.json b/package.json index 9043c78f2..2d2a76dbd 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jest-environment-node-single-context": "^29.4.0", - "lerna": "^8.1.9", + "lerna": "^8.2.4", "lint-staged": "^13.1.0", "memory-fs": "^0.5.0", "minimist": "^1.2.5", diff --git a/yarn.lock b/yarn.lock index 545c377c5..6fc066f28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2545,16 +2545,16 @@ __metadata: languageName: node linkType: hard -"@lerna/create@npm:8.1.9": - version: 8.1.9 - resolution: "@lerna/create@npm:8.1.9" +"@lerna/create@npm:8.2.4": + version: 8.2.4 + resolution: "@lerna/create@npm:8.2.4" dependencies: "@npmcli/arborist": 7.5.4 "@npmcli/package-json": 5.2.0 "@npmcli/run-script": 8.1.0 "@nx/devkit": ">=17.1.2 < 21" "@octokit/plugin-enterprise-rest": 6.0.1 - "@octokit/rest": 19.0.11 + "@octokit/rest": 20.1.2 aproba: 2.0.0 byte-size: 8.1.1 chalk: 4.1.0 @@ -2572,7 +2572,6 @@ __metadata: get-stream: 6.0.0 git-url-parse: 14.0.0 glob-parent: 6.0.2 - globby: 11.1.0 graceful-fs: 4.2.11 has-unicode: 2.0.1 ini: ^1.3.8 @@ -2583,7 +2582,6 @@ __metadata: js-yaml: 4.1.0 libnpmpublish: 9.0.9 load-json-file: 6.2.0 - lodash: ^4.17.21 make-dir: 4.0.0 minimatch: 3.0.5 multimatch: 5.0.0 @@ -2607,10 +2605,10 @@ __metadata: slash: ^3.0.0 ssri: ^10.0.6 string-width: ^4.2.3 - strip-ansi: ^6.0.1 - strong-log-transformer: 2.1.0 tar: 6.2.1 temp-dir: 1.0.0 + through: 2.3.8 + tinyglobby: 0.2.12 upath: 2.0.1 uuid: ^10.0.0 validate-npm-package-license: ^3.0.4 @@ -2620,7 +2618,7 @@ __metadata: write-pkg: 4.0.0 yargs: 17.7.2 yargs-parser: 21.1.1 - checksum: 3c33438b2465bd46634242cf5146a8ea681d4eb5af6ba9edf6bfeba31de7db004b309f2062d0746617d465cee29fe9f21c4ef45d981d51641cc0bf92d43410ea + checksum: 79ccd20fac694813728b6582f806f12b3549a3bc87a91d6df6260e0c623b669fa1f84815d985b1c5c9f6d717a57e7407b8e8c5e5e770d7ff39b3bdba9e91883f languageName: node linkType: hard @@ -3318,56 +3316,53 @@ __metadata: languageName: node linkType: hard -"@octokit/auth-token@npm:^3.0.0": - version: 3.0.3 - resolution: "@octokit/auth-token@npm:3.0.3" - dependencies: - "@octokit/types": ^9.0.0 - checksum: 9b3f569cec1b7e0aa88ab6da68aed4b49b6652261bd957257541fabaf6a4d4ed99f908153cc3dd2fe15b8b0ccaff8caaafaa50bb1a4de3925b0954a47cca1900 +"@octokit/auth-token@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/auth-token@npm:4.0.0" + checksum: d78f4dc48b214d374aeb39caec4fdbf5c1e4fd8b9fcb18f630b1fe2cbd5a880fca05445f32b4561f41262cb551746aeb0b49e89c95c6dd99299706684d0cae2f languageName: node linkType: hard -"@octokit/core@npm:^4.2.1": - version: 4.2.4 - resolution: "@octokit/core@npm:4.2.4" +"@octokit/core@npm:^5.0.2": + version: 5.2.2 + resolution: "@octokit/core@npm:5.2.2" dependencies: - "@octokit/auth-token": ^3.0.0 - "@octokit/graphql": ^5.0.0 - "@octokit/request": ^6.0.0 - "@octokit/request-error": ^3.0.0 - "@octokit/types": ^9.0.0 + "@octokit/auth-token": ^4.0.0 + "@octokit/graphql": ^7.1.0 + "@octokit/request": ^8.4.1 + "@octokit/request-error": ^5.1.1 + "@octokit/types": ^13.0.0 before-after-hook: ^2.2.0 universal-user-agent: ^6.0.0 - checksum: ac8ab47440a31b0228a034aacac6994b64d6b073ad5b688b4c5157fc5ee0d1af1c926e6087bf17fd7244ee9c5998839da89065a90819bde4a97cb77d4edf58a6 + checksum: d4303d808c6b8eca32ce03381db5f6230440c1c6cfd9d73376ed583973094abd8ca56d9a64d490e6b0045f827a8f913b619bd90eae99c2cba682487720dc8002 languageName: node linkType: hard -"@octokit/endpoint@npm:^7.0.0": - version: 7.0.5 - resolution: "@octokit/endpoint@npm:7.0.5" +"@octokit/endpoint@npm:^9.0.6": + version: 9.0.6 + resolution: "@octokit/endpoint@npm:9.0.6" dependencies: - "@octokit/types": ^9.0.0 - is-plain-object: ^5.0.0 + "@octokit/types": ^13.1.0 universal-user-agent: ^6.0.0 - checksum: 81c9e9eabf50e48940cceff7c4d7fbc9327190296507cfe8a199ea00cd492caf8f18a841caf4e3619828924b481996eb16091826db6b5a649bee44c8718ecaa9 + checksum: f853c08f0777a8cc7c3d2509835d478e11a76d722f807d4f2ad7c0e64bf4dd159536409f466b367a907886aa3b78574d3d09ed95ac462c769e4fccaaad81e72a languageName: node linkType: hard -"@octokit/graphql@npm:^5.0.0": - version: 5.0.5 - resolution: "@octokit/graphql@npm:5.0.5" +"@octokit/graphql@npm:^7.1.0": + version: 7.1.1 + resolution: "@octokit/graphql@npm:7.1.1" dependencies: - "@octokit/request": ^6.0.0 - "@octokit/types": ^9.0.0 + "@octokit/request": ^8.4.1 + "@octokit/types": ^13.0.0 universal-user-agent: ^6.0.0 - checksum: eb2d1a6305a3d1f55ff0ce92fb88b677f0bb789757152d58a79ef61171fb65ecf6fe18d6c27e236c0cee6a0c2600c2cb8370f5ac7184f8e9361c085aa4555bb1 + checksum: afb60d5dda6d365334480540610d67b0c5f8e3977dd895fe504ce988f8b7183f29f3b16b88d895a701a739cf29d157d49f8f9fbc71b6c57eb4fc9bd97e099f55 languageName: node linkType: hard -"@octokit/openapi-types@npm:^18.0.0": - version: 18.1.1 - resolution: "@octokit/openapi-types@npm:18.1.1" - checksum: 94f42977fd2fcb9983c781fd199bc11218885a1226d492680bfb1268524a1b2af48a768eef90c63b80a2874437de641d59b3b7f640a5afa93e7c21fe1a79069a +"@octokit/openapi-types@npm:^24.2.0": + version: 24.2.0 + resolution: "@octokit/openapi-types@npm:24.2.0" + checksum: 3c2d2f4cafd21c8a1e6a6fe6b56df6a3c09bc52ab6f829c151f9397694d028aa183ae856f08e006ee7ecaa7bd7eb413a903fbc0ffa6403e7b284ddcda20b1294 languageName: node linkType: hard @@ -3378,97 +3373,78 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-paginate-rest@npm:^6.1.2": - version: 6.1.2 - resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" +"@octokit/plugin-paginate-rest@npm:11.4.4-cjs.2": + version: 11.4.4-cjs.2 + resolution: "@octokit/plugin-paginate-rest@npm:11.4.4-cjs.2" dependencies: - "@octokit/tsconfig": ^1.0.2 - "@octokit/types": ^9.2.3 + "@octokit/types": ^13.7.0 peerDependencies: - "@octokit/core": ">=4" - checksum: a7b3e686c7cbd27ec07871cde6e0b1dc96337afbcef426bbe3067152a17b535abd480db1861ca28c88d93db5f7bfdbcadd0919ead19818c28a69d0e194038065 + "@octokit/core": 5 + checksum: e6d1f4da255d08c24188b5df1436f22680e7fe2608d3af5d2f08a98f40d565bd3df0c58d306f05caae923247fffe861ec12d5f1273a882333fcdb34255e6c8b0 languageName: node linkType: hard -"@octokit/plugin-request-log@npm:^1.0.4": - version: 1.0.4 - resolution: "@octokit/plugin-request-log@npm:1.0.4" +"@octokit/plugin-request-log@npm:^4.0.0": + version: 4.0.1 + resolution: "@octokit/plugin-request-log@npm:4.0.1" peerDependencies: - "@octokit/core": ">=3" - checksum: 2086db00056aee0f8ebd79797b5b57149ae1014e757ea08985b71eec8c3d85dbb54533f4fd34b6b9ecaa760904ae6a7536be27d71e50a3782ab47809094bfc0c + "@octokit/core": 5 + checksum: fd8c0a201490cba00084689a0d1d54fc7b5ab5b6bdb7e447056b947b1754f78526e9685400eab10d3522bfa7b5bc49c555f41ec412c788610b96500b168f3789 languageName: node linkType: hard -"@octokit/plugin-rest-endpoint-methods@npm:^7.1.2": - version: 7.2.3 - resolution: "@octokit/plugin-rest-endpoint-methods@npm:7.2.3" +"@octokit/plugin-rest-endpoint-methods@npm:13.3.2-cjs.1": + version: 13.3.2-cjs.1 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.3.2-cjs.1" dependencies: - "@octokit/types": ^10.0.0 + "@octokit/types": ^13.8.0 peerDependencies: - "@octokit/core": ">=3" - checksum: 21dfb98514dbe900c29cddb13b335bbce43d613800c6b17eba3c1fd31d17e69c1960f3067f7bf864bb38fdd5043391f4a23edee42729d8c7fbabd00569a80336 + "@octokit/core": ^5 + checksum: de38a7fe33aa41ecfa62dd8546d9b603cf43b1a6cf3a31e8c1950684e1cf0f9dc7ccbcff8ef570e825729f3800f42e6ae33447c836dfa12259391ced421df64f languageName: node linkType: hard -"@octokit/request-error@npm:^3.0.0": - version: 3.0.3 - resolution: "@octokit/request-error@npm:3.0.3" +"@octokit/request-error@npm:^5.1.1": + version: 5.1.1 + resolution: "@octokit/request-error@npm:5.1.1" dependencies: - "@octokit/types": ^9.0.0 + "@octokit/types": ^13.1.0 deprecation: ^2.0.0 once: ^1.4.0 - checksum: 5db0b514732686b627e6ed9ef1ccdbc10501f1b271a9b31f784783f01beee70083d7edcfeb35fbd7e569fa31fdd6762b1ff6b46101700d2d97e7e48e749520d0 + checksum: 17d0b3f59c2a8a285715bfe6a85168d9c417aa7a0ff553b9be4198a3bc8bb00384a3530221a448eb19f8f07ea9fc48d264869624f5f84fa63a948a7af8cddc8c languageName: node linkType: hard -"@octokit/request@npm:^6.0.0": - version: 6.2.3 - resolution: "@octokit/request@npm:6.2.3" +"@octokit/request@npm:^8.4.1": + version: 8.4.1 + resolution: "@octokit/request@npm:8.4.1" dependencies: - "@octokit/endpoint": ^7.0.0 - "@octokit/request-error": ^3.0.0 - "@octokit/types": ^9.0.0 - is-plain-object: ^5.0.0 - node-fetch: ^2.6.7 + "@octokit/endpoint": ^9.0.6 + "@octokit/request-error": ^5.1.1 + "@octokit/types": ^13.1.0 universal-user-agent: ^6.0.0 - checksum: fef4097be8375d20bb0b3276d8a3adf866ec628f2b0664d334f3c29b92157da847899497abdc7a5be540053819b55564990543175ad48f04e9e6f25f0395d4d3 - languageName: node - linkType: hard - -"@octokit/rest@npm:19.0.11": - version: 19.0.11 - resolution: "@octokit/rest@npm:19.0.11" - dependencies: - "@octokit/core": ^4.2.1 - "@octokit/plugin-paginate-rest": ^6.1.2 - "@octokit/plugin-request-log": ^1.0.4 - "@octokit/plugin-rest-endpoint-methods": ^7.1.2 - checksum: 147518ad51d214ead88adc717b5fdc4f33317949d58c124f4069bdf07d2e6b49fa66861036b9e233aed71fcb88ff367a6da0357653484e466175ab4fb7183b3b + checksum: 0ba76728583543baeef9fda98690bc86c57e0a3ccac8c189d2b7d144d248c89167eb37a071ed8fead8f4da0a1c55c4dd98a8fc598769c263b95179fb200959de languageName: node linkType: hard -"@octokit/tsconfig@npm:^1.0.2": - version: 1.0.2 - resolution: "@octokit/tsconfig@npm:1.0.2" - checksum: 74d56f3e9f326a8dd63700e9a51a7c75487180629c7a68bbafee97c612fbf57af8347369bfa6610b9268a3e8b833c19c1e4beb03f26db9a9dce31f6f7a19b5b1 - languageName: node - linkType: hard - -"@octokit/types@npm:^10.0.0": - version: 10.0.0 - resolution: "@octokit/types@npm:10.0.0" +"@octokit/rest@npm:20.1.2": + version: 20.1.2 + resolution: "@octokit/rest@npm:20.1.2" dependencies: - "@octokit/openapi-types": ^18.0.0 - checksum: 8aafba2ff0cd2435fb70c291bf75ed071c0fa8a865cf6169648732068a35dec7b85a345851f18920ec5f3e94ee0e954988485caac0da09ec3f6781cc44fe153a + "@octokit/core": ^5.0.2 + "@octokit/plugin-paginate-rest": 11.4.4-cjs.2 + "@octokit/plugin-request-log": ^4.0.0 + "@octokit/plugin-rest-endpoint-methods": 13.3.2-cjs.1 + checksum: 72309dd393f3424f0c4213d045332c1c1a00893bea4db9b54d6add7316d9a9b461932de3afe3c866bff52cc084c79e98f644dabd386cda95068690cc9ae97456 languageName: node linkType: hard -"@octokit/types@npm:^9.0.0, @octokit/types@npm:^9.2.3": - version: 9.3.2 - resolution: "@octokit/types@npm:9.3.2" +"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.1.0, @octokit/types@npm:^13.7.0, @octokit/types@npm:^13.8.0": + version: 13.10.0 + resolution: "@octokit/types@npm:13.10.0" dependencies: - "@octokit/openapi-types": ^18.0.0 - checksum: f55d096aaed3e04b8308d4422104fb888f355988056ba7b7ef0a4c397b8a3e54290d7827b06774dbe0c9ce55280b00db486286954f9c265aa6b03091026d9da8 + "@octokit/openapi-types": ^24.2.0 + checksum: fca3764548d5872535b9025c3b5fe6373fe588b287cb5b5259364796c1931bbe5e9ab8a86a5274ce43bb2b3e43b730067c3b86b6b1ade12a98cd59b2e8b3610d languageName: node linkType: hard @@ -6826,13 +6802,6 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:^0.1.1": - version: 0.1.2 - resolution: "duplexer@npm:0.1.2" - checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -7987,7 +7956,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": +"fast-glob@npm:^3.3.0": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" dependencies: @@ -8057,6 +8026,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.4.3": + version: 6.4.6 + resolution: "fdir@npm:6.4.6" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: fe9f3014901d023cf631831dcb9eae5447f4d7f69218001dd01ecf007eccc40f6c129a04411b5cc273a5f93c14e02e971e17270afc9022041c80be924091eb6f + languageName: node + linkType: hard + "figures@npm:3.2.0, figures@npm:^3.0.0": version: 3.2.0 resolution: "figures@npm:3.2.0" @@ -8675,20 +8656,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:11.1.0": - version: 11.1.0 - resolution: "globby@npm:11.1.0" - dependencies: - array-union: ^2.1.0 - dir-glob: ^3.0.1 - fast-glob: ^3.2.9 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^3.0.0 - checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 - languageName: node - linkType: hard - "globby@npm:^13.2.2": version: 13.2.2 resolution: "globby@npm:13.2.2" @@ -9578,13 +9545,6 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^5.0.0": - version: 5.0.0 - resolution: "is-plain-object@npm:5.0.0" - checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c - languageName: node - linkType: hard - "is-potential-custom-element-name@npm:^1.0.1": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" @@ -10507,7 +10467,7 @@ __metadata: jest: ^29.7.0 jest-environment-jsdom: ^29.7.0 jest-environment-node-single-context: ^29.4.0 - lerna: ^8.1.9 + lerna: ^8.2.4 lint-staged: ^13.1.0 memory-fs: ^0.5.0 minimist: ^1.2.5 @@ -10845,17 +10805,17 @@ __metadata: languageName: node linkType: hard -"lerna@npm:^8.1.9": - version: 8.1.9 - resolution: "lerna@npm:8.1.9" +"lerna@npm:^8.2.4": + version: 8.2.4 + resolution: "lerna@npm:8.2.4" dependencies: - "@lerna/create": 8.1.9 + "@lerna/create": 8.2.4 "@npmcli/arborist": 7.5.4 "@npmcli/package-json": 5.2.0 "@npmcli/run-script": 8.1.0 "@nx/devkit": ">=17.1.2 < 21" "@octokit/plugin-enterprise-rest": 6.0.1 - "@octokit/rest": 19.0.11 + "@octokit/rest": 20.1.2 aproba: 2.0.0 byte-size: 8.1.1 chalk: 4.1.0 @@ -10876,7 +10836,6 @@ __metadata: get-stream: 6.0.0 git-url-parse: 14.0.0 glob-parent: 6.0.2 - globby: 11.1.0 graceful-fs: 4.2.11 has-unicode: 2.0.1 import-local: 3.1.0 @@ -10890,7 +10849,6 @@ __metadata: libnpmaccess: 8.0.6 libnpmpublish: 9.0.9 load-json-file: 6.2.0 - lodash: ^4.17.21 make-dir: 4.0.0 minimatch: 3.0.5 multimatch: 5.0.0 @@ -10916,10 +10874,10 @@ __metadata: slash: 3.0.0 ssri: ^10.0.6 string-width: ^4.2.3 - strip-ansi: ^6.0.1 - strong-log-transformer: 2.1.0 tar: 6.2.1 temp-dir: 1.0.0 + through: 2.3.8 + tinyglobby: 0.2.12 typescript: ">=3 < 6" upath: 2.0.1 uuid: ^10.0.0 @@ -10932,7 +10890,7 @@ __metadata: yargs-parser: 21.1.1 bin: lerna: dist/cli.js - checksum: 2e604325eb455f34b021ccf95ef94796a84ba1dc20f1c2bfa9f74f9e337cdb41ab0d6d997971424ec8b9967b45c55ca0b318432bc7f3de7f92333ba6b65bf82a + checksum: ab46ecdf65a35d5171caa1d34023219c444aba328287e8ba49d22310f43918c98feb50b074c3191fa2da4102dd71f1292a4226b68083057c55aa811486c58cd8 languageName: node linkType: hard @@ -11883,20 +11841,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.7": - version: 2.6.8 - resolution: "node-fetch@npm:2.6.8" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 91f57be68e29f9b1382750693619e199733a6936998e6d618f1aa779853ad8fc4a2facf170db7957bf1d2510bad33449edf74b5802713d81b63de5986fa3be00 - languageName: node - linkType: hard - "node-gettext@npm:^3.0.0": version: 3.0.0 resolution: "node-gettext@npm:3.0.0" @@ -14761,19 +14705,6 @@ __metadata: languageName: node linkType: hard -"strong-log-transformer@npm:2.1.0": - version: 2.1.0 - resolution: "strong-log-transformer@npm:2.1.0" - dependencies: - duplexer: ^0.1.1 - minimist: ^1.2.0 - through: ^2.3.4 - bin: - sl-log-transformer: bin/sl-log-transformer.js - checksum: abf9a4ac143118f26c3a0771b204b02f5cf4fa80384ae158f25e02bfbff761038accc44a7f65869ccd5a5995a7f2c16b1466b83149644ba6cecd3072a8927297 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -14931,13 +14862,23 @@ __metadata: languageName: node linkType: hard -"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.4, through@npm:^2.3.6, through@npm:^2.3.8": +"through@npm:2, through@npm:2.3.8, through@npm:>=2.2.7 <3, through@npm:^2.3.6, through@npm:^2.3.8": version: 2.3.8 resolution: "through@npm:2.3.8" checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd languageName: node linkType: hard +"tinyglobby@npm:0.2.12": + version: 0.2.12 + resolution: "tinyglobby@npm:0.2.12" + dependencies: + fdir: ^6.4.3 + picomatch: ^4.0.2 + checksum: ef9357fa1b2b661afdccd315cb4995f5f36bce948faaace68aae85fe57bdd8f837883045c88efc50d3186bac6586e4ae2f31026b9a3aac061b884217e6092e23 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.7": version: 0.2.10 resolution: "tinyglobby@npm:0.2.10" From ce0d17bd0874f5f4f01fd073749f29087835a315 Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Fri, 1 Aug 2025 16:31:32 +0300 Subject: [PATCH 05/19] chore(release): published v5.4.0 [skip ci] (#2302) --- CHANGELOG.md | 12 +++ lerna.json | 2 +- .../CHANGELOG.md | 4 + .../package.json | 2 +- .../babel-plugin-lingui-macro/CHANGELOG.md | 4 + .../babel-plugin-lingui-macro/package.json | 8 +- packages/cli/CHANGELOG.md | 6 ++ packages/cli/package.json | 14 +-- packages/conf/CHANGELOG.md | 4 + packages/conf/package.json | 2 +- packages/core/CHANGELOG.md | 4 + packages/core/package.json | 6 +- packages/detect-locale/CHANGELOG.md | 4 + packages/detect-locale/package.json | 2 +- packages/extractor-vue/CHANGELOG.md | 4 + packages/extractor-vue/package.json | 8 +- packages/format-csv/CHANGELOG.md | 4 + packages/format-csv/package.json | 4 +- packages/format-json/CHANGELOG.md | 4 + packages/format-json/package.json | 4 +- packages/format-po-gettext/CHANGELOG.md | 4 + packages/format-po-gettext/package.json | 8 +- packages/format-po/CHANGELOG.md | 4 + packages/format-po/package.json | 6 +- packages/loader/CHANGELOG.md | 4 + packages/loader/package.json | 8 +- packages/macro/CHANGELOG.md | 4 + packages/macro/package.json | 8 +- packages/message-utils/CHANGELOG.md | 4 + packages/message-utils/package.json | 2 +- packages/metro-transformer/CHANGELOG.md | 10 +++ packages/metro-transformer/package.json | 8 +- packages/react/CHANGELOG.md | 6 ++ packages/react/package.json | 6 +- packages/vite-plugin/CHANGELOG.md | 4 + packages/vite-plugin/package.json | 6 +- yarn.lock | 86 +++++++++---------- 37 files changed, 185 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f84ac41c1..eeb157b63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +### Bug Fixes + +* remove `VFC`, `FC` type usage ([#2290](https://github.com/lingui/js-lingui/issues/2290)) ([30e5242](https://github.com/lingui/js-lingui/commit/30e5242f132a7e0aa847f45b472330f6113b0168)) +* remove metro peer dep from metro-transformer ([#2287](https://github.com/lingui/js-lingui/issues/2287)) ([eb8a429](https://github.com/lingui/js-lingui/commit/eb8a4295bf3ea216a8bc1cba736f28e6b44c9107)) + + +### Features + +* full concurrency for extract / compile commands ([#2299](https://github.com/lingui/js-lingui/issues/2299)) ([489fb3a](https://github.com/lingui/js-lingui/commit/489fb3a7c999632e57286369e44a0c6e77a3407b)) + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/lerna.json b/lerna.json index 3d03f8495..769852a6f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.3.3", + "version": "5.4.0", "packages": ["packages/*"], "npmClient": "yarn", "command": { diff --git a/packages/babel-plugin-extract-messages/CHANGELOG.md b/packages/babel-plugin-extract-messages/CHANGELOG.md index 8652b62aa..5cd5c381c 100644 --- a/packages/babel-plugin-extract-messages/CHANGELOG.md +++ b/packages/babel-plugin-extract-messages/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/babel-plugin-extract-messages + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/babel-plugin-extract-messages/package.json b/packages/babel-plugin-extract-messages/package.json index 727dfa3e1..aa141d5e3 100644 --- a/packages/babel-plugin-extract-messages/package.json +++ b/packages/babel-plugin-extract-messages/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-extract-messages", - "version": "5.3.3", + "version": "5.4.0", "description": "Babel plugin for collecting messages from source code for internationalization", "main": "./dist/index.cjs", "module": "./dist/index.mjs", diff --git a/packages/babel-plugin-lingui-macro/CHANGELOG.md b/packages/babel-plugin-lingui-macro/CHANGELOG.md index 8ccc360e9..1dd12e80f 100644 --- a/packages/babel-plugin-lingui-macro/CHANGELOG.md +++ b/packages/babel-plugin-lingui-macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/babel-plugin-lingui-macro + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/babel-plugin-lingui-macro/package.json b/packages/babel-plugin-lingui-macro/package.json index 351c7ecd6..9511b2e2e 100644 --- a/packages/babel-plugin-lingui-macro/package.json +++ b/packages/babel-plugin-lingui-macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-lingui-macro", - "version": "5.3.3", + "version": "5.4.0", "description": "Babel plugin for transforming Lingui Macros", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -86,9 +86,9 @@ "@babel/core": "^7.20.12", "@babel/runtime": "^7.20.13", "@babel/types": "^7.20.7", - "@lingui/conf": "5.3.3", - "@lingui/core": "5.3.3", - "@lingui/message-utils": "5.3.3" + "@lingui/conf": "5.4.0", + "@lingui/core": "5.4.0", + "@lingui/message-utils": "5.4.0" }, "peerDependencies": { "babel-plugin-macros": "2 || 3" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 36ba39e91..8a4719167 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +### Features + +* full concurrency for extract / compile commands ([#2299](https://github.com/lingui/js-lingui/issues/2299)) ([489fb3a](https://github.com/lingui/js-lingui/commit/489fb3a7c999632e57286369e44a0c6e77a3407b)) + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/cli/package.json b/packages/cli/package.json index 4eb7de90d..a6e2a5159 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/cli", - "version": "5.3.3", + "version": "5.4.0", "description": "CLI for working wit message catalogs", "keywords": [ "cli", @@ -62,12 +62,12 @@ "@babel/parser": "^7.22.0", "@babel/runtime": "^7.21.0", "@babel/types": "^7.21.2", - "@lingui/babel-plugin-extract-messages": "5.3.3", - "@lingui/babel-plugin-lingui-macro": "5.3.3", - "@lingui/conf": "5.3.3", - "@lingui/core": "5.3.3", - "@lingui/format-po": "5.3.3", - "@lingui/message-utils": "5.3.3", + "@lingui/babel-plugin-extract-messages": "5.4.0", + "@lingui/babel-plugin-lingui-macro": "5.4.0", + "@lingui/conf": "5.4.0", + "@lingui/core": "5.4.0", + "@lingui/format-po": "5.4.0", + "@lingui/message-utils": "5.4.0", "chokidar": "3.5.1", "cli-table": "^0.3.11", "commander": "^10.0.0", diff --git a/packages/conf/CHANGELOG.md b/packages/conf/CHANGELOG.md index 609e5e5c8..242ceb9c6 100644 --- a/packages/conf/CHANGELOG.md +++ b/packages/conf/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/conf + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/conf/package.json b/packages/conf/package.json index f5ef1e650..7eed46037 100644 --- a/packages/conf/package.json +++ b/packages/conf/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/conf", - "version": "5.3.3", + "version": "5.4.0", "sideEffects": false, "description": "Get lingui configuration from package.json", "keywords": [ diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index b1ce4eb47..505a92fd7 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/core + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/core/package.json b/packages/core/package.json index 06aa0f913..190d04085 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/core", - "version": "5.3.3", + "version": "5.4.0", "sideEffects": false, "description": "I18n tools for javascript", "main": "./dist/index.cjs", @@ -62,14 +62,14 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.3.3" + "@lingui/message-utils": "5.4.0" }, "devDependencies": { "@lingui/jest-mocks": "*", "unbuild": "2.0.0" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.3.3", + "@lingui/babel-plugin-lingui-macro": "5.4.0", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/detect-locale/CHANGELOG.md b/packages/detect-locale/CHANGELOG.md index 78f132149..7e4de9647 100644 --- a/packages/detect-locale/CHANGELOG.md +++ b/packages/detect-locale/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/detect-locale + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/detect-locale/package.json b/packages/detect-locale/package.json index 9c89aa71e..e205d4617 100644 --- a/packages/detect-locale/package.json +++ b/packages/detect-locale/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/detect-locale", - "version": "5.3.3", + "version": "5.4.0", "sideEffects": false, "description": "@Lingui package to help you find the correct browser/server locale", "main": "./dist/index.cjs", diff --git a/packages/extractor-vue/CHANGELOG.md b/packages/extractor-vue/CHANGELOG.md index 7be4b0c22..a81a7c436 100644 --- a/packages/extractor-vue/CHANGELOG.md +++ b/packages/extractor-vue/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/extractor-vue + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/extractor-vue/package.json b/packages/extractor-vue/package.json index 1369ba487..c8d2d581b 100644 --- a/packages/extractor-vue/package.json +++ b/packages/extractor-vue/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/extractor-vue", - "version": "5.3.3", + "version": "5.4.0", "description": "Custom Vue.js extractor to be used with the CLI tool", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -43,12 +43,12 @@ "/dist" ], "dependencies": { - "@lingui/cli": "5.3.3", - "@lingui/conf": "5.3.3", + "@lingui/cli": "5.4.0", + "@lingui/conf": "5.4.0", "@vue/compiler-sfc": "^3.2.47" }, "devDependencies": { - "@lingui/babel-plugin-extract-messages": "5.3.3", + "@lingui/babel-plugin-extract-messages": "5.4.0", "unbuild": "2.0.0" } } diff --git a/packages/format-csv/CHANGELOG.md b/packages/format-csv/CHANGELOG.md index 651497282..dd8e4f1ab 100644 --- a/packages/format-csv/CHANGELOG.md +++ b/packages/format-csv/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/format-csv + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/format-csv/package.json b/packages/format-csv/package.json index 071ab0a04..9db4dac42 100644 --- a/packages/format-csv/package.json +++ b/packages/format-csv/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-csv", - "version": "5.3.3", + "version": "5.4.0", "description": "CSV format for Lingui Catalogs", "main": "./dist/csv.cjs", "module": "./dist/csv.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.3.3", + "@lingui/conf": "5.4.0", "papaparse": "^5.4.0" }, "devDependencies": { diff --git a/packages/format-json/CHANGELOG.md b/packages/format-json/CHANGELOG.md index 2f2b742f6..19e59bf5d 100644 --- a/packages/format-json/CHANGELOG.md +++ b/packages/format-json/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/format-json + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/format-json/package.json b/packages/format-json/package.json index d15f9b50a..c9827dd64 100644 --- a/packages/format-json/package.json +++ b/packages/format-json/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-json", - "version": "5.3.3", + "version": "5.4.0", "description": "JSON format for Lingui Catalogs", "main": "./dist/json.cjs", "module": "./dist/json.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.3.3" + "@lingui/conf": "5.4.0" }, "devDependencies": { "unbuild": "^2.0.0" diff --git a/packages/format-po-gettext/CHANGELOG.md b/packages/format-po-gettext/CHANGELOG.md index c64a2e49a..89f65d0a7 100644 --- a/packages/format-po-gettext/CHANGELOG.md +++ b/packages/format-po-gettext/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/format-po-gettext + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/format-po-gettext/package.json b/packages/format-po-gettext/package.json index 6bd1de5b3..35ef91703 100644 --- a/packages/format-po-gettext/package.json +++ b/packages/format-po-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po-gettext", - "version": "5.3.3", + "version": "5.4.0", "description": "Gettext PO format with gettext-style plurals for Lingui Catalogs", "main": "./dist/po-gettext.cjs", "module": "./dist/po-gettext.mjs", @@ -43,9 +43,9 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.3.3", - "@lingui/format-po": "5.3.3", - "@lingui/message-utils": "5.3.3", + "@lingui/conf": "5.4.0", + "@lingui/format-po": "5.4.0", + "@lingui/message-utils": "5.4.0", "@messageformat/parser": "^5.0.0", "cldr-core": "^45.0.0", "node-gettext": "^3.0.0", diff --git a/packages/format-po/CHANGELOG.md b/packages/format-po/CHANGELOG.md index 10ee1aaf1..6813a5969 100644 --- a/packages/format-po/CHANGELOG.md +++ b/packages/format-po/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/format-po + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/format-po/package.json b/packages/format-po/package.json index 7374b4740..d7ad38463 100644 --- a/packages/format-po/package.json +++ b/packages/format-po/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po", - "version": "5.3.3", + "version": "5.4.0", "description": "Gettext PO format for Lingui Catalogs", "main": "./dist/po.cjs", "module": "./dist/po.mjs", @@ -43,8 +43,8 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.3.3", - "@lingui/message-utils": "5.3.3", + "@lingui/conf": "5.4.0", + "@lingui/message-utils": "5.4.0", "date-fns": "^3.6.0", "pofile": "^1.1.4" }, diff --git a/packages/loader/CHANGELOG.md b/packages/loader/CHANGELOG.md index 9f3296dd9..9583fe75a 100644 --- a/packages/loader/CHANGELOG.md +++ b/packages/loader/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/loader + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/loader/package.json b/packages/loader/package.json index 40abbca52..fda92c2fe 100644 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/loader", - "version": "5.3.3", + "version": "5.4.0", "description": "webpack loader for lingui message catalogs", "types": "./dist/index.d.ts", "main": "./dist/index.cjs", @@ -45,11 +45,11 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.3.3", - "@lingui/conf": "5.3.3" + "@lingui/cli": "5.4.0", + "@lingui/conf": "5.4.0" }, "devDependencies": { - "@lingui/format-json": "5.3.3", + "@lingui/format-json": "5.4.0", "unbuild": "2.0.0", "webpack": "^5.76.1" }, diff --git a/packages/macro/CHANGELOG.md b/packages/macro/CHANGELOG.md index 5e9d15056..0ef3dcda7 100644 --- a/packages/macro/CHANGELOG.md +++ b/packages/macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/macro + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/macro/package.json b/packages/macro/package.json index 00d1cd0a8..fca3662e7 100644 --- a/packages/macro/package.json +++ b/packages/macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/macro", - "version": "5.3.3", + "version": "5.4.0", "description": "Macro for generating messages in ICU MessageFormat syntax", "main": "./index.js", "types": "./index.d.ts", @@ -46,11 +46,11 @@ "index.js" ], "dependencies": { - "@lingui/core": "5.3.3", - "@lingui/react": "5.3.3" + "@lingui/core": "5.4.0", + "@lingui/react": "5.4.0" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.3.3", + "@lingui/babel-plugin-lingui-macro": "5.4.0", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/message-utils/CHANGELOG.md b/packages/message-utils/CHANGELOG.md index cc2c43f25..640296e8a 100644 --- a/packages/message-utils/CHANGELOG.md +++ b/packages/message-utils/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/message-utils + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/message-utils/package.json b/packages/message-utils/package.json index e80d775fd..aa1710215 100644 --- a/packages/message-utils/package.json +++ b/packages/message-utils/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/message-utils", - "version": "5.3.3", + "version": "5.4.0", "license": "MIT", "keywords": [], "sideEffects": false, diff --git a/packages/metro-transformer/CHANGELOG.md b/packages/metro-transformer/CHANGELOG.md index e99e964b7..cf86e3209 100644 --- a/packages/metro-transformer/CHANGELOG.md +++ b/packages/metro-transformer/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +### Bug Fixes + +* remove metro peer dep from metro-transformer ([#2287](https://github.com/lingui/js-lingui/issues/2287)) ([eb8a429](https://github.com/lingui/js-lingui/commit/eb8a4295bf3ea216a8bc1cba736f28e6b44c9107)) + +### Features + +* full concurrency for extract / compile commands ([#2299](https://github.com/lingui/js-lingui/issues/2299)) ([489fb3a](https://github.com/lingui/js-lingui/commit/489fb3a7c999632e57286369e44a0c6e77a3407b)) + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/metro-transformer/package.json b/packages/metro-transformer/package.json index c012befca..c6795b31c 100644 --- a/packages/metro-transformer/package.json +++ b/packages/metro-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/metro-transformer", - "version": "5.3.3", + "version": "5.4.0", "description": "Metro bundler transformer for LinguiJS catalogs", "exports": { "./expo": { @@ -58,12 +58,12 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.3.3", - "@lingui/conf": "5.3.3", + "@lingui/cli": "5.4.0", + "@lingui/conf": "5.4.0", "memoize-one": "^6.0.0" }, "devDependencies": { - "@lingui/format-json": "5.3.3", + "@lingui/format-json": "5.4.0", "rimraf": "^6.0.1", "unbuild": "2.0.0" }, diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 935321393..f98c0fb89 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +### Bug Fixes + +* remove `VFC`, `FC` type usage ([#2290](https://github.com/lingui/js-lingui/issues/2290)) ([30e5242](https://github.com/lingui/js-lingui/commit/30e5242f132a7e0aa847f45b472330f6113b0168)) + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/react/package.json b/packages/react/package.json index 90fa7853f..ec1233ad0 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/react", - "version": "5.3.3", + "version": "5.4.0", "sideEffects": false, "description": "React components for translations", "main": "./dist/index.cjs", @@ -79,7 +79,7 @@ "macro/index.js" ], "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.3.3", + "@lingui/babel-plugin-lingui-macro": "5.4.0", "babel-plugin-macros": "2 || 3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -93,7 +93,7 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/core": "5.3.3" + "@lingui/core": "5.4.0" }, "devDependencies": { "@lingui/jest-mocks": "*", diff --git a/packages/vite-plugin/CHANGELOG.md b/packages/vite-plugin/CHANGELOG.md index 439e7a933..3bc79dc89 100644 --- a/packages/vite-plugin/CHANGELOG.md +++ b/packages/vite-plugin/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) + +**Note:** Version bump only for package @lingui/vite-plugin + ## [5.3.3](https://github.com/lingui/js-lingui/compare/v5.3.2...v5.3.3) (2025-07-11) ### Bug Fixes diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index f0e9d5bd8..5fa522c72 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/vite-plugin", - "version": "5.3.3", + "version": "5.4.0", "description": "Vite plugin for Lingui message catalogs", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -41,8 +41,8 @@ "dist/" ], "dependencies": { - "@lingui/cli": "5.3.3", - "@lingui/conf": "5.3.3" + "@lingui/cli": "5.4.0", + "@lingui/conf": "5.4.0" }, "peerDependencies": { "vite": "^3 || ^4 || ^5.0.9 || ^6 || ^7" diff --git a/yarn.lock b/yarn.lock index 6fc066f28..e2a032e58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2622,7 +2622,7 @@ __metadata: languageName: node linkType: hard -"@lingui/babel-plugin-extract-messages@5.3.3, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": +"@lingui/babel-plugin-extract-messages@5.4.0, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages" dependencies: @@ -2635,7 +2635,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/babel-plugin-lingui-macro@5.3.3, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": +"@lingui/babel-plugin-lingui-macro@5.4.0, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro" dependencies: @@ -2644,9 +2644,9 @@ __metadata: "@babel/runtime": ^7.20.13 "@babel/traverse": ^7.20.12 "@babel/types": ^7.20.7 - "@lingui/conf": 5.3.3 - "@lingui/core": 5.3.3 - "@lingui/message-utils": 5.3.3 + "@lingui/conf": 5.4.0 + "@lingui/core": 5.4.0 + "@lingui/message-utils": 5.4.0 "@types/babel-plugin-macros": ^2.8.5 prettier: 2.8.3 unbuild: 2.0.0 @@ -2658,7 +2658,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/cli@5.3.3, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": +"@lingui/cli@5.4.0, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": version: 0.0.0-use.local resolution: "@lingui/cli@workspace:packages/cli" dependencies: @@ -2667,13 +2667,13 @@ __metadata: "@babel/parser": ^7.22.0 "@babel/runtime": ^7.21.0 "@babel/types": ^7.21.2 - "@lingui/babel-plugin-extract-messages": 5.3.3 - "@lingui/babel-plugin-lingui-macro": 5.3.3 - "@lingui/conf": 5.3.3 - "@lingui/core": 5.3.3 - "@lingui/format-po": 5.3.3 + "@lingui/babel-plugin-extract-messages": 5.4.0 + "@lingui/babel-plugin-lingui-macro": 5.4.0 + "@lingui/conf": 5.4.0 + "@lingui/core": 5.4.0 + "@lingui/format-po": 5.4.0 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.3.3 + "@lingui/message-utils": 5.4.0 "@types/convert-source-map": ^2.0.0 "@types/micromatch": ^4.0.1 "@types/normalize-path": ^3.0.0 @@ -2698,7 +2698,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/conf@5.3.3, @lingui/conf@workspace:packages/conf": +"@lingui/conf@5.4.0, @lingui/conf@workspace:packages/conf": version: 0.0.0-use.local resolution: "@lingui/conf@workspace:packages/conf" dependencies: @@ -2712,16 +2712,16 @@ __metadata: languageName: unknown linkType: soft -"@lingui/core@5.3.3, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": +"@lingui/core@5.4.0, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": version: 0.0.0-use.local resolution: "@lingui/core@workspace:packages/core" dependencies: "@babel/runtime": ^7.20.13 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.3.3 + "@lingui/message-utils": 5.4.0 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.3 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2754,9 +2754,9 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/extractor-vue@workspace:packages/extractor-vue" dependencies: - "@lingui/babel-plugin-extract-messages": 5.3.3 - "@lingui/cli": 5.3.3 - "@lingui/conf": 5.3.3 + "@lingui/babel-plugin-extract-messages": 5.4.0 + "@lingui/cli": 5.4.0 + "@lingui/conf": 5.4.0 "@vue/compiler-sfc": ^3.2.47 unbuild: 2.0.0 languageName: unknown @@ -2766,17 +2766,17 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-csv@workspace:packages/format-csv" dependencies: - "@lingui/conf": 5.3.3 + "@lingui/conf": 5.4.0 papaparse: ^5.4.0 unbuild: 2.0.0 languageName: unknown linkType: soft -"@lingui/format-json@5.3.3, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": +"@lingui/format-json@5.4.0, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": version: 0.0.0-use.local resolution: "@lingui/format-json@workspace:packages/format-json" dependencies: - "@lingui/conf": 5.3.3 + "@lingui/conf": 5.4.0 unbuild: ^2.0.0 languageName: unknown linkType: soft @@ -2785,10 +2785,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-po-gettext@workspace:packages/format-po-gettext" dependencies: - "@lingui/conf": 5.3.3 - "@lingui/format-po": 5.3.3 + "@lingui/conf": 5.4.0 + "@lingui/format-po": 5.4.0 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.3.3 + "@lingui/message-utils": 5.4.0 "@messageformat/parser": ^5.0.0 cldr-core: ^45.0.0 mockdate: ^3.0.5 @@ -2799,13 +2799,13 @@ __metadata: languageName: unknown linkType: soft -"@lingui/format-po@5.3.3, @lingui/format-po@workspace:packages/format-po": +"@lingui/format-po@5.4.0, @lingui/format-po@workspace:packages/format-po": version: 0.0.0-use.local resolution: "@lingui/format-po@workspace:packages/format-po" dependencies: - "@lingui/conf": 5.3.3 + "@lingui/conf": 5.4.0 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.3.3 + "@lingui/message-utils": 5.4.0 date-fns: ^3.6.0 mockdate: ^3.0.5 pofile: ^1.1.4 @@ -2824,9 +2824,9 @@ __metadata: resolution: "@lingui/loader@workspace:packages/loader" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.3.3 - "@lingui/conf": 5.3.3 - "@lingui/format-json": 5.3.3 + "@lingui/cli": 5.4.0 + "@lingui/conf": 5.4.0 + "@lingui/format-json": 5.4.0 unbuild: 2.0.0 webpack: ^5.76.1 peerDependencies: @@ -2838,10 +2838,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/macro@workspace:packages/macro" dependencies: - "@lingui/core": 5.3.3 - "@lingui/react": 5.3.3 + "@lingui/core": 5.4.0 + "@lingui/react": 5.4.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.3 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2851,7 +2851,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/message-utils@5.3.3, @lingui/message-utils@workspace:packages/message-utils": +"@lingui/message-utils@5.4.0, @lingui/message-utils@workspace:packages/message-utils": version: 0.0.0-use.local resolution: "@lingui/message-utils@workspace:packages/message-utils" dependencies: @@ -2877,9 +2877,9 @@ __metadata: resolution: "@lingui/metro-transformer@workspace:packages/metro-transformer" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.3.3 - "@lingui/conf": 5.3.3 - "@lingui/format-json": 5.3.3 + "@lingui/cli": 5.4.0 + "@lingui/conf": 5.4.0 + "@lingui/format-json": 5.4.0 memoize-one: ^6.0.0 rimraf: ^6.0.1 unbuild: 2.0.0 @@ -2898,12 +2898,12 @@ __metadata: languageName: unknown linkType: soft -"@lingui/react@5.3.3, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": +"@lingui/react@5.4.0, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": version: 0.0.0-use.local resolution: "@lingui/react@workspace:packages/react" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/core": 5.3.3 + "@lingui/core": 5.4.0 "@lingui/jest-mocks": "*" "@testing-library/react": ^14.0.0 "@types/react": ^18.2.13 @@ -2913,7 +2913,7 @@ __metadata: react-dom: ^18.2.0 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.3 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -2938,8 +2938,8 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/vite-plugin@workspace:packages/vite-plugin" dependencies: - "@lingui/cli": 5.3.3 - "@lingui/conf": 5.3.3 + "@lingui/cli": 5.4.0 + "@lingui/conf": 5.4.0 "@lingui/core": "workspace:^" "@lingui/format-json": "workspace:^" unbuild: 2.0.0 From 96017018433310a6ba7a21dc9b6ce1d4f3c6965a Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Mon, 4 Aug 2025 10:10:25 +0200 Subject: [PATCH 06/19] fix: remove @messageformat/date-skeleton from bundledDependencies (#2293) --- packages/message-utils/package.json | 5 +---- packages/message-utils/src/compileMessage.ts | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/message-utils/package.json b/packages/message-utils/package.json index aa1710215..89dd29aec 100644 --- a/packages/message-utils/package.json +++ b/packages/message-utils/package.json @@ -56,8 +56,5 @@ "@lingui/jest-mocks": "workspace:^", "@messageformat/date-skeleton": "^1.1.0", "unbuild": "2.0.0" - }, - "bundledDependencies": [ - "@messageformat/date-skeleton" - ] + } } diff --git a/packages/message-utils/src/compileMessage.ts b/packages/message-utils/src/compileMessage.ts index 78c53231c..9045ca909 100644 --- a/packages/message-utils/src/compileMessage.ts +++ b/packages/message-utils/src/compileMessage.ts @@ -1,8 +1,10 @@ import { Content, parse, Token } from "@messageformat/parser" +// eslint-disable-next-line import/no-extraneous-dependencies import { DateFormatError, getDateFormatOptions, } from "@messageformat/date-skeleton/lib/options" +// eslint-disable-next-line import/no-extraneous-dependencies import { parseDateTokens } from "@messageformat/date-skeleton" export type CompiledIcuChoices = Record & { From c863faa1040f5616f855d6d3d0121abdb9c3bccb Mon Sep 17 00:00:00 2001 From: Mathis Pinsault Date: Mon, 4 Aug 2025 11:08:43 +0200 Subject: [PATCH 07/19] chore(vite-plugin): add error handling for dynamic import of @lingui/core/macro (#2056) Co-authored-by: Timofei Iatsenko --- packages/vite-plugin/src/index.ts | 10 ++++++++++ .../test/dynamic-macro-error/entrypoint.js | 4 ++++ .../test/dynamic-macro-error/lingui.config.js | 11 +++++++++++ .../vite-plugin/test/dynamic-macro-error/locale/en.po | 5 +++++ .../test/dynamic-macro-error/vite.config.ts | 11 +++++++++++ packages/vite-plugin/test/index.ts | 11 +++++++++++ packages/vite-plugin/test/macro-usage/.linguirc | 10 ---------- .../vite-plugin/test/macro-usage/lingui.config.js | 11 +++++++++++ packages/vite-plugin/test/no-macro-error/.linguirc | 10 ---------- .../vite-plugin/test/no-macro-error/lingui.config.js | 11 +++++++++++ 10 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 packages/vite-plugin/test/dynamic-macro-error/entrypoint.js create mode 100644 packages/vite-plugin/test/dynamic-macro-error/lingui.config.js create mode 100644 packages/vite-plugin/test/dynamic-macro-error/locale/en.po create mode 100644 packages/vite-plugin/test/dynamic-macro-error/vite.config.ts delete mode 100644 packages/vite-plugin/test/macro-usage/.linguirc create mode 100644 packages/vite-plugin/test/macro-usage/lingui.config.js delete mode 100644 packages/vite-plugin/test/no-macro-error/.linguirc create mode 100644 packages/vite-plugin/test/no-macro-error/lingui.config.js diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 372582b6b..5930eba61 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -54,6 +54,16 @@ export function lingui({ ) } }, + resolveDynamicImport(id, importer) { + if (macroIds.has(id as string)) { + throw new Error( + `The macro you imported from "${id}" cannot be dynamically imported. \n` + + `Please check the import statement in file "${importer}". \n` + + `Please see the documentation for how to configure Vite with Lingui correctly: ` + + "https://lingui.dev/tutorials/setup-vite" + ) + } + }, }, { name: "vite-plugin-lingui", diff --git a/packages/vite-plugin/test/dynamic-macro-error/entrypoint.js b/packages/vite-plugin/test/dynamic-macro-error/entrypoint.js new file mode 100644 index 000000000..6ccc058d3 --- /dev/null +++ b/packages/vite-plugin/test/dynamic-macro-error/entrypoint.js @@ -0,0 +1,4 @@ +export async function load() { + const { t } = await import("@lingui/core/macro") + return t`Ola` +} diff --git a/packages/vite-plugin/test/dynamic-macro-error/lingui.config.js b/packages/vite-plugin/test/dynamic-macro-error/lingui.config.js new file mode 100644 index 000000000..3aafad955 --- /dev/null +++ b/packages/vite-plugin/test/dynamic-macro-error/lingui.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from "@lingui/cli" + +export default defineConfig({ + locales: ["en"], + catalogs: [ + { + path: "/locale/{locale}", + }, + ], + format: "po", +}) diff --git a/packages/vite-plugin/test/dynamic-macro-error/locale/en.po b/packages/vite-plugin/test/dynamic-macro-error/locale/en.po new file mode 100644 index 000000000..b4612b13a --- /dev/null +++ b/packages/vite-plugin/test/dynamic-macro-error/locale/en.po @@ -0,0 +1,5 @@ +msgid "Hello World" +msgstr "Hello World" + +msgid "My name is {name}" +msgstr "My name is {name}" diff --git a/packages/vite-plugin/test/dynamic-macro-error/vite.config.ts b/packages/vite-plugin/test/dynamic-macro-error/vite.config.ts new file mode 100644 index 000000000..109143573 --- /dev/null +++ b/packages/vite-plugin/test/dynamic-macro-error/vite.config.ts @@ -0,0 +1,11 @@ +import { createDefaultViteConfig } from "../default-vite.config" +import { UserConfig } from "vite" +import macrosPlugin from "vite-plugin-babel-macros" + +const config: UserConfig = { + ...createDefaultViteConfig(__dirname), +} + +config.plugins.push(macrosPlugin()) + +export default config diff --git a/packages/vite-plugin/test/index.ts b/packages/vite-plugin/test/index.ts index 26d84e711..c3bf0e7ff 100644 --- a/packages/vite-plugin/test/index.ts +++ b/packages/vite-plugin/test/index.ts @@ -64,6 +64,17 @@ skipOnWindows("vite-plugin", () => { expect(res.stderr).toContain("Compilation error for 2 translation(s)") }) + + it("should report error when @lingui/macro is dynamically imported", async () => { + expect.assertions(1) + try { + await runVite(`dynamic-macro-error/vite.config.ts`) + } catch (e) { + expect(e.stderr).toContain( + 'The macro you imported from "@lingui/core/macro" cannot be dynamically imported.' + ) + } + }) }) async function runVite(configPath: string) { diff --git a/packages/vite-plugin/test/macro-usage/.linguirc b/packages/vite-plugin/test/macro-usage/.linguirc deleted file mode 100644 index 67cebe732..000000000 --- a/packages/vite-plugin/test/macro-usage/.linguirc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "locales": ["en"], - "catalogs": [{ - "path": "/locale/{locale}" - }], - "fallbackLocales": { - "default": "en" - }, - "format": "po" -} diff --git a/packages/vite-plugin/test/macro-usage/lingui.config.js b/packages/vite-plugin/test/macro-usage/lingui.config.js new file mode 100644 index 000000000..3aafad955 --- /dev/null +++ b/packages/vite-plugin/test/macro-usage/lingui.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from "@lingui/cli" + +export default defineConfig({ + locales: ["en"], + catalogs: [ + { + path: "/locale/{locale}", + }, + ], + format: "po", +}) diff --git a/packages/vite-plugin/test/no-macro-error/.linguirc b/packages/vite-plugin/test/no-macro-error/.linguirc deleted file mode 100644 index 67cebe732..000000000 --- a/packages/vite-plugin/test/no-macro-error/.linguirc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "locales": ["en"], - "catalogs": [{ - "path": "/locale/{locale}" - }], - "fallbackLocales": { - "default": "en" - }, - "format": "po" -} diff --git a/packages/vite-plugin/test/no-macro-error/lingui.config.js b/packages/vite-plugin/test/no-macro-error/lingui.config.js new file mode 100644 index 000000000..3aafad955 --- /dev/null +++ b/packages/vite-plugin/test/no-macro-error/lingui.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from "@lingui/cli" + +export default defineConfig({ + locales: ["en"], + catalogs: [ + { + path: "/locale/{locale}", + }, + ], + format: "po", +}) From e4f3517850266dfbbaf5a6d6bf33b6674038f6ec Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Mon, 4 Aug 2025 16:44:23 +0200 Subject: [PATCH 08/19] docs: update react native packages in the example (#2305) --- examples/react-native/package.json | 20 +- examples/react-native/yarn.lock | 1056 ++++++++++++---------------- 2 files changed, 445 insertions(+), 631 deletions(-) diff --git a/examples/react-native/package.json b/examples/react-native/package.json index 48c6d8f41..de76cd524 100644 --- a/examples/react-native/package.json +++ b/examples/react-native/package.json @@ -11,27 +11,27 @@ "extract": "lingui extract", "compile": "lingui compile", "no-dev": "npx expo start -c --no-dev --minify", - "fix-deps": "npx expo install expo@53 --check", + "fix-deps": "npx expo install expo@^53 --check", "bundle": "expo export --dev=true --output-dir=dist --platform=ios --no-minify --no-bytecode" }, "dependencies": { "@formatjs/intl-locale": "^4.0.2", "@formatjs/intl-pluralrules": "^5.2.16", - "@lingui/core": "^5.3.1", - "@lingui/react": "^5.3.1", - "expo": "^53.0.7", + "@lingui/core": "^5.4.0", + "@lingui/react": "^5.4.0", + "expo": "^53.0.20", "expo-status-bar": "~2.2.3", - "expo-updates": "~0.28.12", + "expo-updates": "~0.28.17", "react": "19.0.0", - "react-native": "0.79.2", + "react-native": "0.79.5", "react-native-web": "^0.20.0" }, "devDependencies": { "@babel/core": "^7.26.0", - "@lingui/babel-plugin-lingui-macro": "^5.3.1", - "@lingui/cli": "^5.3.1", - "@lingui/macro": "^5.3.1", - "@lingui/metro-transformer": "^5.3.1", + "@lingui/babel-plugin-lingui-macro": "^5.4.0", + "@lingui/cli": "^5.4.0", + "@lingui/macro": "^5.4.0", + "@lingui/metro-transformer": "^5.4.0", "@react-native-community/eslint-config": "^3.2.0", "@types/react": "~19.0.10", "@typescript-eslint/eslint-plugin": "^5.59.11", diff --git a/examples/react-native/yarn.lock b/examples/react-native/yarn.lock index 7a57b0a88..775d5eab7 100644 --- a/examples/react-native/yarn.lock +++ b/examples/react-native/yarn.lock @@ -1934,15 +1934,6 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0": - version: 7.21.5 - resolution: "@babel/runtime@npm:7.21.5" - dependencies: - regenerator-runtime: ^0.13.11 - checksum: 358f2779d3187f5c67ad302e8f8d435412925d0b991d133c7d4a7b1ddd5a3fda1b6f34537cb64628dfd96a27ae46df105bed3895b8d754b88cacdded8d1129dd - languageName: node - linkType: hard - "@babel/runtime@npm:^7.18.6": version: 7.22.5 resolution: "@babel/runtime@npm:7.22.5" @@ -1961,6 +1952,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0": + version: 7.21.5 + resolution: "@babel/runtime@npm:7.21.5" + dependencies: + regenerator-runtime: ^0.13.11 + checksum: 358f2779d3187f5c67ad302e8f8d435412925d0b991d133c7d4a7b1ddd5a3fda1b6f34537cb64628dfd96a27ae46df105bed3895b8d754b88cacdded8d1129dd + languageName: node + linkType: hard + "@babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.8.4": version: 7.27.0 resolution: "@babel/runtime@npm:7.27.0" @@ -2388,28 +2388,28 @@ __metadata: languageName: node linkType: hard -"@expo/cli@npm:0.24.11": - version: 0.24.11 - resolution: "@expo/cli@npm:0.24.11" +"@expo/cli@npm:0.24.20": + version: 0.24.20 + resolution: "@expo/cli@npm:0.24.20" dependencies: "@0no-co/graphql.web": ^1.0.8 "@babel/runtime": ^7.20.0 "@expo/code-signing-certificates": ^0.0.5 - "@expo/config": ~11.0.8 - "@expo/config-plugins": ~10.0.2 + "@expo/config": ~11.0.13 + "@expo/config-plugins": ~10.1.2 "@expo/devcert": ^1.1.2 - "@expo/env": ~1.0.5 - "@expo/image-utils": ^0.7.4 - "@expo/json-file": ^9.1.4 - "@expo/metro-config": ~0.20.13 - "@expo/osascript": ^2.2.4 - "@expo/package-manager": ^1.8.4 - "@expo/plist": ^0.3.4 - "@expo/prebuild-config": ^9.0.5 + "@expo/env": ~1.0.7 + "@expo/image-utils": ^0.7.6 + "@expo/json-file": ^9.1.5 + "@expo/metro-config": ~0.20.17 + "@expo/osascript": ^2.2.5 + "@expo/package-manager": ^1.8.6 + "@expo/plist": ^0.3.5 + "@expo/prebuild-config": ^9.0.11 "@expo/spawn-async": ^1.7.2 "@expo/ws-tunnel": ^1.0.1 "@expo/xcpretty": ^4.3.0 - "@react-native/dev-middleware": 0.79.2 + "@react-native/dev-middleware": 0.79.5 "@urql/core": ^5.0.6 "@urql/exchange-retry": ^1.3.0 accepts: ^1.3.8 @@ -2424,9 +2424,9 @@ __metadata: debug: ^4.3.4 env-editor: ^0.4.1 freeport-async: ^2.0.0 - getenv: ^1.0.0 + getenv: ^2.0.0 glob: ^10.4.2 - lan-network: ^0.1.4 + lan-network: ^0.1.6 minimatch: ^9.0.0 node-forge: ^1.3.1 npm-package-arg: ^11.0.0 @@ -2455,7 +2455,7 @@ __metadata: ws: ^8.12.1 bin: expo-internal: build/bin/cli - checksum: 7fc01eae0610eeb35a3b4035d8ab2c55cd3c504eaa1f5764868ba05d634a9910d8dda4ead691fa625f812df88bde7f07ea6cf352e2ee776cac803296b96db522 + checksum: 5891e7c7c545b3c3e19ba8f41d0378330de2472904949d53ce5e12e18b12a7f1cb83f657ce05c1752d68d742fe2bcab58e20519b89358de3713bab016fc74b62 languageName: node linkType: hard @@ -2469,17 +2469,17 @@ __metadata: languageName: node linkType: hard -"@expo/config-plugins@npm:~10.0.2": - version: 10.0.2 - resolution: "@expo/config-plugins@npm:10.0.2" +"@expo/config-plugins@npm:~10.1.2": + version: 10.1.2 + resolution: "@expo/config-plugins@npm:10.1.2" dependencies: - "@expo/config-types": ^53.0.3 - "@expo/json-file": ~9.1.4 - "@expo/plist": ^0.3.4 + "@expo/config-types": ^53.0.5 + "@expo/json-file": ~9.1.5 + "@expo/plist": ^0.3.5 "@expo/sdk-runtime-versions": ^1.0.0 chalk: ^4.1.2 debug: ^4.3.5 - getenv: ^1.0.0 + getenv: ^2.0.0 glob: ^10.4.2 resolve-from: ^5.0.0 semver: ^7.5.4 @@ -2487,27 +2487,27 @@ __metadata: slugify: ^1.6.6 xcode: ^3.0.1 xml2js: 0.6.0 - checksum: 722529f9a6ded68e7cf118243bb5393c135acf4d4f509068d92308d66d7fcddaa67c543dcb8590c12c469b1d06535c78c2e71057a64e6caf7c930f4985bb1b5b + checksum: 861a6e814aa8dba9c4d27939dbcb9dcd177e46b7e26c158deee549e8992575ea8779f4d6e61024c8f5880f86e3d029de20adac99e3918b5af9caefb5d53ac6cb languageName: node linkType: hard -"@expo/config-types@npm:^53.0.3": - version: 53.0.3 - resolution: "@expo/config-types@npm:53.0.3" - checksum: 325772d4e05d2ab15fbae4a016c98fb6b81e7549ad6d68b1adace26725eb352998df25330f5ac13509c7b05be3e77f5537881110f97013e600109ad67de60e8a +"@expo/config-types@npm:^53.0.5": + version: 53.0.5 + resolution: "@expo/config-types@npm:53.0.5" + checksum: 3f4db2d9590c18fb178f7395739ee2200512ad7c253655be0bad7f3f0d948df89c1c69c7e949f202faa98eecbd4bbae3edfcf9264f97f49d4f7087f85c68af5d languageName: node linkType: hard -"@expo/config@npm:~11.0.6, @expo/config@npm:~11.0.7, @expo/config@npm:~11.0.8": - version: 11.0.8 - resolution: "@expo/config@npm:11.0.8" +"@expo/config@npm:~11.0.12, @expo/config@npm:~11.0.13": + version: 11.0.13 + resolution: "@expo/config@npm:11.0.13" dependencies: "@babel/code-frame": ~7.10.4 - "@expo/config-plugins": ~10.0.2 - "@expo/config-types": ^53.0.3 - "@expo/json-file": ^9.1.4 + "@expo/config-plugins": ~10.1.2 + "@expo/config-types": ^53.0.5 + "@expo/json-file": ^9.1.5 deepmerge: ^4.3.1 - getenv: ^1.0.0 + getenv: ^2.0.0 glob: ^10.4.2 require-from-string: ^2.0.2 resolve-from: ^5.0.0 @@ -2515,7 +2515,7 @@ __metadata: semver: ^7.6.0 slugify: ^1.3.4 sucrase: 3.35.0 - checksum: 7603c6be7dad3d99c7c7a8208f3a5b72ab8bc71b254f087d9edc8321596f3241394a5956d27b5d0b0227e6442dfea5ef6cecd4e71548e61ac1e43f1d8d185885 + checksum: 0af9ba642b44481c7308cbf7ac618d7d69bcc847a626b2427dbd665fae3e138580b522e51bf7476aefe558d6fa99cee46aeac39cc115d7fc0c8c70b68f996b52 languageName: node linkType: hard @@ -2530,143 +2530,145 @@ __metadata: languageName: node linkType: hard -"@expo/env@npm:~1.0.5": - version: 1.0.5 - resolution: "@expo/env@npm:1.0.5" +"@expo/env@npm:~1.0.7": + version: 1.0.7 + resolution: "@expo/env@npm:1.0.7" dependencies: chalk: ^4.0.0 debug: ^4.3.4 dotenv: ~16.4.5 dotenv-expand: ~11.0.6 - getenv: ^1.0.0 - checksum: eb793b3ce5f4ecee18a7e28251a9185c2e3049e230b1ea5d52690a523924c543266a41ad3d3193a0e4bd90494cb7913ccb9649de5349bb373925c0820b470518 + getenv: ^2.0.0 + checksum: 8d0f07e395e6406e1f24b368a3f3c080e15275da580e3f5d9358b7640e72082bd743ab87c75ed45f7221410d245ca62e3ce4855c019813be501c20cb3c2a69ed languageName: node linkType: hard -"@expo/fingerprint@npm:0.12.4": - version: 0.12.4 - resolution: "@expo/fingerprint@npm:0.12.4" +"@expo/fingerprint@npm:0.13.4": + version: 0.13.4 + resolution: "@expo/fingerprint@npm:0.13.4" dependencies: "@expo/spawn-async": ^1.7.2 arg: ^5.0.2 chalk: ^4.1.2 debug: ^4.3.4 find-up: ^5.0.0 - getenv: ^1.0.0 + getenv: ^2.0.0 + glob: ^10.4.2 + ignore: ^5.3.1 minimatch: ^9.0.0 p-limit: ^3.1.0 resolve-from: ^5.0.0 semver: ^7.6.0 bin: fingerprint: bin/cli.js - checksum: 45a3393ef4cdb370790ee2afc0dc51bb0f7c47229fe2a98483879facd172cc3b977f6345f8f776935e8d676969144aa901e208d4e454d9da73a4ab438526141b + checksum: f485d17a2d9f063f95be76c81994780ef11cda8a2cb9f6d98fcb1d6fa0a0715c95846a194be870072eeea3936dd007a68200c57e172c3ed6abea6513aabb563b languageName: node linkType: hard -"@expo/image-utils@npm:^0.7.4": - version: 0.7.4 - resolution: "@expo/image-utils@npm:0.7.4" +"@expo/image-utils@npm:^0.7.6": + version: 0.7.6 + resolution: "@expo/image-utils@npm:0.7.6" dependencies: "@expo/spawn-async": ^1.7.2 chalk: ^4.0.0 - getenv: ^1.0.0 + getenv: ^2.0.0 jimp-compact: 0.16.1 parse-png: ^2.1.0 resolve-from: ^5.0.0 semver: ^7.6.0 temp-dir: ~2.0.0 unique-string: ~2.0.0 - checksum: 77e12335af7a1d93adb347d1d49900b04f40cacd15bab58f24994d33ea9f89bc0799a9b980e1454c222b6f5151a3be9aeee16a91054f0c91ef1c44922df0503b + checksum: f92d1c1748701a06dacc5644539faeef652053786cc962c2f2db7bb8db296abdc18aa7e0ef1388e32976564b5c359b4f779cd20422c5a94841dbab83bef79670 languageName: node linkType: hard -"@expo/json-file@npm:^9.1.4, @expo/json-file@npm:~9.1.4": - version: 9.1.4 - resolution: "@expo/json-file@npm:9.1.4" +"@expo/json-file@npm:^9.1.5, @expo/json-file@npm:~9.1.5": + version: 9.1.5 + resolution: "@expo/json-file@npm:9.1.5" dependencies: "@babel/code-frame": ~7.10.4 json5: ^2.2.3 - checksum: 31337f829276c1c859993a168f067048ec60bc09d89e45aa774570e09a2edc843e78fb6dcdbc7d186d7dc62f3b84035659a6e5689093e5813bdaf08db6de5a40 + checksum: beedf9077dcff476acd895219e391e18079d3c375e58bb4902a4147fffe9774e11d4d1607cfc3488f8e9daec2c30e4d7c17c46fb701035ad7aabacaaf6d465b4 languageName: node linkType: hard -"@expo/metro-config@npm:0.20.13, @expo/metro-config@npm:~0.20.13": - version: 0.20.13 - resolution: "@expo/metro-config@npm:0.20.13" +"@expo/metro-config@npm:0.20.17, @expo/metro-config@npm:~0.20.17": + version: 0.20.17 + resolution: "@expo/metro-config@npm:0.20.17" dependencies: "@babel/core": ^7.20.0 "@babel/generator": ^7.20.5 "@babel/parser": ^7.20.0 "@babel/types": ^7.20.0 - "@expo/config": ~11.0.8 - "@expo/env": ~1.0.5 - "@expo/json-file": ~9.1.4 + "@expo/config": ~11.0.12 + "@expo/env": ~1.0.7 + "@expo/json-file": ~9.1.5 "@expo/spawn-async": ^1.7.2 chalk: ^4.1.0 debug: ^4.3.2 dotenv: ~16.4.5 dotenv-expand: ~11.0.6 - getenv: ^1.0.0 + getenv: ^2.0.0 glob: ^10.4.2 jsc-safe-url: ^0.2.4 lightningcss: ~1.27.0 minimatch: ^9.0.0 postcss: ~8.4.32 resolve-from: ^5.0.0 - checksum: 5df48d9d883ffd3a0c231277f004fc965647cae74d838e1ee31b7f65979aea2174fc5f218b09b4a3b76d3a6301e773296ff5f583e667749370773ecdda250612 + checksum: 5c9210e0e88cff2ac578a032c8b267761e744abb87d43a3c89ae91f3aab93f2d89941247713a09664073ad9c9277fee0fb1bfda870e5e83a28ae984a4ca2d794 languageName: node linkType: hard -"@expo/osascript@npm:^2.2.4": - version: 2.2.4 - resolution: "@expo/osascript@npm:2.2.4" +"@expo/osascript@npm:^2.2.5": + version: 2.2.5 + resolution: "@expo/osascript@npm:2.2.5" dependencies: "@expo/spawn-async": ^1.7.2 exec-async: ^2.2.0 - checksum: a0c24615e6cb6a8ae8b9d8c5df37156137ca9fb71e2a5e2bec9f98ab0bca5738554f5bbddcd5b73f03445f5f705c96437d3dc30221ac586f52f3f209a6893a25 + checksum: 1025a18f02a934326f494fa84f64201a6887324fb4406099792c6434a75f3366f2ffcfe669ebd32451dfaa027c7ee83b5ba8ac53a0a8d31bbab1887a15c2e588 languageName: node linkType: hard -"@expo/package-manager@npm:^1.8.4": - version: 1.8.4 - resolution: "@expo/package-manager@npm:1.8.4" +"@expo/package-manager@npm:^1.8.6": + version: 1.8.6 + resolution: "@expo/package-manager@npm:1.8.6" dependencies: - "@expo/json-file": ^9.1.4 + "@expo/json-file": ^9.1.5 "@expo/spawn-async": ^1.7.2 chalk: ^4.0.0 npm-package-arg: ^11.0.0 ora: ^3.4.0 resolve-workspace-root: ^2.0.0 - checksum: e4cb87217d319ff952e77dfbc69abf1792ef9c14dac5e915865e986c74173daa3d69202e405892d5a3d8bc70a36f87aeccddb4433c84d13b3dce099f2f64a792 + checksum: b2311cd739d80d934415bd1e1389b89ce6363dbc29b4efa086efc5226de25093d42e5b6839426b4c9b182ab5939620ff481ca5f15bd0b7195cad47e971cc4448 languageName: node linkType: hard -"@expo/plist@npm:^0.3.4": - version: 0.3.4 - resolution: "@expo/plist@npm:0.3.4" +"@expo/plist@npm:^0.3.5": + version: 0.3.5 + resolution: "@expo/plist@npm:0.3.5" dependencies: "@xmldom/xmldom": ^0.8.8 base64-js: ^1.2.3 xmlbuilder: ^15.1.1 - checksum: b39ba79f691e08b14cda4b0ec6352656bdc2762fabbed24c2e4e372b0c644bf86179e8bc51de1383cf4896d4ea3e1a68d9e5dbf3d3e0aa514f704cc87f6cd3a7 + checksum: b78fda216c63ab553b24e75e87021be09155cd16e0fcf666846c1a5ea33defa2d7f631ea504788a8e2c5d67b5f59b35d6a46fa79a244d5890ee26870caffec22 languageName: node linkType: hard -"@expo/prebuild-config@npm:^9.0.5": - version: 9.0.5 - resolution: "@expo/prebuild-config@npm:9.0.5" - dependencies: - "@expo/config": ~11.0.7 - "@expo/config-plugins": ~10.0.2 - "@expo/config-types": ^53.0.3 - "@expo/image-utils": ^0.7.4 - "@expo/json-file": ^9.1.4 - "@react-native/normalize-colors": 0.79.2 +"@expo/prebuild-config@npm:^9.0.11": + version: 9.0.11 + resolution: "@expo/prebuild-config@npm:9.0.11" + dependencies: + "@expo/config": ~11.0.13 + "@expo/config-plugins": ~10.1.2 + "@expo/config-types": ^53.0.5 + "@expo/image-utils": ^0.7.6 + "@expo/json-file": ^9.1.5 + "@react-native/normalize-colors": 0.79.5 debug: ^4.3.1 resolve-from: ^5.0.0 semver: ^7.6.0 xml2js: 0.6.0 - checksum: 8ba1a6faea45abbb98b5c7b13c0f24c6e138d5ca60a5cccbcad792cf33c4deebc0f81f5153b60e0b94dc898aec027374400d1e4a451652df81ff94d835136f79 + checksum: 1d61451073095edef41f3224ee8f0b2399d305a108ef87fff92f59107796b053b8b55676358cf4c6bc5bcc84c818083a4324204521979c3f52bf24d5fe4f3d96 languageName: node linkType: hard @@ -3095,49 +3097,47 @@ __metadata: languageName: node linkType: hard -"@lingui/babel-plugin-extract-messages@npm:5.3.1": - version: 5.3.1 - resolution: "@lingui/babel-plugin-extract-messages@npm:5.3.1" - checksum: f0f2e2918c5d75eab9aa518ff20f1a7582c049bec65873a5c1e46309cce809abab986ea84825449c552a11e117d0150c3a6c5392d4f83e2cbb7d8b467925786f +"@lingui/babel-plugin-extract-messages@npm:5.4.0": + version: 5.4.0 + resolution: "@lingui/babel-plugin-extract-messages@npm:5.4.0" + checksum: da6c5db5c814006f394fb922582115450c7847e85ade8cac6263c9a6ff1fdad0158eee5f5bd0250b187620bb83840c73569021bdd48d2e8c55a149ec908c6f8e languageName: node linkType: hard -"@lingui/babel-plugin-lingui-macro@npm:5.3.1, @lingui/babel-plugin-lingui-macro@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/babel-plugin-lingui-macro@npm:5.3.1" +"@lingui/babel-plugin-lingui-macro@npm:5.4.0, @lingui/babel-plugin-lingui-macro@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/babel-plugin-lingui-macro@npm:5.4.0" dependencies: "@babel/core": ^7.20.12 "@babel/runtime": ^7.20.13 "@babel/types": ^7.20.7 - "@lingui/conf": 5.3.1 - "@lingui/core": 5.3.1 - "@lingui/message-utils": 5.3.1 + "@lingui/conf": 5.4.0 + "@lingui/core": 5.4.0 + "@lingui/message-utils": 5.4.0 peerDependencies: babel-plugin-macros: 2 || 3 peerDependenciesMeta: babel-plugin-macros: optional: true - checksum: 1fc22220945f24e0719672d3979b4bb73992db1cb8525d884b8f65ce41e6fd74e86b80d051cb2e5f99dff4a36d4bb0560450e75e58fd898fa01a219a4c5b00de + checksum: 3a3a6a009448bd83801b29612439b142853474a203c4fe0cdc64190b5abe9d30791571bfe331a7aee1be8331ed6cd6399cf0d7034dee9685684da0e33c847092 languageName: node linkType: hard -"@lingui/cli@npm:5.3.1, @lingui/cli@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/cli@npm:5.3.1" +"@lingui/cli@npm:5.4.0, @lingui/cli@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/cli@npm:5.4.0" dependencies: "@babel/core": ^7.21.0 "@babel/generator": ^7.21.1 "@babel/parser": ^7.22.0 "@babel/runtime": ^7.21.0 "@babel/types": ^7.21.2 - "@lingui/babel-plugin-extract-messages": 5.3.1 - "@lingui/babel-plugin-lingui-macro": 5.3.1 - "@lingui/conf": 5.3.1 - "@lingui/core": 5.3.1 - "@lingui/format-po": 5.3.1 - "@lingui/message-utils": 5.3.1 - babel-plugin-macros: ^3.0.1 - chalk: ^4.1.0 + "@lingui/babel-plugin-extract-messages": 5.4.0 + "@lingui/babel-plugin-lingui-macro": 5.4.0 + "@lingui/conf": 5.4.0 + "@lingui/core": 5.4.0 + "@lingui/format-po": 5.4.0 + "@lingui/message-utils": 5.4.0 chokidar: 3.5.1 cli-table: ^0.3.11 commander: ^10.0.0 @@ -3145,106 +3145,102 @@ __metadata: date-fns: ^3.6.0 esbuild: ^0.25.1 glob: ^11.0.0 - inquirer: ^7.3.3 micromatch: ^4.0.7 normalize-path: ^3.0.0 ora: ^5.1.0 - pathe: ^1.1.0 - pkg-up: ^3.1.0 + picocolors: ^1.1.1 pofile: ^1.1.4 pseudolocale: ^2.0.0 source-map: ^0.8.0-beta.0 bin: lingui: ./dist/lingui.js - checksum: 1881b21f3bd1fa44ad89a122930294c8ed66293a361ba235e1ec69f2b2de314d3f227fd22cb1e006ca873b810b2bdc0f00d75a095598d450fc608d3c0709eb71 + checksum: 2692580c3d6355c263caa654bae6df25c60e4818b7377582fea0e8640b5f588c6afe8fc2e2b944ea30545ec57c178f8da2398f5495525a5fd50f72f8d2c7b6ee languageName: node linkType: hard -"@lingui/conf@npm:5.3.1": - version: 5.3.1 - resolution: "@lingui/conf@npm:5.3.1" +"@lingui/conf@npm:5.4.0": + version: 5.4.0 + resolution: "@lingui/conf@npm:5.4.0" dependencies: "@babel/runtime": ^7.20.13 - chalk: ^4.1.0 cosmiconfig: ^8.0.0 jest-validate: ^29.4.3 jiti: ^1.17.1 - checksum: 0c165ab402e0194124d837b5d39bad50923017106a5a29ca6c472430b7683059e38112d327eb9e94e2fee3423a814ad243143c4de999a18978331a5cb07c9b86 + picocolors: ^1.1.1 + checksum: 6127d9d90e943460e9a8b111c1339bd6a44df58e81486cf1012959ebfd68f2b1e492ea48a1a2979f56ff4cdce9d9a3fb09110a2084dab23e0eaffb3e6eb6e00d languageName: node linkType: hard -"@lingui/core@npm:5.3.1, @lingui/core@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/core@npm:5.3.1" +"@lingui/core@npm:5.4.0, @lingui/core@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/core@npm:5.4.0" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/message-utils": 5.3.1 - unraw: ^3.0.0 + "@lingui/message-utils": 5.4.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.1 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": optional: true babel-plugin-macros: optional: true - checksum: 045212642af18cdfd3e6902d54d97e2f6feaf64e0d639347ed1838802619fcc7720dd91d1be003fd44ca0447b0080679ff06ccefaa4cf79768a240321a7660bb + checksum: fd1f23ad4a0e675b05dd51b1a41f7dece627e4fc7c9c80f4662a79d3717ad841acebe5eb9f5efa213bb77932d688c11e3a551afb9a3ef2685a53ed39a1fe73fe languageName: node linkType: hard -"@lingui/format-po@npm:5.3.1": - version: 5.3.1 - resolution: "@lingui/format-po@npm:5.3.1" +"@lingui/format-po@npm:5.4.0": + version: 5.4.0 + resolution: "@lingui/format-po@npm:5.4.0" dependencies: - "@lingui/conf": 5.3.1 - "@lingui/message-utils": 5.3.1 + "@lingui/conf": 5.4.0 + "@lingui/message-utils": 5.4.0 date-fns: ^3.6.0 pofile: ^1.1.4 - checksum: 480c66d2ed59c1749d4eb867f286ac9f917dec5e4376eee93ef89697614750303a304077db59a0fdd0c944d9a6e3c38092088d947dad585fcc2cce251f59ad11 + checksum: e7f12bd5b3642ae5cf7fb130866a922a39c608c1b3a48bae7d069f994ea00d79ae643d164c28de331d2e8ca02381f33458e50b1686d15b79820ead3abe80e1c8 languageName: node linkType: hard -"@lingui/macro@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/macro@npm:5.3.1" +"@lingui/macro@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/macro@npm:5.4.0" dependencies: - "@lingui/core": 5.3.1 - "@lingui/react": 5.3.1 + "@lingui/core": 5.4.0 + "@lingui/react": 5.4.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.1 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": optional: true babel-plugin-macros: optional: true - checksum: dbf51c99b8708eccbf3d0095a45ccaade97899b1220f114a39ebb2d3b50ac9cf3ea467e9b98cd0e60e9d720065413a7fb0d17ae33ef23db9eb6cf6fca46238c0 + checksum: 1e0ffe2648221209f02abd8dc846a7ace260e7e4e6795a3f0171b95ae640a00dc3c6d426dc802689fa345038ed7f5bdf4d8c201df6a8f8a0f9f366ff71326dfa languageName: node linkType: hard -"@lingui/message-utils@npm:5.3.1": - version: 5.3.1 - resolution: "@lingui/message-utils@npm:5.3.1" +"@lingui/message-utils@npm:5.4.0": + version: 5.4.0 + resolution: "@lingui/message-utils@npm:5.4.0" dependencies: "@messageformat/parser": ^5.0.0 js-sha256: ^0.10.1 - checksum: 2d94c1b619084173236c52c33441f4437e792c132ddfee4a4232e23df552f39dcb43b2fb95e758b4ca5cf1bb0cc9b602093d6fd3ad85514ebc7d71dc2f574cc4 + checksum: 2c91359c3d70283fb17b749c03a994309a8295425b49ef8e5a789776f43b6f39f898228ed2843b5436a310477289aa9538eaa9c1352ab7144720ac95ee0f46b2 languageName: node linkType: hard -"@lingui/metro-transformer@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/metro-transformer@npm:5.3.1" +"@lingui/metro-transformer@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/metro-transformer@npm:5.4.0" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.3.1 - "@lingui/conf": 5.3.1 + "@lingui/cli": 5.4.0 + "@lingui/conf": 5.4.0 memoize-one: ^6.0.0 peerDependencies: "@expo/metro-config": "*" "@react-native/metro-babel-transformer": "*" expo: ">=50.0.0" - metro: "*" react-native: ">=0.73.0" peerDependenciesMeta: "@expo/metro-config": @@ -3253,18 +3249,18 @@ __metadata: optional: true expo: optional: true - checksum: 169936069d2a11d9359ff073ddef41f6b3cf2a18757a23306b9efcb9e4299e287b24cc0c9e46c7615ecbdeb8ab0f47877c58a0d2335f0dae2eb314f2d65c2359 + checksum: 34567aa9eb774bfb0a004c03866db783171b6c3cea96b160797880d13874198b7a62fa87bd2b976040ea5406ae0df1b37d806e73340103ddf14f2f82847e8998 languageName: node linkType: hard -"@lingui/react@npm:5.3.1, @lingui/react@npm:^5.3.1": - version: 5.3.1 - resolution: "@lingui/react@npm:5.3.1" +"@lingui/react@npm:5.4.0, @lingui/react@npm:^5.4.0": + version: 5.4.0 + resolution: "@lingui/react@npm:5.4.0" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/core": 5.3.1 + "@lingui/core": 5.4.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.3.1 + "@lingui/babel-plugin-lingui-macro": 5.4.0 babel-plugin-macros: 2 || 3 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -3272,7 +3268,7 @@ __metadata: optional: true babel-plugin-macros: optional: true - checksum: f48526bf77ed7e2df9c53b4f9aa1a6d1b3b2e86aad7a5af7117b44e140c9c13271340650a88efebe34838cc3c3307777b67da7a75f7f20c65f1480ada754d161 + checksum: 4626bfdd897660a9adae687606311a97cf6d3d057c2c45648fc4a09d2631ea95ed778a1f70446727364f7b8df5789924e4c1644b5503a68e5f680a9b5f306f4a languageName: node linkType: hard @@ -3379,26 +3375,26 @@ __metadata: languageName: node linkType: hard -"@react-native/assets-registry@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/assets-registry@npm:0.79.2" - checksum: 12a322d0c89fc3e9e8321429db2e55dd1c9312a3a0927758e4df8067513abd9836fd18d2e6499c0e1f4f97567d9c2314a07d49daaa45fed261e86e3c2d554653 +"@react-native/assets-registry@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/assets-registry@npm:0.79.5" + checksum: fbf1c4ca18f2d16ce7eb2f321032f4923aacabde014e1318a2b0b76711eb7d4cb13afccef1018f10d3b4cfb12077542c3ac05a20cff01c199de49e24aed67a62 languageName: node linkType: hard -"@react-native/babel-plugin-codegen@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/babel-plugin-codegen@npm:0.79.2" +"@react-native/babel-plugin-codegen@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/babel-plugin-codegen@npm:0.79.5" dependencies: "@babel/traverse": ^7.25.3 - "@react-native/codegen": 0.79.2 - checksum: 502c143f68b73dfc59eb4033e7a1489f9dd5f51f81fc13d300a4a1cd4f1a1c80a545a88a365fc0bd7661d72b15aaa6a35220dfe7c75f44b668aae4acc8e32a2c + "@react-native/codegen": 0.79.5 + checksum: 43a681cf480aead43131baa53ec3c28d24e796e120038b4264a524bbb36d76017a010964e70562a9bc965b23c5ae64dfd5b351d965b18bb3a9761b178153332e languageName: node linkType: hard -"@react-native/babel-preset@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/babel-preset@npm:0.79.2" +"@react-native/babel-preset@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/babel-preset@npm:0.79.5" dependencies: "@babel/core": ^7.25.2 "@babel/plugin-proposal-export-default-from": ^7.24.7 @@ -3441,19 +3437,19 @@ __metadata: "@babel/plugin-transform-typescript": ^7.25.2 "@babel/plugin-transform-unicode-regex": ^7.24.7 "@babel/template": ^7.25.0 - "@react-native/babel-plugin-codegen": 0.79.2 + "@react-native/babel-plugin-codegen": 0.79.5 babel-plugin-syntax-hermes-parser: 0.25.1 babel-plugin-transform-flow-enums: ^0.0.2 react-refresh: ^0.14.0 peerDependencies: "@babel/core": "*" - checksum: 8f9504f74725470ca993e16aac534563865b003783bdfa086ebab1a0429791e4ac4d1a256663de224e5f001c141213f5751b78a32bcfbb950e19c5b13b13b652 + checksum: de7e57ed4ccfc62deec2aac2ffab0257b620c8af34ffc4d0fab15a074383800f226f7f95b69ae4117305240c7dba1ec2fc61083dcc21459972eb2712adf70fbc languageName: node linkType: hard -"@react-native/codegen@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/codegen@npm:0.79.2" +"@react-native/codegen@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/codegen@npm:0.79.5" dependencies: glob: ^7.1.1 hermes-parser: 0.25.1 @@ -3462,15 +3458,15 @@ __metadata: yargs: ^17.6.2 peerDependencies: "@babel/core": "*" - checksum: aa0e004f38320bd818ec52edfedb67c475b50e75e5f7564eb15a089b19647757502670c74f725a716d6ccc66ec68fa68168fba939da2141833ed1aeae48b3475 + checksum: 2254bada67ebd4f88c6fff5568a33588062deca1f53f5a371577618bd8fd0d0ab813c4c44f226e54bef25fbf2f8784e7f702b76cd617b39baab24d138346c9e3 languageName: node linkType: hard -"@react-native/community-cli-plugin@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/community-cli-plugin@npm:0.79.2" +"@react-native/community-cli-plugin@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/community-cli-plugin@npm:0.79.5" dependencies: - "@react-native/dev-middleware": 0.79.2 + "@react-native/dev-middleware": 0.79.5 chalk: ^4.0.0 debug: ^2.2.0 invariant: ^2.2.4 @@ -3483,23 +3479,23 @@ __metadata: peerDependenciesMeta: "@react-native-community/cli": optional: true - checksum: 6b51b6b9a7e04354a07f2662137b77181c61faa04efa14d6306913fa1b6887fe81b85203b4f7629591803ee2c2af5dc64b710db43a5523f005b5d0e799f727a9 + checksum: 019fc2e3328063e0619dc8ebc511ac2285b4aa25038fd9ee9ff2e3674e039c9dcef5e2f6dc233b64d635a1e662681107c5512c8982d1b6663f3728e66d3b582e languageName: node linkType: hard -"@react-native/debugger-frontend@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/debugger-frontend@npm:0.79.2" - checksum: 92fb0c2f18fa0c48e22be13955c5162e346c39fd2a0e64a7baa40b9a9c1894c83f0d6f916b8b334f562da7b4346d860a769ac30412b9b47f2e1916170d18e481 +"@react-native/debugger-frontend@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/debugger-frontend@npm:0.79.5" + checksum: 5f468a06ec4916fed8d4d865fe05c6fa0ba5ade7c8870bdede836f4b2210fd07974c6774f07b71098b50c625a45b141df7333aad174e43d8c607d64ff065d6e1 languageName: node linkType: hard -"@react-native/dev-middleware@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/dev-middleware@npm:0.79.2" +"@react-native/dev-middleware@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/dev-middleware@npm:0.79.5" dependencies: "@isaacs/ttlcache": ^1.4.1 - "@react-native/debugger-frontend": 0.79.2 + "@react-native/debugger-frontend": 0.79.5 chrome-launcher: ^0.15.2 chromium-edge-launcher: ^0.2.0 connect: ^3.6.5 @@ -3509,28 +3505,28 @@ __metadata: open: ^7.0.3 serve-static: ^1.16.2 ws: ^6.2.3 - checksum: e06ddb721c0c9cb311dd4da9bd2a1260036b164f31e804398abba4aec64f4f9076f272ede29d3a7956a9746f583e524399f2a61a09d577c10212459f42a93e60 + checksum: 0d2bd347060021287a3b47f37f7f942cda37be7cd58b51fb0aaa5ab3fe1ecc1359adc7cc845c70f301ad9a87731eb3cf91a66b09c15519393013378f16285c95 languageName: node linkType: hard -"@react-native/gradle-plugin@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/gradle-plugin@npm:0.79.2" - checksum: 6e34a290240b6992c3e8e3c7b2c337cd656055cc11071448c8b017f9181e870291ec1d5cba7cca10670bac7fda381f5bbbf0b7692a8ef363c6a2f1976048db6d +"@react-native/gradle-plugin@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/gradle-plugin@npm:0.79.5" + checksum: f459ec6af3f82047af87861f6024014bc7d01c92ba458980a5478326e3286ecbdb7713c10497525bd0253da2d678ffbb8c5b720f3099716844ae534c10cc5e3d languageName: node linkType: hard -"@react-native/js-polyfills@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/js-polyfills@npm:0.79.2" - checksum: 78734691ad169fe759ecd022e522321e24acc28b1afc985a35e7335cb6364fdf2b92f7d4ee9890b6c413e0ac025d6dff9df4ecb58b987a964a5e783b5a3b374c +"@react-native/js-polyfills@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/js-polyfills@npm:0.79.5" + checksum: a51a289ee7147c968e3626b43e5602ecf2c8b1f00c551ba5c8db9fc67fb26ca88cdf1718eca0a1e67281f900897b5fb490367ed9ab10361a1005e1d5ba3c2e34 languageName: node linkType: hard -"@react-native/normalize-colors@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/normalize-colors@npm:0.79.2" - checksum: 5841c7745b731374621c5e173828823a9fa9665226eb69ce59782b4784e13e87c40af0df27f5a641a0cc0eb5f96f69add8c1304b1547e447a2258651a54fa0ca +"@react-native/normalize-colors@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/normalize-colors@npm:0.79.5" + checksum: 0c62e8e4e2473e669f87e425e1ccf49471c00b88606a626c0addb9817f5a782b3115fb98a91b36f3bf4536fae8585fbf17a988e59ccc851f79999008cd64a4e4 languageName: node linkType: hard @@ -3541,9 +3537,9 @@ __metadata: languageName: node linkType: hard -"@react-native/virtualized-lists@npm:0.79.2": - version: 0.79.2 - resolution: "@react-native/virtualized-lists@npm:0.79.2" +"@react-native/virtualized-lists@npm:0.79.5": + version: 0.79.5 + resolution: "@react-native/virtualized-lists@npm:0.79.5" dependencies: invariant: ^2.2.4 nullthrows: ^1.1.1 @@ -3554,7 +3550,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 70933f4feb64d8ad8683152f429fb6fd424d145f26d860a363f045794a59955de4e0d3872b60faff2678f4efb540ab2ecab312b3d1055f0436b14d3fa114b502 + checksum: edde6d639e65ec4b1ee2477e2f1ae7c5f72769d75dcf8cb265e0be5495c143e631221a65dbf8e3f472ab396144605269b3e1e7a88137f56259b2de680f271189 languageName: node linkType: hard @@ -3686,13 +3682,6 @@ __metadata: languageName: node linkType: hard -"@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b - languageName: node - linkType: hard - "@types/react@npm:~19.0.10": version: 19.0.14 resolution: "@types/react@npm:19.0.14" @@ -3935,6 +3924,13 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 86a7f542af277cfbd77dd61e7df8422f90bac512953709003a1c530171a9d019d072e2400eab2b59f84b49ab9dd237be44315ca663ac73e82b3922d10ea5eafa + languageName: node + linkType: hard + "agentkeepalive@npm:^4.2.1": version: 4.3.0 resolution: "agentkeepalive@npm:4.3.0" @@ -4226,17 +4222,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-macros@npm:^3.0.1": - version: 3.1.0 - resolution: "babel-plugin-macros@npm:3.1.0" - dependencies: - "@babel/runtime": ^7.12.5 - cosmiconfig: ^7.0.0 - resolve: ^1.19.0 - checksum: 765de4abebd3e4688ebdfbff8571ddc8cd8061f839bb6c3e550b0344a4027b04c60491f843296ce3f3379fb356cc873d57a9ee6694262547eb822c14a25be9a6 - languageName: node - linkType: hard - "babel-plugin-polyfill-corejs2@npm:^0.4.10": version: 0.4.13 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.13" @@ -4323,9 +4308,9 @@ __metadata: languageName: node linkType: hard -"babel-preset-expo@npm:~13.1.11": - version: 13.1.11 - resolution: "babel-preset-expo@npm:13.1.11" +"babel-preset-expo@npm:~13.2.3": + version: 13.2.3 + resolution: "babel-preset-expo@npm:13.2.3" dependencies: "@babel/helper-module-imports": ^7.25.9 "@babel/plugin-proposal-decorators": ^7.12.9 @@ -4341,7 +4326,7 @@ __metadata: "@babel/plugin-transform-runtime": ^7.24.7 "@babel/preset-react": ^7.22.15 "@babel/preset-typescript": ^7.23.0 - "@react-native/babel-preset": 0.79.2 + "@react-native/babel-preset": 0.79.5 babel-plugin-react-native-web: ~0.19.13 babel-plugin-syntax-hermes-parser: ^0.25.1 babel-plugin-transform-flow-enums: ^0.0.2 @@ -4353,7 +4338,7 @@ __metadata: peerDependenciesMeta: babel-plugin-react-compiler: optional: true - checksum: e442636253dcb3ff0cd4059edaaaa0e1990362412945c95ce5deb492d52931eef29ad7d3087d7f476e50031d5aa56807497622f154c84fa20ecdffb56243d6fd + checksum: 3d95975e5a871de9a694468bedd88732859b71fb6ef1b99dc0deddd677f798e0c38211820ef0a08608d53c1307790da999fdd4564473cca6c3802a09d925d876 languageName: node linkType: hard @@ -4729,13 +4714,6 @@ __metadata: languageName: node linkType: hard -"chardet@npm:^0.7.0": - version: 0.7.0 - resolution: "chardet@npm:0.7.0" - checksum: 6fd5da1f5d18ff5712c1e0aed41da200d7c51c28f11b36ee3c7b483f3696dabc08927fc6b227735eb8f0e1215c9a8abd8154637f3eff8cada5959df7f58b024d - languageName: node - linkType: hard - "chokidar@npm:3.5.1": version: 3.5.1 resolution: "chokidar@npm:3.5.1" @@ -4852,13 +4830,6 @@ __metadata: languageName: node linkType: hard -"cli-width@npm:^3.0.0": - version: 3.0.0 - resolution: "cli-width@npm:3.0.0" - checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6 - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -5075,19 +5046,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^7.0.0": - version: 7.1.0 - resolution: "cosmiconfig@npm:7.1.0" - dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.2.1 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.10.0 - checksum: c53bf7befc1591b2651a22414a5e786cd5f2eeaa87f3678a3d49d6069835a9d8d1aef223728e98aa8fec9a95bf831120d245096db12abe019fecb51f5696c96f - languageName: node - linkType: hard - "cosmiconfig@npm:^8.0.0": version: 8.1.3 resolution: "cosmiconfig@npm:8.1.3" @@ -5950,17 +5908,17 @@ __metadata: languageName: node linkType: hard -"expo-asset@npm:~11.1.5": - version: 11.1.5 - resolution: "expo-asset@npm:11.1.5" +"expo-asset@npm:~11.1.7": + version: 11.1.7 + resolution: "expo-asset@npm:11.1.7" dependencies: - "@expo/image-utils": ^0.7.4 - expo-constants: ~17.1.5 + "@expo/image-utils": ^0.7.6 + expo-constants: ~17.1.7 peerDependencies: expo: "*" react: "*" react-native: "*" - checksum: eb9c4238b5c33f91a32d236e22cdb0cc9c86ebbe10aab397301e6e818f7e197dffe3d57cf1e3a9ec59872bb344a81e2e2e7355061b9414d48201f7e2982da2f1 + checksum: fcbd7b1c1ab665757b3fb8f11592f35f252ada7f093eb70c17461c611347161a4bdd74a4e9717970f62ef191a400e9080426ed199c89042d020abe85007a8c79 languageName: node linkType: hard @@ -5988,45 +5946,45 @@ __metadata: languageName: node linkType: hard -"expo-constants@npm:~17.1.5": - version: 17.1.5 - resolution: "expo-constants@npm:17.1.5" +"expo-constants@npm:~17.1.7": + version: 17.1.7 + resolution: "expo-constants@npm:17.1.7" dependencies: - "@expo/config": ~11.0.7 - "@expo/env": ~1.0.5 + "@expo/config": ~11.0.12 + "@expo/env": ~1.0.7 peerDependencies: expo: "*" react-native: "*" - checksum: 02c7cf4b7533ee54bcc120eb32276f1b60cbbdf676155ec956307cb3bb82f63f0efd2835029d475f95e68edbf399cabc2bd9051387024b9a68a69fbd501c1574 + checksum: c477819c5fb9cd442efa9be0fd32ea5d49cd252c85a7e2ae593ca9afccfbfc1fc8d1b0a743c42c1aa6d0497958dae883c21314caff4d51f71f017ee615f1bd85 languageName: node linkType: hard -"expo-eas-client@npm:~0.14.3": - version: 0.14.3 - resolution: "expo-eas-client@npm:0.14.3" - checksum: ff8fdb64ced1af96accac8aea8737fbef7f158ff104989cfb8cfcadd8c9b0c8257670b92b770c1cee92d2d68f01605c1b775e31080f86bba6bd7d83ecfe3992c +"expo-eas-client@npm:~0.14.4": + version: 0.14.4 + resolution: "expo-eas-client@npm:0.14.4" + checksum: 3b9347b5cc94612c6fb9798e0351efefeea8e4b09c48b9a1c69cbae002eb2952f0ae32f3fdb7c6491dc74b6a8b415977c67ef6906b1f58a71677802ac272e6de languageName: node linkType: hard -"expo-file-system@npm:~18.1.9": - version: 18.1.9 - resolution: "expo-file-system@npm:18.1.9" +"expo-file-system@npm:~18.1.11": + version: 18.1.11 + resolution: "expo-file-system@npm:18.1.11" peerDependencies: expo: "*" react-native: "*" - checksum: fa8cb76ef8b76478a7c09005378962a3510536bffb6f4929924ff491ea3f4194323b1c165612b9645589dc66da9d549e206c5d1c774b07999ecc07c059b8073d + checksum: 8cc9d7cf0835d328174e414be8c2c69ca145716ce7ac83033f7197ee4309b53b435a86b76a3d3072d374b340ae61eb1f8ababdc9aebc5d9e8958944d7904a6c2 languageName: node linkType: hard -"expo-font@npm:~13.3.1": - version: 13.3.1 - resolution: "expo-font@npm:13.3.1" +"expo-font@npm:~13.3.2": + version: 13.3.2 + resolution: "expo-font@npm:13.3.2" dependencies: fontfaceobserver: ^2.1.0 peerDependencies: expo: "*" react: "*" - checksum: 1db08552d60e8fcbab6301f45e08ef382f5a8b7009348ddffd188566f7ce1e9aa5476c2d1f7dc869db85e25338acc1aea6173a85d5a2f5785b2409d5499a4886 + checksum: ea257395f2267c6d5c491561a415a57e3a55473428da1c7c7b1639cc386525fca8b56793d40f079e21ad1ccbb56e3180ecd943dbecc8c5543146e8760f930376 languageName: node linkType: hard @@ -6047,21 +6005,21 @@ __metadata: languageName: node linkType: hard -"expo-manifests@npm:~0.16.4": - version: 0.16.4 - resolution: "expo-manifests@npm:0.16.4" +"expo-manifests@npm:~0.16.6": + version: 0.16.6 + resolution: "expo-manifests@npm:0.16.6" dependencies: - "@expo/config": ~11.0.6 + "@expo/config": ~11.0.12 expo-json-utils: ~0.15.0 peerDependencies: expo: "*" - checksum: 1afb51570474c0b58a8f9c0bcb5c0fefaa127592693b54dcd83e75ae9c89cbe104fd6a3a7afee293173c929e37603b06ecf1f1cff582c2c489ee454862cfecc1 + checksum: 0d64d1c7b19830f362fa841a47e05ba1be27c9c6c5903c8155063d1564334d56fc26809784cd82b5216976edfaca6a702bfed084b33662e6be966ef04032f855 languageName: node linkType: hard -"expo-modules-autolinking@npm:2.1.9": - version: 2.1.9 - resolution: "expo-modules-autolinking@npm:2.1.9" +"expo-modules-autolinking@npm:2.1.14": + version: 2.1.14 + resolution: "expo-modules-autolinking@npm:2.1.14" dependencies: "@expo/spawn-async": ^1.7.2 chalk: ^4.1.0 @@ -6072,16 +6030,16 @@ __metadata: resolve-from: ^5.0.0 bin: expo-modules-autolinking: bin/expo-modules-autolinking.js - checksum: b04603200737de98d3ea766bbd3b89f72317ee5956767925aee57a07ea614340dcd2ea5c1fb27721ac05562061056cc546dca1eae1ca390dca1af2e9bbead96a + checksum: 03b29331ef2bac098c6a7b0127e35bb81b49e990b8648785a74b172ef9842fd748ae7f9e5b70158023b6f327c82c4a35c123d8ad19ddc3094da0c642f6affa97 languageName: node linkType: hard -"expo-modules-core@npm:2.3.12": - version: 2.3.12 - resolution: "expo-modules-core@npm:2.3.12" +"expo-modules-core@npm:2.5.0": + version: 2.5.0 + resolution: "expo-modules-core@npm:2.5.0" dependencies: invariant: ^2.2.4 - checksum: 37f127b3ad31e78b8c81883a6c4f6142a3a46a005e28edf7a5db207f35221c597b49cd2c54c92a966bbf89b06dbbec5668e7deb4be558c5523ba379dc19a6901 + checksum: 7a405f20f0bc056c7409be6d00bf9ad5203cb461301b1ecf0a03380138965ea4fa8e1e2456035a2ea3cb6adb44eac3b40cb2e3a5328a4b91054911982029ad15 languageName: node linkType: hard @@ -6114,18 +6072,18 @@ __metadata: languageName: node linkType: hard -"expo-updates@npm:~0.28.12": - version: 0.28.12 - resolution: "expo-updates@npm:0.28.12" +"expo-updates@npm:~0.28.17": + version: 0.28.17 + resolution: "expo-updates@npm:0.28.17" dependencies: "@expo/code-signing-certificates": 0.0.5 - "@expo/config": ~11.0.7 - "@expo/config-plugins": ~10.0.2 + "@expo/config": ~11.0.13 + "@expo/config-plugins": ~10.1.2 "@expo/spawn-async": ^1.7.2 arg: 4.1.0 chalk: ^4.1.2 - expo-eas-client: ~0.14.3 - expo-manifests: ~0.16.4 + expo-eas-client: ~0.14.4 + expo-manifests: ~0.16.6 expo-structured-headers: ~4.1.0 expo-updates-interface: ~1.1.0 glob: ^10.4.2 @@ -6136,29 +6094,29 @@ __metadata: react: "*" bin: expo-updates: bin/cli.js - checksum: 71dc7ef5a6ff26cbe9305f3308007a8f49590f293a4a9d989ca11e4e3d1303c3b8e874a40a7c225ffef45c2efc9025cfe5b8374555385ec0ba4ba8e3ae46bec1 + checksum: ce0ad1a62b0d9b424c87ca3b71b114e60a9827db2c61a95271652c785d71d439e508c12319202f4044ae1118453ae527ad09b005af8fafdcda79a08037a0dd55 languageName: node linkType: hard -"expo@npm:^53.0.7": - version: 53.0.7 - resolution: "expo@npm:53.0.7" +"expo@npm:^53": + version: 53.0.20 + resolution: "expo@npm:53.0.20" dependencies: "@babel/runtime": ^7.20.0 - "@expo/cli": 0.24.11 - "@expo/config": ~11.0.8 - "@expo/config-plugins": ~10.0.2 - "@expo/fingerprint": 0.12.4 - "@expo/metro-config": 0.20.13 + "@expo/cli": 0.24.20 + "@expo/config": ~11.0.13 + "@expo/config-plugins": ~10.1.2 + "@expo/fingerprint": 0.13.4 + "@expo/metro-config": 0.20.17 "@expo/vector-icons": ^14.0.0 - babel-preset-expo: ~13.1.11 - expo-asset: ~11.1.5 - expo-constants: ~17.1.5 - expo-file-system: ~18.1.9 - expo-font: ~13.3.1 + babel-preset-expo: ~13.2.3 + expo-asset: ~11.1.7 + expo-constants: ~17.1.7 + expo-file-system: ~18.1.11 + expo-font: ~13.3.2 expo-keep-awake: ~14.1.4 - expo-modules-autolinking: 2.1.9 - expo-modules-core: 2.3.12 + expo-modules-autolinking: 2.1.14 + expo-modules-core: 2.5.0 react-native-edge-to-edge: 1.6.0 whatwg-url-without-unicode: 8.0.0-3 peerDependencies: @@ -6178,7 +6136,7 @@ __metadata: expo: bin/cli expo-modules-autolinking: bin/autolinking fingerprint: bin/fingerprint - checksum: eda7923dabd2f93ac3c932edc6c067dec60fc8ee671d46f8169b7755a005f17a8d4621b1f54cb0d6b8f769d20498a4af52856b8301ba789d810fdab65cffde40 + checksum: 54f70106122aeab1e067e0dc2957fb845884861e303d02f20f496a5c4010d946f070b4a1b9ac9045ecd448006f426351dd564185603e366c1d0d258b3eb348fe languageName: node linkType: hard @@ -6228,17 +6186,6 @@ __metadata: languageName: node linkType: hard -"external-editor@npm:^3.0.3": - version: 3.1.0 - resolution: "external-editor@npm:3.1.0" - dependencies: - chardet: ^0.7.0 - iconv-lite: ^0.4.24 - tmp: ^0.0.33 - checksum: 1c2a616a73f1b3435ce04030261bed0e22d4737e14b090bb48e58865da92529c9f2b05b893de650738d55e692d071819b45e1669259b2b354bc3154d27a698c7 - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -6320,15 +6267,6 @@ __metadata: languageName: node linkType: hard -"figures@npm:^3.0.0": - version: 3.2.0 - resolution: "figures@npm:3.2.0" - dependencies: - escape-string-regexp: ^1.0.5 - checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -6386,15 +6324,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^3.0.0": - version: 3.0.0 - resolution: "find-up@npm:3.0.0" - dependencies: - locate-path: ^3.0.0 - checksum: 38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 - languageName: node - linkType: hard - "find-up@npm:^4.1.0": version: 4.1.0 resolution: "find-up@npm:4.1.0" @@ -6659,6 +6588,13 @@ __metadata: languageName: node linkType: hard +"getenv@npm:^2.0.0": + version: 2.0.0 + resolution: "getenv@npm:2.0.0" + checksum: d5e4cd001952db17d546c8ae5961b68dd83d0a6c6027cc4c613cbe0f88ca835f661364a7eff32428953e7677af95fb0a35f035c98b661bef2fcabb5d7c711c86 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.0": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -6904,6 +6840,13 @@ __metadata: languageName: node linkType: hard +"hermes-estree@npm:0.29.1": + version: 0.29.1 + resolution: "hermes-estree@npm:0.29.1" + checksum: a72fe490d99ba2f56b3e22f3d050ca7757cc8dc9ebcb9d907104e46aaabdea9d32b445f73cca724a2537090fad3dde3cce0dc733bad6d7b3930c6bcde484d45c + languageName: node + linkType: hard + "hermes-parser@npm:0.25.1": version: 0.25.1 resolution: "hermes-parser@npm:0.25.1" @@ -6913,6 +6856,15 @@ __metadata: languageName: node linkType: hard +"hermes-parser@npm:0.29.1": + version: 0.29.1 + resolution: "hermes-parser@npm:0.29.1" + dependencies: + hermes-estree: 0.29.1 + checksum: 3a7cd5cbdb191579f521dcb17edf199e24631314b9f69d043007e91762b53cd1f38eeb7688571f5be378b1c118e99af42040139e5f00e74a7cfd5c52c9d262e0 + languageName: node + linkType: hard + "hosted-git-info@npm:^7.0.0": version: 7.0.2 resolution: "hosted-git-info@npm:7.0.2" @@ -6963,6 +6915,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.5": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: ^7.1.2 + debug: 4 + checksum: b882377a120aa0544846172e5db021fa8afbf83fea2a897d397bd2ddd8095ab268c24bc462f40a15f2a8c600bf4aa05ce52927f70038d4014e68aefecfa94e8d + languageName: node + linkType: hard + "humanize-ms@npm:^1.2.1": version: 1.2.1 resolution: "humanize-ms@npm:1.2.1" @@ -6979,7 +6941,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": +"iconv-lite@npm:0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" dependencies: @@ -7103,27 +7065,6 @@ __metadata: languageName: node linkType: hard -"inquirer@npm:^7.3.3": - version: 7.3.3 - resolution: "inquirer@npm:7.3.3" - dependencies: - ansi-escapes: ^4.2.1 - chalk: ^4.1.0 - cli-cursor: ^3.1.0 - cli-width: ^3.0.0 - external-editor: ^3.0.3 - figures: ^3.0.0 - lodash: ^4.17.19 - mute-stream: 0.0.8 - run-async: ^2.4.0 - rxjs: ^6.6.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - through: ^2.3.6 - checksum: 4d387fc1eb6126acbd58cbdb9ad99d2887d181df86ab0c2b9abdf734e751093e2d5882c2b6dc7144d9ab16b7ab30a78a1d7f01fb6a2850a44aeb175d1e3f8778 - languageName: node - linkType: hard - "internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.5": version: 1.0.5 resolution: "internal-slot@npm:1.0.5" @@ -7211,7 +7152,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0": +"is-core-module@npm:^2.11.0": version: 2.12.0 resolution: "is-core-module@npm:2.12.0" dependencies: @@ -7726,12 +7667,12 @@ __metadata: languageName: node linkType: hard -"lan-network@npm:^0.1.4": - version: 0.1.5 - resolution: "lan-network@npm:0.1.5" +"lan-network@npm:^0.1.6": + version: 0.1.7 + resolution: "lan-network@npm:0.1.7" bin: lan-network: dist/lan-network-cli.js - checksum: f30424e6dd955d1a3fe9c713c5cc339e744abb7e77a0c314b6a97c8a1d79100a2a317b1e8281f83ecf0895f791196d75c36ca1ae5f71589de30bd2f959215dbe + checksum: 7b7793a60de60fa152371eba8b00e73c160b4aef28c51790e75c958e6031dcf314fe7a0e10de0610d902dd26cc562c7d88d0cb3cb3f2e23be4e4defb41c258c3 languageName: node linkType: hard @@ -7886,40 +7827,30 @@ __metadata: "@babel/core": ^7.26.0 "@formatjs/intl-locale": ^4.0.2 "@formatjs/intl-pluralrules": ^5.2.16 - "@lingui/babel-plugin-lingui-macro": ^5.3.1 - "@lingui/cli": ^5.3.1 - "@lingui/core": ^5.3.1 - "@lingui/macro": ^5.3.1 - "@lingui/metro-transformer": ^5.3.1 - "@lingui/react": ^5.3.1 + "@lingui/babel-plugin-lingui-macro": ^5.4.0 + "@lingui/cli": ^5.4.0 + "@lingui/core": ^5.4.0 + "@lingui/macro": ^5.4.0 + "@lingui/metro-transformer": ^5.4.0 + "@lingui/react": ^5.4.0 "@react-native-community/eslint-config": ^3.2.0 "@types/react": ~19.0.10 "@typescript-eslint/eslint-plugin": ^5.59.11 eslint: ^8.42.0 eslint-config-prettier: ^8.8.0 eslint-plugin-ft-flow: ^2.0.3 - expo: ^53.0.7 + expo: ^53 expo-atlas: ^0.4.0 expo-status-bar: ~2.2.3 - expo-updates: ~0.28.12 + expo-updates: ~0.28.17 prettier: ^2.8.8 react: 19.0.0 - react-native: 0.79.2 + react-native: 0.79.5 react-native-web: ^0.20.0 typescript: ~5.8.3 languageName: unknown linkType: soft -"locate-path@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-path@npm:3.0.0" - dependencies: - p-locate: ^3.0.0 - path-exists: ^3.0.0 - checksum: 53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 - languageName: node - linkType: hard - "locate-path@npm:^5.0.0": version: 5.0.0 resolution: "locate-path@npm:5.0.0" @@ -7966,7 +7897,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.19, lodash@npm:^4.17.21": +"lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -8138,68 +8069,69 @@ __metadata: languageName: node linkType: hard -"metro-babel-transformer@npm:0.82.1": - version: 0.82.1 - resolution: "metro-babel-transformer@npm:0.82.1" +"metro-babel-transformer@npm:0.82.5": + version: 0.82.5 + resolution: "metro-babel-transformer@npm:0.82.5" dependencies: "@babel/core": ^7.25.2 flow-enums-runtime: ^0.0.6 - hermes-parser: 0.25.1 + hermes-parser: 0.29.1 nullthrows: ^1.1.1 - checksum: f657e8e1c643e5dadb23212da65e2738056f723c9c52116df4a600b7763d4ad1d381eb016f601ce76e1423b1cb7cd7dc87ffbe5b495d3cb54e0ea240e2a63308 + checksum: 3a3a8a9404c74290b5687290236e242f7b4edb3bc25cad6afe2424ddab8632a657b55ccbbd49dfa9b26078b5f3184f00930b8aa8b50d7c922247fd7d63ada395 languageName: node linkType: hard -"metro-cache-key@npm:0.82.1": - version: 0.82.1 - resolution: "metro-cache-key@npm:0.82.1" +"metro-cache-key@npm:0.82.5": + version: 0.82.5 + resolution: "metro-cache-key@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 - checksum: 35b22c1ecd89a47c50e238d75b3d3ae78e6382299713f83a48823fa019214166a843ff7b212d51e1eed16768d081c0bead27f06201acc19e84aec8c7238dc3b7 + checksum: d5dcd86249905c7adad0375111a4bef395a5021df251a463f840eb21bf7b34f4e581ae919a88fb612a63c48a5f379ce50f104a576bd71e052693d89ae6a0d9f0 languageName: node linkType: hard -"metro-cache@npm:0.82.1": - version: 0.82.1 - resolution: "metro-cache@npm:0.82.1" +"metro-cache@npm:0.82.5": + version: 0.82.5 + resolution: "metro-cache@npm:0.82.5" dependencies: exponential-backoff: ^3.1.1 flow-enums-runtime: ^0.0.6 - metro-core: 0.82.1 - checksum: cf4e0027ad7e2c74ad16077babf27a25f73614c2977a0d003020ecde0677d9ca17c5f3960af9547b84c8af73980942654a363ddab561710cd0ed19dd914fd660 + https-proxy-agent: ^7.0.5 + metro-core: 0.82.5 + checksum: d0d193845063b1e1241a770d928630c68418b6bff2a25d7d14e71b88e905c640b65817ac069abf807b6e7c6db5470b8c52fe6236b3850ae55ce68e910747eb63 languageName: node linkType: hard -"metro-config@npm:0.82.1, metro-config@npm:^0.82.0": - version: 0.82.1 - resolution: "metro-config@npm:0.82.1" +"metro-config@npm:0.82.5, metro-config@npm:^0.82.0": + version: 0.82.5 + resolution: "metro-config@npm:0.82.5" dependencies: connect: ^3.6.5 cosmiconfig: ^5.0.5 flow-enums-runtime: ^0.0.6 jest-validate: ^29.7.0 - metro: 0.82.1 - metro-cache: 0.82.1 - metro-core: 0.82.1 - metro-runtime: 0.82.1 - checksum: 02bdae619a02aa443ced64d14e06f00dc71dc80e7f6b3d822427dd32e4e1394e44365c962e91d405bf14e9ee41fcf93ca7d04d1b2c7f09a7be4a3fc5fb848f69 + metro: 0.82.5 + metro-cache: 0.82.5 + metro-core: 0.82.5 + metro-runtime: 0.82.5 + checksum: 641c88d795394e551fffe238670ad09f3c8637b45da767ee95c5b401e11b65d5a4e86694fb68bd13fde1fc148d9c4f738439a0a427fe5325bd36aa19ea7a5fc9 languageName: node linkType: hard -"metro-core@npm:0.82.1, metro-core@npm:^0.82.0": - version: 0.82.1 - resolution: "metro-core@npm:0.82.1" +"metro-core@npm:0.82.5, metro-core@npm:^0.82.0": + version: 0.82.5 + resolution: "metro-core@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 lodash.throttle: ^4.1.1 - metro-resolver: 0.82.1 - checksum: d8cd6a1d4e11acc34fe99d4af4bb44d9db44015c776a019c2fd74d56bfe8c2b2239032e02e40ac86b90791e8337594c82b1b36e9c682de1cf6ee92951d1617b0 + metro-resolver: 0.82.5 + checksum: f6f0c91240ad4ff2ebd61e5cb23f433309fc82e8042e240da1347f8edf61cc6b893bd176cabecad0dc91d214dd315d501af21cb518459aeb0ed613881619b583 languageName: node linkType: hard -"metro-file-map@npm:0.82.1": - version: 0.82.1 - resolution: "metro-file-map@npm:0.82.1" +"metro-file-map@npm:0.82.5": + version: 0.82.5 + resolution: "metro-file-map@npm:0.82.5" dependencies: debug: ^4.4.0 fb-watchman: ^2.0.0 @@ -8210,76 +8142,76 @@ __metadata: micromatch: ^4.0.4 nullthrows: ^1.1.1 walker: ^1.0.7 - checksum: 6ef8a29a0412c2e7ddc9e7d5752467e0a192dee0b2c87ad18e77f33bb3bf879db1557157739fb6ad9cb8b52e31319b6676b965d46a7c61158db96be0bbda1b99 + checksum: 46bda99f0ae892071c1b48b09f884f017f48d564c30b2a1f858f6fae1c6c1848bbbce20f66a5be086d7e0acfec3d8c1ddbf69699aaf2829f10954ae39d8a27d7 languageName: node linkType: hard -"metro-minify-terser@npm:0.82.1": - version: 0.82.1 - resolution: "metro-minify-terser@npm:0.82.1" +"metro-minify-terser@npm:0.82.5": + version: 0.82.5 + resolution: "metro-minify-terser@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 terser: ^5.15.0 - checksum: 3c1d52cfc98257ae6898f2e9db67eae8ddabba89aff30b815bb2adcea9f4f02c78669c1df7878389d6fc5fc7f8138bcb543d06f68f5e1f1741cc32c504eded20 + checksum: 754c150f0928460e1254e90e4e11bd87e069a0b286d21906758cb71fb8b4ec50dc8f78337bf8a9f8a28ddbd34230f5c66dad0fecf18dbe49715bf1300e5318c2 languageName: node linkType: hard -"metro-resolver@npm:0.82.1": - version: 0.82.1 - resolution: "metro-resolver@npm:0.82.1" +"metro-resolver@npm:0.82.5": + version: 0.82.5 + resolution: "metro-resolver@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 - checksum: 66a7018cb43b3abb9a2f79383e631cfab6fbfa816ab12cb67d880602dde7c083ff3ae424016474cd0d81352a9a9554ee3bd96633246d6a1f81406d3539eb0b3f + checksum: d1f7b57687c9cbb100114474689fee2fcfb86428a1228499b28391d16378573ac0f07c750874a2d75eabe237d67eb32a5c947bbbd70cd851885f1f6b13992472 languageName: node linkType: hard -"metro-runtime@npm:0.82.1, metro-runtime@npm:^0.82.0": - version: 0.82.1 - resolution: "metro-runtime@npm:0.82.1" +"metro-runtime@npm:0.82.5, metro-runtime@npm:^0.82.0": + version: 0.82.5 + resolution: "metro-runtime@npm:0.82.5" dependencies: "@babel/runtime": ^7.25.0 flow-enums-runtime: ^0.0.6 - checksum: 8050d325c88870779268b0dda96905512486f1fc83bfcfb5116b80686c2ce99c167dc60193ed8e9ccbf689fbd13c6ba5ab451b89c9237a79295a0c035e6b2806 + checksum: 931c2b581ac1527899cfec6b9c4bbbac75545c78bf192abd8efddd4dbff481b052513857c8544507e7900e7c06f08a8da75e16c864cd86ec3a8c3d6c05738dae languageName: node linkType: hard -"metro-source-map@npm:0.82.1, metro-source-map@npm:^0.82.0": - version: 0.82.1 - resolution: "metro-source-map@npm:0.82.1" +"metro-source-map@npm:0.82.5, metro-source-map@npm:^0.82.0": + version: 0.82.5 + resolution: "metro-source-map@npm:0.82.5" dependencies: "@babel/traverse": ^7.25.3 "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3" "@babel/types": ^7.25.2 flow-enums-runtime: ^0.0.6 invariant: ^2.2.4 - metro-symbolicate: 0.82.1 + metro-symbolicate: 0.82.5 nullthrows: ^1.1.1 - ob1: 0.82.1 + ob1: 0.82.5 source-map: ^0.5.6 vlq: ^1.0.0 - checksum: 139909ff3f5ac45a313d700fd953fe25f08a199f707763373501fab50b2c44b6b8a691bee932e4f33be70849463a18cc3d007c1c0303a0d69c9c6058a6e1300b + checksum: 1bb53abe636524593207c578bfd0e15f47f4e15db919793a49b89359726d043cd69107244b6e1c2c8194983b8df7faa8b56ffa73a5f81c0fefc0cc1727907177 languageName: node linkType: hard -"metro-symbolicate@npm:0.82.1": - version: 0.82.1 - resolution: "metro-symbolicate@npm:0.82.1" +"metro-symbolicate@npm:0.82.5": + version: 0.82.5 + resolution: "metro-symbolicate@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 invariant: ^2.2.4 - metro-source-map: 0.82.1 + metro-source-map: 0.82.5 nullthrows: ^1.1.1 source-map: ^0.5.6 vlq: ^1.0.0 bin: metro-symbolicate: src/index.js - checksum: 6bb0fab407097cbbe4539b28659cd53b618040de80852580ac8d5678a6067c62038d2d182f6911e70588e264eee8327b7409fc380f4b8ceb7d477e0c211abca3 + checksum: ae91be09cca42567ea3c2bee695e0db42512fc8bf28cf2aa281ae8043edc3bbddcadd0793b401b6bcb7e0cc1df1428647662462a8f515ab6c47420421b1e96f8 languageName: node linkType: hard -"metro-transform-plugins@npm:0.82.1": - version: 0.82.1 - resolution: "metro-transform-plugins@npm:0.82.1" +"metro-transform-plugins@npm:0.82.5": + version: 0.82.5 + resolution: "metro-transform-plugins@npm:0.82.5" dependencies: "@babel/core": ^7.25.2 "@babel/generator": ^7.25.0 @@ -8287,34 +8219,34 @@ __metadata: "@babel/traverse": ^7.25.3 flow-enums-runtime: ^0.0.6 nullthrows: ^1.1.1 - checksum: 2f2b6161df8ad087215e7e40ffc17c1173e14f26437e97faf6cc44109f7a3d92184cdfda708958674ffab92d172a726f9dde48dc65d09af01d5546667e48672e + checksum: 891838d529df2c3170614de9e55025d37fb799a8d444d9e898fc203496ec33620ad8066e0ab06244b7abb806ffdae4728b84047d0d01bceee877ea5d69240d04 languageName: node linkType: hard -"metro-transform-worker@npm:0.82.1": - version: 0.82.1 - resolution: "metro-transform-worker@npm:0.82.1" +"metro-transform-worker@npm:0.82.5": + version: 0.82.5 + resolution: "metro-transform-worker@npm:0.82.5" dependencies: "@babel/core": ^7.25.2 "@babel/generator": ^7.25.0 "@babel/parser": ^7.25.3 "@babel/types": ^7.25.2 flow-enums-runtime: ^0.0.6 - metro: 0.82.1 - metro-babel-transformer: 0.82.1 - metro-cache: 0.82.1 - metro-cache-key: 0.82.1 - metro-minify-terser: 0.82.1 - metro-source-map: 0.82.1 - metro-transform-plugins: 0.82.1 + metro: 0.82.5 + metro-babel-transformer: 0.82.5 + metro-cache: 0.82.5 + metro-cache-key: 0.82.5 + metro-minify-terser: 0.82.5 + metro-source-map: 0.82.5 + metro-transform-plugins: 0.82.5 nullthrows: ^1.1.1 - checksum: f0a538643deea37853dd0a9f5c90c1d4036e3e0f3cbd1f7c7488a921ba204c5648eba844a598c54b02eda7322dd3674ebd42d669f03055f7ddac77cd8d9f4435 + checksum: 653868f5fc525ad5b36181e7d1b3bb893c49ce6647791c21b585dd29cccc2f00e68d66b16e00eeb385fcb0c5f205a713aba0fe57971b1ab2bf150938cb820aaa languageName: node linkType: hard -"metro@npm:0.82.1, metro@npm:^0.82.0": - version: 0.82.1 - resolution: "metro@npm:0.82.1" +"metro@npm:0.82.5, metro@npm:^0.82.0": + version: 0.82.5 + resolution: "metro@npm:0.82.5" dependencies: "@babel/code-frame": ^7.24.7 "@babel/core": ^7.25.2 @@ -8331,24 +8263,24 @@ __metadata: error-stack-parser: ^2.0.6 flow-enums-runtime: ^0.0.6 graceful-fs: ^4.2.4 - hermes-parser: 0.25.1 + hermes-parser: 0.29.1 image-size: ^1.0.2 invariant: ^2.2.4 jest-worker: ^29.7.0 jsc-safe-url: ^0.2.2 lodash.throttle: ^4.1.1 - metro-babel-transformer: 0.82.1 - metro-cache: 0.82.1 - metro-cache-key: 0.82.1 - metro-config: 0.82.1 - metro-core: 0.82.1 - metro-file-map: 0.82.1 - metro-resolver: 0.82.1 - metro-runtime: 0.82.1 - metro-source-map: 0.82.1 - metro-symbolicate: 0.82.1 - metro-transform-plugins: 0.82.1 - metro-transform-worker: 0.82.1 + metro-babel-transformer: 0.82.5 + metro-cache: 0.82.5 + metro-cache-key: 0.82.5 + metro-config: 0.82.5 + metro-core: 0.82.5 + metro-file-map: 0.82.5 + metro-resolver: 0.82.5 + metro-runtime: 0.82.5 + metro-source-map: 0.82.5 + metro-symbolicate: 0.82.5 + metro-transform-plugins: 0.82.5 + metro-transform-worker: 0.82.5 mime-types: ^2.1.27 nullthrows: ^1.1.1 serialize-error: ^2.1.0 @@ -8358,7 +8290,7 @@ __metadata: yargs: ^17.6.2 bin: metro: src/cli.js - checksum: add0c55d46c3050af3c9f208f439b0012c1e37dfdaae66fcf5ec301f5c3b704611e64e179b1553dc48bb60a8bb3a03cdced6a69f3d2728767281765da4e24f89 + checksum: 391411e1be9463f4d52e804f0a9680e59be1cfc5c76ca890f3a9e9c014561da65bbf6e3ccc44f7f52601add064b3b70862b3813c963384a0df2218a345a304e5 languageName: node linkType: hard @@ -8616,13 +8548,6 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:0.0.8": - version: 0.0.8 - resolution: "mute-stream@npm:0.0.8" - checksum: ff48d251fc3f827e5b1206cda0ffdaec885e56057ee86a3155e1951bc940fd5f33531774b1cc8414d7668c10a8907f863f6561875ee6e8768931a62121a531a1 - languageName: node - linkType: hard - "mz@npm:^2.7.0": version: 2.7.0 resolution: "mz@npm:2.7.0" @@ -8796,12 +8721,12 @@ __metadata: languageName: node linkType: hard -"ob1@npm:0.82.1": - version: 0.82.1 - resolution: "ob1@npm:0.82.1" +"ob1@npm:0.82.5": + version: 0.82.5 + resolution: "ob1@npm:0.82.5" dependencies: flow-enums-runtime: ^0.0.6 - checksum: 726b28f8f8aafef91ad3de9111fe5809e07bdde45d59e3f9d3bfdd868c028c6616fb80836df54d0518c3d8ed411b66a0c09f828e2637a355992e5121988d0c99 + checksum: 3faa161e5b5307188b6bbbf7e21727b1e434b8f6c31c51386808b2efd5e7238cf85a7ce71416d9a3f073625afb5a2212f80ec267996dc88fe086944adbb525d9 languageName: node linkType: hard @@ -9006,14 +8931,7 @@ __metadata: languageName: node linkType: hard -"os-tmpdir@npm:~1.0.2": - version: 1.0.2 - resolution: "os-tmpdir@npm:1.0.2" - checksum: 5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d - languageName: node - linkType: hard - -"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": +"p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" dependencies: @@ -9031,15 +8949,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^3.0.0": - version: 3.0.0 - resolution: "p-locate@npm:3.0.0" - dependencies: - p-limit: ^2.0.0 - checksum: 83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae - languageName: node - linkType: hard - "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -9128,13 +9037,6 @@ __metadata: languageName: node linkType: hard -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a - languageName: node - linkType: hard - "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -9197,13 +9099,6 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.0": - version: 1.1.0 - resolution: "pathe@npm:1.1.0" - checksum: 6b9be9968ea08a90c0824934799707a1c6a1ad22ac1f22080f377e3f75856d5e53a331b01d327329bfce538a14590587cfb250e8e7947f64408797c84c252056 - languageName: node - linkType: hard - "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -9253,15 +9148,6 @@ __metadata: languageName: node linkType: hard -"pkg-up@npm:^3.1.0": - version: 3.1.0 - resolution: "pkg-up@npm:3.1.0" - dependencies: - find-up: ^3.0.0 - checksum: 5bac346b7c7c903613c057ae3ab722f320716199d753f4a7d053d38f2b5955460f3e6ab73b4762c62fd3e947f58e04f1343e92089e7bb6091c90877406fcd8c8 - languageName: node - linkType: hard - "plist@npm:^3.0.5": version: 3.0.6 resolution: "plist@npm:3.0.6" @@ -9593,18 +9479,18 @@ __metadata: languageName: node linkType: hard -"react-native@npm:0.79.2": - version: 0.79.2 - resolution: "react-native@npm:0.79.2" +"react-native@npm:0.79.5": + version: 0.79.5 + resolution: "react-native@npm:0.79.5" dependencies: "@jest/create-cache-key-function": ^29.7.0 - "@react-native/assets-registry": 0.79.2 - "@react-native/codegen": 0.79.2 - "@react-native/community-cli-plugin": 0.79.2 - "@react-native/gradle-plugin": 0.79.2 - "@react-native/js-polyfills": 0.79.2 - "@react-native/normalize-colors": 0.79.2 - "@react-native/virtualized-lists": 0.79.2 + "@react-native/assets-registry": 0.79.5 + "@react-native/codegen": 0.79.5 + "@react-native/community-cli-plugin": 0.79.5 + "@react-native/gradle-plugin": 0.79.5 + "@react-native/js-polyfills": 0.79.5 + "@react-native/normalize-colors": 0.79.5 + "@react-native/virtualized-lists": 0.79.5 abort-controller: ^3.0.0 anser: ^1.4.9 ansi-regex: ^5.0.0 @@ -9641,7 +9527,7 @@ __metadata: optional: true bin: react-native: cli.js - checksum: fa057ecce31920ed426ad354910f60c4bbe089b53d41edfa1dd59af8cafd89578f018063d9c9ed1536ad5f6538fc9849aacc271ee3880dd50eb5cfce56f61b86 + checksum: 6db9368ca97ad2b4b2326d63edcb4ac151d77ad564afb3cbf1ae5caf8f169fee02bc83cb2411fc8b3e42f9d1ef08b2ac937a4260f67187829bed310e5d431988 languageName: node linkType: hard @@ -9834,19 +9720,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.19.0": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 - languageName: node - linkType: hard - "resolve@npm:^1.22.2": version: 1.22.8 resolution: "resolve@npm:1.22.8" @@ -9895,19 +9768,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.19.0#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 - languageName: node - linkType: hard - "resolve@patch:resolve@^1.22.2#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" @@ -9988,13 +9848,6 @@ __metadata: languageName: node linkType: hard -"run-async@npm:^2.4.0": - version: 2.4.1 - resolution: "run-async@npm:2.4.1" - checksum: a2c88aa15df176f091a2878eb840e68d0bdee319d8d97bbb89112223259cebecb94bc0defd735662b83c2f7a30bed8cddb7d1674eb48ae7322dc602b22d03797 - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -10004,15 +9857,6 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^6.6.0": - version: 6.6.7 - resolution: "rxjs@npm:6.6.7" - dependencies: - tslib: ^1.9.0 - checksum: bc334edef1bb8bbf56590b0b25734ba0deaf8825b703256a93714308ea36dff8a11d25533671adf8e104e5e8f256aa6fdfe39b2e248cdbd7a5f90c260acbbd1b - languageName: node - linkType: hard - "safe-buffer@npm:5.1.2": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" @@ -10779,22 +10623,6 @@ __metadata: languageName: node linkType: hard -"through@npm:^2.3.6": - version: 2.3.8 - resolution: "through@npm:2.3.8" - checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd - languageName: node - linkType: hard - -"tmp@npm:^0.0.33": - version: 0.0.33 - resolution: "tmp@npm:0.0.33" - dependencies: - os-tmpdir: ~1.0.2 - checksum: 902d7aceb74453ea02abbf58c203f4a8fc1cead89b60b31e354f74ed5b3fb09ea817f94fb310f884a5d16987dd9fa5a735412a7c2dd088dd3d415aa819ae3a28 - languageName: node - linkType: hard - "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -10848,7 +10676,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1, tslib@npm:^1.9.0": +"tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd @@ -11042,13 +10870,6 @@ __metadata: languageName: node linkType: hard -"unraw@npm:^3.0.0": - version: 3.0.0 - resolution: "unraw@npm:3.0.0" - checksum: 19eee0bc500ce197d262b79723a2c8c81c1d716baaa2a62c48a4d0d6b9e1fd9d350c5df86262e51343d591ab9c8a47ed150317d0b867b2b65795cdc17ef69873 - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.0.10": version: 1.0.11 resolution: "update-browserslist-db@npm:1.0.11" @@ -11438,13 +11259,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.0": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f - languageName: node - linkType: hard - "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" From decf4cd0e06e1d913b228018ee77d6d5b83d26c3 Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Tue, 5 Aug 2025 13:15:17 +0200 Subject: [PATCH 09/19] fix(extractor): sort placeholders to keep them stable between runs (#2307) --- packages/cli/src/api/catalog.test.ts | 33 +++++++++++++++++++ .../cli/src/api/catalog/extractFromFiles.ts | 2 ++ .../collect-placeholders-sorting/a.ts | 7 ++++ .../collect-placeholders-sorting/b.ts | 7 ++++ .../cli/test/extract-po-format/expected/en.po | 2 +- .../cli/test/extract-po-format/expected/pl.po | 2 +- 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/api/fixtures/collect-placeholders-sorting/a.ts create mode 100644 packages/cli/src/api/fixtures/collect-placeholders-sorting/b.ts diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts index ef79a4ea7..62b952a22 100644 --- a/packages/cli/src/api/catalog.test.ts +++ b/packages/cli/src/api/catalog.test.ts @@ -193,6 +193,39 @@ describe("Catalog", () => { expect(messages).toMatchSnapshot() }) + it("should sort placeholders to keep them stable between runs", async () => { + const runA = await extractFromFiles( + [ + fixture("collect-placeholders-sorting/a.ts"), + fixture("collect-placeholders-sorting/b.ts"), + ], + mockConfig() + ) + + const runB = await extractFromFiles( + [ + fixture("collect-placeholders-sorting/b.ts"), + fixture("collect-placeholders-sorting/a.ts"), + ], + mockConfig() + ) + + expect(Object.values(runA)[0].placeholders[0]).toStrictEqual( + Object.values(runB)[0].placeholders[0] + ) + + expect(Object.values(runA)[0].placeholders).toMatchInlineSnapshot(` + { + 0: [ + getUser(), + getWorld(), + ], + } + `) + + // expect(messages).toMatchSnapshot() + }) + it("should support experimental typescript decorators under a flag", async () => { const messages = await extractFromFiles( [fixture("collect-typescript-jsx/tsx-experimental-decorators.tsx")], diff --git a/packages/cli/src/api/catalog/extractFromFiles.ts b/packages/cli/src/api/catalog/extractFromFiles.ts index a96ada891..a0976b12a 100644 --- a/packages/cli/src/api/catalog/extractFromFiles.ts +++ b/packages/cli/src/api/catalog/extractFromFiles.ts @@ -23,6 +23,8 @@ function mergePlaceholders( if (!res[key].includes(value)) { res[key].push(value) } + + res[key].sort() }) return res diff --git a/packages/cli/src/api/fixtures/collect-placeholders-sorting/a.ts b/packages/cli/src/api/fixtures/collect-placeholders-sorting/a.ts new file mode 100644 index 000000000..f046e7411 --- /dev/null +++ b/packages/cli/src/api/fixtures/collect-placeholders-sorting/a.ts @@ -0,0 +1,7 @@ +import { t } from "@lingui/core/macro"; + +function getUser() { + return 'John' +} + +t`Hello ${getUser()}` \ No newline at end of file diff --git a/packages/cli/src/api/fixtures/collect-placeholders-sorting/b.ts b/packages/cli/src/api/fixtures/collect-placeholders-sorting/b.ts new file mode 100644 index 000000000..77e108dfb --- /dev/null +++ b/packages/cli/src/api/fixtures/collect-placeholders-sorting/b.ts @@ -0,0 +1,7 @@ +import { t } from "@lingui/core/macro" + +function getWorld() { + return "John" +} + +t`Hello ${getWorld()}` \ No newline at end of file diff --git a/packages/cli/test/extract-po-format/expected/en.po b/packages/cli/test/extract-po-format/expected/en.po index 66ae5e0dc..f837f4078 100644 --- a/packages/cli/test/extract-po-format/expected/en.po +++ b/packages/cli/test/extract-po-format/expected/en.po @@ -13,9 +13,9 @@ msgstr "" msgid "addToCart" msgstr "Add To Cart" -#. placeholder {0}: user.name #. placeholder {0}: author.name #. placeholder {0}: moderator.name +#. placeholder {0}: user.name #: fixtures/placeholders.ts:3 #: fixtures/placeholders.ts:4 #: fixtures/placeholders.ts:5 diff --git a/packages/cli/test/extract-po-format/expected/pl.po b/packages/cli/test/extract-po-format/expected/pl.po index 45c1b2868..8c37b0dc2 100644 --- a/packages/cli/test/extract-po-format/expected/pl.po +++ b/packages/cli/test/extract-po-format/expected/pl.po @@ -13,9 +13,9 @@ msgstr "" msgid "addToCart" msgstr "" -#. placeholder {0}: user.name #. placeholder {0}: author.name #. placeholder {0}: moderator.name +#. placeholder {0}: user.name #: fixtures/placeholders.ts:3 #: fixtures/placeholders.ts:4 #: fixtures/placeholders.ts:5 From 296f115904bae526cd4b4807bbdc373b2e50822b Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Mon, 11 Aug 2025 09:59:25 +0300 Subject: [PATCH 10/19] chore(release): published v5.4.1 [skip ci] (#2310) --- CHANGELOG.md | 7 ++ lerna.json | 2 +- .../CHANGELOG.md | 4 + .../package.json | 2 +- .../babel-plugin-lingui-macro/CHANGELOG.md | 4 + .../babel-plugin-lingui-macro/package.json | 8 +- packages/cli/CHANGELOG.md | 6 ++ packages/cli/package.json | 14 +-- packages/conf/CHANGELOG.md | 4 + packages/conf/package.json | 2 +- packages/core/CHANGELOG.md | 4 + packages/core/package.json | 6 +- packages/detect-locale/CHANGELOG.md | 4 + packages/detect-locale/package.json | 2 +- packages/extractor-vue/CHANGELOG.md | 4 + packages/extractor-vue/package.json | 8 +- packages/format-csv/CHANGELOG.md | 4 + packages/format-csv/package.json | 4 +- packages/format-json/CHANGELOG.md | 4 + packages/format-json/package.json | 4 +- packages/format-po-gettext/CHANGELOG.md | 4 + packages/format-po-gettext/package.json | 8 +- packages/format-po/CHANGELOG.md | 4 + packages/format-po/package.json | 6 +- packages/loader/CHANGELOG.md | 4 + packages/loader/package.json | 8 +- packages/macro/CHANGELOG.md | 4 + packages/macro/package.json | 8 +- packages/message-utils/CHANGELOG.md | 6 ++ packages/message-utils/package.json | 2 +- packages/metro-transformer/CHANGELOG.md | 4 + packages/metro-transformer/package.json | 8 +- packages/react/CHANGELOG.md | 4 + packages/react/package.json | 6 +- packages/vite-plugin/CHANGELOG.md | 4 + packages/vite-plugin/package.json | 6 +- yarn.lock | 86 +++++++++---------- 37 files changed, 174 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb157b63..bba3c4a66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +### Bug Fixes + +* **extractor:** sort placeholders to keep them stable between runs ([#2307](https://github.com/lingui/js-lingui/issues/2307)) ([decf4cd](https://github.com/lingui/js-lingui/commit/decf4cd0e06e1d913b228018ee77d6d5b83d26c3)) +* remove @messageformat/date-skeleton from bundledDependencies ([#2293](https://github.com/lingui/js-lingui/issues/2293)) ([9601701](https://github.com/lingui/js-lingui/commit/96017018433310a6ba7a21dc9b6ce1d4f3c6965a)) + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) ### Bug Fixes diff --git a/lerna.json b/lerna.json index 769852a6f..4d892f80a 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.4.0", + "version": "5.4.1", "packages": ["packages/*"], "npmClient": "yarn", "command": { diff --git a/packages/babel-plugin-extract-messages/CHANGELOG.md b/packages/babel-plugin-extract-messages/CHANGELOG.md index 5cd5c381c..0d7b96023 100644 --- a/packages/babel-plugin-extract-messages/CHANGELOG.md +++ b/packages/babel-plugin-extract-messages/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/babel-plugin-extract-messages + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/babel-plugin-extract-messages diff --git a/packages/babel-plugin-extract-messages/package.json b/packages/babel-plugin-extract-messages/package.json index aa141d5e3..a229cf487 100644 --- a/packages/babel-plugin-extract-messages/package.json +++ b/packages/babel-plugin-extract-messages/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-extract-messages", - "version": "5.4.0", + "version": "5.4.1", "description": "Babel plugin for collecting messages from source code for internationalization", "main": "./dist/index.cjs", "module": "./dist/index.mjs", diff --git a/packages/babel-plugin-lingui-macro/CHANGELOG.md b/packages/babel-plugin-lingui-macro/CHANGELOG.md index 1dd12e80f..137297224 100644 --- a/packages/babel-plugin-lingui-macro/CHANGELOG.md +++ b/packages/babel-plugin-lingui-macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/babel-plugin-lingui-macro + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/babel-plugin-lingui-macro diff --git a/packages/babel-plugin-lingui-macro/package.json b/packages/babel-plugin-lingui-macro/package.json index 9511b2e2e..12927f646 100644 --- a/packages/babel-plugin-lingui-macro/package.json +++ b/packages/babel-plugin-lingui-macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-lingui-macro", - "version": "5.4.0", + "version": "5.4.1", "description": "Babel plugin for transforming Lingui Macros", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -86,9 +86,9 @@ "@babel/core": "^7.20.12", "@babel/runtime": "^7.20.13", "@babel/types": "^7.20.7", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/message-utils": "5.4.0" + "@lingui/conf": "5.4.1", + "@lingui/core": "5.4.1", + "@lingui/message-utils": "5.4.1" }, "peerDependencies": { "babel-plugin-macros": "2 || 3" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 8a4719167..8c49ed1fb 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +### Bug Fixes + +* **extractor:** sort placeholders to keep them stable between runs ([#2307](https://github.com/lingui/js-lingui/issues/2307)) ([decf4cd](https://github.com/lingui/js-lingui/commit/decf4cd0e06e1d913b228018ee77d6d5b83d26c3)) + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) ### Features diff --git a/packages/cli/package.json b/packages/cli/package.json index a6e2a5159..a4032a6b0 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/cli", - "version": "5.4.0", + "version": "5.4.1", "description": "CLI for working wit message catalogs", "keywords": [ "cli", @@ -62,12 +62,12 @@ "@babel/parser": "^7.22.0", "@babel/runtime": "^7.21.0", "@babel/types": "^7.21.2", - "@lingui/babel-plugin-extract-messages": "5.4.0", - "@lingui/babel-plugin-lingui-macro": "5.4.0", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/format-po": "5.4.0", - "@lingui/message-utils": "5.4.0", + "@lingui/babel-plugin-extract-messages": "5.4.1", + "@lingui/babel-plugin-lingui-macro": "5.4.1", + "@lingui/conf": "5.4.1", + "@lingui/core": "5.4.1", + "@lingui/format-po": "5.4.1", + "@lingui/message-utils": "5.4.1", "chokidar": "3.5.1", "cli-table": "^0.3.11", "commander": "^10.0.0", diff --git a/packages/conf/CHANGELOG.md b/packages/conf/CHANGELOG.md index 242ceb9c6..365cb3c61 100644 --- a/packages/conf/CHANGELOG.md +++ b/packages/conf/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/conf + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/conf diff --git a/packages/conf/package.json b/packages/conf/package.json index 7eed46037..51ce8afa1 100644 --- a/packages/conf/package.json +++ b/packages/conf/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/conf", - "version": "5.4.0", + "version": "5.4.1", "sideEffects": false, "description": "Get lingui configuration from package.json", "keywords": [ diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 505a92fd7..a65c27543 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/core + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/core diff --git a/packages/core/package.json b/packages/core/package.json index 190d04085..d186fd158 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/core", - "version": "5.4.0", + "version": "5.4.1", "sideEffects": false, "description": "I18n tools for javascript", "main": "./dist/index.cjs", @@ -62,14 +62,14 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.0" + "@lingui/message-utils": "5.4.1" }, "devDependencies": { "@lingui/jest-mocks": "*", "unbuild": "2.0.0" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.0", + "@lingui/babel-plugin-lingui-macro": "5.4.1", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/detect-locale/CHANGELOG.md b/packages/detect-locale/CHANGELOG.md index 7e4de9647..e06e34d58 100644 --- a/packages/detect-locale/CHANGELOG.md +++ b/packages/detect-locale/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/detect-locale + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/detect-locale diff --git a/packages/detect-locale/package.json b/packages/detect-locale/package.json index e205d4617..665b2c1c3 100644 --- a/packages/detect-locale/package.json +++ b/packages/detect-locale/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/detect-locale", - "version": "5.4.0", + "version": "5.4.1", "sideEffects": false, "description": "@Lingui package to help you find the correct browser/server locale", "main": "./dist/index.cjs", diff --git a/packages/extractor-vue/CHANGELOG.md b/packages/extractor-vue/CHANGELOG.md index a81a7c436..25851d892 100644 --- a/packages/extractor-vue/CHANGELOG.md +++ b/packages/extractor-vue/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/extractor-vue + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/extractor-vue diff --git a/packages/extractor-vue/package.json b/packages/extractor-vue/package.json index c8d2d581b..7a467936c 100644 --- a/packages/extractor-vue/package.json +++ b/packages/extractor-vue/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/extractor-vue", - "version": "5.4.0", + "version": "5.4.1", "description": "Custom Vue.js extractor to be used with the CLI tool", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -43,12 +43,12 @@ "/dist" ], "dependencies": { - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0", + "@lingui/cli": "5.4.1", + "@lingui/conf": "5.4.1", "@vue/compiler-sfc": "^3.2.47" }, "devDependencies": { - "@lingui/babel-plugin-extract-messages": "5.4.0", + "@lingui/babel-plugin-extract-messages": "5.4.1", "unbuild": "2.0.0" } } diff --git a/packages/format-csv/CHANGELOG.md b/packages/format-csv/CHANGELOG.md index dd8e4f1ab..ec3bcae3b 100644 --- a/packages/format-csv/CHANGELOG.md +++ b/packages/format-csv/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/format-csv + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/format-csv diff --git a/packages/format-csv/package.json b/packages/format-csv/package.json index 9db4dac42..a62a22dec 100644 --- a/packages/format-csv/package.json +++ b/packages/format-csv/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-csv", - "version": "5.4.0", + "version": "5.4.1", "description": "CSV format for Lingui Catalogs", "main": "./dist/csv.cjs", "module": "./dist/csv.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.0", + "@lingui/conf": "5.4.1", "papaparse": "^5.4.0" }, "devDependencies": { diff --git a/packages/format-json/CHANGELOG.md b/packages/format-json/CHANGELOG.md index 19e59bf5d..590babd14 100644 --- a/packages/format-json/CHANGELOG.md +++ b/packages/format-json/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/format-json + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/format-json diff --git a/packages/format-json/package.json b/packages/format-json/package.json index c9827dd64..05dbba3af 100644 --- a/packages/format-json/package.json +++ b/packages/format-json/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-json", - "version": "5.4.0", + "version": "5.4.1", "description": "JSON format for Lingui Catalogs", "main": "./dist/json.cjs", "module": "./dist/json.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.0" + "@lingui/conf": "5.4.1" }, "devDependencies": { "unbuild": "^2.0.0" diff --git a/packages/format-po-gettext/CHANGELOG.md b/packages/format-po-gettext/CHANGELOG.md index 89f65d0a7..9e8744e3a 100644 --- a/packages/format-po-gettext/CHANGELOG.md +++ b/packages/format-po-gettext/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/format-po-gettext + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/format-po-gettext diff --git a/packages/format-po-gettext/package.json b/packages/format-po-gettext/package.json index 35ef91703..992db7535 100644 --- a/packages/format-po-gettext/package.json +++ b/packages/format-po-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po-gettext", - "version": "5.4.0", + "version": "5.4.1", "description": "Gettext PO format with gettext-style plurals for Lingui Catalogs", "main": "./dist/po-gettext.cjs", "module": "./dist/po-gettext.mjs", @@ -43,9 +43,9 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.0", - "@lingui/format-po": "5.4.0", - "@lingui/message-utils": "5.4.0", + "@lingui/conf": "5.4.1", + "@lingui/format-po": "5.4.1", + "@lingui/message-utils": "5.4.1", "@messageformat/parser": "^5.0.0", "cldr-core": "^45.0.0", "node-gettext": "^3.0.0", diff --git a/packages/format-po/CHANGELOG.md b/packages/format-po/CHANGELOG.md index 6813a5969..8f434a16b 100644 --- a/packages/format-po/CHANGELOG.md +++ b/packages/format-po/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/format-po + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/format-po diff --git a/packages/format-po/package.json b/packages/format-po/package.json index d7ad38463..ce8607c96 100644 --- a/packages/format-po/package.json +++ b/packages/format-po/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po", - "version": "5.4.0", + "version": "5.4.1", "description": "Gettext PO format for Lingui Catalogs", "main": "./dist/po.cjs", "module": "./dist/po.mjs", @@ -43,8 +43,8 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.0", - "@lingui/message-utils": "5.4.0", + "@lingui/conf": "5.4.1", + "@lingui/message-utils": "5.4.1", "date-fns": "^3.6.0", "pofile": "^1.1.4" }, diff --git a/packages/loader/CHANGELOG.md b/packages/loader/CHANGELOG.md index 9583fe75a..9735cab77 100644 --- a/packages/loader/CHANGELOG.md +++ b/packages/loader/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/loader + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/loader diff --git a/packages/loader/package.json b/packages/loader/package.json index fda92c2fe..fbeb01b6d 100644 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/loader", - "version": "5.4.0", + "version": "5.4.1", "description": "webpack loader for lingui message catalogs", "types": "./dist/index.d.ts", "main": "./dist/index.cjs", @@ -45,11 +45,11 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0" + "@lingui/cli": "5.4.1", + "@lingui/conf": "5.4.1" }, "devDependencies": { - "@lingui/format-json": "5.4.0", + "@lingui/format-json": "5.4.1", "unbuild": "2.0.0", "webpack": "^5.76.1" }, diff --git a/packages/macro/CHANGELOG.md b/packages/macro/CHANGELOG.md index 0ef3dcda7..09f065467 100644 --- a/packages/macro/CHANGELOG.md +++ b/packages/macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/macro + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/macro diff --git a/packages/macro/package.json b/packages/macro/package.json index fca3662e7..cc2b9502e 100644 --- a/packages/macro/package.json +++ b/packages/macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/macro", - "version": "5.4.0", + "version": "5.4.1", "description": "Macro for generating messages in ICU MessageFormat syntax", "main": "./index.js", "types": "./index.d.ts", @@ -46,11 +46,11 @@ "index.js" ], "dependencies": { - "@lingui/core": "5.4.0", - "@lingui/react": "5.4.0" + "@lingui/core": "5.4.1", + "@lingui/react": "5.4.1" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.0", + "@lingui/babel-plugin-lingui-macro": "5.4.1", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/message-utils/CHANGELOG.md b/packages/message-utils/CHANGELOG.md index 640296e8a..c4e355ef5 100644 --- a/packages/message-utils/CHANGELOG.md +++ b/packages/message-utils/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +### Bug Fixes + +* remove @messageformat/date-skeleton from bundledDependencies ([#2293](https://github.com/lingui/js-lingui/issues/2293)) ([9601701](https://github.com/lingui/js-lingui/commit/96017018433310a6ba7a21dc9b6ce1d4f3c6965a)) + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/message-utils diff --git a/packages/message-utils/package.json b/packages/message-utils/package.json index 89dd29aec..caf825462 100644 --- a/packages/message-utils/package.json +++ b/packages/message-utils/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/message-utils", - "version": "5.4.0", + "version": "5.4.1", "license": "MIT", "keywords": [], "sideEffects": false, diff --git a/packages/metro-transformer/CHANGELOG.md b/packages/metro-transformer/CHANGELOG.md index cf86e3209..5c71b682f 100644 --- a/packages/metro-transformer/CHANGELOG.md +++ b/packages/metro-transformer/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/metro-transformer + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) ### Bug Fixes diff --git a/packages/metro-transformer/package.json b/packages/metro-transformer/package.json index c6795b31c..abe2ee655 100644 --- a/packages/metro-transformer/package.json +++ b/packages/metro-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/metro-transformer", - "version": "5.4.0", + "version": "5.4.1", "description": "Metro bundler transformer for LinguiJS catalogs", "exports": { "./expo": { @@ -58,12 +58,12 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0", + "@lingui/cli": "5.4.1", + "@lingui/conf": "5.4.1", "memoize-one": "^6.0.0" }, "devDependencies": { - "@lingui/format-json": "5.4.0", + "@lingui/format-json": "5.4.1", "rimraf": "^6.0.1", "unbuild": "2.0.0" }, diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index f98c0fb89..177633f46 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/react + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) ### Bug Fixes diff --git a/packages/react/package.json b/packages/react/package.json index ec1233ad0..b31156a58 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/react", - "version": "5.4.0", + "version": "5.4.1", "sideEffects": false, "description": "React components for translations", "main": "./dist/index.cjs", @@ -79,7 +79,7 @@ "macro/index.js" ], "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.0", + "@lingui/babel-plugin-lingui-macro": "5.4.1", "babel-plugin-macros": "2 || 3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -93,7 +93,7 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/core": "5.4.0" + "@lingui/core": "5.4.1" }, "devDependencies": { "@lingui/jest-mocks": "*", diff --git a/packages/vite-plugin/CHANGELOG.md b/packages/vite-plugin/CHANGELOG.md index 3bc79dc89..9d9a78838 100644 --- a/packages/vite-plugin/CHANGELOG.md +++ b/packages/vite-plugin/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) + +**Note:** Version bump only for package @lingui/vite-plugin + # [5.4.0](https://github.com/lingui/js-lingui/compare/v5.3.3...v5.4.0) (2025-08-01) **Note:** Version bump only for package @lingui/vite-plugin diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index 5fa522c72..b97322ec8 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/vite-plugin", - "version": "5.4.0", + "version": "5.4.1", "description": "Vite plugin for Lingui message catalogs", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -41,8 +41,8 @@ "dist/" ], "dependencies": { - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0" + "@lingui/cli": "5.4.1", + "@lingui/conf": "5.4.1" }, "peerDependencies": { "vite": "^3 || ^4 || ^5.0.9 || ^6 || ^7" diff --git a/yarn.lock b/yarn.lock index e2a032e58..9f68b4289 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2622,7 +2622,7 @@ __metadata: languageName: node linkType: hard -"@lingui/babel-plugin-extract-messages@5.4.0, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": +"@lingui/babel-plugin-extract-messages@5.4.1, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages" dependencies: @@ -2635,7 +2635,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/babel-plugin-lingui-macro@5.4.0, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": +"@lingui/babel-plugin-lingui-macro@5.4.1, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro" dependencies: @@ -2644,9 +2644,9 @@ __metadata: "@babel/runtime": ^7.20.13 "@babel/traverse": ^7.20.12 "@babel/types": ^7.20.7 - "@lingui/conf": 5.4.0 - "@lingui/core": 5.4.0 - "@lingui/message-utils": 5.4.0 + "@lingui/conf": 5.4.1 + "@lingui/core": 5.4.1 + "@lingui/message-utils": 5.4.1 "@types/babel-plugin-macros": ^2.8.5 prettier: 2.8.3 unbuild: 2.0.0 @@ -2658,7 +2658,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/cli@5.4.0, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": +"@lingui/cli@5.4.1, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": version: 0.0.0-use.local resolution: "@lingui/cli@workspace:packages/cli" dependencies: @@ -2667,13 +2667,13 @@ __metadata: "@babel/parser": ^7.22.0 "@babel/runtime": ^7.21.0 "@babel/types": ^7.21.2 - "@lingui/babel-plugin-extract-messages": 5.4.0 - "@lingui/babel-plugin-lingui-macro": 5.4.0 - "@lingui/conf": 5.4.0 - "@lingui/core": 5.4.0 - "@lingui/format-po": 5.4.0 + "@lingui/babel-plugin-extract-messages": 5.4.1 + "@lingui/babel-plugin-lingui-macro": 5.4.1 + "@lingui/conf": 5.4.1 + "@lingui/core": 5.4.1 + "@lingui/format-po": 5.4.1 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.4.0 + "@lingui/message-utils": 5.4.1 "@types/convert-source-map": ^2.0.0 "@types/micromatch": ^4.0.1 "@types/normalize-path": ^3.0.0 @@ -2698,7 +2698,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/conf@5.4.0, @lingui/conf@workspace:packages/conf": +"@lingui/conf@5.4.1, @lingui/conf@workspace:packages/conf": version: 0.0.0-use.local resolution: "@lingui/conf@workspace:packages/conf" dependencies: @@ -2712,16 +2712,16 @@ __metadata: languageName: unknown linkType: soft -"@lingui/core@5.4.0, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": +"@lingui/core@5.4.1, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": version: 0.0.0-use.local resolution: "@lingui/core@workspace:packages/core" dependencies: "@babel/runtime": ^7.20.13 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.4.0 + "@lingui/message-utils": 5.4.1 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.0 + "@lingui/babel-plugin-lingui-macro": 5.4.1 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2754,9 +2754,9 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/extractor-vue@workspace:packages/extractor-vue" dependencies: - "@lingui/babel-plugin-extract-messages": 5.4.0 - "@lingui/cli": 5.4.0 - "@lingui/conf": 5.4.0 + "@lingui/babel-plugin-extract-messages": 5.4.1 + "@lingui/cli": 5.4.1 + "@lingui/conf": 5.4.1 "@vue/compiler-sfc": ^3.2.47 unbuild: 2.0.0 languageName: unknown @@ -2766,17 +2766,17 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-csv@workspace:packages/format-csv" dependencies: - "@lingui/conf": 5.4.0 + "@lingui/conf": 5.4.1 papaparse: ^5.4.0 unbuild: 2.0.0 languageName: unknown linkType: soft -"@lingui/format-json@5.4.0, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": +"@lingui/format-json@5.4.1, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": version: 0.0.0-use.local resolution: "@lingui/format-json@workspace:packages/format-json" dependencies: - "@lingui/conf": 5.4.0 + "@lingui/conf": 5.4.1 unbuild: ^2.0.0 languageName: unknown linkType: soft @@ -2785,10 +2785,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-po-gettext@workspace:packages/format-po-gettext" dependencies: - "@lingui/conf": 5.4.0 - "@lingui/format-po": 5.4.0 + "@lingui/conf": 5.4.1 + "@lingui/format-po": 5.4.1 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.4.0 + "@lingui/message-utils": 5.4.1 "@messageformat/parser": ^5.0.0 cldr-core: ^45.0.0 mockdate: ^3.0.5 @@ -2799,13 +2799,13 @@ __metadata: languageName: unknown linkType: soft -"@lingui/format-po@5.4.0, @lingui/format-po@workspace:packages/format-po": +"@lingui/format-po@5.4.1, @lingui/format-po@workspace:packages/format-po": version: 0.0.0-use.local resolution: "@lingui/format-po@workspace:packages/format-po" dependencies: - "@lingui/conf": 5.4.0 + "@lingui/conf": 5.4.1 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.4.0 + "@lingui/message-utils": 5.4.1 date-fns: ^3.6.0 mockdate: ^3.0.5 pofile: ^1.1.4 @@ -2824,9 +2824,9 @@ __metadata: resolution: "@lingui/loader@workspace:packages/loader" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.4.0 - "@lingui/conf": 5.4.0 - "@lingui/format-json": 5.4.0 + "@lingui/cli": 5.4.1 + "@lingui/conf": 5.4.1 + "@lingui/format-json": 5.4.1 unbuild: 2.0.0 webpack: ^5.76.1 peerDependencies: @@ -2838,10 +2838,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/macro@workspace:packages/macro" dependencies: - "@lingui/core": 5.4.0 - "@lingui/react": 5.4.0 + "@lingui/core": 5.4.1 + "@lingui/react": 5.4.1 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.0 + "@lingui/babel-plugin-lingui-macro": 5.4.1 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2851,7 +2851,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/message-utils@5.4.0, @lingui/message-utils@workspace:packages/message-utils": +"@lingui/message-utils@5.4.1, @lingui/message-utils@workspace:packages/message-utils": version: 0.0.0-use.local resolution: "@lingui/message-utils@workspace:packages/message-utils" dependencies: @@ -2877,9 +2877,9 @@ __metadata: resolution: "@lingui/metro-transformer@workspace:packages/metro-transformer" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.4.0 - "@lingui/conf": 5.4.0 - "@lingui/format-json": 5.4.0 + "@lingui/cli": 5.4.1 + "@lingui/conf": 5.4.1 + "@lingui/format-json": 5.4.1 memoize-one: ^6.0.0 rimraf: ^6.0.1 unbuild: 2.0.0 @@ -2898,12 +2898,12 @@ __metadata: languageName: unknown linkType: soft -"@lingui/react@5.4.0, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": +"@lingui/react@5.4.1, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": version: 0.0.0-use.local resolution: "@lingui/react@workspace:packages/react" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/core": 5.4.0 + "@lingui/core": 5.4.1 "@lingui/jest-mocks": "*" "@testing-library/react": ^14.0.0 "@types/react": ^18.2.13 @@ -2913,7 +2913,7 @@ __metadata: react-dom: ^18.2.0 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.0 + "@lingui/babel-plugin-lingui-macro": 5.4.1 babel-plugin-macros: 2 || 3 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -2938,8 +2938,8 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/vite-plugin@workspace:packages/vite-plugin" dependencies: - "@lingui/cli": 5.4.0 - "@lingui/conf": 5.4.0 + "@lingui/cli": 5.4.1 + "@lingui/conf": 5.4.1 "@lingui/core": "workspace:^" "@lingui/format-json": "workspace:^" unbuild: 2.0.0 From a09c973c914e3a1ab406ea6630691feef5b0c0f9 Mon Sep 17 00:00:00 2001 From: Jack Works <5390719+Jack-Works@users.noreply.github.com> Date: Mon, 18 Aug 2025 22:57:47 +0800 Subject: [PATCH 11/19] feat: add babel parser flag for import defer * as q from '...' (#2309) --- packages/cli/src/api/extractors/babel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/api/extractors/babel.ts b/packages/cli/src/api/extractors/babel.ts index 7eb5eef42..002ba45e6 100644 --- a/packages/cli/src/api/extractors/babel.ts +++ b/packages/cli/src/api/extractors/babel.ts @@ -164,6 +164,7 @@ export function getBabelParserOptions( "importAttributes", // stage3 "explicitResourceManagement", // stage3, "decoratorAutoAccessors", // stage3, + "deferredImportEvaluation", // stage3 ] if ([/\.ts$/, /\.mts$/, /\.cts$/, /\.tsx$/].some((r) => filename.match(r))) { From c4ddc61e002e3443c534088a74f46d8049ee906a Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Tue, 19 Aug 2025 14:52:39 +0200 Subject: [PATCH 12/19] tests: add tests for different line endings (#2315) --- .../test/__snapshots__/jsx-trans.test.ts.snap | 39 +++++++++++++++++++ .../test/jsx-trans.test.ts | 8 ++++ 2 files changed, 47 insertions(+) diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap index e88bbd4fc..4eafbfbd0 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap @@ -446,6 +446,45 @@ import { Trans as _Trans } from "@lingui/react"; `; +exports[`Produce the same ID regardless of CRLF, LF, and CR line endings 1`] = ` +import { Trans } from "@lingui/react/macro"; +hello; +hello; +hello; + +↓ ↓ ↓ ↓ ↓ ↓ + +import { Trans as _Trans } from "@lingui/react"; +<_Trans + { + /*i18n*/ + ...{ + id: "WfCysZ", + message: "hello", + } + } +/>; +<_Trans + { + /*i18n*/ + ...{ + id: "WfCysZ", + message: "hello", + } + } +/>; +<_Trans + { + /*i18n*/ + ...{ + id: "WfCysZ", + message: "hello", + } + } +/>; + +`; + exports[`Production - all props kept if extract: true 1`] = ` import { Trans } from "@lingui/react/macro"; diff --git a/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts b/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts index e1283cc36..0ba43223e 100644 --- a/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts +++ b/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts @@ -273,6 +273,14 @@ macroTester({ `, }, + { + name: "Produce the same ID regardless of CRLF, LF, and CR line endings", + code: + 'import { Trans } from "@lingui/react/macro";\n' + + "\nhello\n;\n" + + "\r\nhello\r\n;\n" + + "\rhello\r;\n", + }, { name: "Keep forced newlines", filename: "./jsx-keep-forced-newlines.js", From 86fbcd849b82d500f67fabd7c4f6abef7e5914f2 Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Fri, 12 Sep 2025 11:28:09 +0300 Subject: [PATCH 13/19] feat(cli): support multithreading in all cli commands (#2320) Co-authored-by: Zxilly --- CONTRIBUTING.md | 6 + packages/cli/package.json | 8 +- packages/cli/src/api/ProgramExit.ts | 7 + packages/cli/src/api/catalog.test.ts | 8 +- packages/cli/src/api/catalog.ts | 109 +++--- .../cli/src/api/catalog/extractFromFiles.ts | 154 +++++--- .../cli/src/api/catalog/getCatalogs.test.ts | 44 +-- packages/cli/src/api/catalog/getCatalogs.ts | 17 +- .../catalog/getTranslationsForCatalog.test.ts | 200 ++++++---- .../api/catalog/getTranslationsForCatalog.ts | 42 +- packages/cli/src/api/compile/compileLocale.ts | 142 +++++++ packages/cli/src/api/extractWorkerPool.ts | 12 + packages/cli/src/api/extractors/index.ts | 9 +- packages/cli/src/api/logger.ts | 3 + .../cli/src/api/resolveWorkersOptions.test.ts | 78 ++++ packages/cli/src/api/resolveWorkersOptions.ts | 23 ++ packages/cli/src/api/stats.test.ts | 2 +- packages/cli/src/api/stats.ts | 34 +- packages/cli/src/api/workerLogger.ts | 22 ++ .../extractFromBundleAndWrite.ts | 113 ++++++ .../workers/extractWorker.ts | 50 +++ packages/cli/src/lingui-compile.ts | 202 ++++------ .../cli/src/lingui-extract-experimental.ts | 178 +++++---- packages/cli/src/lingui-extract-template.ts | 64 +++- packages/cli/src/lingui-extract.ts | 74 +++- .../test/__snapshots__/compile.test.ts.snap | 20 +- packages/cli/src/test/compile.test.ts | 358 ++++++++++++++---- packages/cli/src/tests.ts | 3 - packages/cli/src/workers/compileWorker.ts | 63 +++ packages/cli/src/workers/extractWorker.ts | 38 ++ .../test/extract-po-format/lingui.config.ts | 13 + .../lingui.config.ts | 11 + .../lingui.config.ts | 14 + .../extractor-experimental-clean/package.json | 3 +- .../lingui.config.ts | 14 + .../package.json | 1 + .../extractor-experimental/lingui.config.ts | 14 + .../test/extractor-experimental/package.json | 3 +- packages/cli/test/index.test.ts | 307 ++++++++++----- packages/conf/package.json | 2 +- .../conf/src/__snapshots__/index.test.ts.snap | 1 + packages/conf/src/getConfig.ts | 15 +- packages/conf/src/index.test.ts | 4 +- packages/conf/src/makeConfig.ts | 8 +- packages/conf/src/types.ts | 1 + .../message-utils/src/generateMessageId.ts | 14 +- website/docs/ref/cli.md | 35 ++ yarn.lock | 226 ++++++++++- 48 files changed, 2053 insertions(+), 716 deletions(-) create mode 100644 packages/cli/src/api/ProgramExit.ts create mode 100644 packages/cli/src/api/compile/compileLocale.ts create mode 100644 packages/cli/src/api/extractWorkerPool.ts create mode 100644 packages/cli/src/api/logger.ts create mode 100644 packages/cli/src/api/resolveWorkersOptions.test.ts create mode 100644 packages/cli/src/api/resolveWorkersOptions.ts create mode 100644 packages/cli/src/api/workerLogger.ts create mode 100644 packages/cli/src/extract-experimental/extractFromBundleAndWrite.ts create mode 100644 packages/cli/src/extract-experimental/workers/extractWorker.ts create mode 100644 packages/cli/src/workers/compileWorker.ts create mode 100644 packages/cli/src/workers/extractWorker.ts create mode 100644 packages/cli/test/extract-po-format/lingui.config.ts create mode 100644 packages/cli/test/extract-template-po-format/lingui.config.ts create mode 100644 packages/cli/test/extractor-experimental-clean/lingui.config.ts create mode 100644 packages/cli/test/extractor-experimental-template/lingui.config.ts create mode 100644 packages/cli/test/extractor-experimental/lingui.config.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48f5e544a..ce1efd485 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,6 +117,12 @@ There are two documented ways to do this: first is a generic way described in th YARN_NPM_REGISTRY_SERVER=http://0.0.0.0:4873/ yarn up "@lingui/*" ``` + with PNPM: + + ```sh + pnpm -r up "@lingui/*" --latest --registry=http://0.0.0.0:4873/ + ``` + 5. After you make some changes, you need to run the same process. (Releasing + yarn upgrade) 6. When finished testing, restore default registry (only for NPM) diff --git a/packages/cli/package.json b/packages/cli/package.json index a4032a6b0..d69af4196 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -76,19 +76,23 @@ "esbuild": "^0.25.1", "glob": "^11.0.0", "micromatch": "^4.0.7", + "ms": "^2.1.3", "normalize-path": "^3.0.0", "ora": "^5.1.0", "picocolors": "^1.1.1", "pofile": "^1.1.4", "pseudolocale": "^2.0.0", - "source-map": "^0.8.0-beta.0" + "source-map": "^0.8.0-beta.0", + "threads": "^1.7.0" }, "devDependencies": { "@lingui/jest-mocks": "*", "@types/convert-source-map": "^2.0.0", "@types/micromatch": "^4.0.1", + "@types/ms": "^2.1.0", "@types/normalize-path": "^3.0.0", "mock-fs": "^5.2.0", - "mockdate": "^3.0.5" + "mockdate": "^3.0.5", + "ts-node": "^10.9.2" } } diff --git a/packages/cli/src/api/ProgramExit.ts b/packages/cli/src/api/ProgramExit.ts new file mode 100644 index 000000000..75b4e592e --- /dev/null +++ b/packages/cli/src/api/ProgramExit.ts @@ -0,0 +1,7 @@ +export class ProgramExit extends Error { + constructor() { + super() + + this.name = "ProgramExit" + } +} diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts index 62b952a22..c8cc7aceb 100644 --- a/packages/cli/src/api/catalog.test.ts +++ b/packages/cli/src/api/catalog.test.ts @@ -4,7 +4,7 @@ import mockFs from "mock-fs" import { mockConsole } from "@lingui/jest-mocks" import { LinguiConfig, makeConfig } from "@lingui/conf" -import { Catalog, cleanObsolete, order } from "./catalog" +import { Catalog, cleanObsolete, order, writeCompiled } from "./catalog" import { createCompiledCatalog } from "./compile" import { @@ -688,9 +688,9 @@ describe("writeCompiled", () => { async ({ namespace, extension }) => { const { source } = createCompiledCatalog("en", {}, { namespace }) // Test that the file extension of the compiled catalog is `.mjs` - expect(await catalog.writeCompiled("en", source, namespace)).toMatch( - extension - ) + expect( + await writeCompiled(catalog.path, "en", source, namespace) + ).toMatch(extension) } ) }) diff --git a/packages/cli/src/api/catalog.ts b/packages/cli/src/api/catalog.ts index 931684238..d9a20ce61 100644 --- a/packages/cli/src/api/catalog.ts +++ b/packages/cli/src/api/catalog.ts @@ -6,16 +6,16 @@ import normalize from "normalize-path" import { LinguiConfigNormalized, OrderBy } from "@lingui/conf" import { FormatterWrapper } from "./formats" -import { CliExtractOptions } from "../lingui-extract" -import { CliExtractTemplateOptions } from "../lingui-extract-template" import { CompiledCatalogNamespace } from "./compile" import { getTranslationsForCatalog, GetTranslationsOptions, - TranslationMissingEvent, } from "./catalog/getTranslationsForCatalog" import { mergeCatalog } from "./catalog/mergeCatalog" -import { extractFromFiles } from "./catalog/extractFromFiles" +import { + extractFromFiles, + extractFromFilesWithWorkerPool, +} from "./catalog/extractFromFiles" import { isDirectory, makePathRegexSafe, @@ -24,16 +24,24 @@ import { writeFile, } from "./utils" import { AllCatalogsType, CatalogType, ExtractedCatalogType } from "./types" +import { ExtractWorkerPool } from "./extractWorkerPool" const LOCALE = "{locale}" const LOCALE_SUFFIX_RE = /\{locale\}.*$/ -export type MakeOptions = CliExtractOptions & { +export type MakeOptions = { + files?: string[] + clean: boolean + overwrite: boolean + locale: string[] orderBy?: OrderBy + workerPool?: ExtractWorkerPool } -export type MakeTemplateOptions = CliExtractTemplateOptions & { +export type MakeTemplateOptions = { + files?: string[] orderBy?: OrderBy + workerPool?: ExtractWorkerPool } export type MergeOptions = { @@ -81,7 +89,7 @@ export class Catalog { async make(options: MakeOptions): Promise { const [nextCatalog, prevCatalogs] = await Promise.all([ - this.collect({ files: options.files }), + this.collect({ files: options.files, workerPool: options.workerPool }), this.readAll(), ]) @@ -116,7 +124,10 @@ export class Catalog { async makeTemplate( options: MakeTemplateOptions ): Promise { - const catalog = await this.collect({ files: options.files }) + const catalog = await this.collect({ + files: options.files, + workerPool: options.workerPool, + }) if (!catalog) return false const sorted = order(options.orderBy, catalog as CatalogType) @@ -128,7 +139,7 @@ export class Catalog { * Collect messages from source paths. Return a raw message catalog as JSON. */ async collect( - options: { files?: string[] } = {} + options: { files?: string[]; workerPool?: ExtractWorkerPool } = {} ): Promise { let paths = this.sourcePaths if (options.files) { @@ -140,6 +151,14 @@ export class Catalog { paths = paths.filter((path: string) => regex.test(normalize(path))) } + if (options.workerPool) { + return await extractFromFilesWithWorkerPool( + options.workerPool, + paths, + this.config + ) + } + return await extractFromFiles(paths, this.config) } @@ -181,23 +200,8 @@ export class Catalog { ) } - async getTranslations( - locale: string, - options: Omit - ) { - const missing: TranslationMissingEvent[] = [] - - const messages = await getTranslationsForCatalog(this, locale, { - ...options, - onMissing: (event) => { - missing.push(event) - }, - }) - - return { - missing, - messages, - } + async getTranslations(locale: string, options: GetTranslationsOptions) { + return await getTranslationsForCatalog(this, locale, options) } async write( @@ -217,40 +221,15 @@ export class Catalog { await this.format.write(filename, messages, undefined) } - async writeCompiled( - locale: string, - compiledCatalog: string, - namespace?: CompiledCatalogNamespace - ) { - let ext: string - switch (namespace) { - case "es": - ext = "mjs" - break - case "ts": - case "json": - ext = namespace - break - default: - ext = "js" - } - - const filename = `${replacePlaceholders(this.path, { locale })}.${ext}` - await writeFile(filename, compiledCatalog) - return filename - } - async read(locale: string): Promise { return await this.format.read(this.getFilename(locale), locale) } - async readAll(): Promise { + async readAll(locales: string[] = this.locales): Promise { const res: AllCatalogsType = {} await Promise.all( - this.locales.map( - async (locale) => (res[locale] = await this.read(locale)) - ) + locales.map(async (locale) => (res[locale] = await this.read(locale))) ) // statement above will save locales in object in undetermined order @@ -364,6 +343,30 @@ function orderByOrigin(messages: T): T { }, {} as T) } +export async function writeCompiled( + path: string, + locale: string, + compiledCatalog: string, + namespace?: CompiledCatalogNamespace +) { + let ext: string + switch (namespace) { + case "es": + ext = "mjs" + break + case "ts": + case "json": + ext = namespace + break + default: + ext = "js" + } + + const filename = `${replacePlaceholders(path, { locale })}.${ext}` + await writeFile(filename, compiledCatalog) + return filename +} + export function orderByMessage(messages: T): T { // hardcoded en-US locale to have consistent sorting // @see https://github.com/lingui/js-lingui/pull/1808 diff --git a/packages/cli/src/api/catalog/extractFromFiles.ts b/packages/cli/src/api/catalog/extractFromFiles.ts index a0976b12a..b636c0053 100644 --- a/packages/cli/src/api/catalog/extractFromFiles.ts +++ b/packages/cli/src/api/catalog/extractFromFiles.ts @@ -1,13 +1,10 @@ -import type { - ExtractedMessage, - ExtractorType, - LinguiConfigNormalized, -} from "@lingui/conf" +import type { ExtractedMessage, LinguiConfigNormalized } from "@lingui/conf" import pico from "picocolors" import path from "path" import extract from "../extractors" import { ExtractedCatalogType, MessageOrigin } from "../types" import { prettyOrigin } from "../utils" +import { ExtractWorkerPool } from "../extractWorkerPool" function mergePlaceholders( prev: Record, @@ -15,6 +12,9 @@ function mergePlaceholders( ) { const res = { ...prev } + // Handle case where next is null or undefined + if (!next) return res + Object.entries(next).forEach(([key, value]) => { if (!res[key]) { res[key] = [] @@ -38,62 +38,98 @@ export async function extractFromFiles( let catalogSuccess = true + for (const filename of paths) { + const fileSuccess = await extract( + filename, + (next: ExtractedMessage) => { + mergeExtractedMessage(next, messages, config) + }, + config + ) + catalogSuccess &&= fileSuccess + } + + if (!catalogSuccess) return undefined + + return messages +} + +export function mergeExtractedMessage( + next: ExtractedMessage, + messages: ExtractedCatalogType, + config: LinguiConfigNormalized +) { + if (!messages[next.id]) { + messages[next.id] = { + message: next.message, + context: next.context, + placeholders: {}, + comments: [], + origin: [], + } + } + + const prev = messages[next.id] + + // there might be a case when filename was not mapped from sourcemaps + const filename = next.origin[0] + ? path.relative(config.rootDir, next.origin[0]).replace(/\\/g, "/") + : "" + + const origin: MessageOrigin = [filename, next.origin[1]] + + if (prev.message && next.message && prev.message !== next.message) { + throw new Error( + `Encountered different default translations for message ${pico.yellow( + next.id + )}` + + `\n${pico.yellow(prettyOrigin(prev.origin))} ${prev.message}` + + `\n${pico.yellow(prettyOrigin([origin]))} ${next.message}` + ) + } + + messages[next.id] = { + ...prev, + message: prev.message ?? next.message, + comments: next.comment + ? [...prev.comments, next.comment].sort() + : prev.comments, + origin: ( + [...prev.origin, [filename, next.origin[1]]] as MessageOrigin[] + ).sort((a, b) => a[0].localeCompare(b[0])), + placeholders: mergePlaceholders(prev.placeholders, next.placeholders), + } +} + +export async function extractFromFilesWithWorkerPool( + workerPool: ExtractWorkerPool, + paths: string[], + config: LinguiConfigNormalized +): Promise { + const messages: ExtractedCatalogType = {} + + let catalogSuccess = true + + if (!config.resolvedConfigPath) { + throw new Error( + "Multithreading is only supported when lingui config loaded from file system, not passed by API" + ) + } + await Promise.all( - paths.map(async (filename) => { - const fileSuccess = await extract( - filename, - (next: ExtractedMessage) => { - if (!messages[next.id]) { - messages[next.id] = { - message: next.message, - context: next.context, - placeholders: {}, - comments: [], - origin: [], - } - } - - const prev = messages[next.id] - - // there might be a case when filename was not mapped from sourcemaps - const filename = next.origin[0] - ? path.relative(config.rootDir, next.origin[0]).replace(/\\/g, "/") - : "" - - const origin: MessageOrigin = [filename, next.origin[1]] - - if (prev.message && next.message && prev.message !== next.message) { - throw new Error( - `Encountered different default translations for message ${pico.yellow( - next.id - )}` + - `\n${pico.yellow(prettyOrigin(prev.origin))} ${prev.message}` + - `\n${pico.yellow(prettyOrigin([origin]))} ${next.message}` - ) - } - - messages[next.id] = { - ...prev, - message: prev.message ?? next.message, - comments: next.comment - ? [...prev.comments, next.comment].sort() - : prev.comments, - origin: ( - [...prev.origin, [filename, next.origin[1]]] as MessageOrigin[] - ).sort((a, b) => a[0].localeCompare(b[0])), - placeholders: mergePlaceholders( - prev.placeholders, - next.placeholders - ), - } - }, - config, - { - extractors: config.extractors as ExtractorType[], + paths.map((filename) => + workerPool.queue(async (worker) => { + const result = await worker(filename, config.resolvedConfigPath) + + if (!result.success) { + catalogSuccess = false + } else { + result.messages.forEach((message) => { + mergeExtractedMessage(message, messages, config) + }) } - ) - catalogSuccess &&= fileSuccess - }) + }) + ) ) if (!catalogSuccess) return undefined diff --git a/packages/cli/src/api/catalog/getCatalogs.test.ts b/packages/cli/src/api/catalog/getCatalogs.test.ts index c03db17fe..6ead7b367 100644 --- a/packages/cli/src/api/catalog/getCatalogs.test.ts +++ b/packages/cli/src/api/catalog/getCatalogs.test.ts @@ -1,7 +1,7 @@ import mockFs from "mock-fs" import { getCatalogForFile, - getCatalogForMerge, + getMergedCatalogPath, getCatalogs, } from "./getCatalogs" import { Catalog } from "../catalog" @@ -262,13 +262,7 @@ function cleanCatalog(catalog: Catalog) { delete catalog.format return catalog } -describe("getCatalogForMerge", () => { - let format: FormatterWrapper - - beforeAll(async () => { - format = await getFormat("po", {}, "en") - }) - +describe("getMergedCatalogPath", () => { afterEach(() => { mockFs.restore() }) @@ -277,39 +271,15 @@ describe("getCatalogForMerge", () => { const config = mockConfig({ catalogsMergePath: "locales/{locale}", }) - expect(cleanCatalog(await getCatalogForMerge(config))).toEqual( - cleanCatalog( - new Catalog( - { - name: null, - path: "locales/{locale}", - include: [], - exclude: [], - format, - }, - config - ) - ) - ) + expect(await getMergedCatalogPath(config)).toEqual("locales/{locale}") }) it("should return catalog with custom name for merged messages", async () => { const config = mockConfig({ catalogsMergePath: "locales/{locale}/my/dir", }) - expect(cleanCatalog(await getCatalogForMerge(config))).toStrictEqual( - cleanCatalog( - new Catalog( - { - name: "dir", - path: "locales/{locale}/my/dir", - include: [], - exclude: [], - format, - }, - config - ) - ) + expect(await getMergedCatalogPath(config)).toStrictEqual( + "locales/{locale}/my/dir" ) }) @@ -319,7 +289,7 @@ describe("getCatalogForMerge", () => { }) expect.assertions(1) try { - await getCatalogForMerge(config) + await getMergedCatalogPath(config) } catch (e) { expect((e as Error).message).toBe( 'Remove trailing slash from "locales/{locale}/bad/path/". Catalog path isn\'t a directory, but translation file without extension. For example, catalog path "locales/{locale}/bad/path" results in translation file "locales/en/bad/path.po".' @@ -333,7 +303,7 @@ describe("getCatalogForMerge", () => { }) expect.assertions(1) try { - await getCatalogForMerge(config) + await getMergedCatalogPath(config) } catch (e) { expect((e as Error).message).toBe( "Invalid catalog path: {locale} variable is missing" diff --git a/packages/cli/src/api/catalog/getCatalogs.ts b/packages/cli/src/api/catalog/getCatalogs.ts index ce1accb82..e582d86b3 100644 --- a/packages/cli/src/api/catalog/getCatalogs.ts +++ b/packages/cli/src/api/catalog/getCatalogs.ts @@ -106,7 +106,7 @@ const ensureArray = (value: Array | T | null | undefined): Array => { /** * Create catalog for merged messages. */ -export async function getCatalogForMerge(config: LinguiConfigNormalized) { +export async function getMergedCatalogPath(config: LinguiConfigNormalized) { const format = await getFormat( config.format, config.formatOptions, @@ -114,16 +114,7 @@ export async function getCatalogForMerge(config: LinguiConfigNormalized) { ) validateCatalogPath(config.catalogsMergePath, format.getCatalogExtension()) - return new Catalog( - { - name: getCatalogName(config.catalogsMergePath), - path: normalizeRelativePath(config.catalogsMergePath), - include: [], - exclude: [], - format, - }, - config - ) + return normalizeRelativePath(config.catalogsMergePath) } export function getCatalogForFile(file: string, catalogs: Catalog[]) { @@ -150,6 +141,10 @@ export function getCatalogForFile(file: string, catalogs: Catalog[]) { * Validate that `catalogPath` doesn't end with trailing slash */ function validateCatalogPath(path: string, extension: string) { + if (!path.includes(LOCALE_PH)) { + throw new Error(`Invalid catalog path: ${LOCALE_PH} variable is missing`) + } + if (!path.endsWith(PATHSEP)) { return } diff --git a/packages/cli/src/api/catalog/getTranslationsForCatalog.test.ts b/packages/cli/src/api/catalog/getTranslationsForCatalog.test.ts index 5dac3ac18..76733eb21 100644 --- a/packages/cli/src/api/catalog/getTranslationsForCatalog.test.ts +++ b/packages/cli/src/api/catalog/getTranslationsForCatalog.test.ts @@ -51,17 +51,19 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(missingSpy).not.toBeCalled() - expect(actual).toStrictEqual({ - hashid1: "pl: translation: Lorem", - }) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: pl: translation: Lorem, + }, + missing: [], + } + `) }) it("Should fallback to fallbackLocales.default", async () => { @@ -77,21 +79,22 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "ru", { sourceLocale: "en", fallbackLocales: { default: "pl", }, - onMissing: missingSpy, }) - expect(missingSpy).not.toBeCalled() - - expect(actual).toStrictEqual({ - hashid1: "ru: translation: Lorem", - hashid2: "pl: translation: Ipsum", - }) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: ru: translation: Lorem, + hashid2: pl: translation: Ipsum, + }, + missing: [], + } + `) }) it("Should fallback to single fallbackLocales", async () => { @@ -107,21 +110,22 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "ru", { sourceLocale: "en", fallbackLocales: { ru: "pl", }, - onMissing: missingSpy, }) - expect(missingSpy).not.toBeCalled() - - expect(actual).toStrictEqual({ - hashid1: "ru: translation: Lorem", - hashid2: "pl: translation: Ipsum", - }) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: ru: translation: Lorem, + hashid2: pl: translation: Ipsum, + }, + missing: [], + } + `) }) it("Should fallback to multiple fallbacks and then to default", async () => { @@ -153,26 +157,25 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "ru", { sourceLocale: "en", fallbackLocales: { ru: ["de", "es"], default: "pl", }, - onMissing: missingSpy, }) - expect(missingSpy).not.toBeCalled() expect(actual).toStrictEqual({ - hashid1: "ru: translation: Lorem", - // this fallback to de -> es - hashid2: "es: translation: Ipsum", - // this fallback to de -> es -> default - - hashid3: "pl: translation: Dolor", - // this fallback to de -> es - hashid4: "es: translation: Sit", + messages: { + hashid1: "ru: translation: Lorem", + // this fallback to de -> es + hashid2: "es: translation: Ipsum", + // this fallback to de -> es -> default + hashid3: "pl: translation: Dolor", + // this fallback to de -> es + hashid4: "es: translation: Sit", + }, + missing: [], }) }) @@ -188,18 +191,20 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "en", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(missingSpy).not.toBeCalled() - expect(actual).toStrictEqual({ - hashid1: "Lorem", - hashid2: "en: translation: Ipsum", - }) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: Lorem, + hashid2: en: translation: Ipsum, + }, + missing: [], + } + `) } ) @@ -215,20 +220,24 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(missingSpy).toBeCalledWith({ - id: "hashid1", - source: "Lorem", - }) - expect(actual).toStrictEqual({ - hashid1: "Lorem", - }) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: Lorem, + }, + missing: [ + { + id: hashid1, + source: Lorem, + }, + ], + } + `) }) it("Should add keys from source locale", async () => { @@ -246,20 +255,31 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(actual).toStrictEqual({ - hashid1: "pl: translation: Lorem", - hashid2: "pl: translation: Ipsum", - hashid3: "Dolor", - hashid4: "Sit", - }) - expect(missingSpy).toBeCalledTimes(2) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: pl: translation: Lorem, + hashid2: pl: translation: Ipsum, + hashid3: Dolor, + hashid4: Sit, + }, + missing: [ + { + id: hashid3, + source: Dolor, + }, + { + id: hashid4, + source: Sit, + }, + ], + } + `) }) it("Should not fail if sourceLocale is not set", async () => { @@ -277,18 +297,20 @@ describe("getTranslationsForCatalog", () => { ]) }) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: null, fallbackLocales: {}, - onMissing: missingSpy, }) - expect(actual).toStrictEqual({ - hashid1: "pl: translation: Lorem", - hashid2: "pl: translation: Ipsum", - }) - expect(missingSpy).toBeCalledTimes(0) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: pl: translation: Lorem, + hashid2: pl: translation: Ipsum, + }, + missing: [], + } + `) }) it("Should add keys from template", async () => { @@ -305,20 +327,31 @@ describe("getTranslationsForCatalog", () => { message("hashid4", "Sit", true) ]).tpl) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(actual).toStrictEqual({ - hashid1: "pl: translation: Lorem", - hashid2: "pl: translation: Ipsum", - hashid3: "Dolor", - hashid4: "Sit", - }) - expect(missingSpy).toBeCalledTimes(2) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: pl: translation: Lorem, + hashid2: pl: translation: Ipsum, + hashid3: Dolor, + hashid4: Sit, + }, + missing: [ + { + id: hashid3, + source: Dolor, + }, + { + id: hashid4, + source: Sit, + }, + ], + } + `) }) it("Should not fail if catalog for requested locale does not exists", async () => { @@ -327,16 +360,23 @@ describe("getTranslationsForCatalog", () => { message("hashid1", "Lorem", true), ]).tpl) - const missingSpy = jest.fn() const actual = await getTranslationsForCatalog(catalogStub, "pl", { sourceLocale: "en", fallbackLocales: {}, - onMissing: missingSpy, }) - expect(actual).toStrictEqual({ - hashid1: "Lorem", - }) - expect(missingSpy).toBeCalledTimes(1) + expect(actual).toMatchInlineSnapshot(` + { + messages: { + hashid1: Lorem, + }, + missing: [ + { + id: hashid1, + source: Lorem, + }, + ], + } + `) }) }) diff --git a/packages/cli/src/api/catalog/getTranslationsForCatalog.ts b/packages/cli/src/api/catalog/getTranslationsForCatalog.ts index 65a3698cd..79f92e8d3 100644 --- a/packages/cli/src/api/catalog/getTranslationsForCatalog.ts +++ b/packages/cli/src/api/catalog/getTranslationsForCatalog.ts @@ -7,10 +7,10 @@ export type TranslationMissingEvent = { source: string id: string } + export type GetTranslationsOptions = { sourceLocale: string fallbackLocales: FallbackLocales - onMissing?: (message: TranslationMissingEvent) => void } export async function getTranslationsForCatalog( @@ -18,8 +18,14 @@ export async function getTranslationsForCatalog( locale: string, options: GetTranslationsOptions ) { + const locales = new Set([ + locale, + options.sourceLocale, + ...getFallbackListForLocale(options.fallbackLocales, locale), + ]) + const [catalogs, template] = await Promise.all([ - catalog.readAll(), + catalog.readAll(Array.from(locales)), catalog.readTemplate(), ]) @@ -27,10 +33,29 @@ export async function getTranslationsForCatalog( const input = { ...template, ...sourceLocaleCatalog, ...catalogs[locale] } - return Object.keys(input).reduce<{ [id: string]: string }>((acc, key) => { - acc[key] = getTranslation(catalogs, input[key], locale, key, options) - return acc - }, {}) + const missing: TranslationMissingEvent[] = [] + + const messages = Object.keys(input).reduce<{ [id: string]: string }>( + (acc, key) => { + acc[key] = getTranslation( + catalogs, + input[key], + locale, + key, + (event) => { + missing.push(event) + }, + options + ) + return acc + }, + {} + ) + + return { + missing, + messages, + } } function sourceLocaleFallback(catalog: CatalogType, key: string) { @@ -46,9 +71,10 @@ function getTranslation( msg: MessageType, locale: string, key: string, + onMissing: (message: TranslationMissingEvent) => void, options: GetTranslationsOptions ) { - const { fallbackLocales, sourceLocale, onMissing } = options + const { fallbackLocales, sourceLocale } = options const getTranslation = (_locale: string) => { const localeCatalog = catalogs[_locale] @@ -83,7 +109,7 @@ function getTranslation( sourceLocaleFallback(catalogs[sourceLocale], key)) if (!translation) { - onMissing?.({ + onMissing({ id: key, source: msg.message || sourceLocaleFallback(catalogs[sourceLocale], key), }) diff --git a/packages/cli/src/api/compile/compileLocale.ts b/packages/cli/src/api/compile/compileLocale.ts new file mode 100644 index 000000000..0723ecab5 --- /dev/null +++ b/packages/cli/src/api/compile/compileLocale.ts @@ -0,0 +1,142 @@ +import { Catalog, writeCompiled } from "../catalog" +import { LinguiConfigNormalized } from "@lingui/conf" +import pico from "picocolors" +import { getMergedCatalogPath } from "../catalog/getCatalogs" +import { CliCompileOptions } from "../../lingui-compile" +import { ProgramExit } from "../ProgramExit" +import { createCompiledCatalog } from "../compile" + +import normalizePath from "normalize-path" +import nodepath from "path" +import { createCompilationErrorMessage } from "../messages" +import { getTranslationsForCatalog } from "../catalog/getTranslationsForCatalog" +import { Logger } from "../logger" + +export async function compileLocale( + catalogs: Catalog[], + locale: string, + options: CliCompileOptions, + config: LinguiConfigNormalized, + doMerge: boolean, + logger: Logger +) { + let mergedCatalogs: Record = {} + + for (const catalog of catalogs) { + const { messages, missing: missingMessages } = + await getTranslationsForCatalog(catalog, locale, { + fallbackLocales: config.fallbackLocales, + sourceLocale: config.sourceLocale, + }) + + if ( + !options.allowEmpty && + locale !== config.pseudoLocale && + missingMessages.length > 0 + ) { + logger.error( + pico.red( + `Error: Failed to compile catalog for locale ${pico.bold(locale)}!` + ) + ) + + if (options.verbose) { + logger.error(pico.red("Missing translations:")) + missingMessages.forEach((missing) => { + const source = + missing.source || missing.source === missing.id + ? `: (${missing.source})` + : "" + + logger.error(`${missing.id}${source}`) + }) + } else { + logger.error( + pico.red(`Missing ${missingMessages.length} translation(s)`) + ) + } + logger.error() + throw new ProgramExit() + } + + if (doMerge) { + mergedCatalogs = { ...mergedCatalogs, ...messages } + } else { + if ( + !(await compileAndWrite( + locale, + config, + options, + catalog.path, + messages, + logger + )) + ) { + throw new ProgramExit() + } + } + } + + if (doMerge) { + const result = await compileAndWrite( + locale, + config, + options, + await getMergedCatalogPath(config), + mergedCatalogs, + logger + ) + + if (!result) { + throw new ProgramExit() + } + } +} + +async function compileAndWrite( + locale: string, + config: LinguiConfigNormalized, + options: CliCompileOptions, + writePath: string, + messages: Record, + logger: Logger +): Promise { + const namespace = options.typescript + ? "ts" + : options.namespace || config.compileNamespace + const { source: compiledCatalog, errors } = createCompiledCatalog( + locale, + messages, + { + strict: false, + namespace, + pseudoLocale: config.pseudoLocale, + compilerBabelOptions: config.compilerBabelOptions, + } + ) + + if (errors.length) { + let message = createCompilationErrorMessage(locale, errors) + + if (options.failOnCompileError) { + message += `These errors fail command execution because \`--strict\` option passed` + logger.error(pico.red(message)) + return false + } else { + message += `You can fail command execution on these errors by passing \`--strict\` option` + logger.error(pico.red(message)) + } + } + + let compiledPath = await writeCompiled( + writePath, + locale, + compiledCatalog, + namespace + ) + + compiledPath = normalizePath(nodepath.relative(config.rootDir, compiledPath)) + + options.verbose && logger.error(pico.green(`${locale} ⇒ ${compiledPath}`)) + return true +} diff --git a/packages/cli/src/api/extractWorkerPool.ts b/packages/cli/src/api/extractWorkerPool.ts new file mode 100644 index 000000000..0f3557a66 --- /dev/null +++ b/packages/cli/src/api/extractWorkerPool.ts @@ -0,0 +1,12 @@ +import { Pool, spawn, Worker } from "threads" +import type { ExtractWorkerFunction } from "../workers/extractWorker" + +export type ExtractWorkerPool = ReturnType + +/** @internal */ +export function createExtractWorkerPool(opts: { poolSize: number }) { + return Pool( + () => spawn(new Worker("../workers/extractWorker")), + { size: opts.poolSize } + ) +} diff --git a/packages/cli/src/api/extractors/index.ts b/packages/cli/src/api/extractors/index.ts index 7e1efbb62..f01249b72 100644 --- a/packages/cli/src/api/extractors/index.ts +++ b/packages/cli/src/api/extractors/index.ts @@ -8,17 +8,12 @@ import { const DEFAULT_EXTRACTORS: ExtractorType[] = [babel] -type ExtractOptions = { - extractors?: ExtractorType[] -} - export default async function extract( filename: string, onMessageExtracted: (msg: ExtractedMessage) => void, - linguiConfig: LinguiConfigNormalized, - options: ExtractOptions + linguiConfig: LinguiConfigNormalized ): Promise { - const extractorsToExtract = options.extractors ?? DEFAULT_EXTRACTORS + const extractorsToExtract = linguiConfig.extractors ?? DEFAULT_EXTRACTORS for (const ext of extractorsToExtract) { if (!ext.match(filename)) continue diff --git a/packages/cli/src/api/logger.ts b/packages/cli/src/api/logger.ts new file mode 100644 index 000000000..1b76b8829 --- /dev/null +++ b/packages/cli/src/api/logger.ts @@ -0,0 +1,3 @@ +export type Logger = { + error: (msg?: string) => void +} diff --git a/packages/cli/src/api/resolveWorkersOptions.test.ts b/packages/cli/src/api/resolveWorkersOptions.test.ts new file mode 100644 index 000000000..aa16a3f2e --- /dev/null +++ b/packages/cli/src/api/resolveWorkersOptions.test.ts @@ -0,0 +1,78 @@ +import type { Mock } from "jest-mock" + +jest.mock("node:os", () => ({ availableParallelism: jest.fn() })) + +import os from "node:os" +import { resolveWorkersOptions } from "./resolveWorkersOptions" + +const mockAvail = os.availableParallelism as unknown as Mock< + typeof os.availableParallelism +> +const setCores = (n: number) => mockAvail.mockReturnValue(n) + +describe("resolveWorkerOptions", () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + test("support arg as string", () => { + setCores(8) + expect(resolveWorkersOptions({ workers: "25" })).toEqual({ + poolSize: 25, + }) + }) + + test("workers=1 forces single-threaded", () => { + setCores(8) + expect(resolveWorkersOptions({ workers: 1 })).toEqual({ + poolSize: 0, + }) + }) + + test("workers < 1 forces single-threaded", () => { + setCores(8) + expect(resolveWorkersOptions({ workers: -1 })).toEqual({ + poolSize: 0, + }) + }) + + test("cores=1 → single-threaded even without flags", () => { + setCores(1) + expect(resolveWorkersOptions({})).toEqual({ poolSize: 0 }) + }) + + test("default on tiny machine (cores=2) uses all cores", () => { + setCores(2) + expect(resolveWorkersOptions({})).toEqual({ + poolSize: 2, + }) + }) + + test("default on small machine (cores=3) uses cores-1", () => { + setCores(3) + expect(resolveWorkersOptions({})).toEqual({ + poolSize: 2, + }) + }) + + test("default caps to 8 on big machines (cores=32)", () => { + setCores(32) + expect(resolveWorkersOptions({})).toEqual({ + poolSize: 8, + }) + }) + + test("default on mid machine (cores=4) → 3 threads", () => { + setCores(4) + expect(resolveWorkersOptions({})).toEqual({ + poolSize: 3, + }) + }) + + test("explicit workers value wins over cores (even if > cap)", () => { + setCores(4) + expect(resolveWorkersOptions({ workers: 5 })).toEqual({ + poolSize: 5, + }) + }) +}) diff --git a/packages/cli/src/api/resolveWorkersOptions.ts b/packages/cli/src/api/resolveWorkersOptions.ts new file mode 100644 index 000000000..0ff429ff3 --- /dev/null +++ b/packages/cli/src/api/resolveWorkersOptions.ts @@ -0,0 +1,23 @@ +import os from "node:os" + +export type WorkersOptions = { poolSize: number } + +export function resolveWorkersOptions(opts: { + workers?: number | string +}): WorkersOptions { + const cores = os.availableParallelism() + + if (Number(opts.workers) <= 1 || cores === 1) { + return { poolSize: 0 } + } + + if (!opts.workers) { + if (cores <= 2) { + return { poolSize: cores } // on tiny machines, use all + } + // on big machines cap to 8, to avoid trashing + return { poolSize: Math.min(cores - 1, 8) } + } + + return { poolSize: Number(opts.workers) } +} diff --git a/packages/cli/src/api/stats.test.ts b/packages/cli/src/api/stats.test.ts index 08298a470..4ea83ba6e 100644 --- a/packages/cli/src/api/stats.test.ts +++ b/packages/cli/src/api/stats.test.ts @@ -26,8 +26,8 @@ describe("PrintStats", () => { const { options, ...table } = printStats(config, catalogs) expect(options.head).toEqual(["Language", "Total count", "Missing"]) expect(Object.values(table)).toStrictEqual([ - { en: [2, 0] }, { cs: [2, 2] }, + { en: [2, 0] }, 2, ]) }) diff --git a/packages/cli/src/api/stats.ts b/packages/cli/src/api/stats.ts index e433aa3a3..3723a0af0 100644 --- a/packages/cli/src/api/stats.ts +++ b/packages/cli/src/api/stats.ts @@ -30,20 +30,26 @@ export function printStats( }, }) - Object.keys(catalogs).forEach((locale) => { - if (locale === config.pseudoLocale) return // skip pseudo locale - - const catalog = catalogs[locale] - // catalog is null if no catalog exists on disk and the locale - // was not extracted due to a `--locale` filter - const [all, translated] = catalog ? getStats(catalog) : ["-", "-"] - - if (config.sourceLocale === locale) { - table.push({ [`${pico.bold(locale)} (source)`]: [all, "-"] }) - } else { - table.push({ [locale]: [all, translated] }) - } - }) + Object.keys(catalogs) + .sort((a, b) => { + if (a === config.sourceLocale && b !== config.sourceLocale) return -1 + if (b === config.sourceLocale && a !== config.sourceLocale) return 1 + return a.localeCompare(b) + }) + .forEach((locale) => { + if (locale === config.pseudoLocale) return // skip pseudo locale + + const catalog = catalogs[locale] + // catalog is null if no catalog exists on disk and the locale + // was not extracted due to a `--locale` filter + const [all, translated] = catalog ? getStats(catalog) : ["-", "-"] + + if (config.sourceLocale === locale) { + table.push({ [`${pico.bold(locale)} (source)`]: [all, "-"] }) + } else { + table.push({ [locale]: [all, translated] }) + } + }) return table } diff --git a/packages/cli/src/api/workerLogger.ts b/packages/cli/src/api/workerLogger.ts new file mode 100644 index 000000000..7c8ec6e49 --- /dev/null +++ b/packages/cli/src/api/workerLogger.ts @@ -0,0 +1,22 @@ +import { Logger } from "./logger" + +export type SerializedLogs = { + errors: string +} + +export class WorkerLogger implements Logger { + private errors: string[] = [] + + error(msg?: string): void { + this.errors.push(msg) + } + + flush(): SerializedLogs { + const errors = this.errors.join("\n") + this.errors = [] + + return { + errors, + } + } +} diff --git a/packages/cli/src/extract-experimental/extractFromBundleAndWrite.ts b/packages/cli/src/extract-experimental/extractFromBundleAndWrite.ts new file mode 100644 index 000000000..19935e0f4 --- /dev/null +++ b/packages/cli/src/extract-experimental/extractFromBundleAndWrite.ts @@ -0,0 +1,113 @@ +import { + ExtractedCatalogType, + ExtractedMessage, + LinguiConfigNormalized, +} from "@lingui/conf" +import { FormatterWrapper } from "../api/formats" +import { mergeExtractedMessage } from "../api/catalog/extractFromFiles" +import { writeCatalogs, writeTemplate } from "./writeCatalogs" +import fs from "fs/promises" +import { + extractFromFileWithBabel, + getBabelParserOptions, +} from "../api/extractors/babel" + +async function extractFromBundle( + filename: string, + linguiConfig: LinguiConfigNormalized +) { + const messages: ExtractedCatalogType = {} + + let success: boolean + + try { + const file = await fs.readFile(filename) + + const parserOptions = linguiConfig.extractorParserOptions + + await extractFromFileWithBabel( + filename, + file.toString(), + (msg: ExtractedMessage) => { + mergeExtractedMessage(msg, messages, linguiConfig) + }, + { + linguiConfig, + }, + { + plugins: getBabelParserOptions(filename, parserOptions), + }, + true + ) + + success = true + } catch (e) { + console.error(`Cannot process file ${filename} ${(e as Error).message}`) + console.error((e as Error).stack) + success = false + } + + return { success, messages } +} + +export async function extractFromBundleAndWrite(params: { + entryPoint: string + bundleFile: string + linguiConfig: LinguiConfigNormalized + outputPattern: string + format: FormatterWrapper + template: boolean + locales: string[] + clean: boolean + overwrite: boolean +}) { + const { + linguiConfig, + entryPoint, + format, + outputPattern, + locales, + overwrite, + clean, + template, + } = params + + const { messages, success } = await extractFromBundle( + params.bundleFile, + params.linguiConfig + ) + + if (!success) { + return { success: false } + } + + let stat: string + + if (template) { + stat = ( + await writeTemplate({ + linguiConfig, + clean, + format, + messages, + entryPoint, + outputPattern, + }) + ).statMessage + } else { + stat = ( + await writeCatalogs({ + locales, + linguiConfig, + clean, + format, + messages, + entryPoint, + overwrite, + outputPattern, + }) + ).statMessage + } + + return { success: true, stat } +} diff --git a/packages/cli/src/extract-experimental/workers/extractWorker.ts b/packages/cli/src/extract-experimental/workers/extractWorker.ts new file mode 100644 index 000000000..47b14c395 --- /dev/null +++ b/packages/cli/src/extract-experimental/workers/extractWorker.ts @@ -0,0 +1,50 @@ +import { expose } from "threads/worker" +import { getConfig, LinguiConfigNormalized } from "@lingui/conf" +import { extractFromBundleAndWrite } from "../extractFromBundleAndWrite" +import { FormatterWrapper, getFormat } from "../../api/formats" + +export type ExtractWorkerFunction = typeof extractWorker + +let linguiConfig: LinguiConfigNormalized | undefined +let format: FormatterWrapper | undefined + +const extractWorker = async ( + linguiConfigPath: string, + entryPoint: string, + bundleFile: string, + outputPattern: string, + template: boolean, + locales: string[], + clean: boolean, + overwrite: boolean +): Promise<{ success: boolean; stat?: string }> => { + if (!linguiConfig) { + // initialize config once per worker, speed up workers follow execution + linguiConfig = getConfig({ + configPath: linguiConfigPath, + skipValidation: true, + }) + } + + if (!format) { + format = await getFormat( + linguiConfig.format, + linguiConfig.formatOptions, + linguiConfig.sourceLocale + ) + } + + return await extractFromBundleAndWrite({ + entryPoint, + bundleFile, + outputPattern, + format, + linguiConfig, + locales, + overwrite, + clean, + template, + }) +} + +expose(extractWorker) diff --git a/packages/cli/src/lingui-compile.ts b/packages/cli/src/lingui-compile.ts index 43fd97430..27c2427ba 100644 --- a/packages/cli/src/lingui-compile.ts +++ b/packages/cli/src/lingui-compile.ts @@ -3,15 +3,16 @@ import chokidar from "chokidar" import { program } from "commander" import { getConfig, LinguiConfigNormalized } from "@lingui/conf" - -import { createCompiledCatalog } from "./api/compile" import { helpRun } from "./api/help" -import { createCompilationErrorMessage, getCatalogs, getFormat } from "./api" -import { getCatalogForMerge } from "./api/catalog/getCatalogs" -import normalizePath from "normalize-path" - -import nodepath from "path" -import { Catalog } from "./api/catalog" +import { getCatalogs, getFormat } from "./api" +import { compileLocale } from "./api/compile/compileLocale" +import { Pool, spawn, Worker } from "threads" +import { CompileWorker } from "./workers/compileWorker" +import { + resolveWorkersOptions, + WorkersOptions, +} from "./api/resolveWorkersOptions" +import ms from "ms" export type CliCompileOptions = { verbose?: boolean @@ -20,15 +21,14 @@ export type CliCompileOptions = { typescript?: boolean watch?: boolean namespace?: string + workersOptions: WorkersOptions } -class ProgramExit extends Error {} - export async function command( config: LinguiConfigNormalized, options: CliCompileOptions ) { - const catalogs = await getCatalogs(config) + const startTime = Date.now() // Check config.compile.merge if catalogs for current locale are to be merged into a single compiled file const doMerge = !!config.catalogsMergePath @@ -37,144 +37,73 @@ export async function command( let errored = false - await Promise.all( - config.locales.map(async (locale) => { + if (!options.workersOptions.poolSize) { + // single threaded + const catalogs = await getCatalogs(config) + + for (const locale of config.locales) { try { - await compileLocale(locale, catalogs, options, config, doMerge) + await compileLocale(catalogs, locale, options, config, doMerge, console) } catch (err) { - if (err instanceof ProgramExit) { + if ((err as Error).name === "ProgramExit") { errored = true } else { throw err } } - }) - ) + } + } else { + if (!config.resolvedConfigPath) { + throw new Error( + "Multithreading is only supported when lingui config loaded from file system, not passed by API" + ) + } - return !errored -} + options.verbose && + console.log(`Use worker pool of size ${options.workersOptions.poolSize}`) -async function compileLocale( - locale: string, - catalogs: Catalog[], - options: CliCompileOptions, - config: LinguiConfigNormalized, - doMerge: boolean -) { - let mergedCatalogs = {} - - await Promise.all( - catalogs.map(async (catalog) => { - const { messages, missing: missingMessages } = - await catalog.getTranslations(locale, { - fallbackLocales: config.fallbackLocales, - sourceLocale: config.sourceLocale, - }) + const pool = Pool( + () => spawn(new Worker("./workers/compileWorker")), + { size: options.workersOptions.poolSize } + ) - if ( - !options.allowEmpty && - locale !== config.pseudoLocale && - missingMessages.length > 0 - ) { - console.error( - pico.red( - `Error: Failed to compile catalog for locale ${pico.bold(locale)}!` + try { + for (const locale of config.locales) { + pool.queue(async (worker) => { + const { logs, error, exitProgram } = await worker.compileLocale( + locale, + options, + doMerge, + config.resolvedConfigPath ) - ) - - if (options.verbose) { - console.error(pico.red("Missing translations:")) - missingMessages.forEach((missing) => { - const source = - missing.source || missing.source === missing.id - ? `: (${missing.source})` - : "" - - console.error(`${missing.id}${source}`) - }) - } else { - console.error( - pico.red(`Missing ${missingMessages.length} translation(s)`) - ) - } - console.error() - throw new ProgramExit() - } - if (doMerge) { - mergedCatalogs = { ...mergedCatalogs, ...messages } - } else { - if ( - !(await compileAndWrite(locale, config, options, catalog, messages)) - ) { - throw new ProgramExit() - } - } - }) - ) - - if (doMerge) { - const result = await compileAndWrite( - locale, - config, - options, - await getCatalogForMerge(config), - mergedCatalogs - ) + if (logs.errors) { + console.error(logs.errors) + } - if (!result) { - throw new ProgramExit() - } - } -} + if (exitProgram) { + errored = true + return + } -async function compileAndWrite( - locale: string, - config: LinguiConfigNormalized, - options: CliCompileOptions, - catalogToWrite: Catalog, - messages: Record -): Promise { - const namespace = options.typescript - ? "ts" - : options.namespace || config.compileNamespace - const { source: compiledCatalog, errors } = createCompiledCatalog( - locale, - messages, - { - strict: false, - namespace, - pseudoLocale: config.pseudoLocale, - compilerBabelOptions: config.compilerBabelOptions, - } - ) - - if (errors.length) { - let message = createCompilationErrorMessage(locale, errors) - - if (options.failOnCompileError) { - message += `These errors fail command execution because \`--strict\` option passed` - console.error(pico.red(message)) - return false - } else { - message += `You can fail command execution on these errors by passing \`--strict\` option` - console.error(pico.red(message)) + if (error) { + throw error + } + }) + } + + await pool.completed(true) + } finally { + await pool.terminate() } } - let compiledPath = await catalogToWrite.writeCompiled( - locale, - compiledCatalog, - namespace - ) - - compiledPath = normalizePath(nodepath.relative(config.rootDir, compiledPath)) + console.log(`Done in ${ms(Date.now() - startTime)}`) - options.verbose && console.error(pico.green(`${locale} ⇒ ${compiledPath}`)) - return true + return !errored } -type CliOptions = { +type CliArgs = { verbose?: boolean allowEmpty?: boolean typescript?: boolean @@ -183,17 +112,20 @@ type CliOptions = { strict?: string config?: string debounce?: number + workers?: number } if (require.main === module) { program - .description( - "Add compile message catalogs and add language data (plurals) to compiled bundle." - ) + .description("Compile message catalogs to compiled bundle.") .option("--config ", "Path to the config file") .option("--strict", "Disable defaults for missing translations") .option("--verbose", "Verbose output") .option("--typescript", "Create Typescript definition for compiled bundle") + .option( + "--workers ", + "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process" + ) .option( "--namespace ", "Specify namespace for compiled bundle. Ex: cjs(default) -> module.exports, es -> export, window.test -> window.test" @@ -217,7 +149,7 @@ if (require.main === module) { }) .parse(process.argv) - const options = program.opts() + const options = program.opts() const config = getConfig({ configPath: options.config }) @@ -229,7 +161,7 @@ if (require.main === module) { verbose: options.watch || options.verbose || false, allowEmpty: !options.strict, failOnCompileError: !!options.strict, - + workersOptions: resolveWorkersOptions(options), typescript: options.typescript || config.compileNamespace === "ts" || false, namespace: options.namespace, // we want this to be undefined if user does not specify so default can be used @@ -291,8 +223,6 @@ if (require.main === module) { if (!results) { process.exit(1) } - - console.log("Done!") }) } } diff --git a/packages/cli/src/lingui-extract-experimental.ts b/packages/cli/src/lingui-extract-experimental.ts index 5e3d50ff7..5f15e87f1 100644 --- a/packages/cli/src/lingui-extract-experimental.ts +++ b/packages/cli/src/lingui-extract-experimental.ts @@ -4,33 +4,32 @@ import { getConfig, LinguiConfigNormalized } from "@lingui/conf" import nodepath from "path" import { getFormat } from "./api/formats" import fs from "fs/promises" -import { extractFromFiles } from "./api/catalog/extractFromFiles" import normalizePath from "normalize-path" import { bundleSource } from "./extract-experimental/bundleSource" -import { - writeCatalogs, - writeTemplate, -} from "./extract-experimental/writeCatalogs" import { getEntryPoints } from "./extract-experimental/getEntryPoints" import pico from "picocolors" +import { Pool, spawn, Worker } from "threads" import { - extractFromFileWithBabel, - getBabelParserOptions, -} from "./api/extractors/babel" + resolveWorkersOptions, + WorkersOptions, +} from "./api/resolveWorkersOptions" +import { ExtractWorkerFunction } from "./extract-experimental/workers/extractWorker" +import { extractFromBundleAndWrite } from "./extract-experimental/extractFromBundleAndWrite" export type CliExtractTemplateOptions = { - verbose: boolean + verbose?: boolean files?: string[] template?: boolean locales?: string[] overwrite?: boolean clean?: boolean + workersOptions: WorkersOptions } export default async function command( linguiConfig: LinguiConfigNormalized, - options: Partial + options: CliExtractTemplateOptions ): Promise { options.verbose && console.log("Extracting messages from source files…") @@ -74,96 +73,108 @@ export default async function command( let commandSuccess = true - const format = await getFormat( - linguiConfig.format, - linguiConfig.formatOptions, - linguiConfig.sourceLocale - ) - - linguiConfig.extractors = [ - { - match(_filename: string) { - return true - }, - - async extract(filename, code, onMessageExtracted, ctx) { - const parserOptions = ctx.linguiConfig.extractorParserOptions - - return extractFromFileWithBabel( - filename, - code, - onMessageExtracted, - ctx, - { - plugins: getBabelParserOptions(filename, parserOptions), - }, - true - ) - }, - }, - ] - - for (const outFile of Object.keys(bundleResult.metafile.outputs)) { - const messages = await extractFromFiles([outFile], linguiConfig) - - const { entryPoint } = bundleResult.metafile.outputs[outFile] - - let output: string - - if (!messages) { - commandSuccess = false - continue + if (options.workersOptions.poolSize) { + if (!linguiConfig.resolvedConfigPath) { + throw new Error( + "Multithreading is only supported when lingui config loaded from file system, not passed by API" + ) } - if (options.template) { - output = ( - await writeTemplate({ - linguiConfig, - clean: options.clean, - format, - messages, - entryPoint, - outputPattern: config.output, - }) - ).statMessage - } else { - output = ( - await writeCatalogs({ - locales: options.locales || linguiConfig.locales, - linguiConfig, - clean: options.clean, - format, - messages, - entryPoint, - overwrite: options.overwrite, - outputPattern: config.output, + options.verbose && + console.log(`Use worker pool of size ${options.workersOptions.poolSize}`) + + const pool = Pool( + () => + spawn( + new Worker("./extract-experimental/workers/extractWorker") + ), + { size: options.workersOptions.poolSize } + ) + + try { + for (const outFile of Object.keys(bundleResult.metafile.outputs)) { + const { entryPoint } = bundleResult.metafile.outputs[outFile] + + pool.queue(async (extractFromBundleAndWrite) => { + const { success, stat } = await extractFromBundleAndWrite( + linguiConfig.resolvedConfigPath, + entryPoint, + outFile, + config.output, + options.template, + options.locales || linguiConfig.locales, + options.clean, + options.overwrite + ) + + commandSuccess &&= success + + stats.push({ + entry: normalizePath( + nodepath.relative(linguiConfig.rootDir, entryPoint) + ), + content: stat, + }) }) - ).statMessage + } + + await pool.completed() + } finally { + await pool.terminate() } + } else { + const format = await getFormat( + linguiConfig.format, + linguiConfig.formatOptions, + linguiConfig.sourceLocale + ) - stats.push({ - entry: normalizePath(nodepath.relative(linguiConfig.rootDir, entryPoint)), - content: output, - }) + for (const outFile of Object.keys(bundleResult.metafile.outputs)) { + const { entryPoint } = bundleResult.metafile.outputs[outFile] + + const { success, stat } = await extractFromBundleAndWrite({ + entryPoint, + bundleFile: outFile, + outputPattern: config.output, + format, + linguiConfig, + locales: options.locales || linguiConfig.locales, + overwrite: options.overwrite, + clean: options.clean, + template: options.template, + }) + + commandSuccess &&= success + + stats.push({ + entry: normalizePath( + nodepath.relative(linguiConfig.rootDir, entryPoint) + ), + content: stat, + }) + } } // cleanup temp directory await fs.rm(tempDir, { recursive: true, force: true }) - stats.forEach(({ entry, content }) => { - console.log([`Catalog statistics for ${entry}:`, content, ""].join("\n")) - }) + stats + .sort((a, b) => a.entry.localeCompare(b.entry)) + .forEach(({ entry, content }) => { + console.log([`Catalog statistics for ${entry}:`, content, ""].join("\n")) + }) return commandSuccess } -type CliOptions = { +type CliArgs = { config?: string verbose?: boolean template?: boolean locale?: string overwrite?: boolean clean?: boolean + workers?: number } if (require.main === module) { @@ -174,9 +185,13 @@ if (require.main === module) { .option("--clean", "Remove obsolete translations") .option("--locale ", "Only extract the specified locales") .option("--verbose", "Verbose output") + .option( + "--workers ", + "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process" + ) .parse(process.argv) - const options = program.opts() + const options = program.opts() const config = getConfig({ configPath: options.config, @@ -188,6 +203,7 @@ if (require.main === module) { locales: options.locale?.split(","), overwrite: options.overwrite, clean: options.clean, + workersOptions: resolveWorkersOptions(options), }).then(() => { if (!result) process.exit(1) }) diff --git a/packages/cli/src/lingui-extract-template.ts b/packages/cli/src/lingui-extract-template.ts index 4c1bb41c3..8703537f8 100644 --- a/packages/cli/src/lingui-extract-template.ts +++ b/packages/cli/src/lingui-extract-template.ts @@ -6,10 +6,19 @@ import { getConfig, LinguiConfigNormalized } from "@lingui/conf" import { getCatalogs } from "./api" import nodepath from "path" import normalizePath from "normalize-path" +import { + createExtractWorkerPool, + ExtractWorkerPool, +} from "./api/extractWorkerPool" +import { + resolveWorkersOptions, + WorkersOptions, +} from "./api/resolveWorkersOptions" export type CliExtractTemplateOptions = { verbose: boolean files?: string[] + workersOptions: WorkersOptions } export default async function command( @@ -22,22 +31,39 @@ export default async function command( let commandSuccess = true - await Promise.all( - catalogs.map(async (catalog) => { - const result = await catalog.makeTemplate({ - ...(options as CliExtractTemplateOptions), - orderBy: config.orderBy, - }) + let workerPool: ExtractWorkerPool + + if (options.workersOptions.poolSize) { + options.verbose && + console.log(`Use worker pool of size ${options.workersOptions.poolSize}`) + + workerPool = createExtractWorkerPool(options.workersOptions) + } - if (result) { - catalogStats[ - normalizePath(nodepath.relative(config.rootDir, catalog.templateFile)) - ] = Object.keys(result).length - } - commandSuccess &&= Boolean(result) - }) - ) + try { + await Promise.all( + catalogs.map(async (catalog) => { + const result = await catalog.makeTemplate({ + ...(options as CliExtractTemplateOptions), + orderBy: config.orderBy, + workerPool, + }) + if (result) { + catalogStats[ + normalizePath( + nodepath.relative(config.rootDir, catalog.templateFile) + ) + ] = Object.keys(result).length + } + commandSuccess &&= Boolean(result) + }) + ) + } finally { + if (workerPool) { + await workerPool.terminate() + } + } Object.entries(catalogStats).forEach(([key, value]) => { console.log( `Catalog statistics for ${pico.bold(key)}: ${pico.green(value)} messages` @@ -48,18 +74,23 @@ export default async function command( return commandSuccess } -type CliOptions = { +type CliArgs = { config?: string verbose?: boolean + workers?: number } if (require.main === module) { program .option("--config ", "Path to the config file") .option("--verbose", "Verbose output") + .option( + "--workers ", + "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process" + ) .parse(process.argv) - const options = program.opts() + const options = program.opts() const config = getConfig({ configPath: options.config, @@ -67,6 +98,7 @@ if (require.main === module) { const result = command(config, { verbose: options.verbose || false, + workersOptions: resolveWorkersOptions(options), }).then(() => { if (!result) process.exit(1) }) diff --git a/packages/cli/src/lingui-extract.ts b/packages/cli/src/lingui-extract.ts index 478707dcb..91d98ad81 100644 --- a/packages/cli/src/lingui-extract.ts +++ b/packages/cli/src/lingui-extract.ts @@ -10,6 +10,15 @@ import { printStats } from "./api/stats" import { helpRun } from "./api/help" import ora from "ora" import normalizePath from "normalize-path" +import { + resolveWorkersOptions, + WorkersOptions, +} from "./api/resolveWorkersOptions" +import { + createExtractWorkerPool, + ExtractWorkerPool, +} from "./api/extractWorkerPool" +import ms from "ms" export type CliExtractOptions = { verbose: boolean @@ -19,39 +28,64 @@ export type CliExtractOptions = { locale: string[] prevFormat: string | null watch?: boolean + workersOptions: WorkersOptions } export default async function command( config: LinguiConfigNormalized, options: Partial ): Promise { + const startTime = Date.now() options.verbose && console.log("Extracting messages from source files…") const catalogs = await getCatalogs(config) const catalogStats: { [path: string]: AllCatalogsType } = {} let commandSuccess = true - const spinner = ora().start() + let workerPool: ExtractWorkerPool - await Promise.all( - catalogs.map(async (catalog) => { - const result = await catalog.make({ - ...(options as CliExtractOptions), - orderBy: config.orderBy, - }) + // important to initialize ora before worker pool, otherwise it cause + // MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 unpipe listeners added to [WriteStream]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit + // when workers >= 10 + const spinner = ora() - catalogStats[ - normalizePath(nodepath.relative(config.rootDir, catalog.path)) - ] = result || {} + if (options.workersOptions.poolSize) { + options.verbose && + console.log(`Use worker pool of size ${options.workersOptions.poolSize}`) - commandSuccess &&= Boolean(result) - }) - ) + workerPool = createExtractWorkerPool(options.workersOptions) + } + + spinner.start() + + try { + await Promise.all( + catalogs.map(async (catalog) => { + const result = await catalog.make({ + ...(options as CliExtractOptions), + orderBy: config.orderBy, + workerPool, + }) + + catalogStats[ + normalizePath(nodepath.relative(config.rootDir, catalog.path)) + ] = result || {} + + commandSuccess &&= Boolean(result) + }) + ) + } finally { + if (workerPool) { + await workerPool.terminate() + } + } + + const doneMsg = `Done in ${ms(Date.now() - startTime)}` if (commandSuccess) { - spinner.succeed() + spinner.succeed(doneMsg) } else { - spinner.fail() + spinner.fail(doneMsg) } Object.entries(catalogStats).forEach(([key, value]) => { @@ -97,7 +131,7 @@ export default async function command( return commandSuccess } -type CliOptions = { +type CliArgs = { verbose: boolean config: string convertFrom: string @@ -108,6 +142,7 @@ type CliOptions = { locale: string[] prevFormat: string | null watch?: boolean + workers?: number } if (require.main === module) { @@ -123,6 +158,10 @@ if (require.main === module) { .filter(Boolean) } ) + .option( + "--workers ", + "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process" + ) .option("--overwrite", "Overwrite translations for source locale") .option("--clean", "Remove obsolete translations") .option( @@ -137,7 +176,7 @@ if (require.main === module) { .option("--watch", "Enables Watch Mode") .parse(process.argv) - const options = program.opts() + const options = program.opts() const config = getConfig({ configPath: options.config, @@ -182,6 +221,7 @@ if (require.main === module) { watch: options.watch || false, files: filePath?.length ? filePath : undefined, prevFormat, + workersOptions: resolveWorkersOptions(options), }) } diff --git a/packages/cli/src/test/__snapshots__/compile.test.ts.snap b/packages/cli/src/test/__snapshots__/compile.test.ts.snap index 115b065b8..bd7980e20 100644 --- a/packages/cli/src/test/__snapshots__/compile.test.ts.snap +++ b/packages/cli/src/test/__snapshots__/compile.test.ts.snap @@ -23,15 +23,31 @@ Missing 1 translation(s) `; exports[`CLI Command: Compile allowEmpty = false Should show missing messages verbosely when verbose = true 1`] = ` +en ⇒ en.js Error: Failed to compile catalog for locale pl! Missing translations: mY42CM: (Hello World) 2ZeN02: (Test String) -en ⇒ en.js `; -exports[`CLI Command: Compile failOnCompileError = true Should show error and stop compilation of catalog if message has compilation error 1`] = ` +exports[`CLI Command: Compile failOnCompileError Should show error and continue compilation of catalog if message has compilation error when failOnCompileError = false" 1`] = `/*eslint-disable*/module.exports={messages:JSON.parse("{\\"lg1L7K\\":[\\"Hello User\\"]}")};`; + +exports[`CLI Command: Compile failOnCompileError Should show error and continue compilation of catalog if message has compilation error when failOnCompileError = false" 2`] = ` +Failed to compile catalog for locale pl! + +Compilation error for 1 translation(s): + +mY42CM: Hello {hello +Reason: Unexpected message end at line 1 col 13: + +1 Hello {hello + ^ + +You can fail command execution on these errors by passing \`--strict\` option +`; + +exports[`CLI Command: Compile failOnCompileError Should show error and stop compilation of catalog if message has compilation error when failOnCompileError = true 1`] = ` Failed to compile catalog for locale pl! Compilation error for 1 translation(s): diff --git a/packages/cli/src/test/compile.test.ts b/packages/cli/src/test/compile.test.ts index ec4e8f15c..3511a8961 100644 --- a/packages/cli/src/test/compile.test.ts +++ b/packages/cli/src/test/compile.test.ts @@ -1,10 +1,10 @@ import { command } from "../lingui-compile" -import { makeConfig } from "@lingui/conf" +import { getConfig, LinguiConfig, makeConfig } from "@lingui/conf" import { getConsoleMockCalls, mockConsole } from "@lingui/jest-mocks" import { createFixtures, readFsToListing } from "../tests" describe("CLI Command: Compile", () => { - function getConfig(rootDir: string, pseudoLocale?: string) { + function getTestConfig(rootDir: string, pseudoLocale?: string) { return makeConfig({ locales: ["en", "pl"], sourceLocale: "en", @@ -21,77 +21,77 @@ describe("CLI Command: Compile", () => { } describe("allowEmpty = false", () => { - it( - "Should show error and stop compilation of catalog " + - "if message doesnt have a translation (no template)", - async () => { - expect.assertions(4) + it("Should show error and stop compilation of catalog if message doesnt have a translation (no template)", async () => { + expect.assertions(4) - const rootDir = await createFixtures({ - "en.po": ` + const rootDir = await createFixtures({ + "en.po": ` msgid "Hello World" msgstr "Hello World" `, - "pl.po": ` + "pl.po": ` msgid "Hello World" msgstr "Cześć świat" msgid "Test String" msgstr "" `, - }) + }) - const config = getConfig(rootDir) + const config = getTestConfig(rootDir) - await mockConsole(async (console) => { - const result = await command(config, { - allowEmpty: false, - }) - const actualFiles = readFsToListing(config.rootDir) + await mockConsole(async (console) => { + const result = await command(config, { + allowEmpty: false, + workersOptions: { + poolSize: 0, + }, + }) + const actualFiles = readFsToListing(config.rootDir) - expect(actualFiles["pl.js"]).toBeFalsy() - expect(actualFiles["en.js"]).toBeTruthy() + expect(actualFiles["pl.js"]).toBeFalsy() + expect(actualFiles["en.js"]).toBeTruthy() - const log = getConsoleMockCalls(console.error) - expect(log).toMatchSnapshot() - expect(result).toBeFalsy() - }) - } - ) + const log = getConsoleMockCalls(console.error) + expect(log).toMatchSnapshot() + expect(result).toBeFalsy() + }) + }) - it( - "Should show error and stop compilation of catalog " + - "if message doesnt have a translation (with template)", - async () => { - expect.assertions(3) - const rootDir = await createFixtures({ - "messages.pot": ` + it("Should show error and stop compilation of catalog if message doesnt have a translation (with template)", async () => { + expect.assertions(3) + const rootDir = await createFixtures({ + "messages.pot": ` msgid "Hello World" msgstr "" `, - "pl.po": ``, - }) + "pl.po": ``, + }) - const config = getConfig(rootDir) + const config = getTestConfig(rootDir) - await mockConsole(async (console) => { - const result = await command(config, { - allowEmpty: false, - }) + await mockConsole(async (console) => { + const result = await command(config, { + allowEmpty: false, + workersOptions: { + poolSize: 0, + }, + }) - const actualFiles = readFsToListing(rootDir) + const actualFiles = readFsToListing(rootDir) - expect({ - pl: actualFiles["pl.js"], - en: actualFiles["en.js"], - }).toMatchSnapshot() + expect({ + pl: actualFiles["pl.js"], + en: actualFiles["en.js"], + }).toMatchSnapshot() - const log = getConsoleMockCalls(console.error) - expect(log).toMatchSnapshot() - expect(result).toBeFalsy() - }) - } - ) + let log = getConsoleMockCalls(console.error) + log = log.split("\n\n").sort().join("\n\n") + + expect(log).toMatchSnapshot() + expect(result).toBeFalsy() + }) + }) it("Should allow empty translation for pseudo locale", async () => { expect.assertions(4) @@ -107,11 +107,14 @@ msgstr "" `, }) - const config = getConfig(rootDir, "pl") + const config = getTestConfig(rootDir, "pl") await mockConsole(async (console) => { const result = await command(config, { allowEmpty: false, + workersOptions: { + poolSize: 0, + }, }) const actualFiles = readFsToListing(config.rootDir) @@ -136,12 +139,15 @@ msgstr "" `, }) - const config = getConfig(rootDir) + const config = getTestConfig(rootDir) await mockConsole(async (console) => { const result = await command(config, { allowEmpty: false, verbose: true, + workersOptions: { + poolSize: 0, + }, }) const log = getConsoleMockCalls(console.error) @@ -151,41 +157,80 @@ msgstr "" }) }) - describe("failOnCompileError = true", () => { - it( - "Should show error and stop compilation of catalog " + - "if message has compilation error", - async () => { - expect.assertions(3) + describe("failOnCompileError", () => { + it("Should show error and stop compilation of catalog if message has compilation error when failOnCompileError = true", async () => { + expect.assertions(3) - const rootDir = await createFixtures({ - "en.po": ` + const rootDir = await createFixtures({ + "en.po": ` msgid "Hello World" msgstr "Hello {hello}" `, - "pl.po": ` + "pl.po": ` msgid "Hello World" msgstr "Hello {hello" `, + }) + + const config = getTestConfig(rootDir) + + await mockConsole(async (console) => { + const result = await command(config, { + failOnCompileError: true, + allowEmpty: true, + workersOptions: { + poolSize: 0, + }, }) + const actualFiles = readFsToListing(config.rootDir) + + expect(actualFiles["pl.js"]).toBeFalsy() + + const log = getConsoleMockCalls(console.error) + expect(log).toMatchSnapshot() + expect(result).toBeFalsy() + }) + }) - const config = getConfig(rootDir) + it('Should show error and continue compilation of catalog if message has compilation error when failOnCompileError = false"', async () => { + expect.assertions(3) - await mockConsole(async (console) => { - const result = await command(config, { - failOnCompileError: true, - allowEmpty: true, - }) - const actualFiles = readFsToListing(config.rootDir) + const rootDir = await createFixtures({ + "en.po": ` +msgid "Hello World" +msgstr "Hello {hello}" + +msgid "Hello User" +msgstr "Hello User" + `, + "pl.po": ` +msgid "Hello World" +msgstr "Hello {hello" + +msgid "Hello User" +msgstr "Hello User" + `, + }) - expect(actualFiles["pl.js"]).toBeFalsy() + const config = getTestConfig(rootDir) - const log = getConsoleMockCalls(console.error) - expect(log).toMatchSnapshot() - expect(result).toBeFalsy() + await mockConsole(async (console) => { + const result = await command(config, { + failOnCompileError: false, + allowEmpty: true, + workersOptions: { + poolSize: 0, + }, }) - } - ) + const actualFiles = readFsToListing(config.rootDir) + + expect(actualFiles["pl.js"]).toMatchSnapshot() + + const log = getConsoleMockCalls(console.error) + expect(log).toMatchSnapshot() + expect(result).toBeTruthy() + }) + }) }) describe("merge", () => { @@ -236,7 +281,11 @@ msgstr "[PL] Bar Hello World" const config = getConfig(rootDir) await mockConsole(async (console) => { - const result = await command(config, {}) + const result = await command(config, { + workersOptions: { + poolSize: 0, + }, + }) const actualFiles = readFsToListing(config.rootDir) expect(actualFiles["merged/en.js"]).toMatchSnapshot() @@ -248,4 +297,163 @@ msgstr "[PL] Bar Hello World" }) }) }) + + describe("using worker pool", () => { + function getConfigText() { + const config: LinguiConfig = { + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [ + { + path: "/{locale}", + include: [""], + exclude: [], + }, + ], + } + + return `export default ${JSON.stringify(config)}` + } + + it("Should compile catalogs successfully with multithread enabled", async () => { + const rootDir = await createFixtures({ + "en.po": ` +msgid "Hello World" +msgstr "Hello World" + +msgid "Welcome {name}" +msgstr "Welcome {name}" + `, + "pl.po": ` +msgid "Hello World" +msgstr "Cześć świat" + +msgid "Welcome {name}" +msgstr "Witaj {name}" + `, + "lingui.config.ts": getConfigText(), + }) + + const config = getConfig({ cwd: rootDir }) + + await mockConsole(async (console) => { + const result = await command(config, { + workersOptions: { poolSize: 2 }, + }) + const actualFiles = readFsToListing(config.rootDir) + + expect(actualFiles["en.js"]).toBeTruthy() + expect(actualFiles["pl.js"]).toBeTruthy() + + const log = getConsoleMockCalls(console.error) + expect(log).toBeUndefined() + expect(result).toBeTruthy() + }) + }) + + it("Should produce identical results with multithread enabled and disabled", async () => { + const rootDir = await createFixtures({ + "en.po": ` +msgid "Hello World" +msgstr "Hello World" + +msgid "Complex message" +msgstr "{count, plural, one {# item} other {# items}}" + +msgid "Select message" +msgstr "{gender, select, male {He} female {She} other {They}}" + `, + "pl.po": ` +msgid "Hello World" +msgstr "Cześć świat" + +msgid "Complex message" +msgstr "{count, plural, one {# element} other {# elementów}}" + +msgid "Select message" +msgstr "{gender, select, male {On} female {Ona} other {Oni}}" + `, + "lingui.config.ts": getConfigText(), + }) + + // Compile with multithread disabled + await mockConsole(async () => { + await command(getConfig({ cwd: rootDir }), { + workersOptions: { + poolSize: 0, + }, + }) + }) + const singleThreadFiles = readFsToListing(rootDir) + + // Clean up for multithread test + await createFixtures({ + "en.po": ` +msgid "Hello World" +msgstr "Hello World" + +msgid "Complex message" +msgstr "{count, plural, one {# item} other {# items}}" + +msgid "Select message" +msgstr "{gender, select, male {He} female {She} other {They}}" + `, + "pl.po": ` +msgid "Hello World" +msgstr "Cześć świat" + +msgid "Complex message" +msgstr "{count, plural, one {# element} other {# elementów}}" + +msgid "Select message" +msgstr "{gender, select, male {On} female {Ona} other {Oni}}" + `, + "lingui.config.ts": getConfigText(), + }) + + // Compile with multithread enabled + await mockConsole(async () => { + await command(getConfig({ cwd: rootDir }), { + workersOptions: { + poolSize: 2, + }, + }) + }) + const multiThreadFiles = readFsToListing(rootDir) + + // Compare the results + expect(singleThreadFiles["en.js"]).toEqual(multiThreadFiles["en.js"]) + expect(singleThreadFiles["pl.js"]).toEqual(multiThreadFiles["pl.js"]) + }) + + it("Should handle compilation errors correctly with multithread", async () => { + const rootDir = await createFixtures({ + "en.po": ` +msgid "Valid message" +msgstr "Valid message" + +msgid "Invalid syntax" +msgstr "{plural, }" + `, + "lingui.config.ts": getConfigText(), + }) + + await mockConsole(async (console) => { + const result = await command(getConfig({ cwd: rootDir }), { + failOnCompileError: true, + workersOptions: { + poolSize: 2, + }, + }) + + const actualFiles = readFsToListing(rootDir) + expect(actualFiles["en.js"]).toBeFalsy() + + const log = getConsoleMockCalls(console.error) + expect(log).toContain("invalid syntax at line") + expect(result).toBeFalsy() + }) + }) + }) }) diff --git a/packages/cli/src/tests.ts b/packages/cli/src/tests.ts index 4ee39ee73..136909c60 100644 --- a/packages/cli/src/tests.ts +++ b/packages/cli/src/tests.ts @@ -27,16 +27,13 @@ export async function copyFixture(fixtureDir: string) { } export const defaultMakeOptions: MakeOptions = { - verbose: false, clean: false, overwrite: false, locale: null, - prevFormat: null, orderBy: "messageId", } export const defaultMakeTemplateOptions: MakeTemplateOptions = { - verbose: false, orderBy: "messageId", } diff --git a/packages/cli/src/workers/compileWorker.ts b/packages/cli/src/workers/compileWorker.ts new file mode 100644 index 000000000..8915a5147 --- /dev/null +++ b/packages/cli/src/workers/compileWorker.ts @@ -0,0 +1,63 @@ +import { expose } from "threads/worker" +import { compileLocale } from "../api/compile/compileLocale" +import { CliCompileOptions } from "../lingui-compile" +import { getConfig, LinguiConfigNormalized } from "@lingui/conf" +import { SerializedLogs, WorkerLogger } from "../api/workerLogger" +import { ProgramExit } from "../api/ProgramExit" +import { Catalog } from "../api/catalog" +import { getCatalogs } from "../api/catalog/getCatalogs" + +let linguiConfig: LinguiConfigNormalized | undefined +let catalogs: Catalog[] | undefined + +const compileWorker = { + compileLocale: async ( + locale: string, + options: CliCompileOptions, + doMerge: boolean, + linguiConfigPath: string + ): Promise<{ + logs?: SerializedLogs + error?: unknown + exitProgram?: boolean + }> => { + if (!linguiConfig) { + // initialize config once per worker, speed up workers follow execution + linguiConfig = getConfig({ + configPath: linguiConfigPath, + skipValidation: true, + }) + } + + if (!catalogs) { + // catalogs holds path to the files and message catalogs, so it's kinda configuration object + // it depends only on the config, so we can initialize it once per program execution + catalogs = await getCatalogs(linguiConfig) + } + + const logger = new WorkerLogger() + + try { + await compileLocale( + catalogs, + locale, + options, + linguiConfig, + doMerge, + logger + ) + } catch (error) { + return { + logs: logger.flush(), + error, + exitProgram: error instanceof ProgramExit, + } + } + + return { logs: logger.flush() } + }, +} + +export type CompileWorker = typeof compileWorker + +expose(compileWorker) diff --git a/packages/cli/src/workers/extractWorker.ts b/packages/cli/src/workers/extractWorker.ts new file mode 100644 index 000000000..d947b1ec3 --- /dev/null +++ b/packages/cli/src/workers/extractWorker.ts @@ -0,0 +1,38 @@ +import { expose } from "threads/worker" +import { + ExtractedMessage, + getConfig, + LinguiConfigNormalized, +} from "@lingui/conf" +import extract from "../api/extractors" + +export type ExtractWorkerFunction = typeof extractWorker + +let linguiConfig: LinguiConfigNormalized | undefined + +const extractWorker = async ( + filename: string, + linguiConfigPath: string +): Promise<{ messages?: ExtractedMessage[]; success: boolean }> => { + if (!linguiConfig) { + // initialize config once per worker, speed up workers follow execution + linguiConfig = getConfig({ + configPath: linguiConfigPath, + skipValidation: true, + }) + } + + const messages: ExtractedMessage[] = [] + + const success = await extract( + filename, + (msg: ExtractedMessage) => { + messages.push(msg) + }, + linguiConfig + ) + + return { success, messages } +} + +expose(extractWorker) diff --git a/packages/cli/test/extract-po-format/lingui.config.ts b/packages/cli/test/extract-po-format/lingui.config.ts new file mode 100644 index 000000000..7180d8bc0 --- /dev/null +++ b/packages/cli/test/extract-po-format/lingui.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@lingui/conf" + +export default defineConfig({ + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [ + { + path: "/actual/{locale}", + include: ["/fixtures"], + }, + ], +}) diff --git a/packages/cli/test/extract-template-po-format/lingui.config.ts b/packages/cli/test/extract-template-po-format/lingui.config.ts new file mode 100644 index 000000000..993d7759d --- /dev/null +++ b/packages/cli/test/extract-template-po-format/lingui.config.ts @@ -0,0 +1,11 @@ +export default { + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [ + { + path: "/actual/{locale}", + include: ["/fixtures"], + }, + ], +} diff --git a/packages/cli/test/extractor-experimental-clean/lingui.config.ts b/packages/cli/test/extractor-experimental-clean/lingui.config.ts new file mode 100644 index 000000000..6110511ce --- /dev/null +++ b/packages/cli/test/extractor-experimental-clean/lingui.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "@lingui/conf" + +export default defineConfig({ + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [], + experimental: { + extractor: { + entries: ["/fixtures/pages/**/*.page.{ts,tsx}"], + output: "/actual/{entryName}.{locale}", + }, + }, +}) diff --git a/packages/cli/test/extractor-experimental-clean/package.json b/packages/cli/test/extractor-experimental-clean/package.json index b4e8874a8..ace298ce7 100644 --- a/packages/cli/test/extractor-experimental-clean/package.json +++ b/packages/cli/test/extractor-experimental-clean/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "private": true, "dependencies": { - "@lingui/core": "*" + "@lingui/core": "*", + "@lingui/conf": "*" } } diff --git a/packages/cli/test/extractor-experimental-template/lingui.config.ts b/packages/cli/test/extractor-experimental-template/lingui.config.ts new file mode 100644 index 000000000..6110511ce --- /dev/null +++ b/packages/cli/test/extractor-experimental-template/lingui.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "@lingui/conf" + +export default defineConfig({ + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [], + experimental: { + extractor: { + entries: ["/fixtures/pages/**/*.page.{ts,tsx}"], + output: "/actual/{entryName}.{locale}", + }, + }, +}) diff --git a/packages/cli/test/extractor-experimental-template/package.json b/packages/cli/test/extractor-experimental-template/package.json index 2d42dc40f..3a655ff6a 100644 --- a/packages/cli/test/extractor-experimental-template/package.json +++ b/packages/cli/test/extractor-experimental-template/package.json @@ -5,6 +5,7 @@ "dependencies": { "@lingui/core": "*", "@lingui/react": "*", + "@lingui/conf": "*", "some-package": "*" } } diff --git a/packages/cli/test/extractor-experimental/lingui.config.ts b/packages/cli/test/extractor-experimental/lingui.config.ts new file mode 100644 index 000000000..6110511ce --- /dev/null +++ b/packages/cli/test/extractor-experimental/lingui.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "@lingui/conf" + +export default defineConfig({ + locales: ["en", "pl"], + sourceLocale: "en", + format: "po", + catalogs: [], + experimental: { + extractor: { + entries: ["/fixtures/pages/**/*.page.{ts,tsx}"], + output: "/actual/{entryName}.{locale}", + }, + }, +}) diff --git a/packages/cli/test/extractor-experimental/package.json b/packages/cli/test/extractor-experimental/package.json index ee4fc4d6c..24d2b7e4f 100644 --- a/packages/cli/test/extractor-experimental/package.json +++ b/packages/cli/test/extractor-experimental/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "private": true, "dependencies": { - "@lingui/core": "*" + "@lingui/core": "*", + "@lingui/conf": "*" } } diff --git a/packages/cli/test/index.test.ts b/packages/cli/test/index.test.ts index efaacb914..c35891216 100644 --- a/packages/cli/test/index.test.ts +++ b/packages/cli/test/index.test.ts @@ -5,11 +5,30 @@ import { command as compileCommand } from "../src/lingui-compile" import fs from "fs/promises" import { sync } from "glob" import nodepath from "path" -import { makeConfig } from "@lingui/conf" +import { getConfig, makeConfig } from "@lingui/conf" import { compareFolders } from "../src/tests" import { getConsoleMockCalls, mockConsole } from "@lingui/jest-mocks" import MockDate from "mockdate" +jest.mock("ora", () => { + return () => { + return { + start(...args: any) { + console.log(args) + }, + succeed(...args: any) { + console.log(args) + }, + fail(...args: any) { + console.log(args) + }, + } + } +}) + +function replaceDuration(snaphot: string) { + return snaphot.replace(/Done in .+ms/g, "Done in ms") +} async function prepare(caseFolderName: string) { const rootDir = nodepath.join(__dirname, caseFolderName) @@ -57,12 +76,15 @@ describe("E2E Extractor Test", () => { }, ], }), - {} + { workersOptions: { poolSize: 0 } } ) expect(result).toBeTruthy() expect(getConsoleMockCalls(console.error)).toBeFalsy() - expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` + + Done in ms Catalog statistics for actual/{locale}: ┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ @@ -90,21 +112,9 @@ describe("E2E Extractor Test", () => { }) await mockConsole(async (console) => { - const result = await extractTemplateCommand( - makeConfig({ - rootDir: rootDir, - locales: ["en", "pl"], - sourceLocale: "en", - format: "po", - catalogs: [ - { - path: "/actual/{locale}", - include: ["/fixtures"], - }, - ], - }), - {} - ) + const result = await extractTemplateCommand(getConfig({ cwd: rootDir }), { + workersOptions: { poolSize: 0 }, + }) expect(result).toBeTruthy() expect(getConsoleMockCalls(console.error)).toBeFalsy() @@ -117,48 +127,108 @@ describe("E2E Extractor Test", () => { compareFolders(actualPath, expectedPath) }) + it("extractTemplate should extract into .pot template with worker pool", async () => { + const { rootDir, actualPath, expectedPath } = await prepare( + "extract-template-po-format" + ) + + await fs.rm(actualPath, { + recursive: true, + force: true, + }) + + await mockConsole(async (console) => { + const result = await extractTemplateCommand(getConfig({ cwd: rootDir }), { + workersOptions: { poolSize: 2 }, + verbose: true, + }) + + expect(result).toBeTruthy() + expect(getConsoleMockCalls(console.error)).toBeFalsy() + expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` + Extracting messages from source files… + Use worker pool of size 2 + Catalog statistics for actual/messages.pot: 7 messages + + `) + }) + + compareFolders(actualPath, expectedPath) + }) + + it("Should extract with multiThread enabled", async () => { + const { rootDir, actualPath, expectedPath } = await prepare( + "extract-po-format" + ) + + await mockConsole(async (console) => { + const result = await extractCommand(getConfig({ cwd: rootDir }), { + verbose: true, + workersOptions: { poolSize: 2 }, + }) + + expect(result).toBeTruthy() + expect(getConsoleMockCalls(console.error)).toBeFalsy() + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` + Extracting messages from source files… + Use worker pool of size 2 + + Done in ms + Catalog statistics for actual/{locale}: + ┌─────────────┬─────────────┬─────────┐ + │ Language │ Total count │ Missing │ + ├─────────────┼─────────────┼─────────┤ + │ en (source) │ 10 │ - │ + │ pl │ 10 │ 10 │ + └─────────────┴─────────────┴─────────┘ + + (Use "yarn extract" to update catalogs with new messages.) + (Use "yarn compile" to compile catalogs for production. Alternatively, use bundler plugins: https://lingui.dev/ref/cli#compiling-catalogs-in-ci) + `) + }) + + compareFolders(actualPath, expectedPath) + }) + describe("extractor-experimental", () => { it("should extract to template when --template passed", async () => { const { rootDir, actualPath, expectedPath } = await prepare( "extractor-experimental-template" ) - await mockConsole(async (console) => { - const config = makeConfig({ - rootDir: rootDir, - locales: ["en", "pl"], - sourceLocale: "en", - format: "po", - catalogs: [], - experimental: { - extractor: { - entries: ["/fixtures/pages/**/*.page.{ts,tsx}"], - output: "/actual/{entryName}.{locale}", - }, - }, - }) + const config = getConfig({ cwd: rootDir }) + await mockConsole(async (console) => { const result = await extractExperimentalCommand(config, { template: true, + workersOptions: { + poolSize: 0, + }, }) await compileCommand(config, { allowEmpty: true, + workersOptions: { + poolSize: 0, + }, }) expect(getConsoleMockCalls(console.error)).toBeFalsy() expect(result).toBeTruthy() - expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` You have using an experimental feature Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. - Catalog statistics for fixtures/pages/index.page.ts: - 1 message(s) extracted - Catalog statistics for fixtures/pages/about.page.tsx: 4 message(s) extracted + Catalog statistics for fixtures/pages/index.page.ts: + 1 message(s) extracted + Compiling message catalogs… + Done in ms `) }) @@ -171,32 +241,36 @@ describe("E2E Extractor Test", () => { ) await mockConsole(async (console) => { - const config = makeConfig({ - rootDir: rootDir, - locales: ["en", "pl"], - sourceLocale: "en", - format: "po", - catalogs: [], - experimental: { - extractor: { - entries: ["/fixtures/pages/**/*.page.{ts,tsx}"], - output: "/actual/{entryName}.{locale}", - }, + const config = getConfig({ cwd: rootDir }) + + const result = await extractExperimentalCommand(config, { + workersOptions: { + poolSize: 0, }, }) - const result = await extractExperimentalCommand(config, {}) - await compileCommand(config, { allowEmpty: true, + workersOptions: { + poolSize: 0, + }, }) expect(getConsoleMockCalls(console.error)).toBeFalsy() expect(result).toBeTruthy() - expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` You have using an experimental feature Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. + Catalog statistics for fixtures/pages/about.page.ts: + ┌─────────────┬─────────────┬─────────┐ + │ Language │ Total count │ Missing │ + ├─────────────┼─────────────┼─────────┤ + │ en (source) │ 3 │ - │ + │ pl │ 4 │ 3 │ + └─────────────┴─────────────┴─────────┘ + Catalog statistics for fixtures/pages/index.page.ts: ┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ @@ -205,6 +279,45 @@ describe("E2E Extractor Test", () => { │ pl │ 2 │ 2 │ └─────────────┴─────────────┴─────────┘ + Compiling message catalogs… + Done in ms + `) + }) + + compareFolders(actualPath, expectedPath) + }) + + it("should extract to catalogs with worker pool", async () => { + const { rootDir, actualPath, expectedPath } = await prepare( + "extractor-experimental" + ) + + await mockConsole(async (console) => { + const config = getConfig({ cwd: rootDir }) + + const result = await extractExperimentalCommand(config, { + verbose: true, + workersOptions: { + poolSize: 2, + }, + }) + + await compileCommand(config, { + allowEmpty: true, + workersOptions: { + poolSize: 0, + }, + }) + + expect(getConsoleMockCalls(console.error)).toBeFalsy() + expect(result).toBeTruthy() + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` + Extracting messages from source files… + You have using an experimental feature + Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. + + Use worker pool of size 2 Catalog statistics for fixtures/pages/about.page.ts: ┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ @@ -213,12 +326,22 @@ describe("E2E Extractor Test", () => { │ pl │ 4 │ 3 │ └─────────────┴─────────────┴─────────┘ + Catalog statistics for fixtures/pages/index.page.ts: + ┌─────────────┬─────────────┬─────────┐ + │ Language │ Total count │ Missing │ + ├─────────────┼─────────────┼─────────┤ + │ en (source) │ 2 │ - │ + │ pl │ 2 │ 2 │ + └─────────────┴─────────────┴─────────┘ + Compiling message catalogs… + Done in ms `) }) compareFolders(actualPath, expectedPath) }) + it("should extract and clean obsolete", async () => { const { rootDir, actualPath, expectedPath } = await prepare( "extractor-experimental-clean" @@ -240,30 +363,34 @@ describe("E2E Extractor Test", () => { }, }), { + workersOptions: { + poolSize: 0, + }, clean: true, } ) expect(getConsoleMockCalls(console.error)).toBeFalsy() expect(result).toBeTruthy() - expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` You have using an experimental feature Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. - Catalog statistics for fixtures/pages/index.page.ts: + Catalog statistics for fixtures/pages/about.page.ts: ┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ ├─────────────┼─────────────┼─────────┤ - │ en (source) │ 1 │ - │ - │ pl │ 1 │ 1 │ + │ en (source) │ 2 │ - │ + │ pl │ 3 │ 2 │ └─────────────┴─────────────┴─────────┘ - Catalog statistics for fixtures/pages/about.page.ts: + Catalog statistics for fixtures/pages/index.page.ts: ┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ ├─────────────┼─────────────┼─────────┤ - │ en (source) │ 2 │ - │ - │ pl │ 3 │ 2 │ + │ en (source) │ 1 │ - │ + │ pl │ 1 │ 1 │ └─────────────┴─────────────┴─────────┘ `) @@ -278,23 +405,26 @@ describe("E2E Extractor Test", () => { "extract-partial-consistency" ) - await extractCommand( - makeConfig({ - rootDir: rootDir, - locales: ["en"], - sourceLocale: "en", - format: "po", - catalogs: [ - { - path: "/actual/{locale}", - include: ["/fixtures"], - }, - ], - }), - { - files: [nodepath.join(rootDir, "fixtures", "file-b.tsx")], - } - ) + await mockConsole(async () => { + await extractCommand( + makeConfig({ + rootDir: rootDir, + locales: ["en"], + sourceLocale: "en", + format: "po", + catalogs: [ + { + path: "/actual/{locale}", + include: ["/fixtures"], + }, + ], + }), + { + files: [nodepath.join(rootDir, "fixtures", "file-b.tsx")], + workersOptions: { poolSize: 0 }, + } + ) + }) compareFolders(actualPath, expectedPath) }) @@ -317,23 +447,26 @@ describe("E2E Extractor Test", () => { }, ], }), - {} + { workersOptions: { poolSize: 0 } } ) expect(result).toBeTruthy() expect(getConsoleMockCalls(console.error)).toBeFalsy() - expect(getConsoleMockCalls(console.log)).toMatchInlineSnapshot(` - Catalog statistics for actual/{locale}: - ┌─────────────┬─────────────┬─────────┐ - │ Language │ Total count │ Missing │ - ├─────────────┼─────────────┼─────────┤ - │ en (source) │ 10 │ - │ - │ pl │ 10 │ 10 │ - └─────────────┴─────────────┴─────────┘ - - (Use "yarn extract" to update catalogs with new messages.) - (Use "yarn compile" to compile catalogs for production. Alternatively, use bundler plugins: https://lingui.dev/ref/cli#compiling-catalogs-in-ci) - `) + expect(replaceDuration(getConsoleMockCalls(console.log))) + .toMatchInlineSnapshot(` + + Done in ms + Catalog statistics for actual/{locale}: + ┌─────────────┬─────────────┬─────────┐ + │ Language │ Total count │ Missing │ + ├─────────────┼─────────────┼─────────┤ + │ en (source) │ 10 │ - │ + │ pl │ 10 │ 10 │ + └─────────────┴─────────────┴─────────┘ + + (Use "yarn extract" to update catalogs with new messages.) + (Use "yarn compile" to compile catalogs for production. Alternatively, use bundler plugins: https://lingui.dev/ref/cli#compiling-catalogs-in-ci) + `) }) }) }) diff --git a/packages/conf/package.json b/packages/conf/package.json index 51ce8afa1..07db5b390 100644 --- a/packages/conf/package.json +++ b/packages/conf/package.json @@ -33,7 +33,7 @@ "@babel/runtime": "^7.20.13", "cosmiconfig": "^8.0.0", "jest-validate": "^29.4.3", - "jiti": "^1.17.1", + "jiti": "^2.5.1", "picocolors": "^1.1.1" }, "files": [ diff --git a/packages/conf/src/__snapshots__/index.test.ts.snap b/packages/conf/src/__snapshots__/index.test.ts.snap index c995ab6df..18ff4bf45 100644 --- a/packages/conf/src/__snapshots__/index.test.ts.snap +++ b/packages/conf/src/__snapshots__/index.test.ts.snap @@ -48,6 +48,7 @@ exports[`@lingui/conf should return default config 1`] = ` }, orderBy: message, pseudoLocale: , + resolvedConfigPath: StringContaining .linguirc, rootDir: ., runtimeConfigModule: { Trans: [ diff --git a/packages/conf/src/getConfig.ts b/packages/conf/src/getConfig.ts index df87d5526..2a9716ede 100644 --- a/packages/conf/src/getConfig.ts +++ b/packages/conf/src/getConfig.ts @@ -3,7 +3,7 @@ import { LinguiConfigNormalized } from "./types" import { cosmiconfigSync, LoaderSync } from "cosmiconfig" import path from "path" import { makeConfig } from "./makeConfig" -import type { JITIOptions } from "jiti/dist/types" +import { createJiti } from "jiti" import pico from "picocolors" function configExists(path: string) { @@ -11,12 +11,11 @@ function configExists(path: string) { } function JitiLoader(): LoaderSync { - return (filepath, content) => { - const opts: JITIOptions = { - interopDefault: true, - } - const jiti = require("jiti")(__filename, opts) - return jiti(filepath) + return (filepath) => { + const jiti = createJiti(__filename) + + const mod = jiti(filepath) + return mod?.default ?? mod } } @@ -81,6 +80,6 @@ export function getConfig({ rootDir: result ? path.dirname(result.filepath) : defaultRootDir, ...userConfig, }, - { skipValidation } + { skipValidation, resolvedConfigPath: result.filepath } ) } diff --git a/packages/conf/src/index.test.ts b/packages/conf/src/index.test.ts index 126e2686d..d1414770f 100644 --- a/packages/conf/src/index.test.ts +++ b/packages/conf/src/index.test.ts @@ -21,7 +21,9 @@ describe("@lingui/conf", () => { }) expect(console.error).not.toBeCalled() expect(console.warn).not.toBeCalled() - expect(config).toMatchSnapshot() + expect(config).toMatchSnapshot({ + resolvedConfigPath: expect.stringContaining(".linguirc"), + }) }) }) diff --git a/packages/conf/src/makeConfig.ts b/packages/conf/src/makeConfig.ts index 9a8edb541..09d5fc9c3 100644 --- a/packages/conf/src/makeConfig.ts +++ b/packages/conf/src/makeConfig.ts @@ -15,6 +15,7 @@ export function makeConfig( userConfig: Partial, opts: { skipValidation?: boolean + resolvedConfigPath?: string } = {} ): LinguiConfigNormalized { let config: LinguiConfig = { @@ -36,10 +37,15 @@ export function makeConfig( config = normalizeRuntimeConfigModule(config) as any // `replaceRootDir` should always be the last - return replaceRootDir( + const out = replaceRootDir( config, config.rootDir ) as unknown as LinguiConfigNormalized + + return { + ...out, + resolvedConfigPath: opts.resolvedConfigPath, + } } export const defaultConfig: LinguiConfig = { diff --git a/packages/conf/src/types.ts b/packages/conf/src/types.ts index 9a55f888f..be4a17562 100644 --- a/packages/conf/src/types.ts +++ b/packages/conf/src/types.ts @@ -345,6 +345,7 @@ export type LinguiConfigNormalized = Omit< LinguiConfig, "runtimeConfigModule" > & { + resolvedConfigPath?: string fallbackLocales?: FallbackLocales runtimeConfigModule: { i18n: ModuleSourceNormalized diff --git a/packages/message-utils/src/generateMessageId.ts b/packages/message-utils/src/generateMessageId.ts index d84fc521a..0c642dc37 100644 --- a/packages/message-utils/src/generateMessageId.ts +++ b/packages/message-utils/src/generateMessageId.ts @@ -7,11 +7,15 @@ export function generateMessageId(msg: string, context = "") { } function hexToBase64(hexStr: string) { - let base64 = "" + const base64: string[] = [] + for (let i = 0; i < hexStr.length; i++) { - base64 += !((i - 1) & 1) - ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16)) - : "" + base64.push( + !((i - 1) & 1) + ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16)) + : "" + ) } - return btoa(base64) + + return btoa(base64.join("")) } diff --git a/website/docs/ref/cli.md b/website/docs/ref/cli.md index 84a291921..fc3456a97 100644 --- a/website/docs/ref/cli.md +++ b/website/docs/ref/cli.md @@ -58,6 +58,7 @@ lingui extract [files...] [--convert-from ] [--verbose] [--watch [--debounce ]] + [--workers] ``` The `extract` command scans source files to locate and extract messages, generating separate message catalogs for each language. @@ -129,6 +130,23 @@ Enable watch mode to monitor changes in files located in the paths specified in Delay the extraction by `` milliseconds, bundling multiple file changes together. +#### `--workers` {#extract-workers} + +Specifies the number of worker threads to use. + +Pass `--workers 1` to disable workers and run everything in a single process. + +By default, the tool uses a simple heuristic: + +- On machines with more than 2 cores → `cpu.count - 1` workers +- On 2-core machines → all cores + +Use the `--verbose` flag to see the actual pool size. + +Worker threads can significantly improve performance on large projects. However, on small projects they may provide little benefit or even be slightly slower due to thread startup overhead. + +A larger worker pool also increases memory usage. Adjust this value for your project to achieve the best performance. + ### `extract-template` ```shell @@ -153,6 +171,7 @@ lingui compile [--typescript] [--namespace ] [--watch [--debounce ]] + [--workers] ``` Once you have all the catalogs ready and translated, you can use this command to compile all the catalogs into minified JS/TS files. It compiles message catalogs located in the [`path`](/ref/conf#catalogs) directory and generates minified JavaScript files. The resulting file is a string that is parsed into a plain JS object using `JSON.parse`. @@ -215,6 +234,22 @@ Watch mode. Watches only for changes in locale files in your defined locale cata Delays compilation by `` milliseconds to avoid multiple compilations for subsequent file changes. +#### `--workers` {#compile-workers} + +Specifies the number of worker threads to use. +Pass `--workers 1` to disable workers and run everything in a single process. + +By default, the tool uses a simple heuristic: + +- On machines with more than 2 cores → `cpu.count - 1` workers +- On 2-core machines → all cores + +Use the `--verbose` flag to see the actual pool size. + +Worker threads can significantly improve performance on large projects. However, on small projects they may provide little benefit or even be slightly slower due to thread startup overhead. + +A larger worker pool also increases memory usage. Adjust this value for your project to achieve the best performance. + ## Configuring the Source Locale One limitation of checking for missing translations is that the English message catalog typically does not require translations since our source code is in English. This issue can be resolved by configuring the [`sourceLocale`](/ref/conf#sourcelocale) in the configuration file. diff --git a/yarn.lock b/yarn.lock index 9f68b4289..6c00599fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1403,6 +1403,15 @@ __metadata: languageName: node linkType: hard +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": 0.3.9 + checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + languageName: node + linkType: hard + "@emnapi/core@npm:^1.1.0": version: 1.3.1 resolution: "@emnapi/core@npm:1.3.1" @@ -2504,7 +2513,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.1.0": +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 83b85f72c59d1c080b4cbec0fef84528963a1b5db34e4370fa4bd1e3ff64a0d80e0cee7369d11d73c704e0286fb2865b530acac7a871088fbe92b5edf1000870 @@ -2535,6 +2544,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" @@ -2676,6 +2695,7 @@ __metadata: "@lingui/message-utils": 5.4.1 "@types/convert-source-map": ^2.0.0 "@types/micromatch": ^4.0.1 + "@types/ms": ^2.1.0 "@types/normalize-path": ^3.0.0 chokidar: 3.5.1 cli-table: ^0.3.11 @@ -2687,12 +2707,15 @@ __metadata: micromatch: ^4.0.7 mock-fs: ^5.2.0 mockdate: ^3.0.5 + ms: ^2.1.3 normalize-path: ^3.0.0 ora: ^5.1.0 picocolors: ^1.1.1 pofile: ^1.1.4 pseudolocale: ^2.0.0 source-map: ^0.8.0-beta.0 + threads: ^1.7.0 + ts-node: ^10.9.2 bin: lingui: ./dist/lingui.js languageName: unknown @@ -2706,7 +2729,7 @@ __metadata: "@lingui/jest-mocks": "*" cosmiconfig: ^8.0.0 jest-validate: ^29.4.3 - jiti: ^1.17.1 + jiti: ^2.5.1 picocolors: ^1.1.1 unbuild: ^2.0.0 languageName: unknown @@ -3991,6 +4014,34 @@ __metadata: languageName: node linkType: hard +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node10@npm:1.0.11" + checksum: 51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 + languageName: node + linkType: hard + +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a + languageName: node + linkType: hard + +"@tsconfig/node14@npm:^1.0.0": + version: 1.0.3 + resolution: "@tsconfig/node14@npm:1.0.3" + checksum: 19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d + languageName: node + linkType: hard + +"@tsconfig/node16@npm:^1.0.2": + version: 1.0.4 + resolution: "@tsconfig/node16@npm:1.0.4" + checksum: 202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff + languageName: node + linkType: hard + "@tufjs/canonical-json@npm:2.0.0": version: 2.0.0 resolution: "@tufjs/canonical-json@npm:2.0.0" @@ -4230,6 +4281,13 @@ __metadata: languageName: node linkType: hard +"@types/ms@npm:^2.1.0": + version: 2.1.0 + resolution: "@types/ms@npm:2.1.0" + checksum: 532d2ebb91937ccc4a89389715e5b47d4c66e708d15942fe6cc25add6dc37b2be058230a327dd50f43f89b8b6d5d52b74685a9e8f70516edfc9bdd6be910eff4 + languageName: node + linkType: hard + "@types/node@npm:*, @types/node@npm:20.14.8": version: 20.14.8 resolution: "@types/node@npm:20.14.8" @@ -4791,6 +4849,15 @@ __metadata: languageName: node linkType: hard +"acorn-walk@npm:^8.1.1": + version: 8.3.4 + resolution: "acorn-walk@npm:8.3.4" + dependencies: + acorn: ^8.11.0 + checksum: 4ff03f42323e7cf90f1683e08606b0f460e1e6ac263d2730e3df91c7665b6f64e696db6ea27ee4bed18c2599569be61f28a8399fa170c611161a348c402ca19c + languageName: node + linkType: hard + "acorn@npm:^7.1.1": version: 7.4.1 resolution: "acorn@npm:7.4.1" @@ -4809,6 +4876,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.11.0, acorn@npm:^8.4.1": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" + bin: + acorn: bin/acorn + checksum: 309c6b49aedf1a2e34aaf266de06de04aab6eb097c02375c66fdeb0f64556a6a823540409914fb364d9a11bc30d79d485a2eba29af47992d3490e9886c4391c3 + languageName: node + linkType: hard + "acorn@npm:^8.14.0": version: 8.14.0 resolution: "acorn@npm:8.14.0" @@ -4998,6 +5074,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 544af8dd3f60546d3e4aff084d451b96961d2267d668670199692f8d054f0415d86fc5497d0e641e91546f0aa920e7c29e5250e99fc89f5552a34b5d93b77f43 + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -5671,7 +5754,7 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": +"callsites@npm:^3.0.0, callsites@npm:^3.1.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 @@ -6345,6 +6428,13 @@ __metadata: languageName: node linkType: hard +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff + languageName: node + linkType: hard + "cross-env@npm:^7.0.2": version: 7.0.3 resolution: "cross-env@npm:7.0.3" @@ -6531,6 +6621,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.2.0": + version: 4.4.1 + resolution: "debug@npm:4.4.1" + dependencies: + ms: ^2.1.3 + peerDependenciesMeta: + supports-color: + optional: true + checksum: a43826a01cda685ee4cec00fb2d3322eaa90ccadbef60d9287debc2a886be3e835d9199c80070ede75a409ee57828c4c6cd80e4b154f2843f0dc95a570dc0729 + languageName: node + linkType: hard + "debug@npm:^4.3.2": version: 4.4.0 resolution: "debug@npm:4.4.0" @@ -6723,6 +6825,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: f2c09b0ce4e6b301c221addd83bf3f454c0bc00caa3dd837cf6c127d6edf7223aa2bbe3b688feea110b7f262adbfc845b757c44c8a9f8c0c5b15d8fa9ce9d20d + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -7741,6 +7850,13 @@ __metadata: languageName: node linkType: hard +"esm@npm:^3.2.25": + version: 3.2.25 + resolution: "esm@npm:3.2.25" + checksum: 978aabe2de83541c105605a6d60a26ed8e627ef6bb0a7605fe15a95bbdea6b8348bd045255cb22219c054dd09a81a94823df00843d9e97f42419c92015ce3a64 + languageName: node + linkType: hard + "espree@npm:^10.0.1, espree@npm:^10.3.0": version: 10.3.0 resolution: "espree@npm:10.3.0" @@ -9529,6 +9645,13 @@ __metadata: languageName: node linkType: hard +"is-observable@npm:^2.1.0": + version: 2.1.0 + resolution: "is-observable@npm:2.1.0" + checksum: 93b0e0f9b115ef4b5f0523f4930667a7809a42e9cf1b23a444f8a9c15f72b9c1729b2a4691d55a5c479a05eafd5dda9b51ed1b65336d56027b7989ecb8ef51bf + languageName: node + linkType: hard + "is-plain-obj@npm:^1.0.0, is-plain-obj@npm:^1.1.0": version: 1.1.0 resolution: "is-plain-obj@npm:1.1.0" @@ -10427,7 +10550,7 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.17.1, jiti@npm:^1.19.1, jiti@npm:^1.19.3": +"jiti@npm:^1.19.1, jiti@npm:^1.19.3": version: 1.19.3 resolution: "jiti@npm:1.19.3" bin: @@ -10445,6 +10568,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^2.5.1": + version: 2.5.1 + resolution: "jiti@npm:2.5.1" + bin: + jiti: lib/jiti-cli.mjs + checksum: db901281e01013c27d46d6c5cde5fa817082f32232c92099043df11e135d00ccd1b4356a9ba356a3293e91855bd7437b6df5ae0ae6ad2c384d9bd59df926633c + languageName: node + linkType: hard + "js-lingui-workspaces@workspace:.": version: 0.0.0-use.local resolution: "js-lingui-workspaces@workspace:." @@ -11263,7 +11395,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.3.6": +"make-error@npm:^1.1.1, make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 @@ -12406,6 +12538,13 @@ __metadata: languageName: node linkType: hard +"observable-fns@npm:^0.6.1": + version: 0.6.1 + resolution: "observable-fns@npm:0.6.1" + checksum: b575f23f90c6129a8bead1d5001dbae2d83c6d01724a4790ec8f1c7f2db352440c87eae2ffb562117cb58b4a68b4503ab3a7017a77025916993ad710cd0efdd9 + languageName: node + linkType: hard + "once@npm:^1.3.0, once@npm:^1.3.3, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -14852,6 +14991,22 @@ __metadata: languageName: node linkType: hard +"threads@npm:^1.7.0": + version: 1.7.0 + resolution: "threads@npm:1.7.0" + dependencies: + callsites: ^3.1.0 + debug: ^4.2.0 + is-observable: ^2.1.0 + observable-fns: ^0.6.1 + tiny-worker: ">= 2" + dependenciesMeta: + tiny-worker: + optional: true + checksum: 253574bc5c70d0663756d74c7a438ced64f9c6746ff550abea18b11919a24cc6b1be3322b4d0bdb8c6077e52774eb65f49549bb9deec24e693f149470c316ee1 + languageName: node + linkType: hard + "through2@npm:^2.0.0": version: 2.0.5 resolution: "through2@npm:2.0.5" @@ -14869,6 +15024,15 @@ __metadata: languageName: node linkType: hard +"tiny-worker@npm:>= 2": + version: 2.3.0 + resolution: "tiny-worker@npm:2.3.0" + dependencies: + esm: ^3.2.25 + checksum: 33492c9b0623e064dd39bc64d61e7031a3ba146ed1d6de179c3f8c2e3b965061e204e602c0b019fa363ccca1e6939fc2e8d03c4ad070450cc491d47cd5382409 + languageName: node + linkType: hard + "tinyglobby@npm:0.2.12": version: 0.2.12 resolution: "tinyglobby@npm:0.2.12" @@ -15046,6 +15210,44 @@ __metadata: languageName: node linkType: hard +"ts-node@npm:^10.9.2": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" + dependencies: + "@cspotcode/source-map-support": ^0.8.0 + "@tsconfig/node10": ^1.0.7 + "@tsconfig/node12": ^1.0.7 + "@tsconfig/node14": ^1.0.0 + "@tsconfig/node16": ^1.0.2 + acorn: ^8.4.1 + acorn-walk: ^8.1.1 + arg: ^4.1.0 + create-require: ^1.1.0 + diff: ^4.0.1 + make-error: ^1.1.1 + v8-compile-cache-lib: ^3.0.1 + yn: 3.1.1 + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: fde256c9073969e234526e2cfead42591b9a2aec5222bac154b0de2fa9e4ceb30efcd717ee8bc785a56f3a119bdd5aa27b333d9dbec94ed254bd26f8944c67ac + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.15.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" @@ -15589,6 +15791,13 @@ __metadata: languageName: node linkType: hard +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 78089ad549e21bcdbfca10c08850022b22024cdcc2da9b168bcf5a73a6ed7bf01a9cebb9eac28e03cd23a684d81e0502797e88f3ccd27a32aeab1cfc44c39da0 + languageName: node + linkType: hard + "v8-to-istanbul@npm:^9.0.1": version: 9.1.0 resolution: "v8-to-istanbul@npm:9.1.0" @@ -16303,6 +16512,13 @@ __metadata: languageName: node linkType: hard +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" From 26700f071cd540651822b7f786d3c1d07c9d8625 Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Fri, 12 Sep 2025 11:44:01 +0300 Subject: [PATCH 14/19] chore(release): published v5.5.0 [skip ci] (#2325) --- CHANGELOG.md | 7 ++ lerna.json | 2 +- .../CHANGELOG.md | 4 + .../package.json | 2 +- .../babel-plugin-lingui-macro/CHANGELOG.md | 4 + .../babel-plugin-lingui-macro/package.json | 8 +- packages/cli/CHANGELOG.md | 7 ++ packages/cli/package.json | 14 +-- packages/conf/CHANGELOG.md | 6 ++ packages/conf/package.json | 2 +- packages/core/CHANGELOG.md | 4 + packages/core/package.json | 6 +- packages/detect-locale/CHANGELOG.md | 4 + packages/detect-locale/package.json | 2 +- packages/extractor-vue/CHANGELOG.md | 4 + packages/extractor-vue/package.json | 8 +- packages/format-csv/CHANGELOG.md | 4 + packages/format-csv/package.json | 4 +- packages/format-json/CHANGELOG.md | 4 + packages/format-json/package.json | 4 +- packages/format-po-gettext/CHANGELOG.md | 4 + packages/format-po-gettext/package.json | 8 +- packages/format-po/CHANGELOG.md | 4 + packages/format-po/package.json | 6 +- packages/loader/CHANGELOG.md | 4 + packages/loader/package.json | 8 +- packages/macro/CHANGELOG.md | 4 + packages/macro/package.json | 8 +- packages/message-utils/CHANGELOG.md | 6 ++ packages/message-utils/package.json | 2 +- packages/metro-transformer/CHANGELOG.md | 4 + packages/metro-transformer/package.json | 8 +- packages/react/CHANGELOG.md | 4 + packages/react/package.json | 6 +- packages/vite-plugin/CHANGELOG.md | 4 + packages/vite-plugin/package.json | 6 +- yarn.lock | 86 +++++++++---------- 37 files changed, 177 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bba3c4a66..d8a071154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +### Features + +* add babel parser flag for import defer * as q from '...' ([#2309](https://github.com/lingui/js-lingui/issues/2309)) ([a09c973](https://github.com/lingui/js-lingui/commit/a09c973c914e3a1ab406ea6630691feef5b0c0f9)) +* **cli:** support multithreading in all cli commands ([#2320](https://github.com/lingui/js-lingui/issues/2320)) ([86fbcd8](https://github.com/lingui/js-lingui/commit/86fbcd849b82d500f67fabd7c4f6abef7e5914f2)) + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) ### Bug Fixes diff --git a/lerna.json b/lerna.json index 4d892f80a..73381f780 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.4.1", + "version": "5.5.0", "packages": ["packages/*"], "npmClient": "yarn", "command": { diff --git a/packages/babel-plugin-extract-messages/CHANGELOG.md b/packages/babel-plugin-extract-messages/CHANGELOG.md index 0d7b96023..7c6261d7c 100644 --- a/packages/babel-plugin-extract-messages/CHANGELOG.md +++ b/packages/babel-plugin-extract-messages/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/babel-plugin-extract-messages + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/babel-plugin-extract-messages diff --git a/packages/babel-plugin-extract-messages/package.json b/packages/babel-plugin-extract-messages/package.json index a229cf487..d8f27b695 100644 --- a/packages/babel-plugin-extract-messages/package.json +++ b/packages/babel-plugin-extract-messages/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-extract-messages", - "version": "5.4.1", + "version": "5.5.0", "description": "Babel plugin for collecting messages from source code for internationalization", "main": "./dist/index.cjs", "module": "./dist/index.mjs", diff --git a/packages/babel-plugin-lingui-macro/CHANGELOG.md b/packages/babel-plugin-lingui-macro/CHANGELOG.md index 137297224..4683a3b3f 100644 --- a/packages/babel-plugin-lingui-macro/CHANGELOG.md +++ b/packages/babel-plugin-lingui-macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/babel-plugin-lingui-macro + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/babel-plugin-lingui-macro diff --git a/packages/babel-plugin-lingui-macro/package.json b/packages/babel-plugin-lingui-macro/package.json index 12927f646..194bddf5f 100644 --- a/packages/babel-plugin-lingui-macro/package.json +++ b/packages/babel-plugin-lingui-macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/babel-plugin-lingui-macro", - "version": "5.4.1", + "version": "5.5.0", "description": "Babel plugin for transforming Lingui Macros", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -86,9 +86,9 @@ "@babel/core": "^7.20.12", "@babel/runtime": "^7.20.13", "@babel/types": "^7.20.7", - "@lingui/conf": "5.4.1", - "@lingui/core": "5.4.1", - "@lingui/message-utils": "5.4.1" + "@lingui/conf": "5.5.0", + "@lingui/core": "5.5.0", + "@lingui/message-utils": "5.5.0" }, "peerDependencies": { "babel-plugin-macros": "2 || 3" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 8c49ed1fb..638e4d01a 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +### Features + +* add babel parser flag for import defer * as q from '...' ([#2309](https://github.com/lingui/js-lingui/issues/2309)) ([a09c973](https://github.com/lingui/js-lingui/commit/a09c973c914e3a1ab406ea6630691feef5b0c0f9)) +* **cli:** support multithreading in all cli commands ([#2320](https://github.com/lingui/js-lingui/issues/2320)) ([86fbcd8](https://github.com/lingui/js-lingui/commit/86fbcd849b82d500f67fabd7c4f6abef7e5914f2)) + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) ### Bug Fixes diff --git a/packages/cli/package.json b/packages/cli/package.json index d69af4196..f5a612f3c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/cli", - "version": "5.4.1", + "version": "5.5.0", "description": "CLI for working wit message catalogs", "keywords": [ "cli", @@ -62,12 +62,12 @@ "@babel/parser": "^7.22.0", "@babel/runtime": "^7.21.0", "@babel/types": "^7.21.2", - "@lingui/babel-plugin-extract-messages": "5.4.1", - "@lingui/babel-plugin-lingui-macro": "5.4.1", - "@lingui/conf": "5.4.1", - "@lingui/core": "5.4.1", - "@lingui/format-po": "5.4.1", - "@lingui/message-utils": "5.4.1", + "@lingui/babel-plugin-extract-messages": "5.5.0", + "@lingui/babel-plugin-lingui-macro": "5.5.0", + "@lingui/conf": "5.5.0", + "@lingui/core": "5.5.0", + "@lingui/format-po": "5.5.0", + "@lingui/message-utils": "5.5.0", "chokidar": "3.5.1", "cli-table": "^0.3.11", "commander": "^10.0.0", diff --git a/packages/conf/CHANGELOG.md b/packages/conf/CHANGELOG.md index 365cb3c61..3b4c97d63 100644 --- a/packages/conf/CHANGELOG.md +++ b/packages/conf/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +### Features + +* **cli:** support multithreading in all cli commands ([#2320](https://github.com/lingui/js-lingui/issues/2320)) ([86fbcd8](https://github.com/lingui/js-lingui/commit/86fbcd849b82d500f67fabd7c4f6abef7e5914f2)) + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/conf diff --git a/packages/conf/package.json b/packages/conf/package.json index 07db5b390..bc8f9f9a8 100644 --- a/packages/conf/package.json +++ b/packages/conf/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/conf", - "version": "5.4.1", + "version": "5.5.0", "sideEffects": false, "description": "Get lingui configuration from package.json", "keywords": [ diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index a65c27543..9b0f274dd 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/core + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/core diff --git a/packages/core/package.json b/packages/core/package.json index d186fd158..45b34a62c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/core", - "version": "5.4.1", + "version": "5.5.0", "sideEffects": false, "description": "I18n tools for javascript", "main": "./dist/index.cjs", @@ -62,14 +62,14 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.1" + "@lingui/message-utils": "5.5.0" }, "devDependencies": { "@lingui/jest-mocks": "*", "unbuild": "2.0.0" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.1", + "@lingui/babel-plugin-lingui-macro": "5.5.0", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/detect-locale/CHANGELOG.md b/packages/detect-locale/CHANGELOG.md index e06e34d58..195eb0c64 100644 --- a/packages/detect-locale/CHANGELOG.md +++ b/packages/detect-locale/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/detect-locale + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/detect-locale diff --git a/packages/detect-locale/package.json b/packages/detect-locale/package.json index 665b2c1c3..9c791aff4 100644 --- a/packages/detect-locale/package.json +++ b/packages/detect-locale/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/detect-locale", - "version": "5.4.1", + "version": "5.5.0", "sideEffects": false, "description": "@Lingui package to help you find the correct browser/server locale", "main": "./dist/index.cjs", diff --git a/packages/extractor-vue/CHANGELOG.md b/packages/extractor-vue/CHANGELOG.md index 25851d892..4bdef968c 100644 --- a/packages/extractor-vue/CHANGELOG.md +++ b/packages/extractor-vue/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/extractor-vue + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/extractor-vue diff --git a/packages/extractor-vue/package.json b/packages/extractor-vue/package.json index 7a467936c..30742ae35 100644 --- a/packages/extractor-vue/package.json +++ b/packages/extractor-vue/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/extractor-vue", - "version": "5.4.1", + "version": "5.5.0", "description": "Custom Vue.js extractor to be used with the CLI tool", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -43,12 +43,12 @@ "/dist" ], "dependencies": { - "@lingui/cli": "5.4.1", - "@lingui/conf": "5.4.1", + "@lingui/cli": "5.5.0", + "@lingui/conf": "5.5.0", "@vue/compiler-sfc": "^3.2.47" }, "devDependencies": { - "@lingui/babel-plugin-extract-messages": "5.4.1", + "@lingui/babel-plugin-extract-messages": "5.5.0", "unbuild": "2.0.0" } } diff --git a/packages/format-csv/CHANGELOG.md b/packages/format-csv/CHANGELOG.md index ec3bcae3b..fd406912a 100644 --- a/packages/format-csv/CHANGELOG.md +++ b/packages/format-csv/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/format-csv + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/format-csv diff --git a/packages/format-csv/package.json b/packages/format-csv/package.json index a62a22dec..3b6d6fce8 100644 --- a/packages/format-csv/package.json +++ b/packages/format-csv/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-csv", - "version": "5.4.1", + "version": "5.5.0", "description": "CSV format for Lingui Catalogs", "main": "./dist/csv.cjs", "module": "./dist/csv.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.1", + "@lingui/conf": "5.5.0", "papaparse": "^5.4.0" }, "devDependencies": { diff --git a/packages/format-json/CHANGELOG.md b/packages/format-json/CHANGELOG.md index 590babd14..d1b719cf4 100644 --- a/packages/format-json/CHANGELOG.md +++ b/packages/format-json/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/format-json + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/format-json diff --git a/packages/format-json/package.json b/packages/format-json/package.json index 05dbba3af..a3852f46e 100644 --- a/packages/format-json/package.json +++ b/packages/format-json/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-json", - "version": "5.4.1", + "version": "5.5.0", "description": "JSON format for Lingui Catalogs", "main": "./dist/json.cjs", "module": "./dist/json.mjs", @@ -41,7 +41,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.1" + "@lingui/conf": "5.5.0" }, "devDependencies": { "unbuild": "^2.0.0" diff --git a/packages/format-po-gettext/CHANGELOG.md b/packages/format-po-gettext/CHANGELOG.md index 9e8744e3a..01808ae51 100644 --- a/packages/format-po-gettext/CHANGELOG.md +++ b/packages/format-po-gettext/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/format-po-gettext + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/format-po-gettext diff --git a/packages/format-po-gettext/package.json b/packages/format-po-gettext/package.json index 992db7535..6e7e4e43a 100644 --- a/packages/format-po-gettext/package.json +++ b/packages/format-po-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po-gettext", - "version": "5.4.1", + "version": "5.5.0", "description": "Gettext PO format with gettext-style plurals for Lingui Catalogs", "main": "./dist/po-gettext.cjs", "module": "./dist/po-gettext.mjs", @@ -43,9 +43,9 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.1", - "@lingui/format-po": "5.4.1", - "@lingui/message-utils": "5.4.1", + "@lingui/conf": "5.5.0", + "@lingui/format-po": "5.5.0", + "@lingui/message-utils": "5.5.0", "@messageformat/parser": "^5.0.0", "cldr-core": "^45.0.0", "node-gettext": "^3.0.0", diff --git a/packages/format-po/CHANGELOG.md b/packages/format-po/CHANGELOG.md index 8f434a16b..94207a6db 100644 --- a/packages/format-po/CHANGELOG.md +++ b/packages/format-po/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/format-po + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/format-po diff --git a/packages/format-po/package.json b/packages/format-po/package.json index ce8607c96..30f8f0454 100644 --- a/packages/format-po/package.json +++ b/packages/format-po/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/format-po", - "version": "5.4.1", + "version": "5.5.0", "description": "Gettext PO format for Lingui Catalogs", "main": "./dist/po.cjs", "module": "./dist/po.mjs", @@ -43,8 +43,8 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.4.1", - "@lingui/message-utils": "5.4.1", + "@lingui/conf": "5.5.0", + "@lingui/message-utils": "5.5.0", "date-fns": "^3.6.0", "pofile": "^1.1.4" }, diff --git a/packages/loader/CHANGELOG.md b/packages/loader/CHANGELOG.md index 9735cab77..1d98e44b6 100644 --- a/packages/loader/CHANGELOG.md +++ b/packages/loader/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/loader + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/loader diff --git a/packages/loader/package.json b/packages/loader/package.json index fbeb01b6d..a913682f9 100644 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/loader", - "version": "5.4.1", + "version": "5.5.0", "description": "webpack loader for lingui message catalogs", "types": "./dist/index.d.ts", "main": "./dist/index.cjs", @@ -45,11 +45,11 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.1", - "@lingui/conf": "5.4.1" + "@lingui/cli": "5.5.0", + "@lingui/conf": "5.5.0" }, "devDependencies": { - "@lingui/format-json": "5.4.1", + "@lingui/format-json": "5.5.0", "unbuild": "2.0.0", "webpack": "^5.76.1" }, diff --git a/packages/macro/CHANGELOG.md b/packages/macro/CHANGELOG.md index 09f065467..066127634 100644 --- a/packages/macro/CHANGELOG.md +++ b/packages/macro/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/macro + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/macro diff --git a/packages/macro/package.json b/packages/macro/package.json index cc2b9502e..d50eecd71 100644 --- a/packages/macro/package.json +++ b/packages/macro/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/macro", - "version": "5.4.1", + "version": "5.5.0", "description": "Macro for generating messages in ICU MessageFormat syntax", "main": "./index.js", "types": "./index.d.ts", @@ -46,11 +46,11 @@ "index.js" ], "dependencies": { - "@lingui/core": "5.4.1", - "@lingui/react": "5.4.1" + "@lingui/core": "5.5.0", + "@lingui/react": "5.5.0" }, "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.1", + "@lingui/babel-plugin-lingui-macro": "5.5.0", "babel-plugin-macros": "2 || 3" }, "peerDependenciesMeta": { diff --git a/packages/message-utils/CHANGELOG.md b/packages/message-utils/CHANGELOG.md index c4e355ef5..dcb1f1da7 100644 --- a/packages/message-utils/CHANGELOG.md +++ b/packages/message-utils/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +### Features + +* **cli:** support multithreading in all cli commands ([#2320](https://github.com/lingui/js-lingui/issues/2320)) ([86fbcd8](https://github.com/lingui/js-lingui/commit/86fbcd849b82d500f67fabd7c4f6abef7e5914f2)) + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) ### Bug Fixes diff --git a/packages/message-utils/package.json b/packages/message-utils/package.json index caf825462..f31ef49a8 100644 --- a/packages/message-utils/package.json +++ b/packages/message-utils/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/message-utils", - "version": "5.4.1", + "version": "5.5.0", "license": "MIT", "keywords": [], "sideEffects": false, diff --git a/packages/metro-transformer/CHANGELOG.md b/packages/metro-transformer/CHANGELOG.md index 5c71b682f..d7e118322 100644 --- a/packages/metro-transformer/CHANGELOG.md +++ b/packages/metro-transformer/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/metro-transformer + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/metro-transformer diff --git a/packages/metro-transformer/package.json b/packages/metro-transformer/package.json index abe2ee655..057ce7d34 100644 --- a/packages/metro-transformer/package.json +++ b/packages/metro-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/metro-transformer", - "version": "5.4.1", + "version": "5.5.0", "description": "Metro bundler transformer for LinguiJS catalogs", "exports": { "./expo": { @@ -58,12 +58,12 @@ ], "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.1", - "@lingui/conf": "5.4.1", + "@lingui/cli": "5.5.0", + "@lingui/conf": "5.5.0", "memoize-one": "^6.0.0" }, "devDependencies": { - "@lingui/format-json": "5.4.1", + "@lingui/format-json": "5.5.0", "rimraf": "^6.0.1", "unbuild": "2.0.0" }, diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 177633f46..2784ed757 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/react + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/react diff --git a/packages/react/package.json b/packages/react/package.json index b31156a58..8e5035839 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/react", - "version": "5.4.1", + "version": "5.5.0", "sideEffects": false, "description": "React components for translations", "main": "./dist/index.cjs", @@ -79,7 +79,7 @@ "macro/index.js" ], "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.1", + "@lingui/babel-plugin-lingui-macro": "5.5.0", "babel-plugin-macros": "2 || 3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -93,7 +93,7 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@lingui/core": "5.4.1" + "@lingui/core": "5.5.0" }, "devDependencies": { "@lingui/jest-mocks": "*", diff --git a/packages/vite-plugin/CHANGELOG.md b/packages/vite-plugin/CHANGELOG.md index 9d9a78838..c2a3e08dd 100644 --- a/packages/vite-plugin/CHANGELOG.md +++ b/packages/vite-plugin/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.5.0](https://github.com/lingui/js-lingui/compare/v5.4.1...v5.5.0) (2025-09-12) + +**Note:** Version bump only for package @lingui/vite-plugin + ## [5.4.1](https://github.com/lingui/js-lingui/compare/v5.4.0...v5.4.1) (2025-08-11) **Note:** Version bump only for package @lingui/vite-plugin diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index b97322ec8..29c875821 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@lingui/vite-plugin", - "version": "5.4.1", + "version": "5.5.0", "description": "Vite plugin for Lingui message catalogs", "main": "./dist/index.cjs", "module": "./dist/index.mjs", @@ -41,8 +41,8 @@ "dist/" ], "dependencies": { - "@lingui/cli": "5.4.1", - "@lingui/conf": "5.4.1" + "@lingui/cli": "5.5.0", + "@lingui/conf": "5.5.0" }, "peerDependencies": { "vite": "^3 || ^4 || ^5.0.9 || ^6 || ^7" diff --git a/yarn.lock b/yarn.lock index 6c00599fa..df08d2bc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2641,7 +2641,7 @@ __metadata: languageName: node linkType: hard -"@lingui/babel-plugin-extract-messages@5.4.1, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": +"@lingui/babel-plugin-extract-messages@5.5.0, @lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-extract-messages@workspace:packages/babel-plugin-extract-messages" dependencies: @@ -2654,7 +2654,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/babel-plugin-lingui-macro@5.4.1, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": +"@lingui/babel-plugin-lingui-macro@5.5.0, @lingui/babel-plugin-lingui-macro@workspace:*, @lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro": version: 0.0.0-use.local resolution: "@lingui/babel-plugin-lingui-macro@workspace:packages/babel-plugin-lingui-macro" dependencies: @@ -2663,9 +2663,9 @@ __metadata: "@babel/runtime": ^7.20.13 "@babel/traverse": ^7.20.12 "@babel/types": ^7.20.7 - "@lingui/conf": 5.4.1 - "@lingui/core": 5.4.1 - "@lingui/message-utils": 5.4.1 + "@lingui/conf": 5.5.0 + "@lingui/core": 5.5.0 + "@lingui/message-utils": 5.5.0 "@types/babel-plugin-macros": ^2.8.5 prettier: 2.8.3 unbuild: 2.0.0 @@ -2677,7 +2677,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/cli@5.4.1, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": +"@lingui/cli@5.5.0, @lingui/cli@workspace:*, @lingui/cli@workspace:packages/cli": version: 0.0.0-use.local resolution: "@lingui/cli@workspace:packages/cli" dependencies: @@ -2686,13 +2686,13 @@ __metadata: "@babel/parser": ^7.22.0 "@babel/runtime": ^7.21.0 "@babel/types": ^7.21.2 - "@lingui/babel-plugin-extract-messages": 5.4.1 - "@lingui/babel-plugin-lingui-macro": 5.4.1 - "@lingui/conf": 5.4.1 - "@lingui/core": 5.4.1 - "@lingui/format-po": 5.4.1 + "@lingui/babel-plugin-extract-messages": 5.5.0 + "@lingui/babel-plugin-lingui-macro": 5.5.0 + "@lingui/conf": 5.5.0 + "@lingui/core": 5.5.0 + "@lingui/format-po": 5.5.0 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.4.1 + "@lingui/message-utils": 5.5.0 "@types/convert-source-map": ^2.0.0 "@types/micromatch": ^4.0.1 "@types/ms": ^2.1.0 @@ -2721,7 +2721,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/conf@5.4.1, @lingui/conf@workspace:packages/conf": +"@lingui/conf@5.5.0, @lingui/conf@workspace:packages/conf": version: 0.0.0-use.local resolution: "@lingui/conf@workspace:packages/conf" dependencies: @@ -2735,16 +2735,16 @@ __metadata: languageName: unknown linkType: soft -"@lingui/core@5.4.1, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": +"@lingui/core@5.5.0, @lingui/core@workspace:*, @lingui/core@workspace:^, @lingui/core@workspace:packages/core": version: 0.0.0-use.local resolution: "@lingui/core@workspace:packages/core" dependencies: "@babel/runtime": ^7.20.13 "@lingui/jest-mocks": "*" - "@lingui/message-utils": 5.4.1 + "@lingui/message-utils": 5.5.0 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.1 + "@lingui/babel-plugin-lingui-macro": 5.5.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2777,9 +2777,9 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/extractor-vue@workspace:packages/extractor-vue" dependencies: - "@lingui/babel-plugin-extract-messages": 5.4.1 - "@lingui/cli": 5.4.1 - "@lingui/conf": 5.4.1 + "@lingui/babel-plugin-extract-messages": 5.5.0 + "@lingui/cli": 5.5.0 + "@lingui/conf": 5.5.0 "@vue/compiler-sfc": ^3.2.47 unbuild: 2.0.0 languageName: unknown @@ -2789,17 +2789,17 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-csv@workspace:packages/format-csv" dependencies: - "@lingui/conf": 5.4.1 + "@lingui/conf": 5.5.0 papaparse: ^5.4.0 unbuild: 2.0.0 languageName: unknown linkType: soft -"@lingui/format-json@5.4.1, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": +"@lingui/format-json@5.5.0, @lingui/format-json@workspace:^, @lingui/format-json@workspace:packages/format-json": version: 0.0.0-use.local resolution: "@lingui/format-json@workspace:packages/format-json" dependencies: - "@lingui/conf": 5.4.1 + "@lingui/conf": 5.5.0 unbuild: ^2.0.0 languageName: unknown linkType: soft @@ -2808,10 +2808,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/format-po-gettext@workspace:packages/format-po-gettext" dependencies: - "@lingui/conf": 5.4.1 - "@lingui/format-po": 5.4.1 + "@lingui/conf": 5.5.0 + "@lingui/format-po": 5.5.0 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.4.1 + "@lingui/message-utils": 5.5.0 "@messageformat/parser": ^5.0.0 cldr-core: ^45.0.0 mockdate: ^3.0.5 @@ -2822,13 +2822,13 @@ __metadata: languageName: unknown linkType: soft -"@lingui/format-po@5.4.1, @lingui/format-po@workspace:packages/format-po": +"@lingui/format-po@5.5.0, @lingui/format-po@workspace:packages/format-po": version: 0.0.0-use.local resolution: "@lingui/format-po@workspace:packages/format-po" dependencies: - "@lingui/conf": 5.4.1 + "@lingui/conf": 5.5.0 "@lingui/jest-mocks": "workspace:^" - "@lingui/message-utils": 5.4.1 + "@lingui/message-utils": 5.5.0 date-fns: ^3.6.0 mockdate: ^3.0.5 pofile: ^1.1.4 @@ -2847,9 +2847,9 @@ __metadata: resolution: "@lingui/loader@workspace:packages/loader" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.4.1 - "@lingui/conf": 5.4.1 - "@lingui/format-json": 5.4.1 + "@lingui/cli": 5.5.0 + "@lingui/conf": 5.5.0 + "@lingui/format-json": 5.5.0 unbuild: 2.0.0 webpack: ^5.76.1 peerDependencies: @@ -2861,10 +2861,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/macro@workspace:packages/macro" dependencies: - "@lingui/core": 5.4.1 - "@lingui/react": 5.4.1 + "@lingui/core": 5.5.0 + "@lingui/react": 5.5.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.1 + "@lingui/babel-plugin-lingui-macro": 5.5.0 babel-plugin-macros: 2 || 3 peerDependenciesMeta: "@lingui/babel-plugin-lingui-macro": @@ -2874,7 +2874,7 @@ __metadata: languageName: unknown linkType: soft -"@lingui/message-utils@5.4.1, @lingui/message-utils@workspace:packages/message-utils": +"@lingui/message-utils@5.5.0, @lingui/message-utils@workspace:packages/message-utils": version: 0.0.0-use.local resolution: "@lingui/message-utils@workspace:packages/message-utils" dependencies: @@ -2900,9 +2900,9 @@ __metadata: resolution: "@lingui/metro-transformer@workspace:packages/metro-transformer" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/cli": 5.4.1 - "@lingui/conf": 5.4.1 - "@lingui/format-json": 5.4.1 + "@lingui/cli": 5.5.0 + "@lingui/conf": 5.5.0 + "@lingui/format-json": 5.5.0 memoize-one: ^6.0.0 rimraf: ^6.0.1 unbuild: 2.0.0 @@ -2921,12 +2921,12 @@ __metadata: languageName: unknown linkType: soft -"@lingui/react@5.4.1, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": +"@lingui/react@5.5.0, @lingui/react@workspace:*, @lingui/react@workspace:packages/react": version: 0.0.0-use.local resolution: "@lingui/react@workspace:packages/react" dependencies: "@babel/runtime": ^7.20.13 - "@lingui/core": 5.4.1 + "@lingui/core": 5.5.0 "@lingui/jest-mocks": "*" "@testing-library/react": ^14.0.0 "@types/react": ^18.2.13 @@ -2936,7 +2936,7 @@ __metadata: react-dom: ^18.2.0 unbuild: 2.0.0 peerDependencies: - "@lingui/babel-plugin-lingui-macro": 5.4.1 + "@lingui/babel-plugin-lingui-macro": 5.5.0 babel-plugin-macros: 2 || 3 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -2961,8 +2961,8 @@ __metadata: version: 0.0.0-use.local resolution: "@lingui/vite-plugin@workspace:packages/vite-plugin" dependencies: - "@lingui/cli": 5.4.1 - "@lingui/conf": 5.4.1 + "@lingui/cli": 5.5.0 + "@lingui/conf": 5.5.0 "@lingui/core": "workspace:^" "@lingui/format-json": "workspace:^" unbuild: 2.0.0 From 3a8efa516ff688caa5688234b6a821b84dd572ea Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Mon, 15 Sep 2025 17:03:08 +0300 Subject: [PATCH 15/19] ci: trusted publishing (#2327) --- .github/workflows/release.yml | 36 ++++--------------- .github/workflows/version-bump.yml | 55 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/version-bump.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a464566c7..4b8d1c984 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,9 +3,9 @@ name: release on: workflow_dispatch: inputs: - npmTag: + versionType: type: choice - description: 'NPM tag to release' + description: 'Version type to publish' options: - latest - next @@ -13,8 +13,11 @@ on: default: "latest" jobs: - release: + publish: runs-on: ubuntu-latest + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 @@ -35,32 +38,7 @@ jobs: - name: Build packages run: yarn release:build - - name: Unit Testing - run: yarn test:ci - - - name: Linting & Types - run: yarn lint:all - - - name: Creates local .npmrc - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc - - - name: Prepare Lingui-Bot git account - uses: oleksiyrudenko/gha-git-credentials@v2-latest - with: - name: 'Lingui Bot' - email: 'linguibot@gmail.com' - actor: 'lingui-bot' - token: '${{ secrets.GH_TOKEN }}' - - - name: Versioning packages - env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - run: yarn version:${{github.event.inputs.npmTag}} - - - name: Packaging packages with newer version - run: yarn release:build - - name: Publishing packages env: GH_TOKEN: ${{ secrets.GH_TOKEN }} - run: yarn release:${{github.event.inputs.npmTag}} + run: yarn release:${{github.event.inputs.versionType}} diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml new file mode 100644 index 000000000..0ef1f31ac --- /dev/null +++ b/.github/workflows/version-bump.yml @@ -0,0 +1,55 @@ +name: version-bump + +on: + workflow_dispatch: + inputs: + versionType: + type: choice + description: 'Version type to bump' + options: + - latest + - next + required: true + default: "latest" + +jobs: + version-bump: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup node + uses: actions/setup-node@v4 + with: + always-auth: true + node-version: 20 + cache: 'yarn' + scope: '@lingui' + + - name: Install dependencies if needed + run: yarn install + + - name: Build packages + run: yarn release:build + + - name: Unit Testing + run: yarn test:ci + + - name: Linting & Types + run: yarn lint:all + + - name: Prepare Lingui-Bot git account + uses: oleksiyrudenko/gha-git-credentials@v2-latest + with: + name: 'Lingui Bot' + email: 'linguibot@gmail.com' + actor: 'lingui-bot' + token: '${{ secrets.GH_TOKEN }}' + + - name: Versioning packages + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + run: yarn version:${{github.event.inputs.versionType}} From f9ffc597790c7145e35bc762f3d96366229d56d2 Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Wed, 17 Sep 2025 10:29:30 +0300 Subject: [PATCH 16/19] ci: explicitly install NPM CLI in the release workflow (#2328) --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b8d1c984..5962d097a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,6 +38,9 @@ jobs: - name: Build packages run: yarn release:build + - name: Install npm CLI + run: yarn global add npm + - name: Publishing packages env: GH_TOKEN: ${{ secrets.GH_TOKEN }} From 551950e1f743757101f036cd36282765c4203105 Mon Sep 17 00:00:00 2001 From: Jessica Chong Date: Mon, 22 Sep 2025 23:17:11 -0700 Subject: [PATCH 17/19] docs: Add Gamma to showroom.md (#2329) --- website/docs/misc/showroom.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/misc/showroom.md b/website/docs/misc/showroom.md index d793e0143..12a948aa5 100644 --- a/website/docs/misc/showroom.md +++ b/website/docs/misc/showroom.md @@ -41,6 +41,7 @@ Here are some of them: - [mapflow.ai](https://mapflow.ai) - [lefun.fun](https://lefun.fun) - [Rove.me](https://rove.me) +- [Gamma](https://gamma.app) :::tip Do you use Lingui in production or for hobby project? Please [let us know](https://github.com/lingui/js-lingui/discussions/1404) or [send a PR](https://github.com/lingui/js-lingui/pulls) to list your project here. From 25303c25404ad81e50d7b55840f05a11bd7d7f52 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Mon, 29 Sep 2025 14:45:18 +0200 Subject: [PATCH 18/19] refactor: avoid unnecessary object spreads in Trans (#2333) --- packages/react/src/TransNoContext.tsx | 73 +++++++++++++++------------ packages/react/src/format.ts | 10 ++-- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/packages/react/src/TransNoContext.tsx b/packages/react/src/TransNoContext.tsx index 633970271..cb9278feb 100644 --- a/packages/react/src/TransNoContext.tsx +++ b/packages/react/src/TransNoContext.tsx @@ -52,39 +52,7 @@ export function TransNoContext( lingui: { i18n, defaultComponent }, } = props - const values = { ...props.values } - const components = { ...props.components } - - if (values) { - /* - Replace values placeholders with and add values to `components`. - This makes them processed as JSX children and follow JSX semantics. - - Related discussion: https://github.com/lingui/js-lingui/issues/1904 - - Another use-case is when React components directly passed as values: - - Example: - Translation: 'Hello {name}' - Values: { name: Jane } - - It'll become "Hello <0 />" with components=[Jane] - - Related discussion: https://github.com/lingui/js-lingui/issues/183 - */ - Object.keys(values).forEach((key) => { - const index = Object.keys(components).length - - // simple scalars should be processed as values to be able to apply formatting - if (typeof values[key] === "string" || typeof values[key] === "number") { - return - } - - // react components, arrays, falsy values, all should be processed as JSX children - components[index] = <>{values[key] as ReactNode} - values[key] = `<${index}/>` - }) - } + const { values, components } = getInterpolationValuesAndComponents(props) const _translation: string = i18n && typeof i18n._ === "function" @@ -146,3 +114,42 @@ const RenderFragment = ({ children }: TransRenderProps) => { // cannot use React.Fragment directly because we're passing in props that it doesn't support return {children} } + +const getInterpolationValuesAndComponents = (props: TransProps) => { + if (!props.values) { + return { + values: undefined, + components: props.components, + } + } + + const values = { ...props.values } + const components = { ...props.components } + /* + Replace values placeholders with and add values to `components`. + This makes them processed as JSX children and follow JSX semantics. + + Related discussion: https://github.com/lingui/js-lingui/issues/1904 + + Another use-case is when React components are directly passed as values: + + Example: + Translation: 'Hello {name}' + Values: { name: Jane } + + It'll become "Hello <0 />" with components=[Jane] + + Related discussion: https://github.com/lingui/js-lingui/issues/183 + */ + Object.entries(props.values).forEach(([key, valueForKey]) => { + // simple scalars should be processed as values to be able to apply formatting + if (typeof valueForKey === "string" || typeof valueForKey === "number") { + return + } + const index = Object.keys(components).length + // react components, arrays, falsy values, all should be processed as JSX children + components[index] = <>{valueForKey as ReactNode} + values[key] = `<${index}/>` + }) + return { values, components } +} diff --git a/packages/react/src/format.ts b/packages/react/src/format.ts index d4f2eeac5..7ae1e4dfe 100644 --- a/packages/react/src/format.ts +++ b/packages/react/src/format.ts @@ -27,20 +27,20 @@ const voidElementTags = { /** * `formatElements` - parse string and return tree of react elements * - * `value` is string to be formatted with Paired or (unpaired) - * placeholders. `elements` is a array of react elements which indexes - * correspond to element indexes in formatted string + * `value` is a string to be formatted with Paired or (unpaired) + * placeholders. `elements` is an array of react elements whose indexes + * correspond to element indexes in the formatted string */ function formatElements( value: string, elements: { [key: string]: React.ReactElement } = {} ): string | React.ReactElement | Array { - const uniqueId = makeCounter(0, "$lingui$") const parts = value.split(tagRe) - // no inline elements, return if (parts.length === 1) return value + const uniqueId = makeCounter(0, "$lingui$") + const tree: Array = [] const before = parts.shift() From 0819886702a57c8faa53576d5b202b48549075e6 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Mon, 29 Sep 2025 14:45:32 +0200 Subject: [PATCH 19/19] refactor: enable strictNullChecks in conf package (#2334) --- .../cli/src/api/catalog/getFallbackListForLocale.ts | 7 +++++-- packages/conf/src/getConfig.ts | 4 ++-- packages/conf/src/migrations/setCldrParentLocales.ts | 2 +- packages/conf/src/types.ts | 11 ++++++----- packages/conf/src/utils/replaceRootDir.ts | 5 ++++- packages/conf/tsconfig.json | 1 - 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/cli/src/api/catalog/getFallbackListForLocale.ts b/packages/cli/src/api/catalog/getFallbackListForLocale.ts index 1291fd0d5..9e2c87693 100644 --- a/packages/cli/src/api/catalog/getFallbackListForLocale.ts +++ b/packages/cli/src/api/catalog/getFallbackListForLocale.ts @@ -11,8 +11,11 @@ export function getFallbackListForLocale( Array.isArray(mapping) ? fL.push(...mapping) : fL.push(mapping) } - if (fallbackLocales?.default && locale !== fallbackLocales?.default) { - fL.push(fallbackLocales?.default) + if ( + typeof fallbackLocales?.default === "string" && + locale !== fallbackLocales?.default + ) { + fL.push(fallbackLocales.default) } return fL diff --git a/packages/conf/src/getConfig.ts b/packages/conf/src/getConfig.ts index 2a9716ede..d9f7f612a 100644 --- a/packages/conf/src/getConfig.ts +++ b/packages/conf/src/getConfig.ts @@ -6,8 +6,8 @@ import { makeConfig } from "./makeConfig" import { createJiti } from "jiti" import pico from "picocolors" -function configExists(path: string) { - return path && fs.existsSync(path) +function configExists(path?: string): path is string { + return !!path && fs.existsSync(path) } function JitiLoader(): LoaderSync { diff --git a/packages/conf/src/migrations/setCldrParentLocales.ts b/packages/conf/src/migrations/setCldrParentLocales.ts index 54d9e0019..520a6a126 100644 --- a/packages/conf/src/migrations/setCldrParentLocales.ts +++ b/packages/conf/src/migrations/setCldrParentLocales.ts @@ -10,7 +10,7 @@ export function setCldrParentLocales( } as unknown as LinguiConfigNormalized } - if (!config.fallbackLocales.default) { + if (!config.fallbackLocales?.default) { config.locales.forEach((locale) => { const fl = getCldrParentLocale(locale.toLowerCase()) if (fl && !(config.fallbackLocales as FallbackLocales)[locale]) { diff --git a/packages/conf/src/types.ts b/packages/conf/src/types.ts index be4a17562..07e26c2ad 100644 --- a/packages/conf/src/types.ts +++ b/packages/conf/src/types.ts @@ -106,10 +106,11 @@ export type CatalogConfig = { exclude?: string[] } -type LocaleObject = { - [locale: string]: string[] | string - default?: string -} +type LocaleObject = + | Record + | (Record & { + default: string + }) export type FallbackLocales = LocaleObject @@ -257,7 +258,7 @@ export type LinguiConfig = { * * Note that using as a string token in any other path-based config settings will refer back to this value. * - * @defaul: The root of the directory containing your Lingui configuration file or the package.json. + * @default: The root of the directory containing your Lingui configuration file or the package.json. */ rootDir?: string /** diff --git a/packages/conf/src/utils/replaceRootDir.ts b/packages/conf/src/utils/replaceRootDir.ts index 71e100043..543252b09 100644 --- a/packages/conf/src/utils/replaceRootDir.ts +++ b/packages/conf/src/utils/replaceRootDir.ts @@ -2,8 +2,11 @@ import { LinguiConfig } from "../types" export function replaceRootDir>( config: T, - rootDir: string + rootDir: string | undefined ): T { + if (!rootDir) { + return config + } return (function replaceDeep(value: any, rootDir: string): any { const replace = (s: string) => s.replace("", rootDir) diff --git a/packages/conf/tsconfig.json b/packages/conf/tsconfig.json index a286307af..87e13e4fa 100644 --- a/packages/conf/tsconfig.json +++ b/packages/conf/tsconfig.json @@ -10,7 +10,6 @@ "resolveJsonModule": true, "skipLibCheck": true, "strict": true, - "strictNullChecks": false }, "files": [ "./src/index.ts"