From 8ce6bc4ce136fb4b860bf21d74cbfed0538e1cd0 Mon Sep 17 00:00:00 2001
From: xudaotutou <13435638964@163.com>
Date: Thu, 28 Nov 2024 11:44:27 +0800
Subject: [PATCH 1/2] i18n-costcenter
---
.../costcenter/src/components/CurrencySymbol.tsx | 8 ++++++--
.../costcenter/src/components/RechargeModal.tsx | 6 +++---
.../src/components/billing/AmountDisplay.tsx | 14 ++++++++------
3 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/frontend/providers/costcenter/src/components/CurrencySymbol.tsx b/frontend/providers/costcenter/src/components/CurrencySymbol.tsx
index ef16339b11c..12095b37c78 100644
--- a/frontend/providers/costcenter/src/components/CurrencySymbol.tsx
+++ b/frontend/providers/costcenter/src/components/CurrencySymbol.tsx
@@ -10,8 +10,12 @@ export default function CurrencySymbol({
return type === 'shellCoin' ? (
) : type === 'cny' ? (
- ¥
+
+ ¥
+
) : (
- $
+
+ $
+
);
}
diff --git a/frontend/providers/costcenter/src/components/RechargeModal.tsx b/frontend/providers/costcenter/src/components/RechargeModal.tsx
index 24529ddc6b6..80382bc5fa1 100644
--- a/frontend/providers/costcenter/src/components/RechargeModal.tsx
+++ b/frontend/providers/costcenter/src/components/RechargeModal.tsx
@@ -190,7 +190,7 @@ const BonusBox = (props: {
{t('Double')}!
+
-
+
{props.bouns}
@@ -213,7 +213,7 @@ const BonusBox = (props: {
fontSize="12px"
>
{t('Bonus')}
-
+
{props.bouns}
)}
@@ -536,7 +536,7 @@ const RechargeModal = forwardRef(
>
{t('Bonus')} {getBonus(amount)}
-
+
{list.map((item) => (
{t(item.title)}:
-
+
{formatMoney(item.value).toFixed(2)}
))}
From 98218fece5e72211a12494e8a69d83e8c46ce2da Mon Sep 17 00:00:00 2001
From: xudaotutou <13435638964@163.com>
Date: Thu, 28 Nov 2024 15:46:25 +0800
Subject: [PATCH 2/2] fix(costcenter):i18n
---
.../costcenter/next-i18next.config.js | 2 +-
.../providers/costcenter/src/pages/_app.tsx | 50 +++++++++--------
.../src/pages/cost_overview/index.tsx | 54 +++++++++++--------
.../providers/costcenter/src/stores/env.ts | 2 +
.../costcenter/src/stores/session.ts | 2 -
5 files changed, 64 insertions(+), 46 deletions(-)
diff --git a/frontend/providers/costcenter/next-i18next.config.js b/frontend/providers/costcenter/next-i18next.config.js
index 7a365a52cc5..177b6887711 100644
--- a/frontend/providers/costcenter/next-i18next.config.js
+++ b/frontend/providers/costcenter/next-i18next.config.js
@@ -5,7 +5,7 @@
module.exports = {
i18n: {
- defaultLocale: 'zh',
+ defaultLocale: 'en',
locales: ['en', 'zh'],
localeDetection: false
},
diff --git a/frontend/providers/costcenter/src/pages/_app.tsx b/frontend/providers/costcenter/src/pages/_app.tsx
index 184a002bb54..efe62822101 100644
--- a/frontend/providers/costcenter/src/pages/_app.tsx
+++ b/frontend/providers/costcenter/src/pages/_app.tsx
@@ -1,23 +1,23 @@
import Layout from '@/layout';
-import { sealosApp } from 'sealos-desktop-sdk/app';
-import { EVENT_NAME } from 'sealos-desktop-sdk';
-import '@/styles/globals.scss';
+import { Response as initDataRes } from '@/pages/api/platform/getAppConfig';
+import request from '@/service/request';
+import useAppTypeStore from '@/stores/appType';
+import useBillingStore from '@/stores/billing';
+import useEnvStore from '@/stores/env';
import { theme } from '@/styles/chakraTheme';
+import '@/styles/globals.scss';
+import { ApiResp } from '@/types/api';
import { ChakraProvider } from '@chakra-ui/react';
-import { Hydrate, QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
+import { Hydrate, QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { appWithTranslation } from 'next-i18next';
import type { AppProps } from 'next/app';
import Router, { useRouter } from 'next/router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
-import 'react-day-picker/dist/style.css';
-import { appWithTranslation, i18n } from 'next-i18next';
import { useEffect } from 'react';
-import request from '@/service/request';
-import { ApiResp } from '@/types/api';
-import { Response as initDataRes } from '@/pages/api/platform/getAppConfig';
-import useEnvStore from '@/stores/env';
-import useAppTypeStore from '@/stores/appType';
-import useBillingStore from '@/stores/billing';
+import 'react-day-picker/dist/style.css';
+import { EVENT_NAME } from 'sealos-desktop-sdk';
+import { sealosApp } from 'sealos-desktop-sdk/app';
// Make sure to call `loadStripe` outside a component’s render to avoid
// recreating the `Stripe` object on every render.
@@ -40,24 +40,34 @@ const App = ({ Component, pageProps }: AppProps) => {
const router = useRouter();
const { setAppTypeMap, appTypeMap } = useAppTypeStore();
const { setAppTypeList } = useBillingStore();
+ // init language
+ const changeI18n = (data: { currentLanguage: string }) => {
+ router.replace(router.basePath, router.asPath, { locale: data.currentLanguage });
+ };
useEffect(() => {
- const changeI18n = (data: { currentLanguage: string }) => {
- router.replace(router.basePath, router.asPath, { locale: data.currentLanguage });
+ sealosApp.addAppEventListen(EVENT_NAME.CHANGE_I18N, changeI18n);
+ return () => {
+ sealosApp.removeAppEventListen(EVENT_NAME.CHANGE_I18N);
};
-
+ }, []);
+ useEffect(() => {
+ state.setEnv('i18nIsInitialized', false);
(async () => {
try {
const lang = await sealosApp.getLanguage();
changeI18n({
currentLanguage: lang.lng
});
+ state.setEnv('i18nIsInitialized', true);
} catch (error) {
- changeI18n({
- currentLanguage: 'zh'
- });
+ console.error('get language error');
+ state.setEnv('i18nIsInitialized', false);
}
})();
+ }, [router.asPath]);
+ // init
+ useEffect(() => {
(async () => {
try {
const { data } = await request>('/api/platform/getAppConfig');
@@ -75,10 +85,6 @@ const App = ({ Component, pageProps }: AppProps) => {
console.error('get init config error');
}
})();
- sealosApp.addAppEventListen(EVENT_NAME.CHANGE_I18N, changeI18n);
- return () => {
- sealosApp.removeAppEventListen(EVENT_NAME.CHANGE_I18N);
- };
}, []);
useEffect(() => {
diff --git a/frontend/providers/costcenter/src/pages/cost_overview/index.tsx b/frontend/providers/costcenter/src/pages/cost_overview/index.tsx
index 1c97e073046..9d5333ca121 100644
--- a/frontend/providers/costcenter/src/pages/cost_overview/index.tsx
+++ b/frontend/providers/costcenter/src/pages/cost_overview/index.tsx
@@ -5,6 +5,7 @@ import { Trend } from '@/components/cost_overview/trend';
import { TrendBar } from '@/components/cost_overview/trendBar';
import useNotEnough from '@/hooks/useNotEnough';
import request from '@/service/request';
+import useEnvStore from '@/stores/env';
import useOverviewStore from '@/stores/overview';
import { ApiResp } from '@/types';
import { Box, Flex, useToast } from '@chakra-ui/react';
@@ -13,6 +14,7 @@ import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useRouter } from 'next/router';
import { MutableRefObject, createContext, useEffect, useRef } from 'react';
+import { sealosApp } from 'sealos-desktop-sdk/app';
export const RechargeContext = createContext<{ rechargeRef: MutableRefObject | null }>({
rechargeRef: null
});
@@ -21,27 +23,37 @@ function CostOverview() {
const { t } = useTranslation();
const setRecharge = useOverviewStore((s) => s.setRecharge);
const router = useRouter();
+ const toast = useToast();
+ const { i18nIsInitialized } = useEnvStore();
useEffect(() => {
- const { stripeState } = router.query;
- if (stripeState === 'success') {
- totast({
- status: 'success',
- duration: 3000,
- title: t('Stripe Success'),
- isClosable: true,
- position: 'top'
- });
- } else if (stripeState === 'error') {
- totast({
- status: 'error',
- duration: 3000,
- title: t('Stripe Cancel'),
- isClosable: true,
- position: 'top'
- });
- }
- !!stripeState && router.replace(router.pathname);
- }, []);
+ (async () => {
+ const lng = ((await sealosApp.getLanguage())?.lng || 'en') as 'en' | 'zh';
+ const { stripeState } = router.query;
+ if (!i18nIsInitialized || !router.isReady || !stripeState) return;
+ if (stripeState === 'success') {
+ toast({
+ status: 'success',
+ duration: 3000,
+ title: t('Stripe Success', {
+ lng
+ }),
+ isClosable: true,
+ position: 'top'
+ });
+ } else if (stripeState === 'error') {
+ toast({
+ status: 'error',
+ duration: 3000,
+ title: t('Stripe Cancel', lng),
+ isClosable: true,
+ position: 'top'
+ });
+ } else {
+ return;
+ }
+ !!stripeState && router.replace(router.pathname);
+ })();
+ }, [t, i18nIsInitialized, router.query, router.isReady]);
useEffect(() => {
const { openRecharge } = router.query;
if (openRecharge === 'true') {
@@ -50,7 +62,7 @@ function CostOverview() {
}
}, []);
const { NotEnoughModal } = useNotEnough();
- const totast = useToast();
+
const rechargeRef = useRef();
const { data: balance_raw } = useQuery({
queryKey: ['getAccount'],
diff --git a/frontend/providers/costcenter/src/stores/env.ts b/frontend/providers/costcenter/src/stores/env.ts
index 9f5d9c60512..01426d6815c 100644
--- a/frontend/providers/costcenter/src/stores/env.ts
+++ b/frontend/providers/costcenter/src/stores/env.ts
@@ -9,6 +9,7 @@ type EnvState = {
wechatEnabled: boolean;
stripeEnabled: boolean;
openRecharge: boolean;
+ i18nIsInitialized: boolean;
currency: 'shellCoin' | 'cny' | 'usd';
stripePromise: ReturnType;
setStripe: (pub: string) => void;
@@ -27,6 +28,7 @@ const useEnvStore = create((set, get) => ({
stripeEnabled: false,
gpuEnabled: false,
openRecharge: false,
+ i18nIsInitialized: false,
currency: 'shellCoin',
stripePromise: Promise.resolve(null),
setStripe: (pub: string) => set({ stripePromise: loadStripe(pub) }),
diff --git a/frontend/providers/costcenter/src/stores/session.ts b/frontend/providers/costcenter/src/stores/session.ts
index 0e59adbc30d..c470d6a2217 100644
--- a/frontend/providers/costcenter/src/stores/session.ts
+++ b/frontend/providers/costcenter/src/stores/session.ts
@@ -7,7 +7,6 @@ import { immer } from 'zustand/middleware/immer';
type SessionState = {
session: SessionV1;
- locale: string;
setSession: (ss: SessionV1) => void;
setSessionProp: (key: keyof SessionV1, value: any) => void;
getSession: () => SessionV1;
@@ -21,7 +20,6 @@ const useSessionStore = create()(
persist(
immer((set, get) => ({
session: {} as SessionV1,
- locale: 'zh',
setSession: (ss: SessionV1) => set({ session: ss }),
setSessionProp: (key: keyof SessionV1, value: any) => {
set((state) => {