From dc43f7fea5fb9d819b3dca93503190026292950a Mon Sep 17 00:00:00 2001
From: wraeth-eth <104132113+wraeth-eth@users.noreply.github.com>
Date: Fri, 1 Sep 2023 09:06:26 +1000
Subject: [PATCH] unblock lingui and allow for SSR on almost all pages (#3999)
## What does this PR do and why?
The big kahuna - this breaks lingui out into SSR and will not block for client side compilation/rendering
## Screenshots or screen recordings
_If applicable, provide screenshots or screen recordings to demonstrate the changes._
## Acceptance checklist
- [ ] I have evaluated the [Approval Guidelines](https://github.com/jbx-protocol/juice-interface/blob/main/CONTRIBUTING.md#approval-guidelines) for this PR.
- [ ] (if relevant) I have tested this PR in [all supported browsers](https://github.com/jbx-protocol/juice-interface/blob/main/CONTRIBUTING.md#supported-browsers).
- [ ] (if relevant) I have tested this PR in dark mode and light mode (if applicable).
---
.linguirc.json | 19 ----
lingui.config.js | 25 +++++
next.config.js | 19 +++-
package.json | 2 +
src/components/ErrorNotificationButtons.tsx | 2 +-
.../Navbar/components/DropdownMenu.tsx | 2 +
.../Navbar/components/NavLanguageSelector.tsx | 29 +++---
.../components/SummaryCollapsedView.test.tsx | 2 +
.../ProjectDashboard/utils/modals.tsx | 2 +-
.../common/CoreAppWrapper/CoreAppWrapper.tsx | 32 +++---
src/contexts/Language/LanguageProvider.tsx | 73 +++++---------
.../Language/__mocks__/LanguageProvider.tsx | 7 ++
src/hooks/useLinguiInit.ts | 26 +++++
src/locales/utils.ts | 5 +
src/pages/_app.tsx | 11 ++-
src/pages/about/index.tsx | 3 +
src/pages/account/[addressOrEnsName]/edit.tsx | 10 ++
.../account/[addressOrEnsName]/index.tsx | 40 ++++++--
src/pages/activity/index.tsx | 3 +
src/pages/contact/index.tsx | 3 +
src/pages/create/index.tsx | 3 +
src/pages/experimental/flags/index.tsx | 3 +
src/pages/index.tsx | 3 +
src/pages/legal/index.tsx | 3 +
src/pages/p/[handle]/index.tsx | 16 ++-
src/pages/p/[handle]/safe/index.tsx | 9 +-
src/pages/privacy.tsx | 3 +
src/pages/projects/index.tsx | 3 +
src/pages/success-stories/constitutiondao.tsx | 3 +
src/pages/success-stories/moondao.tsx | 3 +
src/pages/success-stories/sharkdao.tsx | 3 +
src/pages/success-stories/studiodao.tsx | 3 +
.../v2/p/[projectId]/contracts/index.tsx | 3 +
src/pages/v2/p/[projectId]/index.tsx | 54 ++++++++---
src/pages/v2/p/[projectId]/safe/index.tsx | 9 +-
.../p/[projectId]/settings/[settingsPage].tsx | 3 +
src/pages/v2/p/[projectId]/settings/index.tsx | 3 +
.../next-server/globalGetServerSideProps.ts | 23 +++++
src/utils/projectPageLoaders.ts | 4 +-
yarn.lock | 97 +++++++++++++++++++
40 files changed, 424 insertions(+), 142 deletions(-)
delete mode 100644 .linguirc.json
create mode 100644 lingui.config.js
create mode 100644 src/contexts/Language/__mocks__/LanguageProvider.tsx
create mode 100644 src/hooks/useLinguiInit.ts
create mode 100644 src/locales/utils.ts
create mode 100644 src/utils/next-server/globalGetServerSideProps.ts
diff --git a/.linguirc.json b/.linguirc.json
deleted file mode 100644
index ee7f81e809..0000000000
--- a/.linguirc.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "catalogs": [
- {
- "path": "src/locales/{locale}/messages",
- "include": ["src"]
- }
- ],
- "format": "po",
- "formatOptions": {
- "lineNumbers": false,
- "origins": false
- },
- "orderBy": "messageId",
- "fallbackLocales": {
- "default": "en"
- },
- "locales": ["en", "zh"],
- "sourceLocale": "en"
-}
diff --git a/lingui.config.js b/lingui.config.js
new file mode 100644
index 0000000000..1fc467eeb6
--- /dev/null
+++ b/lingui.config.js
@@ -0,0 +1,25 @@
+const { formatter } = require('@lingui/format-po')
+
+const locales = ['en', 'zh']
+
+if (process.env.NODE_ENV !== 'production') {
+ locales.push('pseudo')
+}
+
+/** @type {import('@lingui/conf').LinguiConfig} */
+module.exports = {
+ locales: locales,
+ sourceLocale: 'en',
+ pseudoLocale: 'pseudo',
+ catalogs: [
+ {
+ path: 'src/locales/{locale}/messages',
+ include: ['src'],
+ },
+ ],
+ format: formatter({ origins: false, lineNumbers: false }),
+ orderBy: 'messageId',
+ fallbackLocales: {
+ default: 'en',
+ },
+}
diff --git a/next.config.js b/next.config.js
index 7e027d9b55..689511d3e5 100644
--- a/next.config.js
+++ b/next.config.js
@@ -4,6 +4,7 @@
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
const { withSentryConfig } = require('@sentry/nextjs')
const withBundleAnalyzer = require('@next/bundle-analyzer')
+const linguiConfig = require('./lingui.config')
const webpack = require('webpack')
@@ -112,8 +113,19 @@ const SECURITY_HEADERS = [
}, // NOTE: gnosis safe is still allowed due to frame-ancestors definition
]
+/** @type {import('next').NextConfig} */
const nextConfig = removeImports({
- experimental: { esmExternals: true },
+ experimental: {
+ esmExternals: true,
+ swcPlugins: [
+ '@lingui/swc-plugin',
+ {
+ runtimeModules: {
+ i18n: ['@lingui/core', 'i18n'],
+ },
+ },
+ ],
+ },
staticPageGenerationTimeout: 90,
webpack: config => {
config.resolve.fallback = { fs: false, module: false }
@@ -126,6 +138,11 @@ const nextConfig = removeImports({
return config
},
+ i18n: {
+ localeDetection: false,
+ locales: linguiConfig.locales,
+ defaultLocale: linguiConfig.sourceLocale,
+ },
async redirects() {
return [
{
diff --git a/package.json b/package.json
index aa493e9944..8f9015ff1f 100644
--- a/package.json
+++ b/package.json
@@ -162,6 +162,8 @@
"@graphql-codegen/typescript-operations": "^3.0.3",
"@graphql-codegen/typescript-react-apollo": "^3.3.2",
"@graphql-codegen/typescript-resolvers": "^3.2.0",
+ "@lingui/loader": "^4.4.0",
+ "@lingui/swc-plugin": "4.0.4",
"@next/bundle-analyzer": "^13.2.4",
"@testing-library/cypress": "^8.0.2",
"@testing-library/jest-dom": "^5.16.5",
diff --git a/src/components/ErrorNotificationButtons.tsx b/src/components/ErrorNotificationButtons.tsx
index 32d4c2881c..7142d046c3 100644
--- a/src/components/ErrorNotificationButtons.tsx
+++ b/src/components/ErrorNotificationButtons.tsx
@@ -1,7 +1,7 @@
import { WarningOutlined } from '@ant-design/icons'
import { Trans } from '@lingui/macro'
import { Button } from 'antd'
-import LanguageProvider from 'contexts/Language/LanguageProvider'
+import { LanguageProvider } from 'contexts/Language/LanguageProvider'
import { helpPagePath } from 'utils/routes'
import ExternalLink from './ExternalLink'
diff --git a/src/components/Navbar/components/DropdownMenu.tsx b/src/components/Navbar/components/DropdownMenu.tsx
index 63cc234e35..04862eae4d 100644
--- a/src/components/Navbar/components/DropdownMenu.tsx
+++ b/src/components/Navbar/components/DropdownMenu.tsx
@@ -15,6 +15,7 @@ type LinkItem = {
id: string
label: ReactNode
href: string
+ locale?: string
isExternal?: boolean
}
@@ -130,6 +131,7 @@ export const DropdownMenu = ({
{item.label}
diff --git a/src/components/Navbar/components/NavLanguageSelector.tsx b/src/components/Navbar/components/NavLanguageSelector.tsx
index 0e08d88b36..4af481b0a6 100644
--- a/src/components/Navbar/components/NavLanguageSelector.tsx
+++ b/src/components/Navbar/components/NavLanguageSelector.tsx
@@ -1,9 +1,8 @@
import { LanguageIcon } from '@heroicons/react/24/solid'
-import { Trans } from '@lingui/macro'
+import { useLingui } from '@lingui/react'
import { SUPPORTED_LANGUAGES } from 'constants/locale'
-import { useCallback, useMemo } from 'react'
+import { useRouter } from 'next/router'
import { twMerge } from 'tailwind-merge'
-import { reloadWindow } from 'utils/windowUtils'
import { DropdownMenu } from './DropdownMenu'
// Language select tool seen in top nav
@@ -12,16 +11,10 @@ export default function NavLanguageSelector({
}: {
className?: string
}) {
- // Sets the new language with localStorage and reloads the page
- const setLanguage = useCallback((newLanguage: string) => {
- localStorage.setItem('lang', newLanguage)
- reloadWindow()
- }, [])
-
- const currentLanguage = useMemo(
- () => localStorage.getItem('lang') ?? 'en',
- [],
- )
+ const router = useRouter()
+ const {
+ i18n: { locale },
+ } = useLingui()
return (
- {SUPPORTED_LANGUAGES[currentLanguage].short}
+ {SUPPORTED_LANGUAGES[locale].short}
}
items={Object.values(SUPPORTED_LANGUAGES).map(lang => ({
id: lang.code,
label: lang.long,
- onClick: () => {
- setLanguage(lang.code)
+ // TODO: We want to use the bottom but due to a bug in t macros we cant
+ // locale: lang.code,
+ // href: pathname,
+ onClick: async () => {
+ await router.push(router.asPath, router.asPath, { locale: lang.code })
+ router.reload()
},
}))}
/>
diff --git a/src/components/ProjectDashboard/components/Cart/components/SummaryCollapsedView.test.tsx b/src/components/ProjectDashboard/components/Cart/components/SummaryCollapsedView.test.tsx
index 02a6261611..8012cd6c03 100644
--- a/src/components/ProjectDashboard/components/Cart/components/SummaryCollapsedView.test.tsx
+++ b/src/components/ProjectDashboard/components/Cart/components/SummaryCollapsedView.test.tsx
@@ -7,6 +7,8 @@ import { V2V3_CURRENCY_ETH } from 'utils/v2v3/currency'
import { useCartSummary } from '../hooks/useCartSummary'
import { SummaryCollapsedView } from './SummaryCollapsedView'
+jest.mock('contexts/Language/LanguageProvider')
+
jest.mock('use-resize-observer', () => ({
__esModule: true,
default: jest.fn(() => ({
diff --git a/src/components/ProjectDashboard/utils/modals.tsx b/src/components/ProjectDashboard/utils/modals.tsx
index 3e82146cbd..0dbd071bc8 100644
--- a/src/components/ProjectDashboard/utils/modals.tsx
+++ b/src/components/ProjectDashboard/utils/modals.tsx
@@ -1,6 +1,6 @@
import { Trans } from '@lingui/macro'
import { ModalOnCancelFn, ModalOnOkFn } from 'components/modals/JuiceModal'
-import LanguageProvider from 'contexts/Language/LanguageProvider'
+import { LanguageProvider } from 'contexts/Language/LanguageProvider'
import { ReactNode } from 'react'
import { createRoot } from 'react-dom/client'
import { ConfirmationDeletionModal } from '../components/ui/ConfirmationDeletionModal'
diff --git a/src/components/common/CoreAppWrapper/CoreAppWrapper.tsx b/src/components/common/CoreAppWrapper/CoreAppWrapper.tsx
index 4c9aca9f51..1e37757cea 100644
--- a/src/components/common/CoreAppWrapper/CoreAppWrapper.tsx
+++ b/src/components/common/CoreAppWrapper/CoreAppWrapper.tsx
@@ -8,19 +8,11 @@ import ReactQueryProvider from 'contexts/ReactQueryProvider'
import { ThemeProvider } from 'contexts/Theme/ThemeProvider'
import TxHistoryProvider from 'contexts/Transaction/TxHistoryProvider'
import { installJuiceboxWindowObject } from 'lib/juicebox'
-import dynamic from 'next/dynamic'
import { useRouter } from 'next/router'
import React, { useEffect } from 'react'
import { twJoin } from 'tailwind-merge'
import { redirectTo } from 'utils/windowUtils'
-const LanguageProvider = dynamic(
- () => import('contexts/Language/LanguageProvider'),
- {
- ssr: false,
- },
-)
-
/**
* Contains all the core app providers used by each page.
*
@@ -35,19 +27,17 @@ export const AppWrapper: React.FC<
return (
-
-
-
-
-
-
- <_Wrapper hideNav={hideNav}>{children}
-
-
-
-
-
-
+
+
+
+
+
+ <_Wrapper hideNav={hideNav}>{children}
+
+
+
+
+
)
diff --git a/src/contexts/Language/LanguageProvider.tsx b/src/contexts/Language/LanguageProvider.tsx
index 98f14fea92..15699b9efb 100644
--- a/src/contexts/Language/LanguageProvider.tsx
+++ b/src/contexts/Language/LanguageProvider.tsx
@@ -1,60 +1,33 @@
-import { i18n } from '@lingui/core'
-import {
- detect,
- fromNavigator,
- fromStorage,
- fromUrl,
-} from '@lingui/detect-locale'
+import { Messages } from '@lingui/core'
import { I18nProvider } from '@lingui/react'
-import defaultLocale from 'locales/en/messages'
-import { ReactNode } from 'react'
+import { useLingUiInit } from 'hooks/useLinguiInit'
+import React from 'react'
-import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from 'constants/locale'
-
-const getLocale = (): string => {
- if (typeof window === 'undefined') return DEFAULT_LOCALE
-
- let locale =
- detect(fromUrl('lang'), fromStorage('lang'), fromNavigator()) ??
- DEFAULT_LOCALE
-
- if (!SUPPORTED_LOCALES.includes(locale)) {
- locale = DEFAULT_LOCALE
- }
-
- return locale
-}
-
-const activateDefaultLocale = () => {
- const { messages } = defaultLocale
- i18n.load(DEFAULT_LOCALE, messages)
- i18n.activate(DEFAULT_LOCALE)
+export type I18nProviderProps = {
+ children: React.ReactNode
+ i18n?: { messages: Messages; locale: string }
}
-const dynamicActivate = async (locale: string) => {
- try {
- const { messages } = await import(`../../locales/${locale}/messages`)
+let i18nSingleton: { messages: Messages; locale: string } | undefined
- i18n.load(locale, messages)
- i18n.activate(locale)
- } catch (e) {
- console.error(`Error loading locale "${locale}:"`, e)
- // fall back to default locale
- activateDefaultLocale()
+export const LanguageProvider: React.FC = ({
+ children,
+ i18n: _i18n,
+}) => {
+ if (_i18n) {
+ i18nSingleton = _i18n
+ } else {
+ _i18n = i18nSingleton
}
-}
-const locale = getLocale()
-if (locale === DEFAULT_LOCALE) {
- activateDefaultLocale()
-} else {
- dynamicActivate(locale)
-}
+ if (!_i18n)
+ throw new Error(
+ 'i18n must be provided at least once. This is usually done in _app.tsx',
+ )
+
+ const messages = _i18n?.messages ?? []
+ const locale = _i18n?.locale ?? 'en'
+ const i18n = useLingUiInit(messages, locale)
-export default function LanguageProvider({
- children,
-}: {
- children: ReactNode
-}) {
return {children}
}
diff --git a/src/contexts/Language/__mocks__/LanguageProvider.tsx b/src/contexts/Language/__mocks__/LanguageProvider.tsx
new file mode 100644
index 0000000000..9788b09780
--- /dev/null
+++ b/src/contexts/Language/__mocks__/LanguageProvider.tsx
@@ -0,0 +1,7 @@
+// generate mock for LanguageProvider
+
+import { I18nProviderProps } from '../LanguageProvider'
+
+export const LanguageProvider: React.FC = ({ children }) => {
+ return {children}
+}
diff --git a/src/hooks/useLinguiInit.ts b/src/hooks/useLinguiInit.ts
new file mode 100644
index 0000000000..507f31f753
--- /dev/null
+++ b/src/hooks/useLinguiInit.ts
@@ -0,0 +1,26 @@
+// https://github.com/lingui/js-lingui/pull/1541
+
+import { i18n, Messages } from '@lingui/core'
+import { useEffect } from 'react'
+
+export const useLingUiInit = (messages: Messages, locale: string) => {
+ const isClient = typeof window !== 'undefined'
+
+ if (!isClient && locale !== i18n.locale) {
+ // there is single instance of i18n on the server
+ i18n.loadAndActivate({ locale, messages })
+ }
+ if (isClient && i18n.locale === undefined) {
+ // first client render
+ i18n.loadAndActivate({ locale, messages })
+ }
+
+ useEffect(() => {
+ const localeDidChange = locale !== i18n.locale
+ if (localeDidChange) {
+ i18n.loadAndActivate({ locale, messages })
+ }
+ }, [locale, messages])
+
+ return i18n
+}
diff --git a/src/locales/utils.ts b/src/locales/utils.ts
new file mode 100644
index 0000000000..8c7e998b14
--- /dev/null
+++ b/src/locales/utils.ts
@@ -0,0 +1,5 @@
+export async function loadCatalog(locale: string) {
+ const { messages } = await import(`@lingui/loader!./${locale}/messages.po`)
+
+ return messages
+}
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 67de047a0a..aa442530eb 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,4 +1,5 @@
import { Head } from 'components/common'
+import { LanguageProvider } from 'contexts/Language/LanguageProvider'
import SupabaseSessionProvider from 'contexts/SupabaseSession/SupabaseSessionProvider'
import { initWeb3Onboard, useInitWallet } from 'hooks/Wallet'
import type { AppProps } from 'next/app'
@@ -15,13 +16,19 @@ export default function MyApp({ Component, pageProps }: AppProps) {
// Currently, init() must be called *here* (as opposed to AppWrapper), or else it breaks when navigating between pages.
useInitWallet()
+ if (!pageProps.i18n) {
+ console.error(
+ 'Missing i18n prop - please ensure that page has globalGetServerSideProps',
+ )
+ }
+
return (
- <>
+
{/* Default HEAD - overwritten by specific page SEO */}
- >
+
)
}
diff --git a/src/pages/about/index.tsx b/src/pages/about/index.tsx
index 647ec3fade..1bac5b0ffb 100644
--- a/src/pages/about/index.tsx
+++ b/src/pages/about/index.tsx
@@ -1,5 +1,6 @@
import { AboutDashboard } from 'components/AboutDashboard'
import { AppWrapper, Head } from 'components/common'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function AboutPage() {
return (
@@ -17,3 +18,5 @@ export default function AboutPage() {
>
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/account/[addressOrEnsName]/edit.tsx b/src/pages/account/[addressOrEnsName]/edit.tsx
index f8103df9ae..861e0c0fac 100644
--- a/src/pages/account/[addressOrEnsName]/edit.tsx
+++ b/src/pages/account/[addressOrEnsName]/edit.tsx
@@ -9,6 +9,7 @@ import { User } from 'models/database'
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'
import { Database } from 'types/database.types'
import { isEqualAddress } from 'utils/address'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
type AccountSettingsType = {
initialSession: Session
@@ -18,6 +19,8 @@ type AccountSettingsType = {
export const getServerSideProps: GetServerSideProps<
AccountSettingsType
> = async context => {
+ const global = await globalGetServerSideProps(context)
+
const supabase = createServerSupabaseClient(context)
const {
data: { session },
@@ -28,6 +31,7 @@ export const getServerSideProps: GetServerSideProps<
typeof context.params.addressOrEnsName !== 'string'
) {
return {
+ ...global,
redirect: {
destination: '/',
permanent: false,
@@ -39,6 +43,7 @@ export const getServerSideProps: GetServerSideProps<
)
if (!pair) {
return {
+ ...global,
redirect: {
destination: '/',
permanent: false,
@@ -56,6 +61,7 @@ export const getServerSideProps: GetServerSideProps<
if (!user.data) {
return {
+ ...global,
redirect: {
destination: '/',
permanent: false,
@@ -70,6 +76,7 @@ export const getServerSideProps: GetServerSideProps<
console.info('Error occurred on signout', e)
}
return {
+ ...global,
redirect: {
destination: '/',
permanent: false,
@@ -78,7 +85,10 @@ export const getServerSideProps: GetServerSideProps<
}
return {
+ ...global,
props: {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ...((global as any).props || {}),
initialSession: session,
user: user.data,
},
diff --git a/src/pages/account/[addressOrEnsName]/index.tsx b/src/pages/account/[addressOrEnsName]/index.tsx
index df9e42db3b..704c065ce5 100644
--- a/src/pages/account/[addressOrEnsName]/index.tsx
+++ b/src/pages/account/[addressOrEnsName]/index.tsx
@@ -4,8 +4,10 @@ import Loading from 'components/Loading'
import { AppWrapper, SEO } from 'components/common'
import { isAddress } from 'ethers/lib/utils'
import { resolveAddress } from 'lib/api/ens'
+import { loadCatalog } from 'locales/utils'
import { Profile } from 'models/database'
-import { useRouter } from 'next/router'
+import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next'
+import { useMemo } from 'react'
import { useQuery } from 'react-query'
import { truncateEthAddress } from 'utils/format/formatAddress'
@@ -47,14 +49,17 @@ function _AccountPage({ addressOrEnsName }: { addressOrEnsName: string }) {
)
}
-export default function AccountPage() {
- const router = useRouter()
- const { addressOrEnsName } = router.query as { addressOrEnsName: string }
+export default function AccountPage({
+ addressOrEnsName,
+}: InferGetStaticPropsType) {
+ const addressFound = useMemo(
+ () => isAddress(addressOrEnsName) || addressOrEnsName.endsWith('eth'),
+ [addressOrEnsName],
+ )
return (
- {addressOrEnsName &&
- (isAddress(addressOrEnsName) || addressOrEnsName.endsWith('eth')) ? (
+ {addressOrEnsName && addressFound ? (
<_AccountPage addressOrEnsName={addressOrEnsName as string} />
) : (
Not found
@@ -62,3 +67,26 @@ export default function AccountPage() {
)
}
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ return {
+ paths: [],
+ fallback: 'blocking',
+ }
+}
+
+export const getStaticProps: GetStaticProps<{
+ addressOrEnsName: string
+}> = async context => {
+ const locale = context.locale as string
+ const messages = await loadCatalog(locale)
+ const i18n = { locale, messages }
+
+ const { addressOrEnsName } = context.params as { addressOrEnsName: string }
+ return {
+ props: {
+ addressOrEnsName,
+ i18n,
+ },
+ }
+}
diff --git a/src/pages/activity/index.tsx b/src/pages/activity/index.tsx
index 69e9341364..7fcf572e90 100644
--- a/src/pages/activity/index.tsx
+++ b/src/pages/activity/index.tsx
@@ -1,6 +1,7 @@
import { Trans } from '@lingui/macro'
import { PaymentsFeed } from 'components/Activity'
import { AppWrapper } from 'components/common'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function ActivityPage() {
return (
@@ -18,3 +19,5 @@ export default function ActivityPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/contact/index.tsx b/src/pages/contact/index.tsx
index ea273d80ec..3c3abdc96f 100644
--- a/src/pages/contact/index.tsx
+++ b/src/pages/contact/index.tsx
@@ -1,6 +1,7 @@
import { Contact } from 'components/Contact'
import { Footer } from 'components/Footer'
import { AppWrapper, Head } from 'components/common'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function ContactPage() {
return (
@@ -18,3 +19,5 @@ export default function ContactPage() {
>
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/create/index.tsx b/src/pages/create/index.tsx
index 8909587c19..bcec01e98a 100644
--- a/src/pages/create/index.tsx
+++ b/src/pages/create/index.tsx
@@ -6,6 +6,7 @@ import { V2V3ContractsProvider } from 'contexts/v2v3/Contracts/V2V3ContractsProv
import { V2V3CurrencyProvider } from 'contexts/v2v3/V2V3CurrencyProvider'
import { Provider } from 'react-redux'
import store from 'redux/store'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function V2CreatePage() {
return (
@@ -31,3 +32,5 @@ export default function V2CreatePage() {
>
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/experimental/flags/index.tsx b/src/pages/experimental/flags/index.tsx
index 9c3ef53cc0..e705e5f42f 100644
--- a/src/pages/experimental/flags/index.tsx
+++ b/src/pages/experimental/flags/index.tsx
@@ -5,6 +5,7 @@ import { readNetwork } from 'constants/networks'
import Head from 'next/head'
import { useCallback, useState } from 'react'
import { featureFlagEnabled, setFeatureFlag } from 'utils/featureFlags'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function FlagsPage() {
const [, updateState] = useState({})
@@ -49,3 +50,5 @@ export default function FlagsPage() {
>
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index ab7e4bc2ab..95c09e3c90 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,6 +1,7 @@
import { AppWrapper } from 'components/common'
import { HomePage } from 'components/Home'
import { AnnouncementsProvider } from 'contexts/Announcements/AnnouncementsProvider'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function LandingPage() {
return (
@@ -11,3 +12,5 @@ export default function LandingPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/legal/index.tsx b/src/pages/legal/index.tsx
index 6dad968fc5..c5ba3dbc8c 100644
--- a/src/pages/legal/index.tsx
+++ b/src/pages/legal/index.tsx
@@ -1,6 +1,7 @@
import { Footer } from 'components/Footer/Footer'
import { Legal } from 'components/Legal'
import { AppWrapper, Head } from 'components/common'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function LegalPage() {
return (
@@ -17,3 +18,5 @@ export default function LegalPage() {
>
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/p/[handle]/index.tsx b/src/pages/p/[handle]/index.tsx
index 070883b16c..c3c50dcf56 100644
--- a/src/pages/p/[handle]/index.tsx
+++ b/src/pages/p/[handle]/index.tsx
@@ -8,6 +8,7 @@ import { V1ProjectProvider } from 'contexts/v1/Project/V1ProjectProvider'
import { V1UserProvider } from 'contexts/v1/User/V1UserProvider'
import { V1CurrencyProvider } from 'contexts/v1/V1CurrencyProvider'
import { V1ProjectMetadataProvider } from 'contexts/v1/V1ProjectMetadataProvider'
+import { loadCatalog } from 'locales/utils'
import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next'
import { useRouter } from 'next/router'
import { useContext } from 'react'
@@ -25,7 +26,20 @@ export const getStaticPaths: GetStaticPaths = async context => {
}
export const getStaticProps: GetStaticProps = async context => {
- return getV1StaticProps(context)
+ const locale = context.locale as string
+ const messages = await loadCatalog(locale)
+ const i18n = { locale, messages }
+
+ const v1Props = await getV1StaticProps(context)
+
+ return {
+ ...v1Props,
+ props: {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ...(v1Props as any).props,
+ i18n,
+ },
+ }
}
export default function V1HandlePage({
diff --git a/src/pages/p/[handle]/safe/index.tsx b/src/pages/p/[handle]/safe/index.tsx
index a82e4a734a..330ba3ab1d 100644
--- a/src/pages/p/[handle]/safe/index.tsx
+++ b/src/pages/p/[handle]/safe/index.tsx
@@ -1,11 +1,12 @@
-import { AppWrapper } from 'components/common'
import { ProjectSafeDashboard } from 'components/ProjectSafeDashboard'
+import { AppWrapper } from 'components/common'
import { V1ProjectContext } from 'contexts/v1/Project/V1ProjectContext'
-import { useRouter } from 'next/router'
+import { V1ProjectProvider } from 'contexts/v1/Project/V1ProjectProvider'
import { V1UserProvider } from 'contexts/v1/User/V1UserProvider'
import { V1ProjectMetadataProvider } from 'contexts/v1/V1ProjectMetadataProvider'
-import { V1ProjectProvider } from 'contexts/v1/Project/V1ProjectProvider'
+import { useRouter } from 'next/router'
import { useContext } from 'react'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
function V1ProjectSafeDashboard({ handle }: { handle: string }) {
const { owner } = useContext(V1ProjectContext)
@@ -36,3 +37,5 @@ export default function V1ProjectSafeDashboardPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/privacy.tsx b/src/pages/privacy.tsx
index 0f1a1d10f2..78b440d479 100644
--- a/src/pages/privacy.tsx
+++ b/src/pages/privacy.tsx
@@ -1,6 +1,7 @@
import { AppWrapper } from 'components/common'
import ExternalLink from 'components/ExternalLink'
import Link from 'next/link'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function PrivacyPolicyPage() {
return (
@@ -73,3 +74,5 @@ function PrivacyPolicy() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/projects/index.tsx b/src/pages/projects/index.tsx
index d6045da579..8b92e4ef9b 100644
--- a/src/pages/projects/index.tsx
+++ b/src/pages/projects/index.tsx
@@ -1,5 +1,6 @@
import { ProjectsView } from 'components/Projects/ProjectsView'
import { AppWrapper } from 'components/common'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function ProjectsPage() {
return (
@@ -8,3 +9,5 @@ export default function ProjectsPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/success-stories/constitutiondao.tsx b/src/pages/success-stories/constitutiondao.tsx
index 577c457f24..f532a4965f 100644
--- a/src/pages/success-stories/constitutiondao.tsx
+++ b/src/pages/success-stories/constitutiondao.tsx
@@ -10,6 +10,7 @@ import {
CONSTITUTION_FUNDING_CONFIG,
} from 'constants/successStoryProjects'
import Image from 'next/image'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function ConstitutionDAOPage() {
const constitutionSuccessStoryProject = CASE_STUDY_PROJECTS[0]
@@ -106,3 +107,5 @@ export default function ConstitutionDAOPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/success-stories/moondao.tsx b/src/pages/success-stories/moondao.tsx
index d73ec42021..28da591597 100644
--- a/src/pages/success-stories/moondao.tsx
+++ b/src/pages/success-stories/moondao.tsx
@@ -10,6 +10,7 @@ import {
MOONDAO_FUNDING_CONFIG,
} from 'constants/successStoryProjects'
import Image from 'next/image'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function MoonDAOPage() {
const moonDAOSuccessStoryProject = CASE_STUDY_PROJECTS[1]
@@ -114,3 +115,5 @@ export default function MoonDAOPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/success-stories/sharkdao.tsx b/src/pages/success-stories/sharkdao.tsx
index eb56035b5b..dce2d635cd 100644
--- a/src/pages/success-stories/sharkdao.tsx
+++ b/src/pages/success-stories/sharkdao.tsx
@@ -10,6 +10,7 @@ import {
SHARKDAO_FUNDING_CONFIG,
} from 'constants/successStoryProjects'
import Image from 'next/image'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function SharkDAOPage() {
const sharkDAOSuccessStoryProject = CASE_STUDY_PROJECTS[2]
@@ -133,3 +134,5 @@ export default function SharkDAOPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/success-stories/studiodao.tsx b/src/pages/success-stories/studiodao.tsx
index 367826567a..396ae006d8 100644
--- a/src/pages/success-stories/studiodao.tsx
+++ b/src/pages/success-stories/studiodao.tsx
@@ -10,6 +10,7 @@ import {
STUDIODAO_FUNDING_CONFIG,
} from 'constants/successStoryProjects'
import Image from 'next/image'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function StudioDAOPage() {
const studioDAOSuccessStoryProject = CASE_STUDY_PROJECTS[3]
@@ -117,3 +118,5 @@ export default function StudioDAOPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/v2/p/[projectId]/contracts/index.tsx b/src/pages/v2/p/[projectId]/contracts/index.tsx
index 05ce812863..bc98e38a4a 100644
--- a/src/pages/v2/p/[projectId]/contracts/index.tsx
+++ b/src/pages/v2/p/[projectId]/contracts/index.tsx
@@ -3,6 +3,7 @@ import { V2V3ProjectContractsDashboard } from 'components/v2v3/V2V3Project/V2V3P
import { TransactionProvider } from 'contexts/Transaction/TransactionProvider'
import { V2V3ProjectPageProvider } from 'contexts/v2v3/V2V3ProjectPageProvider'
import { useRouter } from 'next/router'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function V2V3ProjectContractsPage() {
const router = useRouter()
@@ -22,3 +23,5 @@ export default function V2V3ProjectContractsPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/v2/p/[projectId]/index.tsx b/src/pages/v2/p/[projectId]/index.tsx
index 1ab2a1baba..aef545be06 100644
--- a/src/pages/v2/p/[projectId]/index.tsx
+++ b/src/pages/v2/p/[projectId]/index.tsx
@@ -6,9 +6,10 @@ import { PV_V2 } from 'constants/pv'
import { AnnouncementsProvider } from 'contexts/Announcements/AnnouncementsProvider'
import { V2V3ProjectPageProvider } from 'contexts/v2v3/V2V3ProjectPageProvider'
import { paginateDepleteProjectsQueryCall } from 'lib/apollo/paginateDepleteProjectsQuery'
+import { loadCatalog } from 'locales/utils'
import { ProjectMetadata } from 'models/projectMetadata'
import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next'
-import { Suspense, lazy } from 'react'
+import React, { PropsWithChildren, Suspense, lazy } from 'react'
import { featureFlagEnabled } from 'utils/featureFlags'
import { cidFromUrl, ipfsPublicGatewayUrl } from 'utils/ipfs'
import {
@@ -37,12 +38,18 @@ export const getStaticPaths: GetStaticPaths = async () => {
}
export const getStaticProps: GetStaticProps<
- ProjectPageProps
+ ProjectPageProps & { i18n: unknown }
> = async context => {
+ const locale = context.locale as string
+ const messages = await loadCatalog(locale)
+ const i18n = { locale, messages }
+
if (!context.params) throw new Error('params not supplied')
const projectId = parseInt(context.params.projectId as string)
- const props = await getProjectStaticProps(projectId)
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const props = (await getProjectStaticProps(projectId)) as any
+ props.props.i18n = i18n
return {
...props,
@@ -86,19 +93,34 @@ export default function V2ProjectPage({
<>
-
-
-
- {newProjectPageEnabled ? (
- }>
-
-
- ) : (
-
- )}
-
-
-
+ <_Wrapper>
+
+
+
+ {newProjectPageEnabled ? (
+ }>
+
+
+ ) : (
+
+ )}
+
+
+
+
>
)
}
+
+// This is a hack to avoid SSR for now. At the moment when this is not applied to this page, you will see a rehydration error.
+const _Wrapper: React.FC = ({ children }) => {
+ const [hasMounted, setHasMounted] = React.useState(false)
+ React.useEffect(() => {
+ setHasMounted(true)
+ }, [])
+ if (!hasMounted) {
+ return null
+ }
+
+ return <>{children}>
+}
diff --git a/src/pages/v2/p/[projectId]/safe/index.tsx b/src/pages/v2/p/[projectId]/safe/index.tsx
index 58a2d02890..7475419b8e 100644
--- a/src/pages/v2/p/[projectId]/safe/index.tsx
+++ b/src/pages/v2/p/[projectId]/safe/index.tsx
@@ -1,11 +1,12 @@
-import { AppWrapper } from 'components/common'
import { ProjectSafeDashboard } from 'components/ProjectSafeDashboard'
+import { AppWrapper } from 'components/common'
+import { TransactionProvider } from 'contexts/Transaction/TransactionProvider'
import { ProjectMetadataContext } from 'contexts/shared/ProjectMetadataContext'
import { V2V3ProjectContext } from 'contexts/v2v3/Project/V2V3ProjectContext'
-import { useRouter } from 'next/router'
-import { TransactionProvider } from 'contexts/Transaction/TransactionProvider'
import { V2V3ProjectPageProvider } from 'contexts/v2v3/V2V3ProjectPageProvider'
+import { useRouter } from 'next/router'
import { useContext } from 'react'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
import { v2v3ProjectRoute } from 'utils/routes'
function V2V3ProjectSafeDashboard() {
@@ -38,3 +39,5 @@ export default function V2V3ProjectSafeDashboardPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/v2/p/[projectId]/settings/[settingsPage].tsx b/src/pages/v2/p/[projectId]/settings/[settingsPage].tsx
index af82d5f542..d2e4f4af51 100644
--- a/src/pages/v2/p/[projectId]/settings/[settingsPage].tsx
+++ b/src/pages/v2/p/[projectId]/settings/[settingsPage].tsx
@@ -2,6 +2,7 @@ import { ProjectSettingsContent } from 'components/v2v3/V2V3Project/V2V3ProjectS
import { V2V3SettingsPageKey } from 'components/v2v3/V2V3Project/V2V3ProjectSettings/ProjectSettingsDashboard'
import { V2V3SettingsProvider } from 'components/v2v3/V2V3Project/V2V3ProjectSettings/V2V3SettingsProvider'
import { useRouter } from 'next/router'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function V2V3CycleSettingsPage() {
const router = useRouter()
@@ -17,3 +18,5 @@ export default function V2V3CycleSettingsPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/pages/v2/p/[projectId]/settings/index.tsx b/src/pages/v2/p/[projectId]/settings/index.tsx
index d03dd0a5e2..89d29798ef 100644
--- a/src/pages/v2/p/[projectId]/settings/index.tsx
+++ b/src/pages/v2/p/[projectId]/settings/index.tsx
@@ -1,5 +1,6 @@
import { ProjectSettingsDashboard } from 'components/v2v3/V2V3Project/V2V3ProjectSettings'
import { V2V3SettingsProvider } from 'components/v2v3/V2V3Project/V2V3ProjectSettings/V2V3SettingsProvider'
+import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps'
export default function V2V3ProjectSettingsPage() {
return (
@@ -8,3 +9,5 @@ export default function V2V3ProjectSettingsPage() {
)
}
+
+export const getServerSideProps = globalGetServerSideProps
diff --git a/src/utils/next-server/globalGetServerSideProps.ts b/src/utils/next-server/globalGetServerSideProps.ts
new file mode 100644
index 0000000000..4824abe8c4
--- /dev/null
+++ b/src/utils/next-server/globalGetServerSideProps.ts
@@ -0,0 +1,23 @@
+import { loadCatalog } from 'locales/utils'
+import { GetServerSidePropsContext, GetServerSidePropsResult } from 'next'
+
+/**
+ * `getServerSideProps` for all pages.
+ *
+ * This is a global getServerSideProps that is used for all pages. It is used
+ * to load the i18n catalog for the page.
+ *
+ * @param ctx
+ * @returns
+ */
+export default async function globalGetServerSideProps(
+ ctx: GetServerSidePropsContext,
+): Promise> {
+ const locale = ctx.locale as string
+ const messages = await loadCatalog(locale)
+ return {
+ props: {
+ i18n: { messages, locale },
+ },
+ }
+}
diff --git a/src/utils/projectPageLoaders.ts b/src/utils/projectPageLoaders.ts
index 795b5f43bb..ed692770dd 100644
--- a/src/utils/projectPageLoaders.ts
+++ b/src/utils/projectPageLoaders.ts
@@ -48,7 +48,7 @@ export const getV1StaticProps: GetStaticProps<
console.error(
`Failed to load metadata uri for ${JSON.stringify(context.params)}`,
)
- return { notFound: true }
+ return { notFound: true, props: undefined }
}
try {
@@ -63,7 +63,7 @@ export const getV1StaticProps: GetStaticProps<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
if (e?.response?.status === 404) {
- return { notFound: true }
+ return { notFound: true, props: undefined }
}
throw e
}
diff --git a/yarn.lock b/yarn.lock
index 1f168c2412..83870d05b4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4232,6 +4232,46 @@
resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-4.1.2.tgz#68f52ff847e596e16acf089ff1d758928db28a6a"
integrity sha512-FhdfV9XS3MUkQkmYK6SC4q6i2qQhk3HfVG5bhThukB8dHn6iK0sytBK9uL7BLsV4TJR6YKi3mDTO4MMWreYHHw==
+"@lingui/babel-plugin-extract-messages@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-4.4.0.tgz#3f4e003fddc89d5a8071bfe2d15d18d1628e346a"
+ integrity sha512-0pu4bgQCGEa1e7a6qwB9pEEMpq8GzI4LW6V9YaraXUexusahJpnfKP81PIBsm8zj06OlYK5oI2AflkOmGMCiBA==
+
+"@lingui/cli@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-4.4.0.tgz#ef143e2de21916a8f4c1b67b2a86e3ddcd8c90d4"
+ integrity sha512-9mamvFfzXoaa7kSyshfCrHdK54oAhGB3P7S5M8QjHxUINaQn8naRhZ1AEFoW6rw8Jy2I27XplJsuQrdgxkd+Zw==
+ dependencies:
+ "@babel/core" "^7.21.0"
+ "@babel/generator" "^7.21.1"
+ "@babel/parser" "^7.21.2"
+ "@babel/runtime" "^7.21.0"
+ "@babel/types" "^7.21.2"
+ "@lingui/babel-plugin-extract-messages" "4.4.0"
+ "@lingui/conf" "4.4.0"
+ "@lingui/core" "4.4.0"
+ "@lingui/format-po" "4.4.0"
+ "@lingui/message-utils" "4.4.0"
+ babel-plugin-macros "^3.0.1"
+ chalk "^4.1.0"
+ chokidar "3.5.1"
+ cli-table "0.3.6"
+ commander "^10.0.0"
+ convert-source-map "^2.0.0"
+ date-fns "^2.16.1"
+ esbuild "^0.17.10"
+ glob "^7.1.4"
+ inquirer "^7.3.3"
+ micromatch "4.0.2"
+ normalize-path "^3.0.0"
+ ora "^5.1.0"
+ pathe "^1.1.0"
+ pkg-up "^3.1.0"
+ pofile "^1.1.4"
+ pseudolocale "^2.0.0"
+ ramda "^0.27.1"
+ source-map "^0.8.0-beta.0"
+
"@lingui/cli@^4.0.0":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-4.1.2.tgz#39811b2dcb61b0a4c8df79cdd74a8eed2ed71e7f"
@@ -4279,6 +4319,18 @@
jiti "^1.17.1"
lodash.get "^4.4.2"
+"@lingui/conf@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-4.4.0.tgz#0cf0506a26e393aefb36f0565c3e9dc4a7fd800b"
+ integrity sha512-mIAGh5eeWJm5jYM/ag4lbktxlS/73iANOahMM3q5OlEfIVvBzoinwSONRQEVsIgLT1SI6ULbqvVaI42VF5WrAw==
+ dependencies:
+ "@babel/runtime" "^7.20.13"
+ chalk "^4.1.0"
+ cosmiconfig "^8.0.0"
+ jest-validate "^29.4.3"
+ jiti "^1.17.1"
+ lodash.get "^4.4.2"
+
"@lingui/core@4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@lingui/core/-/core-4.1.2.tgz#94bf8d539d8a67b0216aa705919d16b4b29b8cd6"
@@ -4287,6 +4339,15 @@
"@babel/runtime" "^7.20.13"
"@lingui/message-utils" "4.1.2"
+"@lingui/core@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/core/-/core-4.4.0.tgz#d043c2770673d70bafa6b850cfeec3c859844085"
+ integrity sha512-0ngEP+g4bt6f3cNqEzkU5796VkEEamxNXF/JD/QV9Ftxp8QBw91WqAoHjNYs3aYZOctCsRBR7FlvRQ6o2fDWDg==
+ dependencies:
+ "@babel/runtime" "^7.20.13"
+ "@lingui/message-utils" "4.4.0"
+ unraw "^2.0.1"
+
"@lingui/detect-locale@^4.0.0":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@lingui/detect-locale/-/detect-locale-4.1.2.tgz#dae1fb73ce88d09ab6ca0f728b36e8774e595cc7"
@@ -4302,6 +4363,25 @@
date-fns "^2.29.3"
pofile "^1.1.4"
+"@lingui/format-po@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/format-po/-/format-po-4.4.0.tgz#37f119545d39a625698877a2e0ca5bb27b9ea967"
+ integrity sha512-FRk9HD199Klknv+zccytddHfnSJwns6Fv3ZHvm8hoB9VLKnO0RBMR2f3mqw+MYPvSYGtTIxVQXLGISva7nFG4A==
+ dependencies:
+ "@lingui/conf" "4.4.0"
+ "@lingui/message-utils" "4.4.0"
+ date-fns "^2.29.3"
+ pofile "^1.1.4"
+
+"@lingui/loader@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/loader/-/loader-4.4.0.tgz#ec1d316ba9337b5274c83f9cd94b7b002664e6e6"
+ integrity sha512-MDsfuZjG2/bju13/b3PEzxcD45JJBR1Q+i2fKkVtgyiVjh2UUvYeg4PgCQwsbWCblRQ4L9bpTcgbI+yFW8Zb7w==
+ dependencies:
+ "@babel/runtime" "^7.20.13"
+ "@lingui/cli" "4.4.0"
+ "@lingui/conf" "4.4.0"
+
"@lingui/macro@^4.0.0":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-4.1.2.tgz#8f4d27355d72c1d5dc8dc74ef247746877aec73c"
@@ -4320,6 +4400,13 @@
dependencies:
"@messageformat/parser" "^5.0.0"
+"@lingui/message-utils@4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@lingui/message-utils/-/message-utils-4.4.0.tgz#88a7ff9c0ca10fdce25374a92fc27b932a96778a"
+ integrity sha512-SScnNuemsyHx2vyLvLsHgmAaCBHwnaAxUg3LkKoulqXe2Po8CmLBh1/28oNQ20ZhjwadUmy0unGalp9qqEBOkw==
+ dependencies:
+ "@messageformat/parser" "^5.0.0"
+
"@lingui/react@^4.0.0":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@lingui/react/-/react-4.1.2.tgz#763bd93c75e8790f7534fdb0d98bf37f7607f1ab"
@@ -4328,6 +4415,11 @@
"@babel/runtime" "^7.20.13"
"@lingui/core" "4.1.2"
+"@lingui/swc-plugin@4.0.4":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@lingui/swc-plugin/-/swc-plugin-4.0.4.tgz#1e6e753b8aae50edd929eb4905db24a186513dca"
+ integrity sha512-xRnR96Mqi6zwGlVfGJMfoM8QykBbUz/sSnwmcFL9BZ8Y9YBZxzLAVf4t1BbiIQsAs+pMYu/HfujTBD4y/r1ucA==
+
"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9"
@@ -20364,6 +20456,11 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+unraw@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unraw/-/unraw-2.0.1.tgz#7b51dcdfb1e43d59d5e52cdb44d349d029edbaba"
+ integrity sha512-tdOvLfRzHolwYcHS6HIX860MkK9LQ4+oLuNwFYL7bpgTEO64PZrcQxkisgwJYCfF8sKiWLwwu1c83DvMkbefIQ==
+
untildify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"