Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ module.exports = {
"<rootDir>/packages/format-csv",
"<rootDir>/packages/message-utils",
"<rootDir>/packages/extractor-vue",
"<rootDir>/packages/format-xliff",
],
},
],
Expand Down
77 changes: 77 additions & 0 deletions packages/format-xliff/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
[![License][badge-license]][license]
[![Version][badge-version]][package]
[![Downloads][badge-downloads]][package]

# @lingui/format-po

> Read and write message catalogs in Gettext PO format with ICU plurals

`@lingui/format-po` is part of [LinguiJS][linguijs]. See the
[documentation][documentation] for all information, tutorials and examples.

## Catalog example

```po
#, Comment for translators
#: src/App.js:4, src/Component.js:2
msgid "MessageID"
msgstr "Translated Message"
```

## Installation

```sh
npm install --save-dev @lingui/format-po
# yarn add --dev @lingui/format-po
```

## Usage

```js
// lingui.config.{js,ts}
import {formatter} from "@lingui/format-po"

export default {
[...]
format: formatter({lineNumbers: false}),
}
```

Possible options:

```ts
export type PoFormatterOptions = {
/**
* Print places where message is used
*
* @default true
*/
origins?: boolean

/**
* Print line numbers in origins
*
* @default true
*/
lineNumbers?: boolean

/**
* Print `js-lingui-id: Xs4as` statement in extracted comments section
*
* @default false
*/
printLinguiId?: boolean
}
```

## License

This package is licensed under [MIT][license] license.

[license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
[linguijs]: https://github.com/lingui/js-lingui
[documentation]: https://lingui.dev
[package]: https://www.npmjs.com/package/@lingui/format-po
[badge-downloads]: https://img.shields.io/npm/dw/@lingui/format-po.svg
[badge-version]: https://img.shields.io/npm/v/@lingui/format-po.svg
[badge-license]: https://img.shields.io/npm/l/@lingui/format-po.svg
48 changes: 48 additions & 0 deletions packages/format-xliff/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@lingui/format-xliff",
"version": "4.0.0",
"description": "Gettext PO format for Lingui Catalogs",
"main": "./dist/xliff.cjs",
"module": "./dist/xliff.mjs",
"types": "./dist/xliff.d.ts",
"license": "MIT",
"keywords": [
"i18n",
"lingui-format",
"lingui-formatter",
"xliff",
"internationalization",
"i10n",
"localization",
"i9n",
"translation"
],
"scripts": {
"build": "rimraf ./dist && unbuild",
"stub": "unbuild --stub"
},
"repository": {
"type": "git",
"url": "https://github.com/lingui/js-lingui.git"
},
"bugs": {
"url": "https://github.com/lingui/js-lingui/issues"
},
"engines": {
"node": ">=16.0.0"
},
"files": [
"LICENSE",
"README.md",
"dist/"
],
"dependencies": {
"@lingui/cli": "4.1.2",
"@lingui/conf": "4.1.2",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@lingui/jest-mocks": "workspace:^",
"unbuild": "^1.1.2"
}
}
53 changes: 53 additions & 0 deletions packages/format-xliff/src/__snapshots__/xliff.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`xliff format should write catalog in pofile format 1`] = `
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file source-language="en" datatype="plaintext" original="js-lingui" target-language="en">
<body>
<trans-unit id="static" datatype="html">
<target><![CDATA[Static message]]></target>
</trans-unit>
<trans-unit id="withOrigin" datatype="html">
<target><![CDATA[Message with origin]]></target>
<context-group purpose="location">
<context context-type="sourcefile">src/App.js</context>
<context context-type="linenumber">4</context>
</context-group>
</trans-unit>
<trans-unit id="withContext" datatype="html">
<target><![CDATA[Message with context]]></target>
<note priority="1" from="context">my context</note>
</trans-unit>
<trans-unit id="Dgzql1" datatype="html">
<source><![CDATA[with generated id]]></source>
<note priority="1" from="context">my context</note>
</trans-unit>
<trans-unit id="withMultipleOrigins" datatype="html">
<target><![CDATA[Message with multiple origin]]></target>
<context-group purpose="location">
<context context-type="sourcefile">src/App.js</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/Component.js</context>
<context context-type="linenumber">2</context>
</context-group>
</trans-unit>
<trans-unit id="withDescription" datatype="html">
<target><![CDATA[Message with description]]></target>
<note priority="1" from="comment">Description is comment from developers to translators</note>
</trans-unit>
<trans-unit id="veryLongString" datatype="html">
<target><![CDATA[One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked. "What's happened to me?" he thought. It wasn't a dream. His room, a proper human]]></target>
</trans-unit>
<trans-unit id="stringWithPlaceholders" datatype="html">
<source><![CDATA[Hello {world}]]></source>
</trans-unit>
<trans-unit id="stringWithJsxPlaceholders" datatype="html">
<source><![CDATA[Hello <0>String</0>]]></source>
</trans-unit>
</body>
</file>
</xliff>
`;
93 changes: 93 additions & 0 deletions packages/format-xliff/src/xliff.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { formatter as createFormatter } from "./xliff"
import { CatalogType } from "@lingui/conf"

describe("xliff format", () => {
it("should write catalog in pofile format", async () => {
const format = createFormatter({ origins: true })

const catalog: CatalogType = {
static: {
translation: "Static message",
},
withOrigin: {
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: [
["src/App.js", 4],
["src/Component.js", 2],
],
},
withDescription: {
translation: "Message with description",
comments: ["Description is comment from developers to translators"],
},
// obsolete: {
// translation: "Obsolete message",
// obsolete: true,
// },
// withFlags: {
// flags: ["fuzzy", "otherFlag"],
// translation: "Keeps any flags that are defined",
// },
veryLongString: {
translation:
"One morning, when Gregor Samsa woke from troubled dreams, he found himself" +
" transformed in his bed into a horrible vermin. He lay on his armour-like" +
" back, and if he lifted his head a little he could see his brown belly," +
" slightly domed and divided by arches into stiff sections. The bedding was" +
" hardly able to cover it and seemed ready to slide off any moment. His many" +
" legs, pitifully thin compared with the size of the rest of him, waved about" +
" helplessly as he looked. \"What's happened to me?\" he thought. It wasn't" +
" a dream. His room, a proper human",
},

stringWithPlaceholders: {
message: "Hello {world}",
translation: null,
},

stringWithJsxPlaceholders: {
message: "Hello <0>String</0>",
translation: null,
},
}

const actual = format.serialize(catalog, {
locale: "en",
existing: null,
})
expect(actual).toMatchSnapshot()
})

it.todo(
"should read catalog in xliff format" /*, () => {
const format = createFormatter()

const pofile = fs
.readFileSync(path.join(__dirname, "fixtures/messages.po"))
.toString()

const actual = format.parse(pofile)
expect(actual).toMatchSnapshot()
}*/
)

it.todo("should preserve attributes stored on trans unit")
it.todo("should preserve children in trans unit")

it.todo("should not include origins if origins option is false")

it.todo("should not include lineNumbers if lineNumbers option is false")
})
Loading