feat(i18n): 添加播客生成任务的多语言支持

refactor(login): 改进登录后重定向逻辑
style(components): 统一加载中的文本显示
chore(docker): 为服务添加名称配置
This commit is contained in:
hex2077
2025-08-25 22:27:30 +08:00
parent 99fad315d0
commit bf314aa5b4
11 changed files with 41 additions and 21 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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'
}`}

View File

@@ -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" />