Skip to content

Commit 00ca62c

Browse files
vandelpavelIlCallo
andauthored
feat: add i18n reactive support (#4)
Co-authored-by: Alessandro Vandelli <a.vandelli@dreamonkey.com> Co-authored-by: Paolo Caleffi <p.caleffi@dreamonkey.com>
1 parent fc15de0 commit 00ca62c

File tree

4 files changed

+120
-15
lines changed

4 files changed

+120
-15
lines changed

README.md

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,42 +84,42 @@ Here are some examples:
8484
import { LayoutMetaMixin } from "@dreamonkey/quasar-app-extension-meta";
8585

8686
export default {
87-
name: 'MainLayout',
88-
mixins: [LayoutMetaMixin(title => `${title} - FooBarAgency`)],
87+
name: "MainLayout",
88+
mixins: [LayoutMetaMixin((title) => `${title} - FooBarAgency`)],
8989
data() {
90-
...
91-
}
92-
}
90+
// ...
91+
},
92+
};
9393
```
9494

9595
```ts
9696
// src/pages/contacts.vue
9797

9898
import { PageMetaMixin } from "@dreamonkey/quasar-app-extension-meta";
9999

100-
const title = 'Contacts';
100+
const title = "Contacts";
101101
const description =
102-
'Contact FooBarAgency with the online form or reach us in our office at 766 Parkway Street, Los Angeles, California.';
102+
"Contact FooBarAgency with the online form or reach us in our office at 766 Parkway Street, Los Angeles, California.";
103103

104104
export default {
105-
name: 'ContactPage',
105+
name: "ContactPage",
106106
mixins: [PageMetaMixin(title, description)],
107107
data() {
108-
...
109-
}
110-
}
108+
// ...
109+
},
110+
};
111111
```
112112

113113
`` title => `${title} - FooBarAgency` `` argument is useful to add a prefix/suffix to nested pages own title, but if no transformation is needed just leave it blank:
114114

115115
```ts
116116
export default {
117-
name: 'MainLayout',
117+
name: "MainLayout",
118118
mixins: [LayoutMetaMixin()], // <-- no argument here
119119
data() {
120-
...
121-
}
122-
}
120+
// ...
121+
},
122+
};
123123
```
124124

125125
This AE sets `og:url` and `og:image` based on the domain provided into `process.env.APP_DOMAIN` (read more about [process.env](https://quasar.dev/quasar-cli/handling-process-env#Adding-to-process.env)).
@@ -162,6 +162,58 @@ export default {
162162

163163
`metaTag` accepts the meta tag name, or an array of names, as first parameter and the value as second parameter.
164164

165+
## Dynamic support for i18n
166+
167+
Be sure to understand how [App Internationalization (i18n)](https://quasar.dev/options/app-internationalization#Introduction) and [Custom directive localization](http://kazupon.github.io/vue-i18n/guide/directive.html#string-syntax) work before proceeding.
168+
This mixin assumes [`vue-i18n`](https://github.com/kazupon/vue-i18n) has already been set up in your project.
169+
170+
`PageMetaMixin` is perfect until you add internationalization to the mix, which requires to dynamically update you tags and meta tags accordingly to the selected language: `PageMetaI18nMixin` address this use case.
171+
172+
### Using `PageMetaI18nMixin`
173+
174+
You use `PageMetaI18nMixin` exactly how you would use `PageMetaMixin`, except you provide "translation paths" as arguments instead of the text itself.
175+
The mixin automatically react to `$root.$i18n.locale` changes, updating meta tags accordingly.
176+
177+
```ts
178+
// src/i18n/it/contacts.ts <-- Notice these are the website italian translations
179+
180+
export default {
181+
meta: {
182+
title: "Contatti",
183+
description:
184+
"Contatta FooBarAgency con il nostro modulo online o raggiungici in ufficio a Parkway Street 766, Los Angeles, California.",
185+
},
186+
form: {
187+
title: "Contattaci compilando il nostro modulo!",
188+
},
189+
// ... other translations
190+
};
191+
```
192+
193+
```ts
194+
// src/pages/contacts.vue
195+
196+
import { PageMetaI18nMixin } from "@dreamonkey/quasar-app-extension-meta";
197+
198+
const titleLabel = "contacts.meta.title"; // <-- The title 'translation path'
199+
const descriptionLabel = "contacts.meta.description"; // <-- The description 'translation path'
200+
201+
export default {
202+
name: "ContactPage",
203+
mixins: [PageMetaI18nMixin(titleLabel, descriptionLabel)],
204+
data() {
205+
// ...
206+
},
207+
};
208+
```
209+
210+
The "translation paths" are those you use to access translations with `vue-i18n` methods.
211+
In the following snippet the "translation path" is `contacts.form.title`:
212+
213+
```html
214+
<p>{{ $t('contacts.form.title') }}</p>
215+
```
216+
165217
## Testing social preview
166218

167219
If the website is online you can test it using [this tool](https://metatags.io/).
@@ -183,6 +235,10 @@ LayoutMetaMixin(
183235
PageMetaMixin(title: string, description: string);
184236
```
185237

238+
```ts
239+
PageMetaI18nMixin(titleLabel: string, descriptionLabel: string);
240+
```
241+
186242
```ts
187243
metaTag(names: string | string[], value: string);
188244
```

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"@types/node": "^14.11.2",
3232
"typescript": "^4.0.3",
3333
"vue": "^2.6.12",
34+
"vue-i18n": "^8.22.1",
3435
"vue-router": "^3.4.5"
3536
},
3637
"publishConfig": {

src/mixins/meta.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Vue from "vue";
22
import "vue-router";
3+
import "vue-i18n";
34

45
export function LayoutMetaMixin(
56
titleTemplateFn: (title: string) => string = (title) => title
@@ -28,6 +29,48 @@ export function PageMetaMixin(title: string, description: string) {
2829
};
2930
}
3031

32+
export function PageMetaI18nMixin(
33+
titleLabel: string,
34+
descriptionLabel: string
35+
) {
36+
return {
37+
data() {
38+
return {
39+
metaI18nTitle: "",
40+
metaI18nDescription: "",
41+
};
42+
},
43+
watch: {
44+
"$root.$i18n.locale": {
45+
handler: function (
46+
this: Vue & {
47+
metaI18nTitle: string;
48+
metaI18nDescription: string;
49+
}
50+
) {
51+
this.metaI18nTitle = this.$root.$i18n.t(titleLabel).toString();
52+
this.metaI18nDescription = this.$root.$i18n
53+
.t(descriptionLabel)
54+
.toString();
55+
},
56+
immediate: true,
57+
},
58+
},
59+
meta(
60+
this: Vue & {
61+
metaI18nTitle: string;
62+
metaI18nDescription: string;
63+
metaI18nRoutePath: string;
64+
}
65+
) {
66+
return {
67+
title: this.metaI18nTitle,
68+
meta: pageSocialMetaTags(this.metaI18nDescription, this.$route.path),
69+
};
70+
},
71+
};
72+
}
73+
3174
function layoutSocialMetaTags(title: string) {
3275
return {
3376
...metaTag("og:title", title),

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ typescript@^4.0.3:
1212
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5"
1313
integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==
1414

15+
vue-i18n@^8.22.1:
16+
version "8.22.1"
17+
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.22.1.tgz#b9dd098a17e1f5adb91bdf9611f0385310da7cb1"
18+
integrity sha512-JNgiEJ5a8YPfk5y2lKyfOAGLmkpAVfhaUi+T4wGpSppRYZ3XSyawSDDketY5KV2CsAiBLAGEIO6jO+0l2hQubg==
19+
1520
vue-router@^3.4.5:
1621
version "3.4.5"
1722
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.5.tgz#d396ec037b35931bdd1e9b7edd86f9788dc15175"

0 commit comments

Comments
 (0)