From 8ca242efd0b112dc7061574d3396f614cccf1d4a Mon Sep 17 00:00:00 2001 From: Aral Roca Date: Thu, 8 Jun 2023 18:24:22 +0200 Subject: [PATCH] add hoc to fix client components in next-translate-plugin --- package.json | 2 +- src/index.tsx | 1 + src/withTranslationClientComponent.tsx | 59 ++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/withTranslationClientComponent.tsx diff --git a/package.json b/package.json index 3aa53a8..e6852a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-translate", - "version": "2.0.6", + "version": "2.3.0-canary.3", "description": "Tiny and powerful i18n tools (Next plugin + API) to translate your Next.js pages.", "license": "MIT", "keywords": [ diff --git a/src/index.tsx b/src/index.tsx index 8eb03ad..3c0a440 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -115,6 +115,7 @@ declare global { var __NEXT_TRANSLATE__: { namespaces: Record lang: string + pathname?: string } namespace NodeJS { diff --git a/src/withTranslationClientComponent.tsx b/src/withTranslationClientComponent.tsx new file mode 100644 index 0000000..c58014a --- /dev/null +++ b/src/withTranslationClientComponent.tsx @@ -0,0 +1,59 @@ +import React, { useEffect, useReducer } from 'react' +import type { LoaderConfig } from '.' + +/** + * @description HOC for internal use only (used by next-translate-plugin) + */ +export default function withTranslationClientComponent< + P extends JSX.IntrinsicAttributes +>( + Component: React.ComponentType

, + i18nConfig: LoaderConfig +): React.ComponentType

{ + function WithTranslation(props: P) { + // @ts-ignore + const forceUpdate = useReducer(() => [])[1] + const isClient = typeof window !== 'undefined' + + if (isClient && !window.__NEXT_TRANSLATE__) { + window.__NEXT_TRANSLATE__ = { + lang: i18nConfig.defaultLocale!, + namespaces: {}, + } + update(false) + } + + if (isClient && !window.i18nConfig) { + window.i18nConfig = i18nConfig + } + + useEffect(update) + + function update(rerender = true) { + const el = document.getElementById('__NEXT_TRANSLATE_DATA__') + + if (!el) return + + const { lang, ns, pathname } = el.dataset as { + lang: string + ns: string + pathname: string + } + + const shouldRerender = + lang !== window.__NEXT_TRANSLATE__.lang || + pathname !== window.__NEXT_TRANSLATE__.pathname + + window.__NEXT_TRANSLATE__ = { lang, namespaces: JSON.parse(ns), pathname } + + if (shouldRerender && rerender) forceUpdate() + } + + return + } + + const displayName = Component.displayName || Component.name || 'Component' + WithTranslation.displayName = `withTranslationClientComponent(${displayName})` + + return WithTranslation +}