We use cookies to enhance your experience on the site
CodeWorlds

Creating Useful Plugins

In NOVA LAB, every station system is an independent module. Let's see how to create plugins that are truly useful: toast notifications and i18n (internationalization).

Toast Plugin — Notifications

A toast is a short notification displayed temporarily. The plugin will provide a

show()
method available throughout the entire application:

1const ToastPlugin = {
2  install(app, options = {}) {
3    const duration = options.duration || 3000
4    const position = options.position || 'top-right'
5
6    const toasts = ref([])
7    let toastId = 0
8
9    const toast = {
10      show(message, type = 'info') {
11        const id = toastId++
12        toasts.value.push({ id, message, type })
13        setTimeout(() => {
14          toasts.value = toasts.value.filter(t => t.id !== id)
15        }, duration)
16      },
17      success(msg) { this.show(msg, 'success') },
18      error(msg) { this.show(msg, 'error') },
19      warning(msg) { this.show(msg, 'warning') },
20      list: toasts
21    }
22
23    app.provide('toast', toast)
24  }
25}

Usage in a component:

1<script setup>
2import { inject } from 'vue'
3
4const toast = inject('toast')
5
6function onSave() {
7  toast.success('Data saved!')
8}
9
10function onError() {
11  toast.error('Satellite connection error!')
12}
13</script>

i18n Plugin — Multilingual Support

A plugin for translating texts into different languages:

1const I18nPlugin = {
2  install(app, options) {
3    const locale = ref(options.defaultLocale || 'pl')
4    const messages = options.messages || {}
5
6    function t(key) {
7      const keys = key.split('.')
8      let result = messages[locale.value]
9      for (const k of keys) {
10        result = result?.[k]
11      }
12      return result || key
13    }
14
15    function setLocale(lang) {
16      if (messages[lang]) {
17        locale.value = lang
18      }
19    }
20
21    app.provide('i18n', {
22      t,
23      locale,
24      setLocale,
25      availableLocales: Object.keys(messages)
26    })
27
28    app.directive('t', (el, binding) => {
29      el.textContent = t(binding.value)
30    })
31  }
32}

Usage:

1app.use(I18nPlugin, {
2  defaultLocale: 'pl',
3  messages: {
4    pl: {
5      nav: { home: 'Strona główna', settings: 'Ustawienia' },
6      status: { online: 'Połączony', offline: 'Rozłączony' }
7    },
8    en: {
9      nav: { home: 'Home', settings: 'Settings' },
10      status: { online: 'Connected', offline: 'Disconnected' }
11    }
12  }
13})

In a component:

1<script setup>
2import { inject } from 'vue'
3const { t, setLocale, locale } = inject('i18n')
4</script>
5
6<template>
7  <nav>
8    <a>{{ t('nav.home') }}</a>
9    <a>{{ t('nav.settings') }}</a>
10  </nav>
11  <p>Status: {{ t('status.online') }}</p>
12  <button @click="setLocale('en')">EN</button>
13  <button @click="setLocale('pl')">PL</button>
14</template>

Good Plugin Patterns

  1. Provide/Inject — prefer over globalProperties
  2. Options with default values — the plugin must work without configuration
  3. Typing — export interfaces for TypeScript
  4. Cleanup — if the plugin modifies the DOM, ensure proper cleanup
  5. Documentation — describe available options and methods
Go to CodeWorlds