chore: i18n

This commit is contained in:
zhom
2026-04-28 23:50:56 +04:00
parent 97d01e4b54
commit f8ce56481f
62 changed files with 6520 additions and 1322 deletions
+3 -1
View File
@@ -14,6 +14,7 @@ import {
useRef,
useState,
} from "react";
import { useTranslation } from "react-i18next";
import { LuPipette } from "react-icons/lu";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -366,12 +367,13 @@ export const ColorPickerOutput = ({
className: _className,
...props
}: ColorPickerOutputProps) => {
const { t } = useTranslation();
const { mode, setMode } = useColorPicker();
return (
<Select onValueChange={setMode} value={mode}>
<SelectTrigger className="w-20 h-8 text-xs shrink-0" {...props}>
<SelectValue placeholder="Mode" />
<SelectValue placeholder={t("common.labels.mode")} />
</SelectTrigger>
<SelectContent>
{formats.map((format) => (
+11 -79
View File
@@ -1,6 +1,7 @@
"use client";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { LuCheck, LuChevronsUpDown } from "react-icons/lu";
import { Button } from "@/components/ui/button";
@@ -39,13 +40,18 @@ export function Combobox({
options,
value,
onValueChange,
placeholder = "Select option...",
searchPlaceholder = "Search...",
placeholder,
searchPlaceholder,
className,
disabled,
}: ComboboxProps) {
const { t } = useTranslation();
const [open, setOpen] = React.useState(false);
const resolvedPlaceholder = placeholder ?? t("common.buttons.select");
const resolvedSearchPlaceholder =
searchPlaceholder ?? t("common.buttons.search");
return (
<Popover open={open} onOpenChange={disabled ? undefined : setOpen}>
<PopoverTrigger asChild>
@@ -58,15 +64,15 @@ export function Combobox({
>
{value
? options.find((option) => option.value === value)?.label
: placeholder}
: resolvedPlaceholder}
<LuChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<Command>
<CommandInput placeholder={searchPlaceholder} />
<CommandInput placeholder={resolvedSearchPlaceholder} />
<CommandList>
<CommandEmpty>No option found.</CommandEmpty>
<CommandEmpty>{t("common.noResults")}</CommandEmpty>
<CommandGroup>
{options.map((option) => (
<CommandItem
@@ -100,77 +106,3 @@ export function Combobox({
</Popover>
);
}
const frameworks = [
{
value: "next.js",
label: "Next.js",
},
{
value: "sveltekit",
label: "SvelteKit",
},
{
value: "nuxt.js",
label: "Nuxt.js",
},
{
value: "remix",
label: "Remix",
},
{
value: "astro",
label: "Astro",
},
];
export function ComboboxDemo() {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[200px] justify-between"
>
{value
? frameworks.find((framework) => framework.value === value)?.label
: "Select framework..."}
<LuChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search framework..." />
<CommandList>
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
value={framework.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
}}
>
<LuCheck
className={cn(
"mr-2 h-4 w-4",
value === framework.value ? "opacity-100" : "opacity-0",
)}
/>
{framework.label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}
+9 -4
View File
@@ -2,6 +2,7 @@
import { Command as CommandPrimitive } from "cmdk";
import type * as React from "react";
import { useTranslation } from "react-i18next";
import { LuSearch } from "react-icons/lu";
import {
@@ -30,19 +31,23 @@ function Command({
}
function CommandDialog({
title = "Command Palette",
description = "Search for a command to run...",
title,
description,
children,
...props
}: React.ComponentProps<typeof Dialog> & {
title?: string;
description?: string;
}) {
const { t } = useTranslation();
const resolvedTitle = title ?? t("common.commandPalette.title");
const resolvedDescription =
description ?? t("common.commandPalette.description");
return (
<Dialog {...props}>
<DialogHeader className="sr-only">
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
<DialogTitle>{resolvedTitle}</DialogTitle>
<DialogDescription>{resolvedDescription}</DialogDescription>
</DialogHeader>
<DialogContent className="overflow-hidden p-0">
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
+3 -1
View File
@@ -3,6 +3,7 @@
import { AnimatePresence, type HTMLMotionProps, motion } from "motion/react";
import { Dialog as DialogPrimitive } from "radix-ui";
import type * as React from "react";
import { useTranslation } from "react-i18next";
import { RxCross2 } from "react-icons/rx";
import { useControlledState } from "@/hooks/use-controlled-state";
@@ -115,6 +116,7 @@ function DialogContent({
transition = { type: "spring", stiffness: 150, damping: 25 },
...props
}: DialogContentProps) {
const { t } = useTranslation();
const initialRotation =
from === "bottom" || from === "left" ? "20deg" : "-20deg";
const isVertical = from === "top" || from === "bottom";
@@ -166,7 +168,7 @@ function DialogContent({
{children}
<DialogPrimitive.Close className="cursor-pointer ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
<RxCross2 />
<span className="sr-only">Close</span>
<span className="sr-only">{t("common.buttons.close")}</span>
</DialogPrimitive.Close>
</motion.div>
</DialogPrimitive.Content>