diff --git a/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count-chart.tsx b/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count-chart.tsx index cd783de..58dee05 100644 --- a/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count-chart.tsx +++ b/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count-chart.tsx @@ -61,13 +61,13 @@ export default function ViewsCountChart({ gradient: resolvedTheme === 'light' ? { - opacityFrom: 0.8, - opacityTo: 0.4, - } + opacityFrom: 0.8, + opacityTo: 0.4, + } : { - opacityFrom: 0.4, - opacityTo: 0.1, - }, + opacityFrom: 0.4, + opacityTo: 0.1, + }, }, dataLabels: { enabled: false, diff --git a/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count.tsx b/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count.tsx index 0f149ed..b5231b4 100644 --- a/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count.tsx +++ b/apps/web/src/app/[locale]/app/(dashboard)/cards/views-count.tsx @@ -1,11 +1,11 @@ import { dayjs } from '@nivo/dayjs' +import { Dictionary } from '@nivo/i18n' import { Eye } from 'lucide-react' import dynamic from 'next/dynamic' import Link from 'next/link' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { serverClient } from '@/lib/trpc/server' -import { Dictionary } from '@nivo/i18n' const ViewsCountChart = dynamic(() => import('./views-count-chart'), { ssr: false, @@ -26,7 +26,9 @@ export async function ViewsCount({ dictionary }: { dictionary: Dictionary }) { {dictionary.views_count_title}{' '} - {dictionary.views_count_subtitle} + + {dictionary.views_count_subtitle} + diff --git a/apps/web/src/app/[locale]/app/batches/[id]/batch-upload-list.tsx b/apps/web/src/app/[locale]/app/batches/[id]/batch-upload-list.tsx index 0c88393..a92db2d 100644 --- a/apps/web/src/app/[locale]/app/batches/[id]/batch-upload-list.tsx +++ b/apps/web/src/app/[locale]/app/batches/[id]/batch-upload-list.tsx @@ -5,7 +5,6 @@ import { SymbolIcon } from '@radix-ui/react-icons' import { Cable, CopyIcon, Loader2, ReceiptText } from 'lucide-react' import Image from 'next/image' import Link from 'next/link' -import { useDictionary } from '@/state/dictionary' import { CopyButton } from '@/components/copy-button' import { TranscriptionPreview } from '@/components/transcription-preview' @@ -24,6 +23,7 @@ import { } from '@/components/ui/tooltip' import { UploadItemActions } from '@/components/upload-item-actions' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { formatBytes } from '@/utils/format-bytes' import { formatSecondsToMinutes } from '@/utils/format-seconds-to-minutes' @@ -65,8 +65,12 @@ export function BatchUploadList({ batchId }: BatchUploadListProps) { )} - {dictionary.batch_upload_list_duration_column} - {dictionary.batch_upload_list_size_column} + + {dictionary.batch_upload_list_duration_column} + + + {dictionary.batch_upload_list_size_column} +
@@ -178,7 +182,10 @@ export function BatchUploadList({ batchId }: BatchUploadListProps) {
- + )) diff --git a/apps/web/src/app/[locale]/app/batches/[id]/page.tsx b/apps/web/src/app/[locale]/app/batches/[id]/page.tsx index cedfb16..50495bd 100644 --- a/apps/web/src/app/[locale]/app/batches/[id]/page.tsx +++ b/apps/web/src/app/[locale]/app/batches/[id]/page.tsx @@ -1,10 +1,10 @@ +import { getDictionary, Locale } from '@nivo/i18n' import { Metadata } from 'next' import { BatchUploadList } from './batch-upload-list' -import { Locale, getDictionary } from '@nivo/i18n' interface BatchPageProps { - params: { id: string, locale: Locale } + params: { id: string; locale: Locale } } export async function generateMetadata({ @@ -24,7 +24,9 @@ export default async function BatchPage({ params }: BatchPageProps) { return ( <>
-

{dictionary.batch_page_header_title}

+

+ {dictionary.batch_page_header_title} +

diff --git a/apps/web/src/app/[locale]/app/layout.tsx b/apps/web/src/app/[locale]/app/layout.tsx index 9f505c9..0788881 100644 --- a/apps/web/src/app/[locale]/app/layout.tsx +++ b/apps/web/src/app/[locale]/app/layout.tsx @@ -1,11 +1,12 @@ +import { getDictionary, Locale } from '@nivo/i18n' + import { Header } from '@/components/header' -import { Locale, getDictionary } from '@nivo/i18n' export default async function AppLayout({ children, - params: { locale } + params: { locale }, }: { - children: React.ReactNode, + children: React.ReactNode params: { locale: Locale } diff --git a/apps/web/src/app/[locale]/app/upload/page.tsx b/apps/web/src/app/[locale]/app/upload/page.tsx index 9eda7a6..419eee1 100644 --- a/apps/web/src/app/[locale]/app/upload/page.tsx +++ b/apps/web/src/app/[locale]/app/upload/page.tsx @@ -1,11 +1,11 @@ +import { getDictionary, Locale } from '@nivo/i18n' import { AlertCircle } from 'lucide-react' +import Head from 'next/head' import Link from 'next/link' import { serverClient } from '@/lib/trpc/server' import { UploadList } from './upload-list' -import { Locale, getDictionary } from '@nivo/i18n' -import Head from 'next/head' export default async function Upload({ params: { locale }, diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-conversion-progress-column.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-conversion-progress-column.tsx index b995e43..29c2b65 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-conversion-progress-column.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-conversion-progress-column.tsx @@ -18,11 +18,11 @@ import { TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip' +import { useDictionary } from '@/state/dictionary' import { addToAudioConversionQueueAtom, audioConversionAtom, } from '@/state/uploads' -import { useDictionary } from '@/state/dictionary' export interface AudioConversionProgressColumnProps { uploadId: string @@ -68,12 +68,16 @@ export function AudioConversionProgressColumn({ ) : progress === 100 ? ( <> - {dictionary.audio_conversion_complete} + + {dictionary.audio_conversion_complete} + ) : ( <> - {dictionary.audio_conversion_waiting} + + {dictionary.audio_conversion_waiting} + diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-upload-progress-column.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-upload-progress-column.tsx index f64fb05..54809ac 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-upload-progress-column.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/columns/audio-upload-progress-column.tsx @@ -11,8 +11,8 @@ import { useCallback } from 'react' import { Button } from '@/components/ui/button' import { Progress } from '@/components/ui/progress' -import { audioUploadAtom, startAudioUploadAtom } from '@/state/uploads' import { useDictionary } from '@/state/dictionary' +import { audioUploadAtom, startAudioUploadAtom } from '@/state/uploads' export interface AudioUploadProgressColumnProps { uploadId: string @@ -46,7 +46,9 @@ export function AudioUploadProgressColumn({ {progress === 0 && !error ? ( <> - {dictionary.audio_upload_waiting} + + {dictionary.audio_upload_waiting} + ) : error ? ( <> @@ -65,7 +67,9 @@ export function AudioUploadProgressColumn({ ) : ( <> - {dictionary.audio_upload_complete} + + {dictionary.audio_upload_complete} + )}
diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/columns/video-upload-progress-column.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/columns/video-upload-progress-column.tsx index 5ae7685..aaa08b1 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/columns/video-upload-progress-column.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/columns/video-upload-progress-column.tsx @@ -8,10 +8,10 @@ import { import { useAtomValue, useSetAtom } from 'jotai' import { selectAtom } from 'jotai/utils' import { useCallback } from 'react' -import { useDictionary } from '@/state/dictionary' import { Button } from '@/components/ui/button' import { Progress } from '@/components/ui/progress' +import { useDictionary } from '@/state/dictionary' import { startVideoUploadAtom, videoUploadAtom } from '@/state/uploads' export interface VideoUploadProgressColumnProps { @@ -46,7 +46,9 @@ export function VideoUploadProgressColumn({ {progress === 0 && !error ? ( <> - {dictionary.video_upload_waiting} + + {dictionary.video_upload_waiting} + ) : error ? ( <> @@ -65,7 +67,9 @@ export function VideoUploadProgressColumn({ ) : ( <> - {dictionary.video_upload_complete} + + {dictionary.video_upload_complete} + )}
diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/header.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/header.tsx index b77ca63..85428bd 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/header.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/header.tsx @@ -5,7 +5,6 @@ import axios from 'axios' import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { ChevronDownIcon, Loader2 } from 'lucide-react' import { useFormContext } from 'react-hook-form' -import { useDictionary } from '@/state/dictionary' import { AlertDialog, @@ -22,10 +21,11 @@ import { Button } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, - DropdownMenuTrigger, DropdownMenuItem, + DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { Separator } from '@/components/ui/separator' +import { useDictionary } from '@/state/dictionary' import { amountOfUploadsAtom, areUploadsEmptyAtom, @@ -131,13 +131,17 @@ export function Header({ onSubmit }: HeaderProps) { - {dictionary.alert_dialog_title} + + {dictionary.alert_dialog_title} + {dictionary.alert_dialog_description} - {dictionary.alert_dialog_cancel} + + {dictionary.alert_dialog_cancel} + {dictionary.alert_dialog_proceed} diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/index.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/index.tsx index a3b719b..a44f651 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/index.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/index.tsx @@ -1,33 +1,36 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' +import { Dictionary } from '@nivo/i18n' import { useRouter } from 'next/navigation' import { FormProvider, useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' -import { useDictionary } from '@/state/dictionary' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { Header } from './header' import { UploadDropArea } from './upload-drop-area' import { UploadTable } from './upload-table' -import { Dictionary } from '@nivo/i18n' -const uploadsFormSchema = (dictionary: Dictionary) => z.object({ - files: z - .array( - z.object({ - id: z.string(), - title: z.string().min(1), - duration: z.coerce.number().transform(Math.round), - language: z.enum(['pt', 'es']), - sizeInBytes: z.coerce.number(), - tags: z.array(z.string()).min(1, { message: dictionary.upload_list_at_least_one_tag }), - }), - ) - .min(0), -}) +const uploadsFormSchema = (dictionary: Dictionary) => + z.object({ + files: z + .array( + z.object({ + id: z.string(), + title: z.string().min(1), + duration: z.coerce.number().transform(Math.round), + language: z.enum(['pt', 'es']), + sizeInBytes: z.coerce.number(), + tags: z + .array(z.string()) + .min(1, { message: dictionary.upload_list_at_least_one_tag }), + }), + ) + .min(0), + }) export type UploadsFormSchema = z.infer> diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/upload-drop-area.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/upload-drop-area.tsx index a9be4bf..a4a5290 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/upload-drop-area.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/upload-drop-area.tsx @@ -4,8 +4,8 @@ import { UploadIcon } from '@radix-ui/react-icons' import { useSetAtom } from 'jotai' import { useDropzone } from 'react-dropzone' -import { addUploadsAtom } from '@/state/uploads' import { useDictionary } from '@/state/dictionary' +import { addUploadsAtom } from '@/state/uploads' export function UploadDropArea() { const dictionary = useDictionary() @@ -30,8 +30,12 @@ export function UploadDropArea() { >
- {dictionary.upload_drop_area_drop_here} - {dictionary.upload_drop_area_accept_mp4} + + {dictionary.upload_drop_area_drop_here} + + + {dictionary.upload_drop_area_accept_mp4} +
diff --git a/apps/web/src/app/[locale]/app/upload/upload-list/upload-table.tsx b/apps/web/src/app/[locale]/app/upload/upload-list/upload-table.tsx index 0488073..dfe6919 100644 --- a/apps/web/src/app/[locale]/app/upload/upload-list/upload-table.tsx +++ b/apps/web/src/app/[locale]/app/upload/upload-list/upload-table.tsx @@ -15,6 +15,7 @@ import { TableHeader, TableRow, } from '@/components/ui/table' +import { useDictionary } from '@/state/dictionary' import { areUploadsEmptyAtom, deleteUploadAtom, @@ -32,7 +33,6 @@ import { AudioUploadProgressColumn } from './columns/audio-upload-progress-colum import { VideoUploadProgressColumn } from './columns/video-upload-progress-column' import { UploadLanguageInput } from './upload-language-input' import { UploadTagInput } from './upload-tag-input' -import { useDictionary } from '@/state/dictionary' export function UploadTable() { const dictionary = useDictionary() @@ -54,7 +54,7 @@ export function UploadTable() { */ useEffect(() => { if (isThereAnyPendingUpload) { - window.onbeforeunload = function() { + window.onbeforeunload = function () { return dictionary.uploads_warning_on_close } } else { @@ -76,7 +76,9 @@ export function UploadTable() { {dictionary.uploads_table_head_info} - {dictionary.uploads_table_head_metadata} + + {dictionary.uploads_table_head_metadata} +
@@ -95,7 +97,9 @@ export function UploadTable() { {dictionary.uploads_table_head_upload_audio}
- {dictionary.uploads_table_head_actions} + + {dictionary.uploads_table_head_actions} +
diff --git a/apps/web/src/app/[locale]/app/uploads/layout.tsx b/apps/web/src/app/[locale]/app/uploads/layout.tsx index 932527a..3a8c639 100644 --- a/apps/web/src/app/[locale]/app/uploads/layout.tsx +++ b/apps/web/src/app/[locale]/app/uploads/layout.tsx @@ -1,14 +1,22 @@ +import { getDictionary, Locale } from '@nivo/i18n' import { ReactNode, Suspense } from 'react' import { UploadsFilters } from './uploads-filters' -import { Locale, getDictionary } from '@nivo/i18n' -export default async function Layout({ children, params: { locale } }: { children: ReactNode, params: { locale: Locale } }) { +export default async function Layout({ + children, + params: { locale }, +}: { + children: ReactNode + params: { locale: Locale } +}) { const dictionary = await getDictionary(locale) return ( <> -

{dictionary.layout_uploads_title}

+

+ {dictionary.layout_uploads_title} +

diff --git a/apps/web/src/app/[locale]/app/uploads/loading.tsx b/apps/web/src/app/[locale]/app/uploads/loading.tsx index e8875ca..1a4766a 100644 --- a/apps/web/src/app/[locale]/app/uploads/loading.tsx +++ b/apps/web/src/app/[locale]/app/uploads/loading.tsx @@ -22,8 +22,12 @@ export default function Loading() { {dictionary.loading_video} - {dictionary.loading_duration} - {dictionary.loading_size} + + {dictionary.loading_duration} + + + {dictionary.loading_size} +
@@ -36,7 +40,9 @@ export default function Loading() { {dictionary.loading_external_id}
- {dictionary.loading_uploaded_at} + + {dictionary.loading_uploaded_at} +
diff --git a/apps/web/src/app/[locale]/app/uploads/page.tsx b/apps/web/src/app/[locale]/app/uploads/page.tsx index 203f1be..788ca4d 100644 --- a/apps/web/src/app/[locale]/app/uploads/page.tsx +++ b/apps/web/src/app/[locale]/app/uploads/page.tsx @@ -1,7 +1,8 @@ -import { Cable, CopyIcon } from 'lucide-react' -import { useDictionary } from '@/state/dictionary' import { dayjs } from '@nivo/dayjs' +import { getDictionary, Locale } from '@nivo/i18n' +import { Cable, CopyIcon } from 'lucide-react' import { Metadata } from 'next' +import { unstable_noStore } from 'next/cache' import Image from 'next/image' import Link from 'next/link' import { Suspense } from 'react' @@ -27,8 +28,6 @@ import { formatBytes } from '@/utils/format-bytes' import { formatSecondsToMinutes } from '@/utils/format-seconds-to-minutes' import { UploadsPagination } from './uploads-pagination' -import { unstable_noStore } from 'next/cache' -import { Locale, getDictionary } from '@nivo/i18n' export const metadata: Metadata = { title: 'Uploads', @@ -48,9 +47,9 @@ type UploadsPageSearchParams = z.infer export default async function UploadsPage({ searchParams, - params: { locale } + params: { locale }, }: { - searchParams: UploadsPageSearchParams, + searchParams: UploadsPageSearchParams params: { locale: Locale } }) { const dictionary = await getDictionary(locale) @@ -74,8 +73,12 @@ export default async function UploadsPage({ {dictionary.uploads_video} - {dictionary.uploads_duration} - {dictionary.uploads_size} + + {dictionary.uploads_duration} + + + {dictionary.uploads_size} +
diff --git a/apps/web/src/app/[locale]/app/uploads/uploads-filters.tsx b/apps/web/src/app/[locale]/app/uploads/uploads-filters.tsx index d5c1462..a6f053d 100644 --- a/apps/web/src/app/[locale]/app/uploads/uploads-filters.tsx +++ b/apps/web/src/app/[locale]/app/uploads/uploads-filters.tsx @@ -3,12 +3,12 @@ import { Filter, Loader2, X } from 'lucide-react' import { useRouter, useSearchParams } from 'next/navigation' import { FormEvent, useState, useTransition } from 'react' -import { useDictionary } from '@/state/dictionary' import { TagInput } from '@/components/tag-input' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Separator } from '@/components/ui/separator' +import { useDictionary } from '@/state/dictionary' export function UploadsFilters() { const dictionary = useDictionary() diff --git a/apps/web/src/app/[locale]/app/uploads/uploads-pagination.tsx b/apps/web/src/app/[locale]/app/uploads/uploads-pagination.tsx index 8a3ffac..6db1ba0 100644 --- a/apps/web/src/app/[locale]/app/uploads/uploads-pagination.tsx +++ b/apps/web/src/app/[locale]/app/uploads/uploads-pagination.tsx @@ -8,7 +8,6 @@ import { } from '@radix-ui/react-icons' import { useRouter, useSearchParams } from 'next/navigation' import { useCallback } from 'react' -import { useDictionary } from '@/state/dictionary' import { Button } from '@/components/ui/button' import { @@ -18,6 +17,7 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' +import { useDictionary } from '@/state/dictionary' interface UploadsPaginationProps { pageCount: number @@ -62,7 +62,9 @@ export function UploadsPagination({
-

{dictionary.uploads_pagination_rows_per_page}

+

+ {dictionary.uploads_pagination_rows_per_page} +

{errors.title && ( @@ -104,7 +111,9 @@ export function VideoForm({ video }: VideoFormProps) {
- +
- {video.externalStatus || dictionary.video_form_external_status_waiting} + {video.externalStatus || + dictionary.video_form_external_status_waiting} - {dictionary.webhook_table_head_status} - {dictionary.webhook_table_head_executed_at} - {dictionary.webhook_table_head_duration} + + {dictionary.webhook_table_head_status} + + + {dictionary.webhook_table_head_executed_at} + + + {dictionary.webhook_table_head_duration} +
{dictionary.webhook_table_head_metadata} diff --git a/apps/web/src/app/[locale]/app/videos/[id]/transcription-card/index.tsx b/apps/web/src/app/[locale]/app/videos/[id]/transcription-card/index.tsx index 0ed461e..738f9a4 100644 --- a/apps/web/src/app/[locale]/app/videos/[id]/transcription-card/index.tsx +++ b/apps/web/src/app/[locale]/app/videos/[id]/transcription-card/index.tsx @@ -12,10 +12,10 @@ import { Label } from '@/components/ui/label' import { ScrollArea } from '@/components/ui/scroll-area' import { Switch } from '@/components/ui/switch' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { Segment } from './segment' import { TranscriptionSkeleton } from './transcription-skeleton' -import { useDictionary } from '@/state/dictionary' interface TranscriptionCardProps { videoId: string @@ -31,7 +31,9 @@ const transcriptionSegmentsFormSchema = z.object({ ), }) -type TranscriptionSegmentsFormSchema = z.infer +type TranscriptionSegmentsFormSchema = z.infer< + typeof transcriptionSegmentsFormSchema +> export function TranscriptionCard({ videoId, @@ -148,7 +150,9 @@ export function TranscriptionCard({ checked={shouldFollowUserFocus} onCheckedChange={setShouldFollowUserFocus} /> - +
) : (
diff --git a/apps/web/src/components/copy-button.tsx b/apps/web/src/components/copy-button.tsx index 20ff58f..4cf9950 100644 --- a/apps/web/src/components/copy-button.tsx +++ b/apps/web/src/components/copy-button.tsx @@ -3,6 +3,8 @@ import { ComponentProps, useRef, useState } from 'react' import { twMerge } from 'tailwind-merge' +import { useDictionary } from '@/state/dictionary' + import { Button } from './ui/button' export interface CopyButtonProps extends ComponentProps { @@ -10,6 +12,7 @@ export interface CopyButtonProps extends ComponentProps { } export function CopyButton({ textToCopy, ...props }: CopyButtonProps) { + const dictionary = useDictionary() const [wasCopiedRecently, setWasCopiedRecently] = useState(false) const copyTimeoutRef = useRef() @@ -35,7 +38,7 @@ export function CopyButton({ textToCopy, ...props }: CopyButtonProps) { props.className, )} > - {wasCopiedRecently ? 'Copied!' : props.children} + {wasCopiedRecently ? dictionary.copy_button_copied : props.children} ) } diff --git a/apps/web/src/components/create-new-tag-dialog.tsx b/apps/web/src/components/create-new-tag-dialog.tsx index e472d89..fe22047 100644 --- a/apps/web/src/components/create-new-tag-dialog.tsx +++ b/apps/web/src/components/create-new-tag-dialog.tsx @@ -1,12 +1,14 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' +import { Dictionary } from '@nivo/i18n' import { AlertCircle, Loader2 } from 'lucide-react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { Badge } from './ui/badge' import { Button } from './ui/button' @@ -20,18 +22,17 @@ import { } from './ui/dialog' import { Input } from './ui/input' import { Label } from './ui/label' -import { useDictionary } from '@/state/dictionary' -import { Dictionary } from '@nivo/i18n' -const newTagFormSchema = (dictionary: Dictionary) => z.object({ - tag: z - .string({ - required_error: dictionary.new_tag_form_error_required, - }) - .regex(/^[a-zA-Z]+(-[a-zA-Z]+)*$/, { - message: dictionary.new_tag_form_error_format, - }), -}) +const newTagFormSchema = (dictionary: Dictionary) => + z.object({ + tag: z + .string({ + required_error: dictionary.new_tag_form_error_required, + }) + .regex(/^[a-zA-Z]+(-[a-zA-Z]+)*$/, { + message: dictionary.new_tag_form_error_format, + }), + }) type NewTagFormSchema = z.infer> @@ -100,13 +101,16 @@ export function CreateNewTagDialog({

  1. - ignite - {dictionary.example_tag_product} + ignite -{' '} + {dictionary.example_tag_product}
  2. - react - {dictionary.example_tag_technology} + react -{' '} + {dictionary.example_tag_technology}
  3. - fundamentos-do-react - {dictionary.example_tag_course} + fundamentos-do-react -{' '} + {dictionary.example_tag_course}
diff --git a/apps/web/src/components/header/index.tsx b/apps/web/src/components/header/index.tsx index afe42a4..1ceb772 100644 --- a/apps/web/src/components/header/index.tsx +++ b/apps/web/src/components/header/index.tsx @@ -1,3 +1,4 @@ +import { Dictionary } from '@nivo/i18n' import { PlusCircle } from 'lucide-react' import Image from 'next/image' import Link from 'next/link' @@ -10,11 +11,8 @@ import { MenuLink } from './menu-link' import { Search } from './search' import { ThemeSwitcher } from './theme-switcher' import { UserProfileButton } from './user-profile-button' -import { Dictionary } from '@nivo/i18n' -export async function Header({ dictionary }: { - dictionary: Dictionary -}) { +export async function Header({ dictionary }: { dictionary: Dictionary }) { return (
@@ -31,7 +29,9 @@ export async function Header({ dictionary }: {
diff --git a/apps/web/src/components/header/search-item.tsx b/apps/web/src/components/header/search-item.tsx index bb73ce2..924d9ad 100644 --- a/apps/web/src/components/header/search-item.tsx +++ b/apps/web/src/components/header/search-item.tsx @@ -5,9 +5,10 @@ import Image from 'next/image' import { useRouter } from 'next/navigation' import { useEffect, useRef, useTransition } from 'react' +import { useDictionary } from '@/state/dictionary' + import { CommandItem } from '../ui/command' import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip' -import { useDictionary } from '@/state/dictionary' interface SearchItemProps { video: RouterOutput['getUploads']['videos'][number] diff --git a/apps/web/src/components/header/search.tsx b/apps/web/src/components/header/search.tsx index 49afcec..d20ea7b 100644 --- a/apps/web/src/components/header/search.tsx +++ b/apps/web/src/components/header/search.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react' import useDebounceValue from '@/hooks/useDebounceValue' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { Button } from '../ui/button' import { @@ -14,10 +15,9 @@ import { CommandList, } from '../ui/command' import { SearchItem } from './search-item' -import { useDictionary } from '@/state/dictionary' export function Search() { - const dictionary = useDictionary(); + const dictionary = useDictionary() const [open, setOpen] = useState(false) const [search, setSearch] = useState('') diff --git a/apps/web/src/components/header/theme-switcher.tsx b/apps/web/src/components/header/theme-switcher.tsx index cd21163..db824d3 100644 --- a/apps/web/src/components/header/theme-switcher.tsx +++ b/apps/web/src/components/header/theme-switcher.tsx @@ -14,7 +14,7 @@ import { import { useDictionary } from '@/state/dictionary' export function ThemeSwitcher(props: React.ComponentProps) { - const dictionary = useDictionary(); + const dictionary = useDictionary() const { setTheme } = useTheme() return ( @@ -23,7 +23,9 @@ export function ThemeSwitcher(props: React.ComponentProps) { diff --git a/apps/web/src/components/header/user-profile-button.tsx b/apps/web/src/components/header/user-profile-button.tsx index cd601da..ab8c2a2 100644 --- a/apps/web/src/components/header/user-profile-button.tsx +++ b/apps/web/src/components/header/user-profile-button.tsx @@ -1,4 +1,5 @@ import { auth, signOut } from '@nivo/auth' +import { Dictionary } from '@nivo/i18n' import { Code, Cog, LogOut } from 'lucide-react' import Image from 'next/image' import Link from 'next/link' @@ -7,14 +8,17 @@ import { Avatar } from '../ui/avatar' import { DropdownMenu, DropdownMenuContent, - DropdownMenuLabel, DropdownMenuItem, + DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '../ui/dropdown-menu' -import { Dictionary } from '@nivo/i18n' -export async function UserProfileButton({ dictionary }: { dictionary: Dictionary }) { +export async function UserProfileButton({ + dictionary, +}: { + dictionary: Dictionary +}) { const session = await auth() async function handleSignOut() { @@ -41,7 +45,9 @@ export async function UserProfileButton({ dictionary }: { dictionary: Dictionary - {dictionary.user_profile_button_my_account} + + {dictionary.user_profile_button_my_account} + diff --git a/apps/web/src/components/intercepted-sheet-content.tsx b/apps/web/src/components/intercepted-sheet-content.tsx index 35d804a..588624d 100644 --- a/apps/web/src/components/intercepted-sheet-content.tsx +++ b/apps/web/src/components/intercepted-sheet-content.tsx @@ -5,12 +5,15 @@ import { X } from 'lucide-react' import { useRouter } from 'next/navigation' import React from 'react' +import { useDictionary } from '@/state/dictionary' + import { SheetOverlay, sheetVariants } from './ui/sheet' export const InterceptedSheetContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => { + const dictionary = useDictionary() const router = useRouter() const onDismiss = React.useCallback(() => { @@ -33,7 +36,7 @@ export const InterceptedSheetContent = React.forwardRef< className="absolute right-8 top-8 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary" > - Close + {dictionary.intercepted_sheet_close} diff --git a/apps/web/src/components/summary/storage.tsx b/apps/web/src/components/summary/storage.tsx index 9bfad07..ab0be85 100644 --- a/apps/web/src/components/summary/storage.tsx +++ b/apps/web/src/components/summary/storage.tsx @@ -17,7 +17,9 @@ export async function Storage({ dictionary }: { dictionary: Dictionary }) { return ( - {dictionary.storage_title} + + {dictionary.storage_title} + diff --git a/apps/web/src/components/summary/total-count.tsx b/apps/web/src/components/summary/total-count.tsx index 5f27665..86c71dd 100644 --- a/apps/web/src/components/summary/total-count.tsx +++ b/apps/web/src/components/summary/total-count.tsx @@ -13,11 +13,15 @@ export async function TotalCount({ dictionary }: { dictionary: Dictionary }) { return ( - {dictionary.total_count_title} + + {dictionary.total_count_title} + - {String(amountOverall).padStart(4, '0')} + + {String(amountOverall).padStart(4, '0')} +

{`+ ${amountLastMonth} ${dictionary.total_count_last_month}`}

diff --git a/apps/web/src/components/tag-input.tsx b/apps/web/src/components/tag-input.tsx index a22e081..f045e8d 100644 --- a/apps/web/src/components/tag-input.tsx +++ b/apps/web/src/components/tag-input.tsx @@ -7,6 +7,7 @@ import { twMerge } from 'tailwind-merge' import useDebounceValue from '@/hooks/useDebounceValue' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { CreateNewTagDialog } from './create-new-tag-dialog' import { Badge } from './ui/badge' @@ -22,7 +23,6 @@ import { Dialog } from './ui/dialog' import { Popover, PopoverContent, PopoverTrigger } from './ui/popover' import { ScrollArea } from './ui/scroll-area' import { Separator } from './ui/separator' -import { useDictionary } from '@/state/dictionary' export interface TagInputProps { value: string[] diff --git a/apps/web/src/components/transcription-preview.tsx b/apps/web/src/components/transcription-preview.tsx index eada10a..75572e5 100644 --- a/apps/web/src/components/transcription-preview.tsx +++ b/apps/web/src/components/transcription-preview.tsx @@ -15,6 +15,7 @@ import { import { Skeleton } from '@/components/ui/skeleton' import { Textarea } from '@/components/ui/textarea' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' import { Button } from './ui/button' @@ -23,6 +24,7 @@ export interface TranscriptionPreviewProps { } export function TranscriptionPreview({ videoId }: TranscriptionPreviewProps) { + const dictionary = useDictionary() const [isDialogOpen, setIsDialogOpen] = useState(false) const { @@ -51,12 +53,12 @@ export function TranscriptionPreview({ videoId }: TranscriptionPreviewProps) { - Transcrição + {dictionary.transcription_preview_title} {isLoadingTranscription || isPendingTranscription ? (
@@ -76,7 +78,7 @@ export function TranscriptionPreview({ videoId }: TranscriptionPreviewProps) { diff --git a/apps/web/src/components/upload-item-actions.tsx b/apps/web/src/components/upload-item-actions.tsx index ee0de64..454554c 100644 --- a/apps/web/src/components/upload-item-actions.tsx +++ b/apps/web/src/components/upload-item-actions.tsx @@ -25,6 +25,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { trpc } from '@/lib/trpc/react' +import { useDictionary } from '@/state/dictionary' interface UploadItemActionsProps { videoId: string @@ -35,6 +36,7 @@ export function UploadItemActions({ videoId, uploadBatchId, }: UploadItemActionsProps) { + const dictionary = useDictionary() const utils = trpc.useUtils() const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) @@ -52,9 +54,8 @@ export function UploadItemActions({ setIsDeleteDialogOpen(false) } catch { - toast.error('Uh oh! Something went wrong.', { - description: - 'An error ocurred while trying to delete the video. If the error persists, please contact an administrator.', + toast.error(dictionary.upload_item_actions_toast_error, { + description: dictionary.upload_item_actions_toast_error_description, }) } } @@ -69,21 +70,23 @@ export function UploadItemActions({ className="data-[state=open]:bg-muted" > - Open menu + + {dictionary.upload_item_actions_open_menu} + - Edit + {dictionary.upload_item_actions_edit} {uploadBatchId && ( - View batch + {dictionary.upload_item_actions_view_batch} )} @@ -94,7 +97,7 @@ export function UploadItemActions({ disabled={isDeletingVideo} > - Delete + {dictionary.upload_item_actions_delete} @@ -102,28 +105,29 @@ export function UploadItemActions({ - Are you sure? + + {dictionary.upload_item_actions_confirm_title} + +

{dictionary.upload_item_actions_confirm_description}

- This action can't be undone and the video will be permanently - deleted from the server. -

-

- This will{' '} + {dictionary.upload_item_actions_confirm_note_1} - permanently + {dictionary.upload_item_actions_confirm_note_2} :

    -
  1. Delete the MP4, MP3 and subtitles from storage;
  2. -
  3. Delete the video on external provider;
  4. -
  5. Delete the videos on any outside integration;
  6. +
  7. {dictionary.upload_item_actions_confirm_step_1}
  8. +
  9. {dictionary.upload_item_actions_confirm_step_2}
  10. +
  11. {dictionary.upload_item_actions_confirm_step_3}
- Cancel + + {dictionary.upload_item_actions_cancel} + diff --git a/packages/i18n/dictionaries/en.json b/packages/i18n/dictionaries/en.json index f85f4fd..94e220b 100644 --- a/packages/i18n/dictionaries/en.json +++ b/packages/i18n/dictionaries/en.json @@ -334,5 +334,24 @@ "transcription_card_button_save": "Save", "transcription_skeleton_generating": "Transcription is being generated", "transcription_skeleton_auto_refresh": "The page will automatically refresh...", - "metadata_tooltip_request_body": "Request body sent to the webhook" + "metadata_tooltip_request_body": "Request body sent to the webhook", + "copy_button_copied": "Copied!", + "intercepted_sheet_close": "Close", + "transcription_preview_view_transcription": "View transcription", + "transcription_preview_title": "Transcription", + "transcription_preview_button_review": "Review", + "upload_item_actions_toast_error": "Uh oh! Something went wrong.", + "upload_item_actions_toast_error_description": "An error occurred while trying to delete the video. If the error persists, please contact an administrator.", + "upload_item_actions_open_menu": "Open menu", + "upload_item_actions_edit": "Edit", + "upload_item_actions_view_batch": "View batch", + "upload_item_actions_delete": "Delete", + "upload_item_actions_confirm_title": "Are you sure?", + "upload_item_actions_confirm_description": "This action can't be undone and the video will be permanently deleted from the server.", + "upload_item_actions_confirm_note_1": "This will ", + "upload_item_actions_confirm_note_2": "permanently", + "upload_item_actions_confirm_step_1": "Delete the MP4, MP3 and subtitles from storage;", + "upload_item_actions_confirm_step_2": "Delete the video on external provider;", + "upload_item_actions_confirm_step_3": "Delete the videos on any outside integration;", + "upload_item_actions_cancel": "Cancel" } diff --git a/packages/i18n/dictionaries/es.json b/packages/i18n/dictionaries/es.json index 64dc825..168eb6d 100644 --- a/packages/i18n/dictionaries/es.json +++ b/packages/i18n/dictionaries/es.json @@ -328,5 +328,24 @@ "transcription_card_button_save": "Guardar", "transcription_skeleton_generating": "La transcripción está siendo generada", "transcription_skeleton_auto_refresh": "La página se actualizará automáticamente...", - "metadata_tooltip_request_body": "Cuerpo de la solicitud enviado al webhook" + "metadata_tooltip_request_body": "Cuerpo de la solicitud enviado al webhook", + "copy_button_copied": "¡Copiado!", + "intercepted_sheet_close": "Cerrar", + "transcription_preview_view_transcription": "Ver transcripción", + "transcription_preview_title": "Transcripción", + "transcription_preview_button_review": "Revisar", + "upload_item_actions_toast_error": "¡Uh oh! Algo salió mal.", + "upload_item_actions_toast_error_description": "Ocurrió un error al intentar eliminar el video. Si el error persiste, comuníquese con un administrador.", + "upload_item_actions_open_menu": "Abrir menú", + "upload_item_actions_edit": "Editar", + "upload_item_actions_view_batch": "Ver lote", + "upload_item_actions_delete": "Eliminar", + "upload_item_actions_confirm_title": "¿Está seguro?", + "upload_item_actions_confirm_description": "Esta acción no se puede deshacer y el video se eliminará permanentemente del servidor.", + "upload_item_actions_confirm_note_1": "Esto ", + "upload_item_actions_confirm_note_2": "permanentemente", + "upload_item_actions_confirm_step_1": "Eliminar el MP4, MP3 y subtítulos del almacenamiento;", + "upload_item_actions_confirm_step_2": "Eliminar el video en el proveedor externo;", + "upload_item_actions_confirm_step_3": "Eliminar los videos en cualquier integración externa;", + "upload_item_actions_cancel": "Cancelar" } diff --git a/packages/i18n/dictionaries/pt.json b/packages/i18n/dictionaries/pt.json index 7fa722f..35409ec 100644 --- a/packages/i18n/dictionaries/pt.json +++ b/packages/i18n/dictionaries/pt.json @@ -328,5 +328,24 @@ "transcription_card_button_save": "Salvar", "transcription_skeleton_generating": "A transcrição está sendo gerada", "transcription_skeleton_auto_refresh": "A página será atualizada automaticamente...", - "metadata_tooltip_request_body": "Corpo da solicitação enviado para o webhook" + "metadata_tooltip_request_body": "Corpo da solicitação enviado para o webhook", + "copy_button_copied": "Copiado!", + "intercepted_sheet_close": "Fechar", + "transcription_preview_view_transcription": "Ver transcrição", + "transcription_preview_title": "Transcrição", + "transcription_preview_button_review": "Revisar", + "upload_item_actions_toast_error": "Uh oh! Algo deu errado.", + "upload_item_actions_toast_error_description": "Ocorreu um erro ao tentar excluir o vídeo. Se o erro persistir, entre em contato com um administrador.", + "upload_item_actions_open_menu": "Abrir menu", + "upload_item_actions_edit": "Editar", + "upload_item_actions_view_batch": "Ver lote", + "upload_item_actions_delete": "Excluir", + "upload_item_actions_confirm_title": "Você tem certeza?", + "upload_item_actions_confirm_description": "Esta ação não pode ser desfeita e o vídeo será permanentemente excluído do servidor.", + "upload_item_actions_confirm_note_1": "Isto ", + "upload_item_actions_confirm_note_2": "permanentemente", + "upload_item_actions_confirm_step_1": "Excluir o MP4, MP3 e legendas do armazenamento;", + "upload_item_actions_confirm_step_2": "Excluir o vídeo no provedor externo;", + "upload_item_actions_confirm_step_3": "Excluir os vídeos em qualquer integração externa;", + "upload_item_actions_cancel": "Cancelar" }