storybook-addon-intl icon indicating copy to clipboard operation
storybook-addon-intl copied to clipboard

update "lang" attribute on html element when switching languages

Open andyford opened this issue 6 years ago • 2 comments

Maybe I missed it, but when you switch between languages, the lang attribute of the html element is not updated.

One side effect is that if you're using hyphens: auto in CSS, the browser does not know how to properly hyphenate for the current language.

There are some issues on the storybook repo related to the html lang attribute (https://github.com/storybooks/storybook/pulls?utf8=%E2%9C%93&q=lang+attribute) but my storybook implementation does not have a lang attribute, so maybe I did something wrong, but I would expect/hope the html lang attribute would change when using the language switcher, but it does not.

Is this a missing feature of this addon or have I perhaps misconfigured something?

andyford avatar Dec 06 '18 10:12 andyford

What about using an additional decorator class which sets the lang attribute.

Example:

function updateDocumentLanguage(lang) {
	window.document.documentElement.lang = lang;
}

class DocumentLanguageUpdater extends React.Component {
	componentDidMount() {
		updateDocumentLanguage(this.intl.locale);
	}

	componentDidUpdate() {
		updateDocumentLanguage(this.intl.locale);
	}

	render() {
		return this.props.children
	}
}

const DocumentLanguageUpdaterWithIntl = injectIntl(DocumentLanguageUpdater);

function decorator(storyFn) {
	return (
		<DocumentLanguageUpdater>
			{storyFn()}
		</DocumentLanguageUpdater>
	);
}

Except of the decorator function everything could be used in a normal React application which uses react-intl.

floriangosse avatar Feb 25 '19 14:02 floriangosse

I updated @floriangosse example a bit, and it works for me:

import React, { useEffect } from 'react';
import { injectIntl } from 'react-intl';

function DocumentLangUpdater(props) {
  useEffect(() => {
    window.document.documentElement.lang = props.intl.locale;
  }, [props.intl.locale]);

  return props.children
}

const DocumentLangUpdaterWithIntl = injectIntl(DocumentLangUpdater);

export function withDocumentLangUpdater(storyFn) {
  return (
    <DocumentLangUpdaterWithIntl>
      {storyFn()}
    </DocumentLangUpdaterWithIntl>
  );
}

And add the decorator in my storybook config

storybook.addDecorator(withDocumentLangUpdater);

But recieving this warning in browser console:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in $$Date (created by $Example)
    in div (created by Date_Doc$Example)
    in div (created by LayoutContainer)
    in LayoutContainer (created by Stack)
    in Stack (created by Documentation$Impl$Example)
    in div (created by Documentation$Impl$Example)
    in Documentation$Impl$Example (created by Date_Doc$Example)
    in Date_Doc$Example (created by Documentation$Impl)
    in div (created by LayoutContainer)
    in LayoutContainer (created by Stack)
    in Stack (created by Documentation$Impl)
    in Documentation$Impl
    in IntlProvider (created by WithIntl)

Do you have an idea why this happened? Maybe storybook decorator needs to do cleanup?

ixzzd avatar Mar 11 '20 12:03 ixzzd