diff --git a/apps/mail/app/(error)/not-found.tsx b/apps/mail/app/(error)/not-found.tsx index 5e6d24c89f..1c1dad7f51 100644 --- a/apps/mail/app/(error)/not-found.tsx +++ b/apps/mail/app/(error)/not-found.tsx @@ -3,26 +3,28 @@ import { AlertCircle, ArrowLeft } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; +import { useTranslations } from "next-intl"; export function NotFound() { const router = useRouter(); + const t = useTranslations(); return ( -
-
+
+
-

404

+

404

- +
{/* Message */}
-

Page Not Found

-

- Oops! The page you're looking for doesn't exist or has been moved. -

+

+ {t("pages.error.notFound.title")} +

+

{t("pages.error.notFound.description")}

{/* Buttons */} @@ -30,10 +32,10 @@ export function NotFound() {
diff --git a/apps/mail/app/(routes)/settings/[...settings]/page.tsx b/apps/mail/app/(routes)/settings/[...settings]/page.tsx index b4dbf83cd4..96360eac08 100644 --- a/apps/mail/app/(routes)/settings/[...settings]/page.tsx +++ b/apps/mail/app/(routes)/settings/[...settings]/page.tsx @@ -6,6 +6,7 @@ import AppearancePage from "../appearance/page"; import ShortcutsPage from "../shortcuts/page"; import SecurityPage from "../security/page"; import { useParams } from "next/navigation"; +import { useTranslations } from "next-intl"; import GeneralPage from "../general/page"; const settingsPages: Record = { @@ -20,11 +21,12 @@ const settingsPages: Record = { export default function SettingsPage() { const params = useParams(); const section = params.settings?.[0] || "general"; + const t = useTranslations(); const SettingsComponent = settingsPages[section]; if (!SettingsComponent) { - return
404 - Settings page not found
; + return
{t("pages.error.settingsNotFound")}
; } return ; diff --git a/apps/mail/app/(routes)/settings/appearance/page.tsx b/apps/mail/app/(routes)/settings/appearance/page.tsx index a439bb4e2c..5888167f71 100644 --- a/apps/mail/app/(routes)/settings/appearance/page.tsx +++ b/apps/mail/app/(routes)/settings/appearance/page.tsx @@ -7,6 +7,7 @@ import { ModeToggle } from "@/components/theme/theme-switcher"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; +import { useTranslations } from "next-intl"; import { useForm } from "react-hook-form"; import { useState } from "react"; import * as z from "zod"; @@ -18,6 +19,7 @@ const formSchema = z.object({ export default function AppearancePage() { const [isSaving, setIsSaving] = useState(false); + const t = useTranslations(); const form = useForm>({ resolver: zodResolver(formSchema), @@ -37,15 +39,20 @@ export default function AppearancePage() { return (
+ {isSaving ? t("common.actions.saving") : t("common.actions.saveChanges")} + + } >
- - + +
diff --git a/apps/mail/app/(routes)/settings/connections/page.tsx b/apps/mail/app/(routes)/settings/connections/page.tsx index 947b9bece1..b96cad62fd 100644 --- a/apps/mail/app/(routes)/settings/connections/page.tsx +++ b/apps/mail/app/(routes)/settings/connections/page.tsx @@ -11,13 +11,14 @@ import { } from "@/components/ui/dialog"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { SettingsCard } from "@/components/settings/settings-card"; +import { AddConnectionDialog } from "@/components/connection/add"; import { emailProviders } from "@/constants/emailProviders"; import { useConnections } from "@/hooks/use-connections"; import { deleteConnection } from "@/actions/connections"; -import { AddConnectionDialog } from "@/components/connection/add"; import { Skeleton } from "@/components/ui/skeleton"; import { Button } from "@/components/ui/button"; import { useSession } from "@/lib/auth-client"; +import { useTranslations } from "next-intl"; import { Trash, Plus } from "lucide-react"; import { useState } from "react"; import Image from "next/image"; @@ -27,47 +28,51 @@ export default function ConnectionsPage() { const { refetch } = useSession(); const { data: connections, mutate, isLoading } = useConnections(); const [openTooltip, setOpenTooltip] = useState(null); + const t = useTranslations(); const disconnectAccount = async (connectionId: string) => { try { await deleteConnection(connectionId); - toast.success("Account disconnected successfully"); + toast.success(t("pages.settings.connections.disconnectSuccess")); mutate(); refetch(); } catch (error) { console.error("Error disconnecting account:", error); - toast.error("Failed to disconnect account"); + toast.error(t("pages.settings.connections.disconnectError")); } }; return (
- +
{isLoading ? ( -
+
{[...Array(3)].map((_, i) => (
-
+
- +
))}
) : connections?.length ? ( -
+
{connections.map((connection) => (
{connection.picture ? ( @@ -81,7 +86,7 @@ export default function ConnectionsPage() { ) : (
- +
)} @@ -123,24 +128,28 @@ export default function ConnectionsPage() { - Disconnect Email Account + {t("pages.settings.connections.disconnectTitle")} - Are you sure you want to disconnect this email? + {t("pages.settings.connections.disconnectDescription")}
- + - +
@@ -152,13 +161,13 @@ export default function ConnectionsPage() {
- diff --git a/apps/mail/app/(routes)/settings/general/page.tsx b/apps/mail/app/(routes)/settings/general/page.tsx index d11dce91b0..747e26eb05 100644 --- a/apps/mail/app/(routes)/settings/general/page.tsx +++ b/apps/mail/app/(routes)/settings/general/page.tsx @@ -16,12 +16,15 @@ import { SelectValue, } from "@/components/ui/select"; import { SettingsCard } from "@/components/settings/settings-card"; +import { availableLocales, defaultLocale } from "@/i18n/config"; import { zodResolver } from "@hookform/resolvers/zod"; import { Globe, Clock, LogOut } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; import { signOut } from "@/lib/auth-client"; import { useRouter } from "next/navigation"; +import { changeLocale } from "@/i18n/utils"; +import { useTranslations, useLocale } from "next-intl"; import { useForm } from "react-hook-form"; import { useState } from "react"; import { toast } from "sonner"; @@ -37,11 +40,12 @@ const formSchema = z.object({ export default function GeneralPage() { const router = useRouter(); const [isSaving, setIsSaving] = useState(false); + const locale = useLocale(); const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { - language: "en", + language: locale, timezone: "UTC", dynamicContent: false, externalImages: true, @@ -53,6 +57,8 @@ export default function GeneralPage() { // TODO: Save settings in user's account + changeLocale(values.language); + // Simulate API call setTimeout(() => { console.log(values); @@ -70,26 +76,28 @@ export default function GeneralPage() { }, }), { - loading: "Signing out...", - success: () => "Signed out successfully!", - error: "Error signing out", + loading: t("common.actions.signingOut"), + success: () => t("common.actions.signedOutSuccess"), + error: t("common.actions.signOutError"), }, ); }; + const t = useTranslations(); + return (
} @@ -102,7 +110,7 @@ export default function GeneralPage() { name="language" render={({ field }) => ( - Language + {t("pages.settings.general.language")} @@ -123,7 +135,7 @@ export default function GeneralPage() { render={({ field }) => ( // TODO: Add all timezones - Timezone + {t("pages.settings.general.timezone")} setToInput(e.target.value)} onKeyDown={(e) => { @@ -325,12 +328,12 @@ export function CreateEmail() {
- Subject + {t("common.searchBar.subject")}
{ setSubjectInput(e.target.value); @@ -341,7 +344,7 @@ export function CreateEmail() {
- Body + {t("pages.createEmail.body")}
{defaultValue && ( @@ -349,7 +352,7 @@ export function CreateEmail() { initialValue={defaultValue} onChange={(newContent) => setMessageContent(newContent)} key={resetEditorKey} - placeholder="Write your message here..." + placeholder={t("pages.createEmail.writeYourMessageHere")} /> )}
@@ -366,16 +369,20 @@ export function CreateEmail() {
-

Attachments

+

+ {t("pages.createEmail.attachments")} +

- {attachments.length} file{attachments.length !== 1 ? "s" : ""} attached + {attachments.length}{" "} + {t("common.replyCompose.fileCount", { count: attachments.length })}

@@ -418,7 +425,7 @@ export function CreateEmail() { onClick={() => document?.getElementById("file-upload")?.click()} > - Attachments + {t("pages.createEmail.attachments")} - Send + {t("common.replyCompose.send")}
diff --git a/apps/mail/components/mail/mail-display.tsx b/apps/mail/components/mail/mail-display.tsx index b52f9bc2b6..93cef877ef 100644 --- a/apps/mail/components/mail/mail-display.tsx +++ b/apps/mail/components/mail/mail-display.tsx @@ -6,6 +6,7 @@ import AttachmentDialog from "./attachment-dialog"; import { useSummary } from "@/hooks/use-summary"; import { TextShimmer } from "../ui/text-shimmer"; import { Separator } from "../ui/separator"; +import { useTranslations } from "next-intl"; import { useEffect, useState } from "react"; import { MailIframe } from "./mail-iframe"; import { ParsedMessage } from "@/types"; @@ -86,6 +87,8 @@ const MailDisplay = ({ emailData, isMuted, index, demo }: Props) => { url: string; }>(null); const [openDetailsPopover, setOpenDetailsPopover] = useState(false); + const t = useTranslations(); + const { data } = demo ? { data: { @@ -143,7 +146,7 @@ const MailDisplay = ({ emailData, isMuted, index, demo }: Props) => { className="h-auto p-0 text-xs underline hover:bg-transparent" onClick={() => setOpenDetailsPopover(true)} > - Details + {t("common.mailDisplay.details")} { >
- From: + + {t("common.mailDisplay.from")}: +
{emailData?.sender?.name} @@ -163,39 +168,52 @@ const MailDisplay = ({ emailData, isMuted, index, demo }: Props) => {
- To: + + {t("common.mailDisplay.to")}: + {emailData?.sender?.email}
- Cc: + + {t("common.mailDisplay.cc")}: + {emailData?.sender?.email}
- Date: + + {t("common.mailDisplay.date")}: + {format(new Date(emailData?.receivedOn), "PPpp")}
- Mailed-By: + + {t("common.mailDisplay.mailedBy")}: + {emailData?.sender?.email}
- Signed-By: + + {t("common.mailDisplay.signedBy")}: + {emailData?.sender?.email}
- Security: + + {t("common.mailDisplay.security")}: +
- Standard encryption (TLS) + {" "} + {t("common.mailDisplay.standardEncryption")} (TLS)
diff --git a/apps/mail/components/mail/mail-iframe.tsx b/apps/mail/components/mail/mail-iframe.tsx index e6f33ca876..6b2bf71dc7 100644 --- a/apps/mail/components/mail/mail-iframe.tsx +++ b/apps/mail/components/mail/mail-iframe.tsx @@ -1,5 +1,6 @@ import { fixNonReadableColors, template } from "@/lib/email-utils"; import { useEffect, useMemo, useRef, useState } from "react"; +import { useTranslations } from "next-intl"; import { Loader2 } from "lucide-react"; import { useTheme } from "next-themes"; import { cn } from "@/lib/utils"; @@ -12,6 +13,8 @@ export function MailIframe({ html }: { html: string }) { const iframeDoc = useMemo(() => template(html), [html]); + const t = useTranslations(); + useEffect(() => { if (!iframeRef.current) return; const url = URL.createObjectURL(new Blob([iframeDoc], { type: "text/html" })); @@ -44,7 +47,7 @@ export function MailIframe({ html }: { html: string }) { {!loaded && (
- Loading email content... + {t("common.mailDisplay.loadingMailContent")}
)}