Skip to content

Commit

Permalink
support hash based ids in po formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko committed Feb 15, 2023
1 parent d4dfa63 commit 6f3d408
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 38 deletions.
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@babel/core": "^7.20.12",
"@lingui/babel-plugin-extract-messages": "3.17.1",
"@lingui/conf": "3.17.1",
"@lingui/message-id": "3.17.1",
"@lingui/core": "3.17.1",
"@messageformat/parser": "^5.0.0",
"babel-plugin-macros": "^3.0.1",
Expand Down
64 changes: 39 additions & 25 deletions packages/cli/src/api/__snapshots__/catalog.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Object {
exports[`Catalog collect should extract messages from source files 1`] = `
Object {
Component A: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
origin: Array [
Expand All @@ -27,6 +28,7 @@ Object {
],
},
Component B: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
origin: Array [
Expand All @@ -37,6 +39,7 @@ Object {
],
},
Hello World: Object {
context: undefined,
extractedComments: Array [
Comment A,
Comment A again,
Expand All @@ -59,6 +62,7 @@ Object {
],
},
custom.id: Object {
context: undefined,
extractedComments: Array [],
message: Message with id,
origin: Array [
Expand All @@ -74,6 +78,7 @@ Object {
exports[`Catalog collect should extract only files passed on options 1`] = `
Object {
Component A: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
origin: Array [
Expand All @@ -84,6 +89,7 @@ Object {
],
},
Hello World: Object {
context: undefined,
extractedComments: Array [
Comment A,
Comment A again,
Expand All @@ -106,6 +112,7 @@ Object {
],
},
custom.id: Object {
context: undefined,
extractedComments: Array [],
message: Message with id,
origin: Array [
Expand All @@ -122,75 +129,82 @@ exports[`Catalog collect should support Flow syntax if enabled 1`] = `Object {}`

exports[`Catalog collect should support JSX and Typescript 1`] = `
Object {
Description: Object {
extractedComments: Array [
description,
],
message: undefined,
ID Some: Object {
context: undefined,
extractedComments: Array [],
message: Message with id some,
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
6,
11,
],
],
},
Hi, my name is {name}: Object {
MHrjPM: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
message: Title,
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
17,
19,
],
],
},
ID Some: Object {
extractedComments: Array [],
message: Message with id some,
Nu4oKW: Object {
context: undefined,
extractedComments: Array [
description,
],
message: Description,
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
11,
6,
],
],
},
Message: Object {
YikuIL: Object {
context: Context1,
extractedComments: Array [],
message: undefined,
message: Some message,
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
4,
18,
],
],
},
Some message: Object {
esnaQO: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
message: {count, plural, one {# book} other {# books}},
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
18,
21,
],
],
},
Title: Object {
stjtW+: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
message: Hi, my name is {name},
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
19,
17,
],
],
},
{count, plural, one {# book} other {# books}}: Object {
xDAtGP: Object {
context: undefined,
extractedComments: Array [],
message: undefined,
message: Message,
origin: Array [
Array [
collect-typescript-jsx/macro.tsx,
21,
4,
],
],
},
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/api/formats/__snapshots__/po.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ msgstr "Static message"
msgid "withOrigin"
msgstr "Message with origin"
msgctxt "my context"
msgid "withContext"
msgstr "Message with context"
#, generated-id
msgctxt "my context"
msgid "with generated id"
msgstr ""
#: src/App.js:4
#: src/Component.js:2
msgid "withMultipleOrigins"
Expand Down
33 changes: 33 additions & 0 deletions packages/cli/src/api/formats/po.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ describe("pofile format", () => {
translation: "Message with origin",
origin: [["src/App.js", 4]],
},
withContext: {
translation: "Message with context",
context: "my context",
},
Dgzql1: {
message: "with generated id",
translation: "",
context: "my context",
},
withMultipleOrigins: {
translation: "Message with multiple origin",
origin: [
Expand Down Expand Up @@ -97,6 +106,30 @@ describe("pofile format", () => {
expect(actual).toMatchSnapshot()
})

it("should serialize and deserialize messages with generated id", () => {
mockFs({
locale: {
en: mockFs.directory(),
},
})

const catalog: CatalogType = {
// with generated id
Dgzql1: {
message: "with generated id",
translation: "",
context: "my context",
},
}

const filename = path.join("locale", "en", "messages.po")
format.write(filename, catalog, { origins: true, locale: "en" })

const actual = format.read(filename)
mockFs.restore()
expect(actual).toMatchObject(catalog)
})

it("should correct badly used comments", () => {
const po = PO.parse(`
#. First description
Expand Down
50 changes: 37 additions & 13 deletions packages/cli/src/api/formats/po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import PO from "pofile"
import { joinOrigin, splitOrigin, writeFileIfChanged } from "../utils"
import { CatalogType, MessageType } from "../catalog"
import { CatalogFormatOptionsInternal, CatalogFormatter } from "."
import { generateMessageId } from "@lingui/message-id"

type POItem = InstanceType<typeof PO.Item>

function isGeneratedId(id: string, message: MessageType): boolean {
return id === generateMessageId(message.message, message.context)
}
function getCreateHeaders(language = "no"): PO["headers"] {
return {
"POT-Creation-Date": formatDate(new Date(), "yyyy-MM-dd HH:mmxxxx"),
Expand All @@ -28,17 +32,34 @@ export const serialize = (
const message = catalog[id]

const item = new PO.Item()
item.msgid = id
item.msgstr = [message.translation]
item.comments = message.comments || []

// The extractedComments array may be modified in this method, so create a new array with the message's elements.
// Destructuring `undefined` is forbidden, so fallback to `[]` if the message has no extracted comments.
item.extractedComments = [...(message.extractedComments ?? [])]
// The extractedComments array may be modified in this method,
// so create a new array with the message's elements.
item.extractedComments = [...(message.extractedComments || [])]

item.flags = (message.flags || []).reduce<Record<string, boolean>>(
(acc, flag) => {
acc[flag] = true
return acc
},
{}
)

if (isGeneratedId(id, message)) {
item.msgid = message.message
item.flags["generated-id"] = true
// item.extractedComments.push(`lingui_id: ${id}`)
} else {
item.msgid = id
}

if (message.context) {
item.msgctxt = message.context
}

item.msgstr = [message.translation]
item.comments = message.comments || []

if (options.origins !== false) {
if (message.origin && options.lineNumbers === false) {
item.references = message.origin.map(([path]) => path)
Expand All @@ -47,12 +68,6 @@ export const serialize = (
}
}
item.obsolete = message.obsolete
item.flags = message.flags
? message.flags.reduce<Record<string, boolean>>((acc, flag) => {
acc[flag] = true
return acc
}, {})
: {}

return postProcessItem ? postProcessItem(item, message, id) : item
})
Expand All @@ -65,7 +80,7 @@ export function deserialize(
return items.reduce<CatalogType>((catalog, item) => {
onItem(item)

catalog[item.msgid] = {
const message: MessageType = {
translation: item.msgstr[0],
extractedComments: item.extractedComments || [],
comments: item.comments || [],
Expand All @@ -75,6 +90,15 @@ export function deserialize(
flags: Object.keys(item.flags).map((flag) => flag.trim()),
}

let id = item.msgid

// if generated id, recreate it
if (item.flags["generated-id"]) {
id = generateMessageId(item.msgid, item.msgctxt)
message.message = item.msgid
}

catalog[id] = message
return catalog
}, {})
}
Expand Down

0 comments on commit 6f3d408

Please sign in to comment.