Skip to content

Commit 49f45b2

Browse files
authored
feat: add cli option to extract only a specific locale (#816)
1 parent 2211d09 commit 49f45b2

7 files changed

Lines changed: 97 additions & 8 deletions

File tree

docs/ref/cli.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Commands
4343
``extract``
4444
-----------
4545

46-
.. lingui-cli:: extract [--clean] [--overwrite] [--format <format>] [--convert-from <format>] [--verbose]
46+
.. lingui-cli:: extract [--clean] [--overwrite] [--format <format>] [--locale <locale>] [--convert-from <format>] [--verbose]
4747

4848
This command extracts messages from source files and creates a message catalog for
4949
each language using the following steps:
@@ -65,6 +65,10 @@ Update translations for :conf:`sourceLocale` from source.
6565

6666
Format of message catalogs (see :conf:`format` option).
6767

68+
.. lingui-cli-option:: --locale <locale>
69+
70+
Only extract data for the specified locale.
71+
6872
.. lingui-cli-option:: --convert-from <format>
6973

7074
Convert message catalogs from previous format (see :conf:`format` option).

packages/cli/src/api/__snapshots__/catalog.test.ts.snap

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,47 @@ Object {
211211
}
212212
`;
213213

214+
exports[`Catalog make should only update the specified locale 1`] = `
215+
Object {
216+
cs: null,
217+
en: null,
218+
}
219+
`;
220+
221+
exports[`Catalog make should only update the specified locale 2`] = `
222+
Object {
223+
cs: null,
224+
en: Object {
225+
Component A: Object {
226+
comment: undefined,
227+
comments: Array [],
228+
flags: Array [],
229+
obsolete: false,
230+
origin: Array [
231+
Array [
232+
collect/componentA/componentA.js,
233+
1,
234+
],
235+
],
236+
translation: ,
237+
},
238+
Hello World: Object {
239+
comment: undefined,
240+
comments: Array [],
241+
flags: Array [],
242+
obsolete: false,
243+
origin: Array [
244+
Array [
245+
collect/componentA/index.js,
246+
1,
247+
],
248+
],
249+
translation: ,
250+
},
251+
},
252+
}
253+
`;
254+
214255
exports[`Catalog makeTemplate should collect and write a template 1`] = `null`;
215256

216257
exports[`Catalog makeTemplate should collect and write a template 2`] = `

packages/cli/src/api/catalog.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,30 @@ describe("Catalog", function () {
5959
expect(catalog.readAll()).toMatchSnapshot()
6060
})
6161

62+
it("should only update the specified locale", function () {
63+
const localeDir = copyFixture(fixture("locales", "initial"))
64+
const catalog = new Catalog(
65+
{
66+
name: "messages",
67+
path: path.join(localeDir, "{locale}", "messages"),
68+
include: [
69+
fixture("collect/componentA/"),
70+
fixture("collect/componentB"),
71+
],
72+
exclude: [],
73+
},
74+
mockConfig({
75+
locales: ["en", "cs"],
76+
})
77+
)
78+
79+
// Everything should be empty
80+
expect(catalog.readAll()).toMatchSnapshot()
81+
82+
catalog.make({ ...defaultMakeOptions, locale: "en" })
83+
expect(catalog.readAll()).toMatchSnapshot()
84+
})
85+
6286
it("should merge with existing catalogs", function () {
6387
const localeDir = copyFixture(fixture("locales", "existing"))
6488
const catalog = new Catalog(

packages/cli/src/api/catalog.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,14 @@ export class Catalog {
9393
order(options.orderBy)
9494
)
9595
) as unknown) as (catalog: AllCatalogsType) => AllCatalogsType
96-
this.writeAll(cleanAndSort(catalogs))
96+
97+
const sortedCatalogs = cleanAndSort(catalogs);
98+
99+
if (options.locale) {
100+
this.write(options.locale, sortedCatalogs[options.locale])
101+
} else {
102+
this.writeAll(sortedCatalogs)
103+
}
97104
}
98105

99106
makeTemplate(options: MakeTemplateOptions) {

packages/cli/src/api/stats.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export function printStats(config: LinguiConfig, catalogs: AllCatalogsType) {
2626
})
2727

2828
Object.keys(catalogs).forEach((locale) => {
29-
const [all, translated] = getStats(catalogs[locale])
29+
const catalog = catalogs[locale]
30+
// catalog is null if no catalog exists on disk and the locale
31+
// was not extracted due to a `--locale` filter
32+
const [all, translated] = catalog ? getStats(catalog) : ["-", "-"]
33+
3034
if (config.sourceLocale === locale) {
3135
table.push({ [`${chalk.bold(locale)} (source)`]: [all, "-"] })
3236
} else {

packages/cli/src/lingui-extract.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type CliExtractOptions = {
1313
verbose: boolean
1414
clean: boolean
1515
overwrite: boolean
16+
locale: string
1617
prevFormat: string | null
1718
}
1819

@@ -70,6 +71,7 @@ export default function command(
7071
if (require.main === module) {
7172
program
7273
.option("--config <path>", "Path to the config file")
74+
.option("--locale <locale>", "Only extract the specified locale")
7375
.option("--overwrite", "Overwrite translations for source locale")
7476
.option("--clean", "Remove obsolete translations")
7577
.option("--verbose", "Verbose output")
@@ -120,12 +122,19 @@ if (require.main === module) {
120122
process.exit(1)
121123
}
122124

125+
if (program.locale && !config.locales.includes(program.locale)) {
126+
hasErrors = true
127+
console.error(`Locale ${chalk.bold(program.locale)} does not exist.`)
128+
console.error()
129+
}
130+
123131
if (hasErrors) process.exit(1)
124132

125133
const result = command(config, {
126134
verbose: program.verbose || false,
127135
clean: program.clean || false,
128136
overwrite: program.overwrite || false,
137+
locale: program.locale,
129138
prevFormat,
130139
})
131140

packages/cli/src/tests.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ import { Catalog, MakeOptions, MakeTemplateOptions, MergeOptions } from "./api/c
77
import { ExtractedMessageType, MessageType } from "./api/types"
88

99
export function copyFixture(fixtureDir) {
10-
const tmpDir = path.join(os.tmpdir(), `lingui-test-${process.pid}`)
11-
12-
if (!fs.existsSync(fixtureDir)) {
13-
fs.mkdirpSync(tmpDir)
14-
} else {
10+
const tmpDir = fs.mkdtempSync(
11+
path.join(os.tmpdir(), `lingui-test-${process.pid}`)
12+
)
13+
if (fs.existsSync(fixtureDir)) {
1514
fs.copySync(fixtureDir, tmpDir)
1615
}
1716
return tmpDir
@@ -21,6 +20,7 @@ export const defaultMakeOptions: MakeOptions = {
2120
verbose: false,
2221
clean: false,
2322
overwrite: false,
23+
locale: null,
2424
prevFormat: null,
2525
orderBy: "messageId",
2626
}

0 commit comments

Comments
 (0)