|
| 1 | +# Web components |
| 2 | + |
| 3 | +:::tip Support Version |
| 4 | +:new: 9.2+ |
| 5 | +::: |
| 6 | + |
| 7 | +Vue 3.2 later, we can use the WebComponents as described in the [official documentation](https://v3.vuejs.org/guide/web-components.html). |
| 8 | + |
| 9 | +This will support the use of Vue I18n in Web Components starting with Vue I18n v9.2. |
| 10 | + |
| 11 | +There are a few things to keep in mind when using Vue I18n with Web Components. |
| 12 | + |
| 13 | +## Make preparetion for Web Components to host the I18n instance |
| 14 | + |
| 15 | +Using `defineCustomElement`, which is supported since Vue 3.2, we can provide Vue components implemented in SFC as Web Components. This means that Vue components implemented using `useI18n` can be served as Web Components with i18n support. |
| 16 | + |
| 17 | +However, the provided Web Components cannot be inserted directly into HTML. You need to prepare the following Web Components to host the i18n instance created by `createI18n`. |
| 18 | + |
| 19 | +Web Components that host the i18n instance: |
| 20 | +```html |
| 21 | +<script lang="ts"> |
| 22 | +import { defineComponent, provide } from 'vue' |
| 23 | +import { createI18n, I18nInjectionKey } from 'vue-i18n' |
| 24 | +
|
| 25 | +/** |
| 26 | + * create an i18n instance to host for other web components |
| 27 | + */ |
| 28 | +const i18n = createI18n<false>({ |
| 29 | + legacy: false, // must set to `false` |
| 30 | + locale: 'en', |
| 31 | + messages: { |
| 32 | + en: { |
| 33 | + hello: 'Hello!' |
| 34 | + }, |
| 35 | + ja: { |
| 36 | + hello: 'こんにちは!' |
| 37 | + } |
| 38 | + } |
| 39 | +}) |
| 40 | +
|
| 41 | +export default defineComponent({ |
| 42 | + // ... |
| 43 | + setup(props) { |
| 44 | + /** |
| 45 | + * provide i18n instance with `I18nInjectionKey` for other web components |
| 46 | + */ |
| 47 | + provide(I18nInjectionKey, i18n) |
| 48 | +
|
| 49 | + // ... |
| 50 | +
|
| 51 | + return {} |
| 52 | + } |
| 53 | +}) |
| 54 | +</script> |
| 55 | + |
| 56 | +<!-- template to slot the content --> |
| 57 | +<template> |
| 58 | + <slot /> |
| 59 | +</template> |
| 60 | +``` |
| 61 | + |
| 62 | +The above code has the following three points. |
| 63 | + |
| 64 | +- Call `createI18n` to create an i18n instance |
| 65 | +- In `setup`, specify the i18n instance created with `createI18n` along with `I18nInjectionKey` in `provide` |
| 66 | +- template has `slot` element only |
| 67 | + |
| 68 | +In the `script` block, we first use `createI18n` to create an i18n instance. In a Vue application, the i18n instance created by `createI18n` can be used as a Vue plugin by specifying the i18n instance in the Vue application `app.use` created by `createApp`. 18n instance to the Vue application `app.use` generated by `createApp`, we needed to install Vue I18n as a Vue plugin to the Vue application. |
| 69 | + |
| 70 | +If you use `defineCustomElement`, the Vue component can no longer be controlled from the Vue application side, so even if you run the Web Components version of the component in your Vue application, you can't attach the i18n instance created with `createI18n` to the target Web Components via `app.use` from the Vue application side. |
| 71 | + |
| 72 | +So, in order to attach i18n instances to Web Components, we use `provide` in `setup` to expose i18n instances to other Web Components. This allows Web Components that implement i18n with `useI18n` to work by being hosted by Web Components that work `provide`. |
| 73 | + |
| 74 | +Then, to host other Web Components, the `template` block makes it possible by using the `slot` element. |
| 75 | + |
| 76 | +Export this hosted Web Components as follows: |
| 77 | + |
| 78 | +```javascript |
| 79 | +import { defineCustomElement } from 'vue' |
| 80 | +import I18nHost from './components/I18nHost.ce.vue' |
| 81 | + |
| 82 | +const I18nHostElement = defineCustomElement(I18nHost) |
| 83 | + |
| 84 | +export { I18nHostElement } |
| 85 | +``` |
| 86 | + |
| 87 | +The following `useI18n` implements and exports Web Components to: |
| 88 | + |
| 89 | +```html |
| 90 | +<script setup lang="ts"> |
| 91 | +import { useI18n } from 'vue-i18n' |
| 92 | +
|
| 93 | +const { t } = useI18n() |
| 94 | +</script> |
| 95 | + |
| 96 | +<template> |
| 97 | + <p>{{ t('hello') }}</p> |
| 98 | +</template> |
| 99 | +``` |
| 100 | + |
| 101 | +```javascript |
| 102 | +import { defineCustomElement } from 'vue' |
| 103 | +import HelloI18n from './components/HelloI18n.ce.vue' |
| 104 | + |
| 105 | +const HelloI18nElement = defineCustomElement(HelloI18n) |
| 106 | +export { HelloI18nElement } |
| 107 | +``` |
| 108 | + |
| 109 | +When the following Vue application is registered as a custom element of Web Components: |
| 110 | + |
| 111 | +```javascript |
| 112 | +import { createApp } from 'vue' |
| 113 | +import { I18nHostElement } from './paht/to/I18nHostElement' |
| 114 | +import { HelloI18nElement } from './paht/to/HelloI18nElement' |
| 115 | +import App from './App.vue' |
| 116 | + |
| 117 | +customElements.define('i18n-host', I18nHostElement) |
| 118 | +customElements.define('hello-i18n', HelloI18nElement) |
| 119 | + |
| 120 | +createApp(App).mount('#app') |
| 121 | +``` |
| 122 | + |
| 123 | +So, In `App.vue`, which is the entry point of a Vue application, the following template will work: |
| 124 | + |
| 125 | +```html |
| 126 | +<template> |
| 127 | + <i18n-host> |
| 128 | + <h1>Vue I18n in Web component</h1> |
| 129 | + <hello-i18n /> |
| 130 | + </i18n-host> |
| 131 | +</template> |
| 132 | +``` |
| 133 | + |
| 134 | +The complete example described so far can be looked [here](https://github.com/intlify/vue-i18n-next/tree/master/examples/web-components). |
| 135 | + |
| 136 | +## Limitations |
| 137 | +1. The Vue I18n that can be used to implement Web Components is only **Composition API**. |
| 138 | +2. When implementing Web Components, **Vue components implemented with `useI18n` cannot be imported and used together**. This is due to the [Provide / Inject](https://v3.vuejs.org/guide/web-components.html#definecustomelement) limitations of Vue.js for Web Components. |
| 139 | + |
| 140 | + |
0 commit comments