A tale of updating i18 locale based on global parameters: a guide

I am in the process of transitioning from @storybook/addon-knobs to @storybook/addon-controls, but I have encountered a problem.

I have a knob that is used to update the i18n locale.
It also switches from rtl to ltr.
This knob works perfectly:

import { select } from '@storybook/addon-knobs'
import Vue from "vue";

// import vue plugins
import VueI18n from "vue-i18n";

// import language file
const message = require("./translations.json");

// i18n and store
Vue.use(VueI18n);

import store from "../src/store";
addDecorator(() => ({
  template: "<story/>",
  i18n: new VueI18n({
    defaultLocale: 'en',
    locale: 'en',
    locales: [ 'en', 'ar' ],
    messages: {
      en: message.en,
      ar: message.ar,
    },
  }),
  // add a props to toggle language
  props: {
    storybookLocale: {
      type: String,
      default: select('I18n locale', ['en', 'ar'], 'en'),
    },
  },
  watch: {
    // add a watcher to toggle language
    storybookLocale: {
      handler() {
        this.$i18n.locale = this.storybookLocale;
        let dir = this.storybookLocale === 'ar' ? 'rtl' : 'ltr';
        document.querySelector('html').setAttribute('dir', dir);
      },
      immediate: true,
    },
  },
}));

Now, when trying to use @storybook/addon-controls, I am struggling to understand how to implement it.

I have gone through the Storybook documentation and managed to replace my knob with a new select option in the toolbar.

export const globalTypes = {
  storybookLocale: {
    name: 'storybookLocale',
    description: 'Internationalization locale',
    defaultValue: 'en',
    toolbar: {
      icon: 'globe',
      items: [
        { value: 'en', right: 'πŸ‡ΊπŸ‡Έ', title: 'English' },
        { value: 'ar', right: 'πŸ‡¦πŸ‡ͺ', title: 'Arabic' },
      ],
    },
  },
};

Here is an example of a story:

import SectionTitle from '../src/components/onboarding/section-title.vue'

export default {
  title: 'Onboarding/Components/Title',
  component: SectionTitle,
};

const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { SectionTitle },
  template: '<SectionTitle v-bind="$props" />',
});

export const Title:any = Template.bind({});
Title.args = {
  stepNumber: 1,
}

I am unsure of how to watch for changes in this global variable to update my i18n settings and language direction.
The documentation shows how to consume the global within a story, but I want it to be applied globally.

Any assistance would be greatly appreciated.

Answer β„–1

Although my expertise lies in React, I believe the following approach should do the trick.

Solution

  • Take note of context.globals which is passed as the second argument to the decorator.
  • Swap out addDecorator with the exported array decorators.
  • Make sure to update this.storybookLocale to context.globals.storybookLocale.

Notes

  • For information on using a decorator for globals, refer to the docs here.
  • I came across this relevant article, but didn't find it very useful since you already had the basic setup in place. They cover some additional steps, but their necessity in your case is uncertain.

.storybook/preview.js

import Vue from "vue";
import VueI18n from "vue-i18n";
import store from "../src/store";
import message from "./translations.json";

Vue.use(VueI18n);

export const globalTypes = {
  storybookLocale: {
    name: 'storybookLocale',
    description: 'Internationalization locale',
    defaultValue: 'en',
    toolbar: {
      icon: 'globe',
      items: [
        { value: 'en', right: 'πŸ‡ΊπŸ‡Έ', title: 'English' },
        { value: 'ar', right: 'πŸ‡¦πŸ‡ͺ', title: 'Arabic' },
      ],
    },
  },
};

export const decorators = [
  (story, context) => ({
    template: "<story/>",
    i18n: new VueI18n({
      defaultLocale: 'en',
      locale: 'en',
      locales: [ 'en', 'ar' ],
      messages: {
        en: message.en,
        ar: message.ar,
      },
    }),
    props: {
      storybookLocale: {
        type: String,
        default: 'en',
      },
    },
    watch: {
      storybookLocale: {
        handler() {
          this.$i18n.locale = context.globals.storybookLocale;
          let dir = storybookLocale === 'ar' ? 'rtl' : 'ltr';
          document.querySelector('html').setAttribute('dir', dir);
        },
        immediate: true,
      },
    },
  })
];

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the most effective method for locating and updating an object within an array using JavaScript?

I have a list of products structured like this: var itemsList = [ { id: 'as5', name: 'Coca-Cola', price: 17.5, unit: 'Bottles', quantity: 23 }, { id: 'q7s ...

When typed into the search bar input box, text becomes reversed

I've encountered an issue where text entered into a text field appears in reverse order. For instance, when I type " Hi how are you ", it displays as " UYO REA OH HI ". How can this be resolved? I am using the silent WP theme and have tried inspecting ...

Tips for changing the default event name in Vuetify V-Calendar?

Currently, I am in the process of developing an application that utilizes API Rest as the back-end and Vue.js for the front-end. Within this project, I have incorporated the Vuetify framework and integrated the V-Calendar component, which has been working ...

What is the method by which frameworks such as Angular encapsulate CSS within a component?

I have a question out of curiosity, rather than seeking a solution to a specific issue. Can you explain how frameworks such as Angular manage to keep CSS contained within a component and prevent it from spreading across the entire webpage? ...

Is an encrypted JSON API that utilizes cookies for authentication and nonces considered to be secure in general?

Is it possible to create a secure SSL'ed API that authenticates using a session ID within a cookie, includes a nonce as a query parameter, and always responds with a JSON 'Object' response? How effective would this be against XSRF attacks? ...

I am looking for JavaScript or jQuery code that allows me to incorporate a "Save This Page As" button

Is there a way to enhance the saving process for users visiting an HTML page, rather than requiring them to go through File > Save As? I am interested in implementing a "Save Page As" button on the page that would trigger the save as dialog when clicke ...

Guidance on implementing fallback font formats using FontFace API

I am exploring the FontFace API (not @fontface) and wondering if there is an easy way to include multiple font formats, similar to providing multiple sources in @fontface. Alternatively, is there a simple method to identify which font formats are supporte ...

The CSS transition fails to function correctly when rendering a React element within an array

When rendering a React component within an array using CSS transitions, I noticed that the elements in the array re-order and change style. Surprisingly, only the elements moving up have transitions applied, while the ones moving down do not. I expect all ...

before the ajax response is received, running ahead

I've encountered an issue where I'm attempting to execute a function after an ajax return has finished using then, but it appears to be running before the return completes. Here is the code snippet in question: var existingUser = false; $.ajax( ...

Generating a JavaScript array in PHP

As I work on developing a dynamic Google Geochart, one key aspect is creating an array to hold the data. The structure includes the country as the unique identifier and the color value to determine the map shading. arrayData = [['Country',' ...

Is the stacking or overriding of promise requests possible in Javascript with $q?

Hey there, I'm new to AngularJs and have a question for you all. Does a $q promise request in AngularJs overwrite or stack? Here's the scenario... I have a function called prom function prom{} that returns a $q promise. So, if I call prom twice, ...

Sending Location Data From JavaScript to PHP via Cookies

I encountered an issue while attempting to send Geolocation coordinates from JavaScript to PHP using Cookies. The error message I am receiving is: Notice: Undefined index: data in /Applications/XAMPP/xamppfiles/htdocs/samepage.php on line 24 The file name ...

What is the process for converting and transferring the date in Google Apps Script to generate a new event in Google Calendar?

To create an event in GAS, follow this link: https://developers.google.com/apps-script/reference/calendar/calendar#createEvent(String,Date,Date,Object) var event = CalendarApp.getDefaultCalendar().createEvent('Apollo 11 Landing', new Date(& ...

The functionality for PHP photo upload preview is currently not compatible with images taken with a mobile camera

In my responsive web app, users can upload photos. Everything works perfectly on desktop, but on mobile devices, there's a peculiar issue. When attempting to upload a photo by using the camera option, the preview doesn't show up unless an alert i ...

Learning how to interpret input from the command line in Vertx

Would appreciate some guidance on how to read command line arguments in vert.x using JavaScript. For instance, I am wondering how to go about reading: arguments(arg1, arg2, arg3) vertx run example.js arg1 arg2 arg3 ...

Change of weekly scheduled date for hyperlink url

Each week, I release a newsletter with a consistent file path and similar file name except for the date. The newsletter is published every 7 days, requiring me to update the link by adding 7 days to the date each time. It's important that the date is ...

The redirection to the HTML page happens too soon, causing the ASYNC functions to fail in saving the user's image and data to the server

Hey everyone! I'm facing an issue with async/await functions. Here's the code snippet from my backend where I'm trying to save details of a newly registered user. I'm puzzled as to why the Redirect() function is executing before the f ...

My app.js failed to launch on Heroku, receiving a Code H10 status 503 error

Starting with some screenshots: https://i.sstatic.net/E0pyj.png https://i.sstatic.net/SkZDv.png https://i.sstatic.net/HJ3Iw.png https://i.sstatic.net/LKFv2.png The full error log is below: 2020-06-15T10:46:45.640400+00:00 heroku[web.1]: Starting pro ...

Locate the initial ancestor element that contains a specific child element on the first level

Looking to retrieve the primary parent element of a selected item that contains a checkbox as a direct child. HTML $('input[type="checkbox"]').change(function(e) { $(this) .parent() .parents("li:has(input[type='checkbox'] ...

HTML drag-and-drop setDragImage fails to show ghost image on initial drag operation

Currently, I am working on developing a drag and drop menu feature that allows users to drag an image thumbnail from one div to a canvas element. The main issue I am facing is that the source div uses a sprite for displaying its background thumbnail. As a ...