Skip to content

Commit ed0de3e

Browse files
chore: add @lingui/vue
add Vue.js support with components, plugins, extractor and compiler
1 parent afc962c commit ed0de3e

27 files changed

+2176
-1
lines changed

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module.exports = {
7171
"<rootDir>/packages/format-csv",
7272
"<rootDir>/packages/message-utils",
7373
"<rootDir>/packages/extractor-vue",
74+
"<rootDir>/packages/vue",
7475
],
7576
},
7677
],

packages/vue/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[![License][badge-license]][license]
2+
[![Version][badge-version]][package]
3+
[![Downloads][badge-downloads]][package]
4+
5+
# @lingui/vue
6+
7+
> vue components for internationalization
8+
9+
`@lingui/vue` is part of [LinguiJS][linguijs]. See the [documentation][documentation] for all information, tutorials and examples.
10+
11+
## Installation
12+
13+
```sh
14+
npm install --save @lingui/vue
15+
# yarn add @lingui/vue
16+
```
17+
18+
## Usage
19+
20+
See the [tutorial][tutorial] or [reference][reference] documentation.
21+
22+
## License
23+
24+
[MIT][license]
25+
26+
[license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
27+
[linguijs]: https://github.com/lingui/js-lingui
28+
[documentation]: https://lingui.dev
29+
[tutorial]: https://lingui.dev/tutorials/vue
30+
[reference]: https://lingui.dev/ref/vue
31+
[package]: https://www.npmjs.com/package/@lingui/vue
32+
[badge-downloads]: https://img.shields.io/npm/dw/@lingui/vue.svg
33+
[badge-version]: https://img.shields.io/npm/v/@lingui/vue.svg
34+
[badge-license]: https://img.shields.io/npm/l/@lingui/vue.svg

packages/vue/package.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"name": "@lingui/vue",
3+
"version": "4.8.0-next.1",
4+
"sideEffects": false,
5+
"description": "Vue components & tools for translations",
6+
"main": "./dist/index.cjs",
7+
"module": "./dist/index.mjs",
8+
"types": "./dist/index.d.ts",
9+
"author": {
10+
"name": "Jérôme Steunou",
11+
"email": "jerome.steunou@gmail.com"
12+
},
13+
"license": "MIT",
14+
"keywords": [
15+
"vue",
16+
"component",
17+
"i18n",
18+
"internationalization",
19+
"i9n",
20+
"translation",
21+
"icu",
22+
"messageformat",
23+
"multilingual",
24+
"localization",
25+
"l10n"
26+
],
27+
"scripts": {
28+
"build": "rimraf ./dist && unbuild",
29+
"stub": "unbuild --stub"
30+
},
31+
"repository": {
32+
"type": "git",
33+
"url": "https://github.com/lingui/js-lingui.git"
34+
},
35+
"bugs": {
36+
"url": "https://github.com/lingui/js-lingui/issues"
37+
},
38+
"engines": {
39+
"node": ">=16.0.0"
40+
},
41+
"exports": {
42+
".": {
43+
"require": {
44+
"types": "./dist/index.d.cts",
45+
"default": "./dist/index.cjs"
46+
},
47+
"import": {
48+
"types": "./dist/index.d.mts",
49+
"default": "./dist/index.mjs"
50+
}
51+
},
52+
"./compiler": {
53+
"require": {
54+
"types": "./dist/compiler/index.d.cts",
55+
"default": "./dist/compiler/index.cjs"
56+
},
57+
"import": {
58+
"types": "./dist/compiler/index.d.mts",
59+
"default": "./dist/compiler/index.mjs"
60+
}
61+
},
62+
"./extractor": {
63+
"require": {
64+
"types": "./dist/extractor/index.d.cts",
65+
"default": "./dist/extractor/index.cjs"
66+
},
67+
"import": {
68+
"types": "./dist/extractor/index.d.mts",
69+
"default": "./dist/extractor/index.mjs"
70+
}
71+
},
72+
"./package.json": "./package.json"
73+
},
74+
"files": [
75+
"LICENSE",
76+
"README.md",
77+
"dist/"
78+
],
79+
"dependencies": {
80+
"@lingui/cli": "4.8.0-next.1",
81+
"@lingui/core": "4.8.0-next.1",
82+
"@lingui/message-utils": "4.8.0-next.1",
83+
"@vue/compiler-core": "^3.3.4",
84+
"@vue/compiler-sfc": "^3.3.4",
85+
"vue": "^3.3.4"
86+
},
87+
"devDependencies": {
88+
"@types/babel__core": "^7.20.5",
89+
"unbuild": "2.0.0"
90+
}
91+
}

packages/vue/src/common/Trans.test.ts

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import { getContent, getContext, getId } from "./Trans"
2+
import { run } from "../test/utils"
3+
import { generateMessageId } from "@lingui/message-utils/generateMessageId"
4+
5+
//
6+
7+
describe("getContext", () => {
8+
it("should get the context", () => {
9+
run(
10+
`
11+
<Trans context="direction">right</Trans>
12+
`,
13+
(node) => {
14+
expect(getContext(node)).toEqual("direction")
15+
}
16+
)
17+
})
18+
19+
it("should return undefined when context is empty", () => {
20+
run(
21+
`
22+
<Trans context="">right</Trans>
23+
`,
24+
(node) => {
25+
expect(getContext(node)).toEqual(undefined)
26+
}
27+
)
28+
})
29+
30+
it("should return undefined when context is a directive", () => {
31+
run(
32+
`
33+
<Trans :context="direction">right</Trans>
34+
`,
35+
(node) => {
36+
expect(getContext(node)).toEqual(undefined)
37+
}
38+
)
39+
})
40+
41+
it("should return undefined when no context", () => {
42+
run(
43+
`
44+
<Trans>right</Trans>
45+
`,
46+
(node) => {
47+
expect(getContext(node)).toEqual(undefined)
48+
}
49+
)
50+
})
51+
})
52+
53+
describe("getId", () => {
54+
it("should return the given id when set", () => {
55+
run(
56+
`
57+
<Trans id="direction.right">right</Trans>
58+
`,
59+
(node) => {
60+
expect(getId(node, "right")).toEqual("direction.right")
61+
}
62+
)
63+
})
64+
65+
it("should return the generated id when not set", () => {
66+
run(
67+
`
68+
<Trans>right</Trans>
69+
`,
70+
(node) => {
71+
expect(getId(node, "right")).toEqual(generateMessageId("right"))
72+
}
73+
)
74+
})
75+
76+
it("should return the generated id when not set but with context", () => {
77+
run(
78+
`
79+
<Trans context="direction">right</Trans>
80+
`,
81+
(node) => {
82+
expect(getId(node, "right")).toEqual(
83+
generateMessageId("right", "direction")
84+
)
85+
}
86+
)
87+
})
88+
89+
it("should return the generated id when id is empty but with context", () => {
90+
run(
91+
`
92+
<Trans id="" context="direction">right</Trans>
93+
`,
94+
(node) => {
95+
expect(getId(node, "right")).toEqual(
96+
generateMessageId("right", "direction")
97+
)
98+
}
99+
)
100+
})
101+
102+
it("should return the generated id when id is empty and context empty", () => {
103+
run(
104+
`
105+
<Trans id="" context="">right</Trans>
106+
`,
107+
(node) => {
108+
expect(getId(node, "right")).toEqual(generateMessageId("right"))
109+
}
110+
)
111+
})
112+
113+
it("should return the generated id when id is a directive", () => {
114+
run(
115+
`
116+
<Trans :id="direction.right">right</Trans>
117+
`,
118+
(node) => {
119+
expect(getId(node, "right")).toEqual(generateMessageId("right"))
120+
}
121+
)
122+
})
123+
})
124+
125+
describe("getContent", () => {
126+
it("should return the content of a Trans component", () => {
127+
run(
128+
`
129+
<Trans>This is some random content</Trans>
130+
`,
131+
(node) => {
132+
expect(getContent(node).content).toEqual("This is some random content")
133+
}
134+
)
135+
})
136+
137+
it("should return the content without blank", () => {
138+
run(
139+
`
140+
<Trans> This is some random content </Trans>
141+
`,
142+
(node) => {
143+
expect(getContent(node).content).toEqual("This is some random content")
144+
}
145+
)
146+
})
147+
148+
it("should return the content without line break", () => {
149+
run(
150+
`
151+
<Trans>
152+
This is some random content
153+
</Trans>
154+
`,
155+
(node) => {
156+
expect(getContent(node).content).toEqual("This is some random content")
157+
}
158+
)
159+
})
160+
161+
it("should return the content with named placeholder when var", () => {
162+
run(
163+
`
164+
<Trans>Hello {{ name }}</Trans>
165+
`,
166+
(node) => {
167+
expect(getContent(node).content).toEqual("Hello {name}")
168+
}
169+
)
170+
})
171+
172+
it("should return the content with all named placeholder when var", () => {
173+
run(
174+
`
175+
<Trans>Hello {{ name }} welcome to {{ town }} you are now a {{ persona }}!</Trans>
176+
`,
177+
(node) => {
178+
expect(getContent(node).content).toEqual(
179+
"Hello {name} welcome to {town} you are now a {persona}!"
180+
)
181+
}
182+
)
183+
})
184+
185+
it("should return the content with placeholder when inner tag", () => {
186+
run(
187+
`
188+
<Trans>Hello <em>{{ name }}</em> welcome to {{ town }} <br /> <span>you are now <em><i>a {{ persona }}</i></em></span>!</Trans>
189+
`,
190+
(node) => {
191+
expect(getContent(node).content).toEqual(
192+
"Hello <0>{name}</0> welcome to {town} <1/> <2>you are now <3><4>a {persona}</4></3></2>!"
193+
)
194+
}
195+
)
196+
})
197+
198+
it("should return the content with placeholder when contains complex interpolation", () => {
199+
run(
200+
`
201+
<Trans>Hello {{ user.name }}</Trans>
202+
`,
203+
(node) => {
204+
expect(getContent(node).content).toEqual("Hello {0}")
205+
}
206+
)
207+
})
208+
209+
it("should return the content with placeholders sequentially when contains multiple complex interpolation", () => {
210+
run(
211+
`
212+
<Trans>Hello {{ user ? user : "John" }} and {{ guest.name }}</Trans>
213+
`,
214+
(node) => {
215+
expect(getContent(node).content).toEqual("Hello {0} and {1}")
216+
}
217+
)
218+
})
219+
})

0 commit comments

Comments
 (0)