Skip to content

Commit

Permalink
Add Storybook template for i18n (#4764)
Browse files Browse the repository at this point in the history
Co-authored-by: Tobbe Lundberg <tobbe@tlundberg.com>
Co-authored-by: Peter Colapietro <petercolapietro+github@gmail.com>
Co-authored-by: David Price <thedavid@thedavidprice.com>
  • Loading branch information
4 people committed Mar 30, 2022
1 parent 6e4e213 commit dd9656b
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 49 deletions.
14 changes: 13 additions & 1 deletion packages/cli/src/commands/setup/i18n/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { errorTelemetry } from '@redwoodjs/telemetry'

import { getPaths, writeFile } from '../../../lib'
import c from '../../../lib/colors'
import configureStorybook from '../../../lib/configureStorybook.js'

export const command = 'i18n'
export const description = 'Set up i18n'
Expand Down Expand Up @@ -72,7 +73,7 @@ export const handler = async ({ force }) => {
},
},
{
title: 'Configuring i18n...',
title: 'Configure i18n...',
task: () => {
/**
* Write i18n.js in web/src
Expand Down Expand Up @@ -169,6 +170,17 @@ export const handler = async ({ force }) => {
}
},
},
{
title: 'Configuring Storybook...',
task: async () =>
configureStorybook(
{ force },
fs.readFileSync(
path.join(__dirname, 'templates', 'storybook.preview.js.template'),
'utf-8'
)
),
},
{
title: 'One more thing...',
task: (_ctx, task) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ export default HomePage
*/

i18n
.use(initReactI18next)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
.use(initReactI18next)
.init({
interpolation: { escapeValue: false }, // React already does escaping
fallbackLng: 'en',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react'
import { I18nextProvider } from 'react-i18next'
import i18n from 'web/src/i18n'

/** @type { import("@storybook/csf").GlobalTypes } */
export const globalTypes = {
locale: {
name: 'Locale',
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'fr', right: '🇫🇷', title: 'Français' },
],
},
},
}

//**
* We're following Storybook's naming convention here. See for example
* https://github.com/storybookjs/addon-kit/blob/main/src/withGlobals.ts
* Unfortunately that will make eslint complain, so we have to disable it when
* using a hook below
*
* @param { import("@storybook/addons").StoryFn} StoryFn
* @param { import("@storybook/addons").StoryContext} context
* @returns a story wrapped in an I18nextProvider
*/
const withI18n = (StoryFn, context) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useEffect(() => {
i18n.changeLanguage(context.globals.locale)
}, [context.globals.locale])

return (
<I18nextProvider i18n={i18n}>
<StoryFn />
</I18nextProvider>
)
}

export const decorators = [withI18n]
23 changes: 17 additions & 6 deletions packages/cli/src/commands/setup/ui/libraries/chakra-ui.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import fs from 'fs'
import path from 'path'

import execa from 'execa'
import Listr from 'listr'

import c from '../../../../lib/colors'
import {
checkStorybookStatus,
configureStorybook,
} from '../tasks/configure-storybook'
import configureStorybook from '../../../../lib/configureStorybook.js'
import { checkSetupStatus, wrapWithChakraProvider } from '../tasks/setup-chakra'

export const command = 'chakra-ui'
Expand Down Expand Up @@ -62,8 +62,19 @@ export async function handler({ force, install }) {
},
{
title: 'Configure Storybook...',
skip: () => checkStorybookStatus({ force }) === 'done',
task: async () => configureStorybook(),
task: async () =>
configureStorybook(
{ force },
fs.readFileSync(
path.join(
__dirname,
'..',
'templates',
'storybook.preview.js.template'
),
'utf-8'
)
),
},
])

Expand Down
40 changes: 0 additions & 40 deletions packages/cli/src/commands/setup/ui/tasks/configure-storybook.js

This file was deleted.

71 changes: 71 additions & 0 deletions packages/cli/src/lib/configureStorybook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import fs from 'fs-extra'

import { getPaths } from '.'

/**
* Configure Storybook for the given template by creating a custom preview config
*/
export default function configureStorybook({ force }, newStorybookPreview) {
const storybookPreviewConfigPath = getPaths().web.storybookPreviewConfig

let storybookPreviewConfig
/**
* Check if storybookPreviewConfigPath already exists.
* Merge both files if it does.
* By removing import react and export decorator from new config
* And put new config inside current config after last import
*/
if (fs.existsSync(storybookPreviewConfigPath)) {
if (force) {
fs.unlinkSync(storybookPreviewConfigPath)
storybookPreviewConfig = newStorybookPreview
} else {
const currentConfig = fs
.readFileSync(storybookPreviewConfigPath)
.toString()

const newDecoratorsName = newStorybookPreview.match(
/export const decorators = \[(.*?)\]/
)[1]

const currentDecoratorsName = currentConfig.match(
/export const decorators = \[(.*?)\]/
)[1]

const decoratorsExport = `export const decorators = [${currentDecoratorsName}, ${newDecoratorsName}]`

const insideNewStorybookConfigWithoutReactAndDecoration =
newStorybookPreview
.replace(/import \* as React from 'react'/, '')
.replace(/export const decorators = .*/, '')

const currentConfigWithoutDecoration = currentConfig.replace(
/export const decorators = .*/,
''
)

const reversedCurrentConfig = currentConfigWithoutDecoration
.split('\n')
.reverse()

const indexOfLastImport = reversedCurrentConfig.findIndex((value) =>
/^import /.test(value)
)
reversedCurrentConfig.splice(
indexOfLastImport,
0,
insideNewStorybookConfigWithoutReactAndDecoration
)
storybookPreviewConfig =
reversedCurrentConfig.reverse().join(`\n`) +
`\n` +
currentConfig +
`\n` +
decoratorsExport
}
} else {
storybookPreviewConfig = newStorybookPreview
}

fs.outputFileSync(storybookPreviewConfigPath, storybookPreviewConfig)
}

0 comments on commit dd9656b

Please sign in to comment.