Skip to content

Commit

Permalink
feat: add @lingui/vue
Browse files Browse the repository at this point in the history
add Vue.js support with components, plugins, extractor and compiler
  • Loading branch information
JSteunouSteeple committed Apr 29, 2024
1 parent afc962c commit a0b37e8
Show file tree
Hide file tree
Showing 27 changed files with 2,176 additions and 1 deletion.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ module.exports = {
"<rootDir>/packages/format-csv",
"<rootDir>/packages/message-utils",
"<rootDir>/packages/extractor-vue",
"<rootDir>/packages/vue",
],
},
],
Expand Down
34 changes: 34 additions & 0 deletions packages/vue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[![License][badge-license]][license]
[![Version][badge-version]][package]
[![Downloads][badge-downloads]][package]

# @lingui/vue

> vue components for internationalization
`@lingui/vue` is part of [LinguiJS][linguijs]. See the [documentation][documentation] for all information, tutorials and examples.

## Installation

```sh
npm install --save @lingui/vue
# yarn add @lingui/vue
```

## Usage

See the [tutorial][tutorial] or [reference][reference] documentation.

## License

[MIT][license]

[license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
[linguijs]: https://github.com/lingui/js-lingui
[documentation]: https://lingui.dev
[tutorial]: https://lingui.dev/tutorials/vue
[reference]: https://lingui.dev/ref/vue
[package]: https://www.npmjs.com/package/@lingui/vue
[badge-downloads]: https://img.shields.io/npm/dw/@lingui/vue.svg
[badge-version]: https://img.shields.io/npm/v/@lingui/vue.svg
[badge-license]: https://img.shields.io/npm/l/@lingui/vue.svg
91 changes: 91 additions & 0 deletions packages/vue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"name": "@lingui/vue",
"version": "4.8.0-next.1",
"sideEffects": false,
"description": "Vue components & tools for translations",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"author": {
"name": "J茅r么me Steunou",
"email": "[email protected]"
},
"license": "MIT",
"keywords": [
"vue",
"component",
"i18n",
"internationalization",
"i9n",
"translation",
"icu",
"messageformat",
"multilingual",
"localization",
"l10n"
],
"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"
},
"exports": {
".": {
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
},
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}
},
"./compiler": {
"require": {
"types": "./dist/compiler/index.d.cts",
"default": "./dist/compiler/index.cjs"
},
"import": {
"types": "./dist/compiler/index.d.mts",
"default": "./dist/compiler/index.mjs"
}
},
"./extractor": {
"require": {
"types": "./dist/extractor/index.d.cts",
"default": "./dist/extractor/index.cjs"
},
"import": {
"types": "./dist/extractor/index.d.mts",
"default": "./dist/extractor/index.mjs"
}
},
"./package.json": "./package.json"
},
"files": [
"LICENSE",
"README.md",
"dist/"
],
"dependencies": {
"@lingui/cli": "4.8.0-next.1",
"@lingui/core": "4.8.0-next.1",
"@lingui/message-utils": "4.8.0-next.1",
"@vue/compiler-core": "^3.3.4",
"@vue/compiler-sfc": "^3.3.4",
"vue": "^3.3.4"
},
"devDependencies": {
"@types/babel__core": "^7.20.5",
"unbuild": "2.0.0"
}
}
219 changes: 219 additions & 0 deletions packages/vue/src/common/Trans.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { getContent, getContext, getId } from "./Trans"
import { run } from "../test/utils"
import { generateMessageId } from "@lingui/message-utils/generateMessageId"

//

describe("getContext", () => {
it("should get the context", () => {
run(
`
<Trans context="direction">right</Trans>
`,
(node) => {
expect(getContext(node)).toEqual("direction")
}
)
})

it("should return undefined when context is empty", () => {
run(
`
<Trans context="">right</Trans>
`,
(node) => {
expect(getContext(node)).toEqual(undefined)
}
)
})

it("should return undefined when context is a directive", () => {
run(
`
<Trans :context="direction">right</Trans>
`,
(node) => {
expect(getContext(node)).toEqual(undefined)
}
)
})

it("should return undefined when no context", () => {
run(
`
<Trans>right</Trans>
`,
(node) => {
expect(getContext(node)).toEqual(undefined)
}
)
})
})

describe("getId", () => {
it("should return the given id when set", () => {
run(
`
<Trans id="direction.right">right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual("direction.right")
}
)
})

it("should return the generated id when not set", () => {
run(
`
<Trans>right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual(generateMessageId("right"))
}
)
})

it("should return the generated id when not set but with context", () => {
run(
`
<Trans context="direction">right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual(
generateMessageId("right", "direction")
)
}
)
})

it("should return the generated id when id is empty but with context", () => {
run(
`
<Trans id="" context="direction">right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual(
generateMessageId("right", "direction")
)
}
)
})

it("should return the generated id when id is empty and context empty", () => {
run(
`
<Trans id="" context="">right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual(generateMessageId("right"))
}
)
})

it("should return the generated id when id is a directive", () => {
run(
`
<Trans :id="direction.right">right</Trans>
`,
(node) => {
expect(getId(node, "right")).toEqual(generateMessageId("right"))
}
)
})
})

describe("getContent", () => {
it("should return the content of a Trans component", () => {
run(
`
<Trans>This is some random content</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("This is some random content")
}
)
})

it("should return the content without blank", () => {
run(
`
<Trans> This is some random content </Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("This is some random content")
}
)
})

it("should return the content without line break", () => {
run(
`
<Trans>
This is some random content
</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("This is some random content")
}
)
})

it("should return the content with named placeholder when var", () => {
run(
`
<Trans>Hello {{ name }}</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("Hello {name}")
}
)
})

it("should return the content with all named placeholder when var", () => {
run(
`
<Trans>Hello {{ name }} welcome to {{ town }} you are now a {{ persona }}!</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual(
"Hello {name} welcome to {town} you are now a {persona}!"
)
}
)
})

it("should return the content with placeholder when inner tag", () => {
run(
`
<Trans>Hello <em>{{ name }}</em> welcome to {{ town }} <br /> <span>you are now <em><i>a {{ persona }}</i></em></span>!</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual(
"Hello <0>{name}</0> welcome to {town} <1/> <2>you are now <3><4>a {persona}</4></3></2>!"
)
}
)
})

it("should return the content with placeholder when contains complex interpolation", () => {
run(
`
<Trans>Hello {{ user.name }}</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("Hello {0}")
}
)
})

it("should return the content with placeholders sequentially when contains multiple complex interpolation", () => {
run(
`
<Trans>Hello {{ user ? user : "John" }} and {{ guest.name }}</Trans>
`,
(node) => {
expect(getContent(node).content).toEqual("Hello {0} and {1}")
}
)
})
})

0 comments on commit a0b37e8

Please sign in to comment.