From 813b7f4639c4925662e0902172d284b900d2d2d5 Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Tue, 21 Mar 2023 14:26:10 +0100 Subject: [PATCH] ref(cli): extend formatters api with source lang (#1542) --- packages/cli/src/api/catalog.test.ts | 4 +- .../cli/src/api/catalog/getCatalogs.test.ts | 6 +- packages/cli/src/api/catalog/getCatalogs.ts | 12 +- .../src/api/formats/formatterWrapper.test.ts | 124 +++++++++++------- .../cli/src/api/formats/formatterWrapper.ts | 4 +- packages/cli/src/api/formats/index.ts | 7 +- .../getExperimentalCatalogs.ts | 3 +- packages/cli/src/lingui-compile.ts | 6 +- .../cli/src/lingui-extract-experimental.ts | 3 +- packages/cli/src/tests.ts | 6 +- packages/conf/src/types.ts | 9 +- packages/format-json/src/json.test.ts | 16 ++- website/docs/guides/custom-formatter.md | 4 +- 13 files changed, 134 insertions(+), 70 deletions(-) diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts index e33b740a8..e338c9299 100644 --- a/packages/cli/src/api/catalog.test.ts +++ b/packages/cli/src/api/catalog.test.ts @@ -39,7 +39,7 @@ describe("Catalog", () => { let format: FormatterWrapper beforeAll(async () => { - format = await getFormat("po", {}) + format = await getFormat("po", {}, "en") }) afterEach(() => { @@ -595,7 +595,7 @@ describe("writeCompiled", () => { path: path.join(localeDir, "{locale}", "messages"), include: [], exclude: [], - format: await getFormat("po", {}), + format: await getFormat("po", {}, "en"), }, mockConfig() ) diff --git a/packages/cli/src/api/catalog/getCatalogs.test.ts b/packages/cli/src/api/catalog/getCatalogs.test.ts index 7229e452d..70a8e4c31 100644 --- a/packages/cli/src/api/catalog/getCatalogs.test.ts +++ b/packages/cli/src/api/catalog/getCatalogs.test.ts @@ -25,7 +25,7 @@ describe("getCatalogs", () => { let format: FormatterWrapper beforeAll(async () => { - format = await getFormat("po", {}) + format = await getFormat("po", {}, "en") }) afterEach(() => { @@ -254,7 +254,7 @@ describe("getCatalogForMerge", () => { let format: FormatterWrapper beforeAll(async () => { - format = await getFormat("po", {}) + format = await getFormat("po", {}, "en") }) afterEach(() => { @@ -333,7 +333,7 @@ describe("getCatalogForFile", () => { let format: FormatterWrapper beforeAll(async () => { - format = await getFormat("po", {}) + format = await getFormat("po", {}, "en") }) it("should return null if catalog cannot be found", () => { diff --git a/packages/cli/src/api/catalog/getCatalogs.ts b/packages/cli/src/api/catalog/getCatalogs.ts index 7c52086fc..f764a33e6 100644 --- a/packages/cli/src/api/catalog/getCatalogs.ts +++ b/packages/cli/src/api/catalog/getCatalogs.ts @@ -19,7 +19,11 @@ export async function getCatalogs( const catalogsConfig = config.catalogs const catalogs: Catalog[] = [] - const format = await getFormat(config.format, config.formatOptions) + const format = await getFormat( + config.format, + config.formatOptions, + config.sourceLocale + ) catalogsConfig.forEach((catalog) => { validateCatalogPath(catalog.path, format.getCatalogExtension()) @@ -105,7 +109,11 @@ const ensureArray = (value: Array | T | null | undefined): Array => { * Create catalog for merged messages. */ export async function getCatalogForMerge(config: LinguiConfigNormalized) { - const format = await getFormat(config.format, config.formatOptions) + const format = await getFormat( + config.format, + config.formatOptions, + config.sourceLocale + ) validateCatalogPath(config.catalogsMergePath, format.getCatalogExtension()) return new Catalog( diff --git a/packages/cli/src/api/formats/formatterWrapper.test.ts b/packages/cli/src/api/formats/formatterWrapper.test.ts index 671c35fdc..8f65da76c 100644 --- a/packages/cli/src/api/formats/formatterWrapper.test.ts +++ b/packages/cli/src/api/formats/formatterWrapper.test.ts @@ -4,23 +4,29 @@ import fs from "fs" describe("FormatterWrapper", () => { it("should return template and catalog extension", () => { - const wrapper = new FormatterWrapper({ - serialize: () => "", - parse: () => ({}), - catalogExtension: ".po", - templateExtension: ".pot", - }) + const wrapper = new FormatterWrapper( + { + serialize: () => "", + parse: () => ({}), + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) expect(wrapper.getCatalogExtension()).toBe(".po") expect(wrapper.getTemplateExtension()).toBe(".pot") }) it("should return catalog extension for templateExtension if not defined", () => { - const wrapper = new FormatterWrapper({ - serialize: () => "", - parse: () => ({}), - catalogExtension: ".po", - templateExtension: null, - }) + const wrapper = new FormatterWrapper( + { + serialize: () => "", + parse: () => ({}), + catalogExtension: ".po", + templateExtension: null, + }, + "en" + ) expect(wrapper.getCatalogExtension()).toBe(".po") expect(wrapper.getTemplateExtension()).toBe(".po") @@ -28,12 +34,15 @@ describe("FormatterWrapper", () => { describe("read", () => { it("should not throw if file not exists", async () => { - const format = new FormatterWrapper({ - serialize: () => "", - parse: () => ({}), - catalogExtension: ".po", - templateExtension: ".pot", - }) + const format = new FormatterWrapper( + { + serialize: () => "", + parse: () => ({}), + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) mockFs({}) @@ -46,12 +55,15 @@ describe("FormatterWrapper", () => { const parseMock = jest .fn() .mockImplementation((content: string) => content.split(",") as any) - const format = new FormatterWrapper({ - serialize: () => "", - parse: parseMock, - catalogExtension: ".po", - templateExtension: ".pot", - }) + const format = new FormatterWrapper( + { + serialize: () => "", + parse: parseMock, + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) mockFs({ "test.file": "red,green,blue", @@ -65,6 +77,7 @@ describe("FormatterWrapper", () => { { filename: test.file, locale: en, + sourceLocale: en, }, ] `) @@ -72,14 +85,17 @@ describe("FormatterWrapper", () => { }) it("should rethrow error with filename if failed to parse file", async () => { - const format = new FormatterWrapper({ - serialize: () => "", - parse: () => { - throw new Error("Unable to parse") + const format = new FormatterWrapper( + { + serialize: () => "", + parse: () => { + throw new Error("Unable to parse") + }, + catalogExtension: ".po", + templateExtension: ".pot", }, - catalogExtension: ".po", - templateExtension: ".pot", - }) + "en" + ) mockFs({ "test.file": "blabla", @@ -97,12 +113,15 @@ describe("FormatterWrapper", () => { describe("write", () => { it("should write to FS and serialize catalog using provided formatter", async () => { - const format = new FormatterWrapper({ - serialize: (catalog) => JSON.stringify(catalog), - parse: () => ({}), - catalogExtension: ".po", - templateExtension: ".pot", - }) + const format = new FormatterWrapper( + { + serialize: (catalog) => JSON.stringify(catalog), + parse: () => ({}), + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) mockFs({}) @@ -126,12 +145,15 @@ describe("FormatterWrapper", () => { .fn() .mockImplementation((catalog) => JSON.stringify(catalog)) - const format = new FormatterWrapper({ - serialize: serializeMock, - parse: () => ({}), - catalogExtension: ".po", - templateExtension: ".pot", - }) + const format = new FormatterWrapper( + { + serialize: serializeMock, + parse: () => ({}), + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) mockFs({ "messages.json": `{"existing":{"translation":"Existing message"}}`, @@ -159,6 +181,7 @@ describe("FormatterWrapper", () => { existing: {"existing":{"translation":"Existing message"}}, filename: messages.json, locale: en, + sourceLocale: en, }, ] `) @@ -168,12 +191,15 @@ describe("FormatterWrapper", () => { }) it("should write only if file was changed", async () => { - const format = new FormatterWrapper({ - serialize: (catalog) => JSON.stringify(catalog), - parse: () => ({}), - catalogExtension: ".po", - templateExtension: ".pot", - }) + const format = new FormatterWrapper( + { + serialize: (catalog) => JSON.stringify(catalog), + parse: () => ({}), + catalogExtension: ".po", + templateExtension: ".pot", + }, + "en" + ) const catalog = { static: { diff --git a/packages/cli/src/api/formats/formatterWrapper.ts b/packages/cli/src/api/formats/formatterWrapper.ts index 50dfb08cd..8f4ffa00a 100644 --- a/packages/cli/src/api/formats/formatterWrapper.ts +++ b/packages/cli/src/api/formats/formatterWrapper.ts @@ -3,7 +3,7 @@ import { readFile, writeFileIfChanged } from "../utils" import { RethrownError } from "../rethrownError" export class FormatterWrapper { - constructor(private f: CatalogFormatter) {} + constructor(private f: CatalogFormatter, private sourceLocale: string) {} getCatalogExtension() { return this.f.catalogExtension @@ -20,6 +20,7 @@ export class FormatterWrapper { ): Promise { const content = await this.f.serialize(catalog, { locale, + sourceLocale: this.sourceLocale, existing: await readFile(filename), filename, }) @@ -37,6 +38,7 @@ export class FormatterWrapper { try { return this.f.parse(content, { locale, + sourceLocale: this.sourceLocale, filename, }) } catch (e) { diff --git a/packages/cli/src/api/formats/index.ts b/packages/cli/src/api/formats/index.ts index 102af7fc3..f5b28bbfd 100644 --- a/packages/cli/src/api/formats/index.ts +++ b/packages/cli/src/api/formats/index.ts @@ -67,10 +67,11 @@ export { FormatterWrapper } export async function getFormat( _format: CatalogFormat | CatalogFormatter, - options: CatalogFormatOptions + options: CatalogFormatOptions, + sourceLocale: string ): Promise { if (typeof _format !== "string") { - return new FormatterWrapper(_format) + return new FormatterWrapper(_format, sourceLocale) } const format = formats[_format] @@ -83,5 +84,5 @@ export async function getFormat( ) } - return new FormatterWrapper((await format())(options)) + return new FormatterWrapper((await format())(options), sourceLocale) } diff --git a/packages/cli/src/extract-experimental/getExperimentalCatalogs.ts b/packages/cli/src/extract-experimental/getExperimentalCatalogs.ts index 03adcc21f..423b7444c 100644 --- a/packages/cli/src/extract-experimental/getExperimentalCatalogs.ts +++ b/packages/cli/src/extract-experimental/getExperimentalCatalogs.ts @@ -13,7 +13,8 @@ export async function getExperimentalCatalogs( const format = await getFormat( linguiConfig.format, - linguiConfig.formatOptions + linguiConfig.formatOptions, + linguiConfig.sourceLocale ) return entryPoints.map((entryPoint) => { diff --git a/packages/cli/src/lingui-compile.ts b/packages/cli/src/lingui-compile.ts index 42cda69b6..929f4fd9d 100644 --- a/packages/cli/src/lingui-compile.ts +++ b/packages/cli/src/lingui-compile.ts @@ -213,7 +213,11 @@ if (require.main === module) { if (options.watch) { console.info(chalk.bold("Initializing Watch Mode...")) ;(async function initWatch() { - const format = await getFormat(config.format, config.formatOptions) + const format = await getFormat( + config.format, + config.formatOptions, + config.sourceLocale + ) const catalogs = await getCatalogs(config) const paths: string[] = [] diff --git a/packages/cli/src/lingui-extract-experimental.ts b/packages/cli/src/lingui-extract-experimental.ts index d6a66cb82..6324a05a7 100644 --- a/packages/cli/src/lingui-extract-experimental.ts +++ b/packages/cli/src/lingui-extract-experimental.ts @@ -66,7 +66,8 @@ export default async function command( const format = await getFormat( linguiConfig.format, - linguiConfig.formatOptions + linguiConfig.formatOptions, + linguiConfig.sourceLocale ) for (const outFile of Object.keys(bundleResult.metafile.outputs)) { diff --git a/packages/cli/src/tests.ts b/packages/cli/src/tests.ts index 76e1f5623..f3eeaf65c 100644 --- a/packages/cli/src/tests.ts +++ b/packages/cli/src/tests.ts @@ -58,7 +58,11 @@ export const makeCatalog = async (_config: Partial = {}) => { path: "{locale}/messages", include: [], exclude: [], - format: await getFormat(config.format, config.formatOptions), + format: await getFormat( + config.format, + config.formatOptions, + config.sourceLocale + ), }, config ) diff --git a/packages/conf/src/types.ts b/packages/conf/src/types.ts index eff0010a5..17d9daa71 100644 --- a/packages/conf/src/types.ts +++ b/packages/conf/src/types.ts @@ -62,11 +62,16 @@ export type CatalogFormatter = { templateExtension?: string parse( content: string, - ctx: { locale: string | null; filename: string } + ctx: { locale: string | null; sourceLocale: string; filename: string } ): Promise | CatalogType serialize( catalog: CatalogType, - ctx: { locale: string | null; filename: string; existing: string | null } + ctx: { + locale: string | null + sourceLocale: string + filename: string + existing: string | null + } ): Promise | string } diff --git a/packages/format-json/src/json.test.ts b/packages/format-json/src/json.test.ts index 859b54dbc..8c57bed43 100644 --- a/packages/format-json/src/json.test.ts +++ b/packages/format-json/src/json.test.ts @@ -63,6 +63,7 @@ describe("json format", () => { locale: "en", filename, existing: null, + sourceLocale: "en", }) expect(actual).toMatchSnapshot() }) @@ -75,7 +76,11 @@ describe("json format", () => { .toString() const filename = path.join("locale", "en", "messages.json") - const actual = format.parse(lingui, { locale: "en", filename }) + const actual = format.parse(lingui, { + locale: "en", + filename, + sourceLocale: "en", + }) expect(actual).toMatchSnapshot() }) @@ -104,6 +109,7 @@ describe("json format", () => { locale: "en", filename, existing: null, + sourceLocale: "en", }) const linguiOriginProperty = '"origin"' expect(actual).toEqual(expect.not.stringContaining(linguiOriginProperty)) @@ -133,6 +139,7 @@ describe("json format", () => { locale: "en", filename, existing: null, + sourceLocale: "en", }) expect(actual).toMatchInlineSnapshot(` { @@ -204,6 +211,7 @@ describe("json format", () => { locale: "en", filename, existing: null, + sourceLocale: "en", }) expect(actual).toMatchSnapshot() }) @@ -220,7 +228,11 @@ describe("json format", () => { }` const filename = path.join("locale", "en", "messages.json") - const actual = format.parse(content, { locale: "en", filename }) + const actual = format.parse(content, { + locale: "en", + filename, + sourceLocale: "en", + }) expect(actual).toMatchSnapshot() }) }) diff --git a/website/docs/guides/custom-formatter.md b/website/docs/guides/custom-formatter.md index 4e45b2c73..270bcea48 100644 --- a/website/docs/guides/custom-formatter.md +++ b/website/docs/guides/custom-formatter.md @@ -30,11 +30,11 @@ export type CatalogFormatter = { templateExtension?: string parse( content: string, - ctx: { locale: string | null; filename: string } + ctx: { locale: string | null; sourceLang: string, filename: string } ): Promise | CatalogType serialize( catalog: CatalogType, - ctx: { locale: string | null; filename: string; existing: string | null } + ctx: { locale: string | null; sourceLang: string, filename: string; existing: string | null } ): Promise | string } ```