refactor code

This commit is contained in:
littletry 2025-04-21 00:09:42 +08:00
parent 740b3ea975
commit af708b9043
30 changed files with 231 additions and 329 deletions

View File

@ -1,3 +1,8 @@
{ {
"extends": "next/core-web-vitals" "extends": "next/core-web-vitals",
"rules": {
"@next/next/no-img-element": "off",
"react-hooks/exhaustive-deps": "off",
"@next/next/no-html-link-for-pages": "off"
}
} }

6
.gitignore vendored
View File

@ -34,3 +34,9 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts
.idea
.vscode
yarn.lock
pnpm-lock.yaml
package-lock.json

View File

@ -10,7 +10,7 @@
"dependencies": { "dependencies": {
"@headlessui/react": "^1.7.18", "@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.1", "@heroicons/react": "^2.1.1",
"@next/third-parties": "^14.1.3", "@next/third-parties": "^14.2.25",
"@stripe/stripe-js": "^3.0.7", "@stripe/stripe-js": "^3.0.7",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"ahooks": "^3.7.10", "ahooks": "^3.7.10",
@ -18,9 +18,9 @@
"clsx": "^2.1.0", "clsx": "^2.1.0",
"date-fns": "^3.3.1", "date-fns": "^3.3.1",
"google-auth-library": "^9.6.3", "google-auth-library": "^9.6.3",
"next": "14.1.3", "next": "14.2.25",
"next-auth": "^4.24.6", "next-auth": "^4.24.6",
"next-intl": "^3.9.2", "next-intl": "^3.26.0",
"pg": "^8.11.3", "pg": "^8.11.3",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
@ -36,7 +36,7 @@
"@types/react-dom": "^18", "@types/react-dom": "^18",
"autoprefixer": "^10.0.1", "autoprefixer": "^10.0.1",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "14.1.3", "eslint-config-next": "14.2.25",
"postcss": "^8", "postcss": "^8",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5" "typescript": "^5"

View File

@ -1,25 +0,0 @@
-- auto-generated definition
create table works_translate_task
(
id bigint generated by default as identity
primary key,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null,
uid varchar,
origin_language varchar,
status varchar
);
comment on table works_translate_task is 'works_translate_task';
comment on column works_translate_task.id is '自增id';
comment on column works_translate_task.created_at is '创建时间';
comment on column works_translate_task.updated_at is '更新时间';
comment on column works_translate_task.uid is 'uid';
comment on column works_translate_task.origin_language is 'origin_language';
comment on column works_translate_task.status is 'status: 0未翻译1已翻译';

View File

@ -1,78 +0,0 @@
import {getDb} from "~/libs/db";
import {locales} from "~/config";
import {translateContent} from "~/servers/translate";
export const maxDuration = 300;
export async function GET() {
const db = getDb();
const timeFlag = 'workTranslate' + '-=->' + new Date().getTime();
console.time(timeFlag);
const results = await db.query('select * from works_translate_task where status=$1 order by created_at asc limit 3', [0]);
const rows = results.rows;
if (rows.length <= 0) {
console.log('没有任务需要处理');
console.timeEnd(timeFlag);
return Response.json({message: '没有任务需要处理'});
}
for (let i = 0; i < rows.length; i++) {
const oneTask = rows[i];
// 翻译为除了原始语言的其他语言,如果原始语言不在支持列表,就翻译为支持的十种语言
const origin_language = oneTask.origin_language;
const uid = oneTask.uid;
const needLanguage = getNeedTranslateLanguage(origin_language);
if (needLanguage.length <= 0) {
// 更新状态为已翻译完成
await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]);
console.log('没有需要翻译的语言-=->', uid);
console.timeEnd(timeFlag);
return Response.json({message: '没有需要翻译的语言'});
}
// 查出原始数据
const resultsOrigin = await db.query('select * from works where uid=$1 and is_origin=$2 and is_delete=$3', [uid, true, false]);
const rowsOrigin = resultsOrigin.rows;
if (rowsOrigin.length <= 0) {
console.log('没有原始数据-=->', uid);
console.timeEnd(timeFlag);
// 更新状态为已翻译完成
await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]);
return Response.json({message: '没有原始数据'});
}
const originData = rowsOrigin[0];
if (originData.output_url == '') {
// 如果原始数据的url还没生成就不翻译了
console.log('原始数据的url还没生成-=->', uid);
console.timeEnd(timeFlag);
return Response.json({message: '原始数据的url还没生成'});
}
const timeFlagCurrent = '翻译' + '-=->' + uid;
console.time(timeFlagCurrent);
for (let i = 0; i < needLanguage.length; i++) {
const toLanguage = needLanguage[i];
const translateText = await translateContent(originData.input_text, toLanguage);
const sqlStr = 'insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)';
const data = [uid, translateText, originData.output_url, originData.is_public, originData.status, originData.user_id, originData.revised_text, false, originData.origin_language, toLanguage];
await db.query(sqlStr, data);
}
console.timeEnd(timeFlagCurrent);
console.log('翻译完-=->', uid);
// 更新状态为已翻译完成
await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]);
}
console.timeEnd(timeFlag);
return Response.json({message: '本次翻译任务翻译完'});
}
function getNeedTranslateLanguage(origin_language: string) {
const needTranslateLanguage = [];
// 判断出需要翻译的语言,并调用翻译
for (let i = 0; i < locales.length; i++) {
if (origin_language != locales[i]) {
needTranslateLanguage.push(locales[i]);
}
}
return needTranslateLanguage;
}

View File

@ -1,13 +1,12 @@
import {getUserById} from "~/servers/user"; import { getUserById } from "~/servers/user";
import {checkUserTimes, countDownUserTimes} from "~/servers/manageUserTimes"; import { checkUserTimes, countDownUserTimes } from "~/servers/manageUserTimes";
import {v4 as uuidv4} from 'uuid'; import { v4 as uuidv4 } from "uuid";
import {getReplicateClient} from "~/libs/replicateClient"; import { getReplicateClient } from "~/libs/replicateClient";
import {getInput} from "~/libs/replicate"; import { getInput } from "~/libs/replicate";
import {getDb} from "~/libs/db"; import { getDb } from "~/libs/db";
import {getLanguage} from "~/servers/language"; import { getLanguage } from "~/servers/language";
import {checkSubscribe} from "~/servers/subscribe"; import { checkSubscribe } from "~/servers/subscribe";
import {checkSensitiveInputText} from "~/servers/checkInput"; import { checkSensitiveInputText } from "~/servers/checkInput";
export async function POST(req: Request, res: Response) { export async function POST(req: Request, res: Response) {
let json = await req.json(); let json = await req.json();
@ -15,14 +14,14 @@ export async function POST(req: Request, res: Response) {
let user_id = json.user_id; let user_id = json.user_id;
let is_public = json.is_public; let is_public = json.is_public;
if (!user_id && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0') { if (!user_id && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0") {
return Response.json({msg: "Login to continue.", status: 601}); return Response.json({ msg: "Login to continue.", status: 601 });
} }
// 检查用户在数据库是否存在,不存在则返回需登录 // 检查用户在数据库是否存在,不存在则返回需登录
const resultsUser = await getUserById(user_id); const resultsUser = await getUserById(user_id);
if (resultsUser.email == '' && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0') { if (resultsUser.email == "" && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0") {
return Response.json({msg: "Login to continue.", status: 601}); return Response.json({ msg: "Login to continue.", status: 601 });
} }
const checkSubscribeStatus = await checkSubscribe(user_id); const checkSubscribeStatus = await checkSubscribe(user_id);
@ -30,14 +29,14 @@ export async function POST(req: Request, res: Response) {
if (!is_public) { if (!is_public) {
// 判断用户是否订阅状态,否则返回错误 // 判断用户是否订阅状态,否则返回错误
if (!checkSubscribeStatus) { if (!checkSubscribeStatus) {
return Response.json({msg: "Pricing to continue.", status: 602}); return Response.json({ msg: "Pricing to continue.", status: 602 });
} }
} }
if (!checkSubscribeStatus) { if (!checkSubscribeStatus) {
const check = await checkUserTimes(user_id); const check = await checkUserTimes(user_id);
if (!check && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != '0') { if (!check && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != "0") {
return Response.json({msg: "Pricing to continue.", status: 602}); return Response.json({ msg: "Pricing to continue.", status: 602 });
} }
} }
@ -46,7 +45,7 @@ export async function POST(req: Request, res: Response) {
// 敏感词没通过,校验是否订阅 // 敏感词没通过,校验是否订阅
if (!checkSubscribeStatus) { if (!checkSubscribeStatus) {
// 未订阅则返回付费再继续 // 未订阅则返回付费再继续
return Response.json({msg: "Pricing to continue.", status: 602}); return Response.json({ msg: "Pricing to continue.", status: 602 });
} else { } else {
// 订阅强制设置其为用户私有,不公开 // 订阅强制设置其为用户私有,不公开
is_public = false; is_public = false;
@ -63,23 +62,30 @@ export async function POST(req: Request, res: Response) {
input: input, input: input,
webhook: `${process.env.REPLICATE_WEBHOOK}/api/generate/callByReplicate?uid=${uid}`, webhook: `${process.env.REPLICATE_WEBHOOK}/api/generate/callByReplicate?uid=${uid}`,
webhook_events_filter: ["completed"], webhook_events_filter: ["completed"],
}) });
const db = getDb(); const db = getDb();
// 创建新的数据 // 创建新的数据
await db.query('insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)', await db.query("insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", [
[uid, textStr, '', is_public, 0, user_id, input.prompt, true, origin_language, origin_language]); uid,
// 创建一条翻译任务 textStr,
await db.query('insert into works_translate_task(uid,origin_language,status) values($1,$2,$3)', [uid, origin_language, 0]); "",
is_public,
0,
user_id,
input.prompt,
true,
origin_language,
origin_language,
]);
// 需要登录,且需要支付时,才操作该项 // 需要登录,且需要支付时,才操作该项
if (process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != '0' && !checkSubscribeStatus) { if (process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0" && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != "0" && !checkSubscribeStatus) {
// 减少用户次数 // 减少用户次数
await countDownUserTimes(user_id); await countDownUserTimes(user_id);
} }
const resultInfo = { const resultInfo = {
uid: uid uid: uid,
} };
return Response.json(resultInfo); return Response.json(resultInfo);
} }

View File

@ -1,14 +1,14 @@
import clsx from 'clsx'; import clsx from 'clsx';
import {Inter} from 'next/font/google'; import { Inter } from 'next/font/google';
import {notFound} from 'next/navigation'; import { notFound } from 'next/navigation';
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import {ReactNode} from 'react'; import { ReactNode } from 'react';
import {locales} from '~/config'; import { locales } from '~/i18n/config';
import {CommonProvider} from '~/context/common-context'; import { CommonProvider } from '~/context/common-context';
import {NextAuthProvider} from '~/context/next-auth-context'; import { NextAuthProvider } from '~/context/next-auth-context';
import {getAuthText, getCommonText, getMenuText, getPricingText} from "~/configs/languageText"; import { getAuthText, getCommonText, getMenuText, getPricingText } from "~/i18n/languageText";
const inter = Inter({subsets: ['latin']}); const inter = Inter({ subsets: ['latin'] });
type Props = { type Props = {
children: ReactNode; children: ReactNode;
@ -16,19 +16,19 @@ type Props = {
}; };
export function generateStaticParams() { export function generateStaticParams() {
return locales.map((locale) => ({locale})); return locales.map((locale) => ({ locale }));
} }
export default async function LocaleLayout({ export default async function LocaleLayout({
children, children,
params: {locale} params: { locale }
}: Props) { }: Props) {
// Validate that the incoming `locale` parameter is valid // Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale as any)) notFound(); if (!locales.includes(locale as any)) notFound();
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const commonText = await getCommonText(); const commonText = await getCommonText();
const authText = await getAuthText(); const authText = await getAuthText();
@ -37,21 +37,21 @@ export default async function LocaleLayout({
return ( return (
<html lang={locale}> <html lang={locale}>
<head> <head>
<script src="https://accounts.google.com/gsi/client" async defer></script> <script src="https://accounts.google.com/gsi/client" async defer></script>
</head> </head>
<body suppressHydrationWarning={true} className={clsx(inter.className, 'flex flex-col background-div')}> <body suppressHydrationWarning={true} className={clsx(inter.className, 'flex flex-col background-div')}>
<NextAuthProvider> <NextAuthProvider>
<CommonProvider <CommonProvider
commonText={commonText} commonText={commonText}
authText={authText} authText={authText}
menuText={menuText} menuText={menuText}
pricingText={pricingText} pricingText={pricingText}
> >
{children} {children}
</CommonProvider> </CommonProvider>
</NextAuthProvider> </NextAuthProvider>
</body> </body>
</html> </html>
); );
} }

View File

@ -1,13 +1,13 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getWorksText getWorksText
} from "~/configs/languageText"; } from "~/i18n/languageText";
export default async function IndexPage({params: {locale = ''}}) { export default async function IndexPage({ params: { locale = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const worksText = await getWorksText(); const worksText = await getWorksText();

View File

@ -1,16 +1,16 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getIndexPageText, getIndexPageText,
getQuestionText getQuestionText
} from "~/configs/languageText"; } from "~/i18n/languageText";
import {getLatestPublicResultList} from "~/servers/works"; import { getLatestPublicResultList } from "~/servers/works";
export const revalidate = 120; export const revalidate = 120;
export default async function IndexPage({params: {locale = ''}, searchParams: searchParams}) { export default async function IndexPage({ params: { locale = '' }, searchParams: searchParams }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const indexText = await getIndexPageText(); const indexText = await getIndexPageText();
const questionText = await getQuestionText(); const questionText = await getQuestionText();

View File

@ -1,9 +1,9 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
export default async function IndexPage({params: {locale = ''}}) { export default async function IndexPage({ params: { locale = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
return ( return (
<PageComponent <PageComponent

View File

@ -1,13 +1,13 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getPrivacyPolicyText getPrivacyPolicyText
} from "~/configs/languageText"; } from "~/i18n/languageText";
export default async function IndexPage({params: {locale = ''}}) { export default async function IndexPage({ params: { locale = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const privacyPolicyText = await getPrivacyPolicyText(); const privacyPolicyText = await getPrivacyPolicyText();

View File

@ -1,15 +1,15 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import {getSearchText} from "~/configs/languageText"; import { getSearchText } from "~/i18n/languageText";
import {getLatestPublicResultList} from "~/servers/works"; import { getLatestPublicResultList } from "~/servers/works";
import {getCountSticker} from "~/servers/keyValue"; import { getCountSticker } from "~/servers/keyValue";
import {searchByWords, addSearchLog} from "~/servers/search"; import { searchByWords, addSearchLog } from "~/servers/search";
export const revalidate = 0; export const revalidate = 0;
export default async function SearchPage({params: {locale = ''}, searchParams: {sticker = ''}}) { export default async function SearchPage({ params: { locale = '' }, searchParams: { sticker = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const countSticker = await getCountSticker(); const countSticker = await getCountSticker();

View File

@ -1,19 +1,19 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getDetailText, getDetailText,
} from "~/configs/languageText"; } from "~/i18n/languageText";
import {getSimilarList, getWorkDetailByUid} from "~/servers/works"; import { getSimilarList, getWorkDetailByUid } from "~/servers/works";
import {notFound} from "next/navigation"; import { notFound } from "next/navigation";
// export const revalidate = 86400; // export const revalidate = 86400;
export const dynamicParams = true export const dynamicParams = true
export const dynamic = 'error'; export const dynamic = 'error';
export default async function IndexPage({params: {locale = '', uid = ''}}) { export default async function IndexPage({ params: { locale = '', uid = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const workDetail = await getWorkDetailByUid(locale, uid); const workDetail = await getWorkDetailByUid(locale, uid);
if (workDetail.status == 404) { if (workDetail.status == 404) {

View File

@ -1,19 +1,19 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getExploreText, getExploreText,
} from "~/configs/languageText"; } from "~/i18n/languageText";
import {getPagination, getPublicResultList} from "~/servers/works"; import { getPagination, getPublicResultList } from "~/servers/works";
import {notFound} from "next/navigation"; import { notFound } from "next/navigation";
import {getCountSticker} from "~/servers/keyValue"; import { getCountSticker } from "~/servers/keyValue";
export const revalidate = 300; export const revalidate = 300;
export const dynamic = "force-static"; export const dynamic = "force-static";
export default async function IndexPage({params: {locale = '', page = 2}}) { export default async function IndexPage({ params: { locale = '', page = 2 } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const countSticker = await getCountSticker(); const countSticker = await getCountSticker();

View File

@ -1,17 +1,17 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getExploreText, getExploreText,
} from "~/configs/languageText"; } from "~/i18n/languageText";
import {getPagination, getPublicResultList} from "~/servers/works"; import { getPagination, getPublicResultList } from "~/servers/works";
import {getCountSticker} from "~/servers/keyValue"; import { getCountSticker } from "~/servers/keyValue";
export const revalidate = 300; export const revalidate = 300;
export default async function IndexPage({params: {locale = ''}}) { export default async function IndexPage({ params: { locale = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const countSticker = await getCountSticker(); const countSticker = await getCountSticker();

View File

@ -1,13 +1,13 @@
import PageComponent from "./PageComponent"; import PageComponent from "./PageComponent";
import {unstable_setRequestLocale} from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { import {
getTermsOfServiceText getTermsOfServiceText
} from "~/configs/languageText"; } from "~/i18n/languageText";
export default async function IndexPage({params: {locale = ''}}) { export default async function IndexPage({ params: { locale = '' } }) {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(locale); setRequestLocale(locale);
const termsOfServiceText = await getTermsOfServiceText(); const termsOfServiceText = await getTermsOfServiceText();

View File

@ -1,15 +1,15 @@
import {languages} from "~/config"; import { languages } from "~/i18n/config";
const HeadInfo = ({ const HeadInfo = ({
locale, locale,
page, page,
title, title,
description, description,
}) => { }) => {
return ( return (
<> <>
<title>{title}</title> <title>{title}</title>
<meta name="description" content={description}/> <meta name="description" content={description} />
{ {
languages.map((item) => { languages.map((item) => {
const currentPage = page; const currentPage = page;
@ -29,7 +29,7 @@ const HeadInfo = ({
href = `${process.env.NEXT_PUBLIC_SITE_URL}/`; href = `${process.env.NEXT_PUBLIC_SITE_URL}/`;
} }
} }
return <link key={href} rel="alternate" hrefLang={hrefLang} href={href}/> return <link key={href} rel="alternate" hrefLang={hrefLang} href={href} />
}) })
} }
{ {
@ -49,7 +49,7 @@ const HeadInfo = ({
} }
} }
if (locale == item.lang) { if (locale == item.lang) {
return <link key={href + 'canonical'} rel="canonical" hrefLang={hrefLang} href={href}/> return <link key={href + 'canonical'} rel="canonical" hrefLang={hrefLang} href={href} />
} }
}) })
} }

View File

@ -1,25 +1,25 @@
'use client' 'use client'
import {useState} from 'react' import { useState } from 'react'
import {Dialog} from '@headlessui/react' import { Dialog } from '@headlessui/react'
import {Bars3Icon, XMarkIcon} from '@heroicons/react/24/outline' import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
import {GlobeAltIcon} from '@heroicons/react/24/outline' import { GlobeAltIcon } from '@heroicons/react/24/outline'
import {Fragment} from 'react' import { Fragment } from 'react'
import {Menu, Transition} from '@headlessui/react' import { Menu, Transition } from '@headlessui/react'
import {ChevronDownIcon} from '@heroicons/react/20/solid' import { ChevronDownIcon } from '@heroicons/react/20/solid'
import Link from "next/link"; import Link from "next/link";
import {languages} from "~/config"; import { languages } from "~/i18n/config";
import {useCommonContext} from '~/context/common-context' import { useCommonContext } from '~/context/common-context'
import LoadingModal from "./LoadingModal"; import LoadingModal from "./LoadingModal";
import GeneratingModal from "~/components/GeneratingModal"; import GeneratingModal from "~/components/GeneratingModal";
import LoginButton from './LoginButton'; import LoginButton from './LoginButton';
import LoginModal from './LoginModal'; import LoginModal from './LoginModal';
import LogoutModal from "./LogoutModal"; import LogoutModal from "./LogoutModal";
import {getLinkHref} from "~/configs/buildLink"; import { getLinkHref } from "~/configs/buildLink";
export default function Header({ export default function Header({
locale, locale,
page page
}) { }) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const { const {
setShowLoadingModal, setShowLoadingModal,
@ -47,8 +47,8 @@ export default function Header({
return ( return (
<header className="top-0 z-20 w-full"> <header className="top-0 z-20 w-full">
<LoadingModal loadingText={commonText.loadingText}/> <LoadingModal loadingText={commonText.loadingText} />
<GeneratingModal generatingText={commonText.generateText}/> <GeneratingModal generatingText={commonText.generateText} />
<LoginModal <LoginModal
loadingText={commonText.loadingText} loadingText={commonText.loadingText}
redirectPath={pageResult} redirectPath={pageResult}
@ -83,7 +83,7 @@ export default function Header({
onClick={() => setMobileMenuOpen(true)} onClick={() => setMobileMenuOpen(true)}
> >
<span className="sr-only">Open main menu</span> <span className="sr-only">Open main menu</span>
<Bars3Icon className="h-6 w-6" aria-hidden="true"/> <Bars3Icon className="h-6 w-6" aria-hidden="true" />
</button> </button>
</div> </div>
<div className="hidden lg:ml-14 lg:flex lg:flex-1 lg:gap-x-6"> <div className="hidden lg:ml-14 lg:flex lg:flex-1 lg:gap-x-6">
@ -121,8 +121,8 @@ export default function Header({
<div> <div>
<Menu.Button <Menu.Button
className="inline-flex w-full justify-center gap-x-1.5 border border-[rgba(255,255,255,0.5)] rounded-md px-3 py-2 text-sm font-semibold text-white hover:border-[rgba(255,255,255,0.9)]"> className="inline-flex w-full justify-center gap-x-1.5 border border-[rgba(255,255,255,0.5)] rounded-md px-3 py-2 text-sm font-semibold text-white hover:border-[rgba(255,255,255,0.9)]">
<GlobeAltIcon className="w-5 h-5 text-white"/>{locale == 'default' ? 'EN' : locale.toUpperCase()} <GlobeAltIcon className="w-5 h-5 text-white" />{locale == 'default' ? 'EN' : locale.toUpperCase()}
<ChevronDownIcon className="-mr-1 h-5 w-5 text-white" aria-hidden="true"/> <ChevronDownIcon className="-mr-1 h-5 w-5 text-white" aria-hidden="true" />
</Menu.Button> </Menu.Button>
</div> </div>
<Transition <Transition
@ -146,11 +146,11 @@ export default function Header({
return ( return (
<Menu.Item key={item.lang}> <Menu.Item key={item.lang}>
<Link href={hrefValue} onClick={() => checkLocalAndLoading(item.lang)} className={"z-30"}> <Link href={hrefValue} onClick={() => checkLocalAndLoading(item.lang)} className={"z-30"}>
<span <span
className={'text-gray-700 block px-4 py-2 text-sm hover:text-[#2d6ae0] z-30'} className={'text-gray-700 block px-4 py-2 text-sm hover:text-[#2d6ae0] z-30'}
> >
{item.language} {item.language}
</span> </span>
</Link> </Link>
</Menu.Item> </Menu.Item>
) )
@ -163,20 +163,20 @@ export default function Header({
{ {
process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' ? process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' ?
<div className="hidden lg:ml-2 lg:relative lg:inline-block lg:text-left lg:text-white"> <div className="hidden lg:ml-2 lg:relative lg:inline-block lg:text-left lg:text-white">
<LoginButton buttonType={userData.email ? 1 : 0} loginText={authText.loginText}/> <LoginButton buttonType={userData.email ? 1 : 0} loginText={authText.loginText} />
</div> </div>
: :
null null
} }
</nav> </nav>
<Dialog as="div" className="lg:hidden" open={mobileMenuOpen} onClose={setMobileMenuOpen}> <Dialog as="div" className="lg:hidden" open={mobileMenuOpen} onClose={setMobileMenuOpen}>
<div className="fixed inset-0 z-30"/> <div className="fixed inset-0 z-30" />
<Dialog.Panel <Dialog.Panel
className="fixed inset-y-0 right-0 z-30 w-full overflow-y-auto background-div px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10"> className="fixed inset-y-0 right-0 z-30 w-full overflow-y-auto background-div px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex"> <div className="flex">
<Link href={getLinkHref(locale, '')} className="-m-1.5 ml-0.5 p-1.5" <Link href={getLinkHref(locale, '')} className="-m-1.5 ml-0.5 p-1.5"
onClick={() => checkLocalAndLoading(locale)}> onClick={() => checkLocalAndLoading(locale)}>
<img <img
className="h-8 w-auto" className="h-8 w-auto"
src="/website.svg" src="/website.svg"
@ -192,7 +192,7 @@ export default function Header({
onClick={() => setMobileMenuOpen(false)} onClick={() => setMobileMenuOpen(false)}
> >
<span className="sr-only">Close menu</span> <span className="sr-only">Close menu</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true"/> <XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button> </button>
</div> </div>
<div className="mt-6 flow-root"> <div className="mt-6 flow-root">
@ -233,8 +233,8 @@ export default function Header({
<div> <div>
<Menu.Button <Menu.Button
className="inline-flex w-full justify-center gap-x-1.5 border border-[rgba(255,255,255,0.5)] rounded-md px-3 py-2 text-sm font-semibold text-white hover:border-[rgba(255,255,255,0.9)]"> className="inline-flex w-full justify-center gap-x-1.5 border border-[rgba(255,255,255,0.5)] rounded-md px-3 py-2 text-sm font-semibold text-white hover:border-[rgba(255,255,255,0.9)]">
<GlobeAltIcon className="w-5 h-5 text-white"/>{locale == 'default' ? 'EN' : locale.toUpperCase()} <GlobeAltIcon className="w-5 h-5 text-white" />{locale == 'default' ? 'EN' : locale.toUpperCase()}
<ChevronDownIcon className="-mr-1 h-5 w-5 text-white" aria-hidden="true"/> <ChevronDownIcon className="-mr-1 h-5 w-5 text-white" aria-hidden="true" />
</Menu.Button> </Menu.Button>
</div> </div>
<Transition <Transition
@ -258,11 +258,11 @@ export default function Header({
return ( return (
<Menu.Item key={item.lang}> <Menu.Item key={item.lang}>
<Link href={hrefValue} onClick={() => checkLocalAndLoading(item.lang)}> <Link href={hrefValue} onClick={() => checkLocalAndLoading(item.lang)}>
<span <span
className={'text-gray-700 block px-4 py-2 text-sm hover:text-[#2d6ae0]'} className={'text-gray-700 block px-4 py-2 text-sm hover:text-[#2d6ae0]'}
> >
{item.language} {item.language}
</span> </span>
</Link> </Link>
</Menu.Item> </Menu.Item>
) )
@ -277,7 +277,7 @@ export default function Header({
process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' ? process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' ?
<div <div
className="relative inline-block text-left text-base font-semibold text-white ml-2"> className="relative inline-block text-left text-base font-semibold text-white ml-2">
<LoginButton buttonType={userData.email ? 1 : 0} loginText={authText.loginText}/> <LoginButton buttonType={userData.email ? 1 : 0} loginText={authText.loginText} />
</div> </div>
: :
null null

View File

@ -1,34 +0,0 @@
import {Pathnames} from 'next-intl/navigation';
export const locales = ['en', 'zh'] as const;
export const languages = [
{
code: "en-US",
lang: "en",
language: "English",
},
{
code: "zh-CN",
lang: "zh",
language: "简体中文",
},
]
export const pathnames = {
'/': '/',
} satisfies Pathnames<typeof locales>;
// Use the default: `always`,设置为 as-needed可不显示默认路由
export const localePrefix = 'as-needed';
export type AppPathnames = keyof typeof pathnames;
export const getLanguageByLang = (lang) => {
for (let i = 0; i < languages.length; i++) {
if (lang == languages[i].lang) {
return languages[i];
}
}
}

View File

@ -1,10 +0,0 @@
import {getRequestConfig} from 'next-intl/server';
export default getRequestConfig(async ({locale}) => ({
messages: (
await (locale === 'en'
? // When using Turbopack, this will enable HMR for `default`
import('../messages/en.json')
: import(`../messages/${locale}.json`))
).default
}));

22
src/i18n/config.ts Normal file
View File

@ -0,0 +1,22 @@
export const locales = ["en", "zh"] as const;
export const languages = [
{
code: "en-US",
lang: "en",
language: "English",
},
{
code: "zh-CN",
lang: "zh",
language: "简体中文",
},
];
export const getLanguageByLang = (lang) => {
for (let i = 0; i < languages.length; i++) {
if (lang == languages[i].lang) {
return languages[i];
}
}
};

4
src/i18n/navigation.ts Normal file
View File

@ -0,0 +1,4 @@
import { createNavigation } from "next-intl/navigation";
import { routing } from "./routing";
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);

17
src/i18n/request.ts Normal file
View File

@ -0,0 +1,17 @@
import { getRequestConfig } from "next-intl/server";
import { routing } from "./routing";
export default getRequestConfig(async ({ requestLocale }) => {
// This typically corresponds to the `[locale]` segment
let locale = await requestLocale;
// Ensure that a valid locale is used
if (!locale || !routing.locales.includes(locale as any)) {
locale = routing.defaultLocale;
}
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
};
});

13
src/i18n/routing.ts Normal file
View File

@ -0,0 +1,13 @@
import { defineRouting } from "next-intl/routing";
import { locales } from "./config";
export const routing = defineRouting({
// A list of all locales that are supported
locales: locales,
// Used when no locale matches
defaultLocale: "en",
// Use the default: `always`,设置为 as-needed可不显示默认路由
localePrefix: "as-needed",
localeDetection: false,
alternateLinks: false,
});

View File

@ -1,26 +1,19 @@
import createMiddleware from 'next-intl/middleware'; import createMiddleware from "next-intl/middleware";
import {pathnames, locales, localePrefix} from './config'; import { routing } from "./i18n/routing";
export default createMiddleware({ export default createMiddleware(routing);
defaultLocale: 'en',
locales,
pathnames,
localePrefix,
localeDetection: false,
alternateLinks: false
});
export const config = { export const config = {
matcher: [ matcher: [
// Enable a redirect to a matching locale at the root // Enable a redirect to a matching locale at the root
'/', "/",
// Set a cookie to remember the previous locale for // Set a cookie to remember the previous locale for
// all requests that have a locale prefix // all requests that have a locale prefix
'/(en|zh)/:path*', "/(en|zh)/:path*",
// Enable redirects that add missing locales // Enable redirects that add missing locales
// (e.g. `/pathnames` -> `/en/pathnames`) // (e.g. `/pathnames` -> `/en/pathnames`)
'/((?!_next|_vercel|.*\\..*).*)' "/((?!_next|_vercel|.*\\..*).*)",
] ],
}; };

View File

@ -1,9 +0,0 @@
import {createLocalizedPathnamesNavigation} from 'next-intl/navigation';
import {locales, pathnames, localePrefix} from './config';
export const {Link, redirect, usePathname, useRouter} =
createLocalizedPathnamesNavigation({
locales,
pathnames,
localePrefix
});

View File

@ -1,8 +0,0 @@
{
"crons": [
{
"path": "/api/cron/workTranslate",
"schedule": "*/1 * * * *"
}
]
}