Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module.exports = {
extends: 'eslint-config-ns-ts',
extends: [
'eslint-config-ns-ts',
// @see https://nextjs.org/docs/basic-features/eslint
'plugin:@next/next/recommended'
],
rules: {
/**
* This rule was disabled because of NextJS' Link API.
Expand Down
42 changes: 42 additions & 0 deletions .storybook/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { initReactI18next } from 'react-i18next'
import i18n from 'i18next';

import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';


/**
* Example
* - @see https://github.com/i18next/react-i18next/blob/7cfab9746b3ccc6f833cd9c892e7c3c804944a5e/example/react-typescript4.1/namespaces/src/i18n/config.ts#L13
*/
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
lng: 'en',
fallbackLng: 'en',
// have a common namespace used around the full app
ns: ['common'],
defaultNS: 'common',
debug: true,
interpolation: {
escapeValue: false, // not needed for react!!
},
// resources: {
// en: {
// 'common': {
// "home": "Home GERMAN",
// "home_EN": "Home English"
// }
// },
// de: {
// 'common': {
// "home": "Home DEUTSCH",
// "home_EN": "Home ENGLISCH"
// }
// }
// },
})

export default i18n
20 changes: 20 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ module.exports = {
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'storybook-addon-next-router',
'storybook-addon-i18next/register',
{
/**
* NOTE: fix Storybook issue with PostCSS@8
Expand Down Expand Up @@ -44,6 +46,24 @@ module.exports = {
...config.resolve?.alias,
'@': [path.resolve(__dirname, '../src/'), path.resolve(__dirname, '../')],
}

/**
* Fixes issue with `next-i18next` and is ready for webpack@5
* @see https://github.com/isaachinman/next-i18next/issues/1012#issuecomment-792697008
* @see https://github.com/storybookjs/storybook/issues/4082#issuecomment-758272734
* @see https://webpack.js.org/migrate/5/
*
* source: https://github.com/isaachinman/next-i18next/issues/1012#issuecomment-818042184
*/
config.resolve.fallback = {
...config.resolve?.fallback,
fs: false,
// tls: false,
// net: false,
// module: false,
// path: require.resolve('path-browserify'),
}

return config
},
}
29 changes: 19 additions & 10 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { withNextRouter } from 'storybook-addon-next-router'
import React, { Suspense } from 'react';
import { RouterContext } from "next/dist/next-server/lib/router-context";
// import { I18nextProvider } from 'react-i18next';
import { withI18next } from 'storybook-addon-i18next';

import '../src/styles/index.scss'

// @see https://www.npmjs.com/package/storybook-addon-next-router
export const decorators = [
withNextRouter({
path: '/', // defaults to `/`
asPath: '/', // defaults to `/`
query: {}, // defaults to `{}`
push() {}, // defaults to using addon actions integration, can override any method in the router
}),
]
import i18n from './i18n'

export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
Expand All @@ -20,4 +15,18 @@ export const parameters = {
date: /Date$/,
},
},
// @see https://www.npmjs.com/package/storybook-addon-next-router
nextRouter: {
Provider: RouterContext.Provider,
path: '/', // defaults to `/`
asPath: '/', // defaults to `/`
query: {}, // defaults to `{}`
push() {}, // defaults to using addon actions integration, can override any method in the router
}
}

export const decorators = [
// Story => <I18nextProvider i18n={i18n}><Story /></I18nextProvider>,
withI18next({ i18n, languages: { en: 'English', de: 'Deutsch' }}),
Story => <Suspense fallback='loading...'><Story /></Suspense>
]
80 changes: 80 additions & 0 deletions __mocks__/react-i18next.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable react/display-name */
/* eslint-disable no-confusing-arrow */

/**
* Setup i18n in tests
*
* Docs
* @see https://react.i18next.com/misc/testing
*
* Inspired by
* @see https://github.com/i18next/react-i18next/blob/552ed79036c28f282afe7c6ccb525b82b76e71d5/example/test-jest/src/__mocks__/react-i18next.js
*
* Alternative examples using `i18n.use()...`
* @see https://github.com/i18next/react-i18next/blob/552ed79036c28f282afe7c6ccb525b82b76e71d5/example/test-jest/src/setupTests.js#L4-L23
* @see https://github.com/i18next/react-i18next/blob/552ed79036c28f282afe7c6ccb525b82b76e71d5/test/i18n.js
* @see https://github.com/isaachinman/next-i18next/issues/377#issuecomment-700516821
*/

const React = require('react')
const reactI18next = require('react-i18next')

const hasChildren = node =>
node && (node.children || (node.props && node.props.children))

const getChildren = node =>
node && node.children ? node.children : node.props && node.props.children

const renderNodes = reactNodes => {
if (typeof reactNodes === 'string') {
return reactNodes
}

return Object.keys(reactNodes).map((key, i) => {
const child = reactNodes[key]
const isElement = React.isValidElement(child)

if (typeof child === 'string') {
return child
}
if (hasChildren(child)) {
const inner = renderNodes(getChildren(child))
return React.cloneElement(child, { ...child.props, key: i }, inner)
}
if (typeof child === 'object' && !isElement) {
return Object.keys(child).reduce(
(str, childKey) => `${str}${child[childKey]}`,
'',
)
}

return child
})
}

/**
* @type any
*/
const useMock = [k => k, {}]
useMock.t = k => k
useMock.i18n = {}

module.exports = {
// this mock makes sure any components using the translate HoC receive the t function as a prop
withTranslation: () => Component => props => (
<Component t={k => k} {...props} />
),
Trans: ({ children }) =>
Array.isArray(children) ? renderNodes(children) : renderNodes([children]),
Translation: ({ children }) => children(k => k, { i18n: {} }),
useTranslation: () => useMock,

// mock if needed
I18nextProvider: reactI18next.I18nextProvider,
initReactI18next: reactI18next.initReactI18next,
setDefaults: reactI18next.setDefaults,
getDefaults: reactI18next.getDefaults,
setI18n: reactI18next.setI18n,
getI18n: reactI18next.getI18n,
}
3 changes: 2 additions & 1 deletion cypress.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"baseUrl": "http://localhost:3000"
"baseUrl": "http://localhost:3000",
"video": false
}
26 changes: 0 additions & 26 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable import/no-extraneous-dependencies */
import 'jest-preset-ns/presets/react/jest-setup.js'

import { setConfig } from 'next/config'
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants'
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import { NextRouter } from 'next/router'

// @ts-ignore
Expand All @@ -22,29 +19,6 @@ const { publicRuntimeConfig, serverRuntimeConfig } = NextConfig(
*/
setConfig({ publicRuntimeConfig, serverRuntimeConfig })

/**
* Setup i18n in tests
*
* @see https://github.com/i18next/react-i18next/blob/552ed79036c28f282afe7c6ccb525b82b76e71d5/example/test-jest/src/setupTests.js#L4-L23
* @see https://github.com/isaachinman/next-i18next/issues/377#issuecomment-700516821
*/
i18n.use(initReactI18next).init({
lng: 'en',
fallbackLng: 'en',

// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',

// debug: true,

interpolation: {
escapeValue: false, // not needed for react!!
},

resources: { en: { translations: {} } },
})

/**
* mockRouter mocks the initial router state of Next.js
* @see https://github.com/vercel/next.js/issues/7479#issuecomment-752418517
Expand Down
17 changes: 1 addition & 16 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

type NextConfig = {
publicRuntimeConfig: {
NODE_ENV: string
/**
* version of the app
*/
VERSION: string
}
serverRuntimeConfig: Record<string, unknown>
}

declare module 'next/config' {
export declare function setConfig(configValue: any): void
export default function getConfig(): NextConfig
}
/// <reference types="next/image-types/global" />
12 changes: 5 additions & 7 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ const version = require('./version')
* – It should be availabe already: https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/config-shared.ts#L12
*/
const nextConfig = {
poweredByHeader: false,
/**
* Opt-in to webpack 5 support
* @see https://github.com/vercel/next.js/issues/21679#issuecomment-771941447
*/
future: {
webpack5: true,
eslint: {
// We have manual checks in place to make sure we do not build dangerous
// code.
ignoreDuringBuilds: true,
},
i18n,
poweredByHeader: false,
publicRuntimeConfig: {
NODE_ENV: process.env.NODE_ENV,
VERSION: version,
Expand Down
Loading