Add i18n support for import page and translations tabs
Local Build and Deploy / deploy (push) Successful in 1m7s
Local Build and Deploy / deploy (push) Successful in 1m7s
This commit is contained in:
1 parent
574a499e14
commit
5ae29e2a58
3 files changed
+55
-24
No files matched your search
@@ -1,29 +1,31 @@
|
|||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { BadgeCheck, Cat, Copy, Dumbbell, Puzzle, Shirt, Wrench } from "lucide-react";
|
import { BadgeCheck, Cat, Copy, Dumbbell, Puzzle, Shirt, Wrench } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||||
|
|
||||||
const SECTIONS = [
|
|
||||||
{ href: "/admin/import/badges", label: "Badges", icon: BadgeCheck, description: "Import and manage badge assets from external sources." },
|
|
||||||
{ href: "/admin/import/furni", label: "Furni", icon: Puzzle, description: "Import furniture definitions, SWF files, and icons." },
|
|
||||||
{ href: "/admin/import/clothing", label: "Clothing", icon: Shirt, description: "Import clothing and wearables for avatars." },
|
|
||||||
{ href: "/admin/import/effects", label: "Effects", icon: Dumbbell, description: "Import avatar effects and animations." },
|
|
||||||
{ href: "/admin/import/pets", label: "Pets", icon: Cat, description: "Import pet data and icons." },
|
|
||||||
{ href: "/admin/import/clone", label: "Clone", icon: Copy, description: "Clone existing items from one source to another." },
|
|
||||||
{ href: "/admin/import/repair", label: "Repair", icon: Wrench, description: "Audit and repair imported assets." },
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export default async function ImportPage() {
|
export default async function ImportPage() {
|
||||||
|
const t = await getTranslations("pages.admin.import");
|
||||||
const { session, permissions } = await getAdminContext();
|
const { session, permissions } = await getAdminContext();
|
||||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||||
redirect("/admin");
|
redirect("/admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SECTIONS = [
|
||||||
|
{ href: "/admin/import/badges", label: t("badges"), icon: BadgeCheck, description: t("badgesDescription") },
|
||||||
|
{ href: "/admin/import/furni", label: t("furni"), icon: Puzzle, description: t("furniDescription") },
|
||||||
|
{ href: "/admin/import/clothing", label: t("clothing"), icon: Shirt, description: t("clothingDescription") },
|
||||||
|
{ href: "/admin/import/effects", label: t("effects"), icon: Dumbbell, description: t("effectsDescription") },
|
||||||
|
{ href: "/admin/import/pets", label: t("pets"), icon: Cat, description: t("petsDescription") },
|
||||||
|
{ href: "/admin/import/clone", label: t("clone"), icon: Copy, description: t("cloneDescription") },
|
||||||
|
{ href: "/admin/import/repair", label: t("repair"), icon: Wrench, description: t("repairDescription") },
|
||||||
|
] as const;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold">Import</h1>
|
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||||
<p className="text-muted-foreground">Import assets from external sources into your hotel.</p>
|
<p className="text-muted-foreground">{t("subtitle")}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { Gamepad2, Globe, Server } from "lucide-react";
|
import { Gamepad2, Globe, Server } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const TABS = [
|
|
||||||
{ href: "/admin/translations/cms", label: "CMS", icon: Globe },
|
|
||||||
{ href: "/admin/translations/client", label: "Client (Nitro)", icon: Gamepad2 },
|
|
||||||
{ href: "/admin/translations/emulator", label: "Emulator", icon: Server },
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export function TranslationsTabs() {
|
export function TranslationsTabs() {
|
||||||
|
const t = useTranslations("pages.admin.translations.tabs");
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const TABS = [
|
||||||
|
{ href: "/admin/translations/cms", label: t("cms"), icon: Globe },
|
||||||
|
{ href: "/admin/translations/client", label: t("client"), icon: Gamepad2 },
|
||||||
|
{ href: "/admin/translations/emulator", label: t("emulator"), icon: Server },
|
||||||
|
] as const;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-1 border-b">
|
<div className="flex gap-1 border-b">
|
||||||
{TABS.map((t) => {
|
{TABS.map((tab) => {
|
||||||
const active = pathname === t.href || pathname.startsWith(`${t.href}/`);
|
const active = pathname === tab.href || pathname.startsWith(`${tab.href}/`);
|
||||||
const Icon = t.icon;
|
const Icon = tab.icon;
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={t.href}
|
key={tab.href}
|
||||||
href={t.href}
|
href={tab.href}
|
||||||
className={cn(
|
className={cn(
|
||||||
"-mb-px flex items-center gap-2 border-b-2 px-4 py-2 text-sm font-medium transition-colors",
|
"-mb-px flex items-center gap-2 border-b-2 px-4 py-2 text-sm font-medium transition-colors",
|
||||||
active
|
active
|
||||||
@@ -31,7 +33,7 @@ export function TranslationsTabs() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className="h-4 w-4" />
|
<Icon className="h-4 w-4" />
|
||||||
{t.label}
|
{tab.label}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -2007,6 +2007,33 @@
|
|||||||
"save": "Save as favicon"
|
"save": "Save as favicon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"import": {
|
||||||
|
"title": "Import",
|
||||||
|
"subtitle": "Import assets from external sources into your hotel.",
|
||||||
|
"badges": "Badges",
|
||||||
|
"badgesDescription": "Import and manage badge assets from external sources.",
|
||||||
|
"furni": "Furni",
|
||||||
|
"furniDescription": "Import furniture definitions, SWF files, and icons.",
|
||||||
|
"clothing": "Clothing",
|
||||||
|
"clothingDescription": "Import clothing and wearables for avatars.",
|
||||||
|
"effects": "Effects",
|
||||||
|
"effectsDescription": "Import avatar effects and animations.",
|
||||||
|
"pets": "Pets",
|
||||||
|
"petsDescription": "Import pet data and icons.",
|
||||||
|
"clone": "Clone",
|
||||||
|
"cloneDescription": "Clone existing items from one source to another.",
|
||||||
|
"repair": "Repair",
|
||||||
|
"repairDescription": "Audit and repair imported assets."
|
||||||
|
},
|
||||||
|
"translations": {
|
||||||
|
"title": "Translations",
|
||||||
|
"subtitle": "Translate your hotel into multiple languages.",
|
||||||
|
"tabs": {
|
||||||
|
"cms": "CMS",
|
||||||
|
"client": "Client (Nitro)",
|
||||||
|
"emulator": "Emulator"
|
||||||
|
}
|
||||||
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "CMS Settings",
|
"title": "CMS Settings",
|
||||||
"subtitle": "Manage key/value CMS configuration",
|
"subtitle": "Manage key/value CMS configuration",
|
||||||
|
|||||||
Reference in new issue
Block a user