UKR*_*man 5 next.js react-hooks next-i18next
为了创建一个网站,我使用 nextjs,在创建页面时,我将带有页眉和页脚的总体布局放入一个单独的临时组件中,并将页面组件包装在文件中_app.jsx:
function App({ Component, ...rest }) {
const { store, props } = wrapper.useWrappedStore(rest)
return (
<Provider store={store}>
<Layout>
<Component {...props.pageProps} />
</Layout>
</Provider>
)
}
Run Code Online (Sandbox Code Playgroud)
一切正常,直到本地化成为问题,使用next-18next库进行翻译并添加后serverSideTranslations,每个页面上开始出现两个错误:
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
frontend-node_1 | TypeError: Cannot read properties of undefined (reading 'label')
frontend-node_1 | at DropdownSwitcher (webpack-internal:///./src/components/header/translation/DropdownSwitcher.jsx:45:36)
frontend-node_1 | at renderWithHooks (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5658:16)
frontend-node_1 | at renderIndeterminateComponent (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5731:15)
frontend-node_1 | at renderElement (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5946:7)
frontend-node_1 | at renderMemo (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5868:3)
frontend-node_1 | at renderElement (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6011:11)
frontend-node_1 | at renderNodeDestructiveImpl (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6104:11)
frontend-node_1 | at renderNodeDestructive (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6076:14)
frontend-node_1 | at renderNode (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6259:12)
frontend-node_1 | at renderHostElement (/app/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5642:3)
Run Code Online (Sandbox Code Playgroud)
出现“label”错误是因为服务器上的 i18n 对象为空:
const DropdownSwitcher = () => {
const { i18n } = useTranslation()
const currentLanguage = useMemo(() => { // language as undefined
return LANGUAGES.find((item) => item.language === i18n.language)
}, [i18n.language])
....
Run Code Online (Sandbox Code Playgroud)
但客户端一切正常,没有错误。可能是什么原因以及如何修复它,因为文件中的应用程序本身_app.jsx被包装在appWithTranslationfrom next-i18next.
因此,出现了两个问题,如何修复react-i18next:: You will need to pass in an i18next instance by using initReactI18next以及为什么服务器上没有 i18n 对象?
我将布局移动到页面本身的级别,将其从 _app.js 中删除,但由于某种原因,然后某些内容useEffect()在标头中重复,尽管标头组件没有以任何方式更改并将布局带到该级别修复_app.jsx它
如果没有足够的信息或者您需要一个直观的示例,我将尝试创建一个小程序来用开源来演示这一点。请写在评论中。
我解决了我的问题,但我忘了在这里提供答案,但我注意到有人也有这个问题,所以我会尽力帮助遇到这篇文章的人,尽管它仅与nextjs版本12相关,因为外观版本 14 的结构已经改进了很多,我认为应该不会再有像我这样的问题了。
1. 渲染布局
在官方文档中,有一整节内容描述了如何正确划分布局,使其根据 SPA 类型工作。
页面/index.jsx
// pages/index.jsx
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return (
/** Your content */
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
Run Code Online (Sandbox Code Playgroud)
页面/_app.js
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Run Code Online (Sandbox Code Playgroud)
这种组件方法方法比使用它的方向要好得多,_app.jsx因为您可以扩展或替换它们,而不是制作一个粗糙的整体,例如我如何使用它:
// pages/ingex.jsx
function HomePage() {
return (
<HomeLayout>
<Main />
</HomeLayout>
)
}
HomePage.getLayout = (page) => <MainLayout>{page}</MainLayout>
Run Code Online (Sandbox Code Playgroud)
// pages/about-us.jsx
const AboutUsPage = () => {
return (
<>
<HomeLayout>
<AboutUs />
</HomeLayout>
</>
)
}
AboutUsPage.getLayout = (page) => (
<MainLayout withNav>
<LayoutContext.Consumer>
{({ device }) => device.isMobile && <NavigationMobile />}
</LayoutContext.Consumer>
{page}
</MainLayout>
)
Run Code Online (Sandbox Code Playgroud)
通过这种方法,React 仍然像一个 spa 和一个类似的页面一样工作about-us,其中也将有NavigationMobile,将简单地比较它。
2. next-i18next 错误
关键在于 next-i18next 库首先配置不正确(更准确地说,需要纠正)。为了正确配置所有内容,我必须执行以下操作:
- 将包含翻译文件的文件夹移至公共文件夹。这是必要的,以便库配置(我们将在下面进行一些配置)可以看到翻译文件并与它们交互
- 配置 next-i18next.config.js 以与客户端配合使用。这是一个带有一些注释的示例设置。还有文档的链接以及我在设置时找到的一些其他资源。
下一个-i18next.config.js
const path = require('path')
const LANGUAGES = ['en', 'pl', 'uk']
const DEFAULT_LANGUAGE = 'en'
// if it is the server, then the full path, if the client, then the relative path.
const localePath =
typeof window === 'undefined' ? path.resolve('public', 'translation') : '/public/translation'
module.exports = {
i18n: {
defaultLocale: DEFAULT_LANGUAGE,
locales: LANGUAGES,
fallbackLng: LANGUAGES,
nsSeparator: '::',
keySeparator: '::',
// How to use libraries for i18next like LanguageDetector
use: [require('i18next-intervalplural-postprocessor')],
serializeConfig: false,
},
localePath: localePath,
}
Run Code Online (Sandbox Code Playgroud)
- 在 _app.jsx 文件中配置 next-i18next。这里一切都如文档中所述。
import { appWithTranslation } from 'next-i18next'
import nextI18NextConfig from '../../next-i18next.config'
function App({ Component, ...rest }) {
const { store, props } = wrapper.useWrappedStore(rest)
const getLayout = Component.getLayout || ((page) => page)
//WARNING!!! You don't have to have your own i18next initialization like i18next.use(LanguageDetector).use(intervalPlural).init({ detection: options }) this is all done by the next-i18next library
return (
<Provider store={store}>
<AppHOC>{getLayout(<Component {...props.pageProps} />)}</AppHOC>
</Provider>
)
}
export default appWithTranslation(App, nextI18NextConfig)
Run Code Online (Sandbox Code Playgroud)
- 调用serverSideTranslations函数时需要传递配置。为了让您的生活更轻松,最好将此函数的实现转移到另一个文件中,这是我的做法的示例:
// utils/serverSideTranslations.js
import { serverSideTranslations as baseServerSideTranslations } from 'next-i18next/serverSideTranslations'
import { dt } from '../../constants/defaultTranslate'
import { DEFAULT_LANGUAGE } from '../../constants/languages'
import nextI18NextConfig from '../../../next-i18next.config.js'
const serverSideTranslations = async (locale, domains = []) => {
return await baseServerSideTranslations(locale, [...dt, ...domains], nextI18NextConfig, [
DEFAULT_LANGUAGE,
])
}
export default serverSideTranslations
Run Code Online (Sandbox Code Playgroud)
- 最后,在页面上使用此功能。
import MainLayout from '../components/layouts/MainLayout'
import serverSideTranslations from '../utils/serverSideTranslations'
import HomeLayout from '../components/home/HomeLayout'
import Main from '../components/home/main/Main'
function HomePage() {
return (
<HomeLayout>
<Main />
</HomeLayout>
)
}
HomePage.getLayout = (page) => <MainLayout>{page}</MainLayout>
export const getServerSideProps = async ({ locale }) => {
// Wrapping in Promis.all is not necessary, I use it simply so that if there are any other asynchronous operations, then not to use them through await and not to block each other's work
const [translations] = await Promise.all([
serverSideTranslations(locale, ['home']),
])
return {
props: {
...translations,
},
}
}
export default HomePage
Run Code Online (Sandbox Code Playgroud)
希望对大家有帮助,有什么意见可以在评论里留言
| 归档时间: |
|
| 查看次数: |
1429 次 |
| 最近记录: |