diff --git a/packages/cli/package.json b/packages/cli/package.json index a169a2919..c1889b815 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -71,6 +71,7 @@ "micromatch": "4.0.2", "normalize-path": "^3.0.0", "ora": "^5.1.0", + "pathe": "^1.1.0", "pkg-up": "^3.1.0", "pofile": "^1.1.4", "pseudolocale": "^2.0.0", diff --git a/packages/cli/src/api/catalog/getCatalogDependentFiles.test.ts b/packages/cli/src/api/catalog/getCatalogDependentFiles.test.ts index ded62ee4e..6c8b578be 100644 --- a/packages/cli/src/api/catalog/getCatalogDependentFiles.test.ts +++ b/packages/cli/src/api/catalog/getCatalogDependentFiles.test.ts @@ -2,6 +2,7 @@ import { getCatalogDependentFiles, getFormat } from "@lingui/cli/api" import { makeConfig } from "@lingui/conf" import { Catalog } from "../catalog" import { FormatterWrapper } from "../formats" +import mockFs from "mock-fs" describe("getCatalogDependentFiles", () => { let format: FormatterWrapper @@ -9,8 +10,22 @@ describe("getCatalogDependentFiles", () => { beforeAll(async () => { format = await getFormat("po", {}, "en") }) + afterEach(() => { + mockFs.restore() + }) + + it("Should return list template + fallbacks + sourceLocale", async () => { + mockFs({ + "src/locales": { + "messages.pot": "bla", + "en.po": "bla", + "pl.po": "bla", + "es.po": "bla", + "pt-PT.po": "bla", + "pt-BR.po": "bla", + }, + }) - it("Should return list template + fallbacks + sourceLocale", () => { const config = makeConfig( { locales: ["en", "pl", "es", "pt-PT", "pt-BR"], @@ -34,7 +49,10 @@ describe("getCatalogDependentFiles", () => { config ) - expect(getCatalogDependentFiles(catalog, "pt-PT")).toMatchInlineSnapshot(` + const actual = await getCatalogDependentFiles(catalog, "pt-PT") + mockFs.restore() + + expect(actual).toMatchInlineSnapshot(` [ src/locales/messages.pot, src/locales/pt-BR.po, @@ -43,7 +61,18 @@ describe("getCatalogDependentFiles", () => { `) }) - it("Should not return itself", () => { + it("Should not return itself", async () => { + mockFs({ + "src/locales": { + "messages.pot": "bla", + "en.po": "bla", + "pl.po": "bla", + "es.po": "bla", + "pt-PT.po": "bla", + "pt-BR.po": "bla", + }, + }) + const config = makeConfig( { locales: ["en", "pl", "es", "pt-PT", "pt-BR"], @@ -67,10 +96,59 @@ describe("getCatalogDependentFiles", () => { config ) - expect(getCatalogDependentFiles(catalog, "en")).toMatchInlineSnapshot(` + const actual = await getCatalogDependentFiles(catalog, "en") + mockFs.restore() + + expect(actual).toMatchInlineSnapshot(` [ src/locales/messages.pot, ] `) }) + + it("Should not return non-existing files", async () => { + mockFs({ + "src/locales": { + // "messages.pot": "bla", + "en.po": "bla", + "pl.po": "bla", + "es.po": "bla", + "pt-PT.po": "bla", + "pt-BR.po": "bla", + }, + }) + + const config = makeConfig( + { + locales: ["en", "pl", "es", "pt-PT", "pt-BR"], + sourceLocale: "en", + fallbackLocales: { + "pt-PT": "pt-BR", + default: "en", + }, + }, + { skipValidation: true } + ) + + const catalog = new Catalog( + { + name: null, + path: "src/locales/{locale}", + include: ["src/"], + exclude: [], + format, + }, + config + ) + + const actual = await getCatalogDependentFiles(catalog, "pt-PT") + mockFs.restore() + + expect(actual).toMatchInlineSnapshot(` + [ + src/locales/pt-BR.po, + src/locales/en.po, + ] + `) + }) }) diff --git a/packages/cli/src/api/catalog/getCatalogDependentFiles.ts b/packages/cli/src/api/catalog/getCatalogDependentFiles.ts index 8b5fbf31b..8c2459b01 100644 --- a/packages/cli/src/api/catalog/getCatalogDependentFiles.ts +++ b/packages/cli/src/api/catalog/getCatalogDependentFiles.ts @@ -1,13 +1,18 @@ import { Catalog } from "../catalog" import { getFallbackListForLocale } from "./getFallbackListForLocale" +import path from "pathe" +import fs from "node:fs/promises" + +const fileExists = async (path: string) => + !!(await fs.stat(path).catch(() => false)) /** * Return all files catalog implicitly depends on. */ -export function getCatalogDependentFiles( +export async function getCatalogDependentFiles( catalog: Catalog, locale: string -): string[] { +): Promise { const files = new Set([catalog.templateFile]) getFallbackListForLocale(catalog.config.fallbackLocales, locale).forEach( (locale) => { @@ -19,5 +24,14 @@ export function getCatalogDependentFiles( files.add(catalog.getFilename(catalog.config.sourceLocale)) } - return Array.from(files.values()) + const out: string[] = [] + + for (const file of files) { + const filePath = path.join(catalog.config.rootDir, file) + if (await fileExists(filePath)) { + out.push(filePath) + } + } + + return out } diff --git a/packages/loader/src/webpackLoader.ts b/packages/loader/src/webpackLoader.ts index 19a540b33..7c44521be 100644 --- a/packages/loader/src/webpackLoader.ts +++ b/packages/loader/src/webpackLoader.ts @@ -29,9 +29,8 @@ const loader: LoaderDefinitionFunction = async function ( await getCatalogs(config) ) - getCatalogDependentFiles(catalog, locale).forEach((locale) => { - this.addDependency(catalog.getFilename(locale)) - }) + const dependency = await getCatalogDependentFiles(catalog, locale) + dependency.forEach((file) => this.addDependency(file)) const messages = await catalog.getTranslations(locale, { fallbackLocales: config.fallbackLocales, diff --git a/packages/loader/test/json-format/lingui.config.ts b/packages/loader/test/json-format/lingui.config.ts index 174399ac6..60943a07b 100644 --- a/packages/loader/test/json-format/lingui.config.ts +++ b/packages/loader/test/json-format/lingui.config.ts @@ -7,5 +7,8 @@ export default { path: "/locale/{locale}", }, ], + fallbackLocales: { + default: "en", + }, format: formatter({ style: "minimal" }), } diff --git a/packages/loader/test/po-format/.linguirc b/packages/loader/test/po-format/.linguirc index ddd83ead8..67cebe732 100644 --- a/packages/loader/test/po-format/.linguirc +++ b/packages/loader/test/po-format/.linguirc @@ -3,5 +3,8 @@ "catalogs": [{ "path": "/locale/{locale}" }], + "fallbackLocales": { + "default": "en" + }, "format": "po" } diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index d18679ede..4575d2cc1 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -53,9 +53,8 @@ Please check that catalogs.path is filled properly.\n` const { locale, catalog } = fileCatalog - getCatalogDependentFiles(catalog, locale).forEach((locale) => { - this.addWatchFile(catalog.getFilename(locale)) - }) + const dependency = await getCatalogDependentFiles(catalog, locale) + dependency.forEach((file) => this.addWatchFile(file)) const messages = await catalog.getTranslations(locale, { fallbackLocales: config.fallbackLocales, diff --git a/packages/vite-plugin/test/json-format/lingui.config.ts b/packages/vite-plugin/test/json-format/lingui.config.ts index 174399ac6..60943a07b 100644 --- a/packages/vite-plugin/test/json-format/lingui.config.ts +++ b/packages/vite-plugin/test/json-format/lingui.config.ts @@ -7,5 +7,8 @@ export default { path: "/locale/{locale}", }, ], + fallbackLocales: { + default: "en", + }, format: formatter({ style: "minimal" }), } diff --git a/packages/vite-plugin/test/po-format/.linguirc b/packages/vite-plugin/test/po-format/.linguirc index ddd83ead8..67cebe732 100644 --- a/packages/vite-plugin/test/po-format/.linguirc +++ b/packages/vite-plugin/test/po-format/.linguirc @@ -3,5 +3,8 @@ "catalogs": [{ "path": "/locale/{locale}" }], + "fallbackLocales": { + "default": "en" + }, "format": "po" } diff --git a/yarn.lock b/yarn.lock index 36c899485..f70b3dc4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2694,6 +2694,7 @@ __metadata: mockdate: ^3.0.5 normalize-path: ^3.0.0 ora: ^5.1.0 + pathe: ^1.1.0 pkg-up: ^3.1.0 pofile: ^1.1.4 pseudolocale: ^2.0.0