feat(i18n): 添加播客生成任务的多语言支持
refactor(login): 改进登录后重定向逻辑 style(components): 统一加载中的文本显示 chore(docker): 为服务添加名称配置
This commit is contained in:
@@ -4,14 +4,19 @@ import { createPointsAccount, recordPointsTransaction, checkUserPointsAccount }
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const sessionData = await getSessionData();
|
||||
console.log('获取到的 session:', sessionData);
|
||||
let baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "/";
|
||||
const pathname = request.nextUrl.searchParams.get('pathname');
|
||||
if(!!pathname){
|
||||
baseUrl += pathname.replace('/','');
|
||||
}
|
||||
|
||||
// 如果没有获取到 session,直接重定向到根目录
|
||||
if (!sessionData?.user) {
|
||||
const url = new URL('/', request.url);
|
||||
const url = new URL(baseUrl, request.url);
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
|
||||
const userId = sessionData.user.id; // 获取 userId
|
||||
|
||||
// 检查用户是否已存在积分账户
|
||||
@@ -34,7 +39,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
// 创建一个 URL 对象,指向要重定向到的根目录
|
||||
const url = new URL('/', request.url);
|
||||
const url = new URL(baseUrl, request.url);
|
||||
// 返回重定向响应
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ export async function PUT(request: NextRequest) {
|
||||
// 5. 扣减积分
|
||||
const pointsToDeduct = parseInt(process.env.POINTS_PER_PODCAST || '10', 10); // 从环境变量获取,默认10
|
||||
const reasonCode = "podcast_generation";
|
||||
const description = `播客生成任务:${task_id}`; // Keep this as is if task_id is dynamic or not translatable
|
||||
const description = `${t("podcast_generation_task")}: ${task_id}`; // 多语言实现
|
||||
|
||||
await deductUserPoints(userId, pointsToDeduct, reasonCode, description);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ lang }) => {
|
||||
const { t, i18n } = useTranslation(lang, 'components'); // 初始化 useTranslation
|
||||
const router = useRouter();
|
||||
const currentPath = usePathname(); // 将 usePathname 移到组件顶层
|
||||
// console.log('i18n.language', i18n.language, lang);
|
||||
|
||||
const switchLanguage = (locale: string) => {
|
||||
// 获取当前路径,并替换语言部分
|
||||
@@ -34,7 +35,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ lang }) => {
|
||||
<button
|
||||
onClick={() => switchLanguage('zh-CN')}
|
||||
className={`px-3 py-1 rounded-md text-sm font-medium text-gray-500 ${
|
||||
i18n.language === 'zh-CN'
|
||||
lang === 'zh-CN'
|
||||
? 'text-gray-900 transition-colors duration-200'
|
||||
: 'hover:text-gray-900 transition-colors duration-200'
|
||||
}`}
|
||||
@@ -44,7 +45,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ lang }) => {
|
||||
<button
|
||||
onClick={() => switchLanguage('')}
|
||||
className={`px-3 py-1 rounded-md text-sm font-medium text-gray-500 ${
|
||||
i18n.language === 'en'
|
||||
lang === 'en'
|
||||
? 'text-gray-900 transition-colors duration-200'
|
||||
: 'hover:text-gray-900 transition-colors duration-200'
|
||||
}`}
|
||||
@@ -54,7 +55,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ lang }) => {
|
||||
<button
|
||||
onClick={() => switchLanguage('ja')}
|
||||
className={`px-3 py-1 rounded-md text-sm font-medium text-gray-500 ${
|
||||
i18n.language === 'ja'
|
||||
lang === 'ja'
|
||||
? 'text-gray-900 transition-colors duration-200'
|
||||
: 'hover:text-gray-900 transition-colors duration-200'
|
||||
}`}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { createPortal } from "react-dom";
|
||||
import { XMarkIcon } from "@heroicons/react/24/outline"; // 导入关闭图标
|
||||
import { AiOutlineChrome, AiOutlineGithub } from "react-icons/ai"; // 从 react-icons/ai 导入 Google 和 GitHub 图标
|
||||
import { useTranslation } from '../i18n/client'; // 导入 useTranslation
|
||||
import { usePathname } from 'next/navigation'; // 导入 usePathname
|
||||
import { getTruePathFromPathname } from '../lib/utils'; // 导入新函数
|
||||
|
||||
interface LoginModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -30,6 +32,8 @@ const LoginModal: FC<LoginModalProps> = ({ isOpen, onClose, lang }) => {
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const pathname = usePathname();
|
||||
const truePath = getTruePathFromPathname(pathname, lang);
|
||||
// 使用 React Portal 将模态框渲染到 body 下,避免Z-index问题和父组件样式影响
|
||||
return createPortal(
|
||||
<div
|
||||
@@ -58,7 +62,7 @@ const LoginModal: FC<LoginModalProps> = ({ isOpen, onClose, lang }) => {
|
||||
|
||||
<div className="space-y-4">
|
||||
<button
|
||||
onClick={() => signIn.social({ provider: "google" , newUserCallbackURL: "/api/newuser?provider=google"})}
|
||||
onClick={() => signIn.social({ provider: "google" , newUserCallbackURL: "/api/newuser?provider=google&pathname=" + truePath})}
|
||||
className="w-full flex items-center justify-center gap-3 px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-lg font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
||||
>
|
||||
<AiOutlineChrome className="h-6 w-6" />
|
||||
@@ -66,7 +70,7 @@ const LoginModal: FC<LoginModalProps> = ({ isOpen, onClose, lang }) => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => signIn.social({ provider: "github" , newUserCallbackURL: "/api/newuser?provider=github" })}
|
||||
onClick={() => signIn.social({ provider: "github" , newUserCallbackURL: "/api/newuser?provider=github&pathname=" + truePath })}
|
||||
className="w-full flex items-center justify-center gap-3 px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-lg font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
||||
>
|
||||
<AiOutlineGithub className="h-6 w-6" />
|
||||
|
||||
Reference in New Issue
Block a user