解决多语言切换的bug
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Index": {
|
"Header": {
|
||||||
"appName": "Fast3DText",
|
"appName": "Fast3DText",
|
||||||
|
"editorName": "Editor"
|
||||||
|
},
|
||||||
|
"HomePage": {
|
||||||
"heroTitle": "Create Stunning 3D Text Designs",
|
"heroTitle": "Create Stunning 3D Text Designs",
|
||||||
"heroSubtitle": "Generate and customize beautiful 3D text effects for your projects",
|
"heroSubtitle": "Generate and customize beautiful 3D text effects for your projects",
|
||||||
"toolTitle": "3D Text Generator Tool",
|
"toolTitle": "3D Text Generator Tool",
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Index": {
|
"Header": {
|
||||||
"appName": "Fast3DText",
|
"appName": "Fast3DText",
|
||||||
|
"editorName": "编辑器"
|
||||||
|
},
|
||||||
|
"HomePage": {
|
||||||
"heroTitle": "创建惊艳的3D文字设计",
|
"heroTitle": "创建惊艳的3D文字设计",
|
||||||
"heroSubtitle": "为您的项目生成并定制精美的3D文字效果",
|
"heroSubtitle": "为您的项目生成并定制精美的3D文字效果",
|
||||||
"toolTitle": "3D文字生成工具",
|
"toolTitle": "3D文字生成工具",
|
||||||
|
|||||||
@@ -7,17 +7,10 @@ import { Metadata } from "next";
|
|||||||
import Editor from "@/components/SimpleEditor";
|
import Editor from "@/components/SimpleEditor";
|
||||||
import { FontNames, FontWeights, TextProp } from "@/components/common/TextSetting";
|
import { FontNames, FontWeights, TextProp } from "@/components/common/TextSetting";
|
||||||
|
|
||||||
export default function Page({
|
export default function Page() {
|
||||||
params,
|
|
||||||
}: {
|
|
||||||
params: Promise<{ locale: string }>;
|
|
||||||
}) {
|
|
||||||
const { locale } = use(params);
|
|
||||||
// Enable static rendering
|
|
||||||
setRequestLocale(locale);
|
|
||||||
|
|
||||||
const t = useTranslations("DoNotWriteOnThisPage");
|
const t = useTranslations("DoNotWriteOnThisPage");
|
||||||
const indexT = useTranslations("Index");
|
const indexT = useTranslations("HomePage");
|
||||||
|
|
||||||
const text = TextProp.default("Do Not Write On This Page");
|
const text = TextProp.default("Do Not Write On This Page");
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import Footer from "@/components/Footer";
|
|||||||
import FullEditor from "@/components/FullEditor";
|
import FullEditor from "@/components/FullEditor";
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import { Locales } from "@/i18n/config";
|
import { Locales } from "@/i18n/config";
|
||||||
import { Box, Flex } from "@radix-ui/themes";
|
import { Flex } from "@radix-ui/themes";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
|
import { use } from "react";
|
||||||
const host = process.env.NEXT_PUBLIC_HOST;
|
const host = process.env.NEXT_PUBLIC_HOST;
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
|
||||||
|
|||||||
@@ -8,16 +8,9 @@ import { Locales } from "@/i18n/config";
|
|||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { Box, Flex, Heading, Section, Text } from "@radix-ui/themes";
|
import { Box, Flex, Heading, Section, Text } from "@radix-ui/themes";
|
||||||
const host = process.env.NEXT_PUBLIC_HOST;
|
const host = process.env.NEXT_PUBLIC_HOST;
|
||||||
export default function HomePage({
|
export default function HomePage() {
|
||||||
params,
|
|
||||||
}: {
|
|
||||||
params: Promise<{ locale: string }>;
|
|
||||||
}) {
|
|
||||||
const { locale } = use(params);
|
|
||||||
// Enable static rendering
|
|
||||||
setRequestLocale(locale);
|
|
||||||
|
|
||||||
const t = useTranslations("Index");
|
const t = useTranslations("HomePage");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen overflow-hidden">
|
<div className="flex flex-col min-h-screen overflow-hidden">
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
|
'use client'
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import LanguageSwitcher from "./LanguageSwitcher";
|
import LanguageSwitcher from "./LanguageSwitcher";
|
||||||
import { ModeToggle } from "./ModeToggle";
|
import { ModeToggle } from "./ModeToggle";
|
||||||
import { Box, Flex, Link, Strong, Text } from "@radix-ui/themes";
|
import { Box, Flex, Link, Strong, Text } from "@radix-ui/themes";
|
||||||
|
import { useRouter } from "@/i18n/navigation";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const t = useTranslations("Index");
|
|
||||||
|
const t = useTranslations("Header");
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="w-full py-2 border-b-1 ">
|
<header className="w-full py-2 border-b-1 ">
|
||||||
<Flex justify="center" gap="9" align="center">
|
<Flex justify="center" gap="9" align="center">
|
||||||
@@ -16,9 +22,9 @@ export default function Header() {
|
|||||||
|
|
||||||
<Flex gap={"4"} justify={"center"} align={"center"} className="w-1/2">
|
<Flex gap={"4"} justify={"center"} align={"center"} className="w-1/2">
|
||||||
<Link
|
<Link
|
||||||
href="/editor"
|
onClick={() => { router.push("/editor") }}
|
||||||
>
|
>
|
||||||
Editor
|
{t("editorName")}
|
||||||
</Link>
|
</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,12 @@
|
|||||||
"use client";
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { usePathname, useRouter } from "@/i18n/navigation";
|
import { usePathname, useRouter } from "@/i18n/navigation";
|
||||||
import { Locales } from "@/i18n/config";
|
|
||||||
import { Button, DropdownMenu } from "@radix-ui/themes";
|
import { Button, DropdownMenu } from "@radix-ui/themes";
|
||||||
|
import { useLocale } from "next-intl";
|
||||||
|
|
||||||
const LanguageSwitcher = () => {
|
const LanguageSwitcher = () => {
|
||||||
const router = useRouter();
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [currentLanguage, setCurrentLanguage] = useState("en");
|
const locale = useLocale();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const savedLanguage =
|
|
||||||
document.cookie
|
|
||||||
.split("; ")
|
|
||||||
.find((row) => row.startsWith("NEXT_LOCALE="))
|
|
||||||
?.split("=")[1] || "en";
|
|
||||||
setCurrentLanguage(savedLanguage);
|
|
||||||
|
|
||||||
const urlLanguage = pathname.split("/")[1];
|
|
||||||
if (Locales.includes(urlLanguage)) {
|
|
||||||
setCurrentLanguage(urlLanguage);
|
|
||||||
}
|
|
||||||
}, [pathname]);
|
|
||||||
|
|
||||||
const changeLanguage = (newLanguage: string) => {
|
|
||||||
setCurrentLanguage(newLanguage);
|
|
||||||
document.cookie = `NEXT_LOCALE=${newLanguage}; path=/;`;
|
|
||||||
|
|
||||||
const segments = pathname.split("/");
|
|
||||||
if (Locales.includes(segments[1])) {
|
|
||||||
segments[1] = newLanguage;
|
|
||||||
} else {
|
|
||||||
segments.splice(1, 0, newLanguage);
|
|
||||||
}
|
|
||||||
|
|
||||||
router.push(segments.join("/"));
|
|
||||||
router.refresh();
|
|
||||||
};
|
|
||||||
|
|
||||||
const languageLabels = {
|
const languageLabels = {
|
||||||
en: "English",
|
en: "English",
|
||||||
@@ -48,21 +16,26 @@ const LanguageSwitcher = () => {
|
|||||||
// jp: "日本語",
|
// jp: "日本語",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
const labels = [];
|
const labels = [];
|
||||||
for (let l in languageLabels) {
|
for (let l in languageLabels) {
|
||||||
const key = l as keyof typeof languageLabels;
|
const key = l as keyof typeof languageLabels;
|
||||||
labels.push(
|
labels.push(
|
||||||
<DropdownMenu.Item key={l} onClick={() => changeLanguage(l)}>
|
<DropdownMenu.Item key={l} onClick={() => {
|
||||||
|
if (l !== locale) {
|
||||||
|
router.push(pathname, { locale: l });
|
||||||
|
}
|
||||||
|
}}>
|
||||||
{languageLabels[key]}
|
{languageLabels[key]}
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu.Root dir={currentLanguage === "ar" ? "rtl" : "ltr"}>
|
<DropdownMenu.Root dir={locale === "ar" ? "rtl" : "ltr"}>
|
||||||
<DropdownMenu.Trigger >
|
<DropdownMenu.Trigger >
|
||||||
<Button variant="outline" size={"2"}>
|
<Button variant="outline" size={"2"}>
|
||||||
{languageLabels[currentLanguage as keyof typeof languageLabels]}
|
{languageLabels[locale as keyof typeof languageLabels]}
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<DropdownMenu.Content align="end">
|
<DropdownMenu.Content align="end">
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import BackgroundSelector, {
|
|||||||
} from "./common/BackgroundSelector";
|
} from "./common/BackgroundSelector";
|
||||||
import PreviewToolbar from "./common/PreviewToolbar";
|
import PreviewToolbar from "./common/PreviewToolbar";
|
||||||
import SimpleTextSetting from "./common/SimpleTextSetting";
|
import SimpleTextSetting from "./common/SimpleTextSetting";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { TextProp } from "./common/TextSetting";
|
import { TextProp } from "./common/TextSetting";
|
||||||
|
import { useRouter } from "@/i18n/navigation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 简易工具
|
* 简易工具
|
||||||
@@ -16,7 +17,9 @@ import { TextProp } from "./common/TextSetting";
|
|||||||
export default function Page({ textProp, backgroundProp }: { textProp: TextProp | undefined, backgroundProp: BackgroundProp | undefined }) {
|
export default function Page({ textProp, backgroundProp }: { textProp: TextProp | undefined, backgroundProp: BackgroundProp | undefined }) {
|
||||||
|
|
||||||
const t = useTranslations("TextEditor");
|
const t = useTranslations("TextEditor");
|
||||||
const tIndex = useTranslations("Index");
|
const tIndex = useTranslations("HomePage");
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const [background, setBackground] = useState<BackgroundProp>(backgroundProp || {
|
const [background, setBackground] = useState<BackgroundProp>(backgroundProp || {
|
||||||
type: "color",
|
type: "color",
|
||||||
@@ -26,6 +29,34 @@ export default function Page({ textProp, backgroundProp }: { textProp: TextProp
|
|||||||
|
|
||||||
const [text, setText] = useState<TextProp>(textProp || TextProp.default(t("defaultText")));
|
const [text, setText] = useState<TextProp>(textProp || TextProp.default(t("defaultText")));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let bg = sessionStorage.getItem("background");
|
||||||
|
|
||||||
|
if (bg) {
|
||||||
|
console.log("初始化设置 bg", bg);
|
||||||
|
|
||||||
|
setBackground(JSON.parse(bg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let txt = sessionStorage.getItem("text");
|
||||||
|
|
||||||
|
if (txt) {
|
||||||
|
console.log("初始化设置 txt", txt);
|
||||||
|
|
||||||
|
setText(JSON.parse(txt));
|
||||||
|
}
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sessionStorage.setItem("background", JSON.stringify(background));
|
||||||
|
}, [background]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sessionStorage.setItem("text", JSON.stringify(text));
|
||||||
|
|
||||||
|
}, [text]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap={"2"}>
|
<Flex gap={"2"}>
|
||||||
<Flex gap={"2"} direction={"column"} className="w-1/3">
|
<Flex gap={"2"} direction={"column"} className="w-1/3">
|
||||||
@@ -39,7 +70,7 @@ export default function Page({ textProp, backgroundProp }: { textProp: TextProp
|
|||||||
<Flex className="w-2/3" direction={"column"} justify={"between"}>
|
<Flex className="w-2/3" direction={"column"} justify={"between"}>
|
||||||
<PreviewToolbar background={background} text={text} />
|
<PreviewToolbar background={background} text={text} />
|
||||||
|
|
||||||
<Box className="text-center"> <Link href="./editor">{tIndex("toolMore")}?</Link> </Box>
|
<Box className="text-center"> <Link onClick={() => { router.push("/editor") }}>{tIndex("toolMore")}?</Link> </Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ export default function PreviewToolbar({
|
|||||||
} else {
|
} else {
|
||||||
const box = container.current;
|
const box = container.current;
|
||||||
const split = Sizes[aspectRadio].split("x").map(Number);
|
const split = Sizes[aspectRadio].split("x").map(Number);
|
||||||
threeInit(box, split[0], split[1]);
|
const initSuccess = threeInit(box, split[0], split[1]);
|
||||||
console.log("three init");
|
console.log("three init ", initSuccess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,13 +59,26 @@ export default function PreviewToolbar({
|
|||||||
useEffect(updateSize, [aspectRadio]);
|
useEffect(updateSize, [aspectRadio]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateBackground(background);
|
|
||||||
console.log("background init");
|
const timeoutId = setTimeout(() => {
|
||||||
|
updateBackground(background);
|
||||||
|
|
||||||
|
console.log("background change", background);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
|
||||||
}, [background]);
|
}, [background]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateTextProps(text);
|
|
||||||
console.log("text init");
|
const timeoutId = setTimeout(() => {
|
||||||
|
updateTextProps(text);
|
||||||
|
|
||||||
|
console.log("text change", text);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
}, [text]);
|
}, [text]);
|
||||||
|
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
|
|||||||
@@ -13,11 +13,20 @@ let camera: THREE.PerspectiveCamera,
|
|||||||
controls: OrbitControls,
|
controls: OrbitControls,
|
||||||
container: HTMLCanvasElement;
|
container: HTMLCanvasElement;
|
||||||
|
|
||||||
|
console.log("three tool loaded");
|
||||||
|
|
||||||
|
let inited = false;
|
||||||
|
|
||||||
export function init(
|
export function init(
|
||||||
_container: HTMLCanvasElement,
|
_container: HTMLCanvasElement,
|
||||||
width: number,
|
width: number,
|
||||||
height: number
|
height: number
|
||||||
) {
|
) {
|
||||||
|
// if (inited) {
|
||||||
|
// renderer.dispose();
|
||||||
|
// }
|
||||||
|
|
||||||
|
inited = true;
|
||||||
container = _container;
|
container = _container;
|
||||||
scene = new THREE.Scene();
|
scene = new THREE.Scene();
|
||||||
|
|
||||||
@@ -156,6 +165,7 @@ export async function updateTextProps(textProps: TextProp) {
|
|||||||
(textMesh.material as THREE.MeshLambertMaterial).color.set(textProps.color);
|
(textMesh.material as THREE.MeshLambertMaterial).color.set(textProps.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scene.add(textMesh);
|
||||||
lastTextProps = textProps;
|
lastTextProps = textProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const routing = defineRouting({
|
|||||||
|
|
||||||
// Used when no locale matches
|
// Used when no locale matches
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
localeDetection: true,
|
localeDetection: false,
|
||||||
//to remove the locale prefix from the url
|
//to remove the locale prefix from the url
|
||||||
localePrefix: "never",
|
localePrefix: "as-needed",
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user