From 71678ba9dde40b9f5fb3c07a481120cbcb841bb7 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sun, 9 Jun 2024 09:27:16 -0400 Subject: [PATCH] client side i18n fully implemented --- components/Announcement.tsx | 21 ++- components/CollectionCard.tsx | 18 +- components/CollectionListing.tsx | 8 +- components/FilterSearchDropdown.tsx | 51 +++--- components/InstallApp.tsx | 20 ++- components/LinkViews/LinkCard.tsx | 19 ++- .../LinkViews/LinkComponents/LinkActions.tsx | 23 +-- .../LinkComponents/LinkGroupedIconURL.tsx | 53 ------ components/LinkViews/LinkList.tsx | 8 +- components/LinkViews/LinkMasonry.tsx | 19 ++- components/Loader.tsx | 7 - components/MobileNavigation.tsx | 30 ++-- .../ModalContent/BulkDeleteLinksModal.tsx | 42 ++--- .../ModalContent/BulkEditLinksModal.tsx | 19 ++- .../ModalContent/DeleteCollectionModal.tsx | 63 ++++--- components/ModalContent/DeleteLinkModal.tsx | 21 +-- components/ModalContent/DeleteUserModal.tsx | 14 +- .../ModalContent/EditCollectionModal.tsx | 45 +++-- .../EditCollectionSharingModal.tsx | 62 ++++--- components/ModalContent/EditLinkModal.tsx | 69 +++----- .../EmailChangeVerificationModal.tsx | 24 +-- .../ModalContent/NewCollectionModal.tsx | 48 +++--- components/ModalContent/NewLinkModal.tsx | 81 +++------ components/ModalContent/NewTokenModal.tsx | 61 ++++--- components/ModalContent/NewUserModal.tsx | 35 ++-- .../ModalContent/PreservedFormatsModal.tsx | 64 +++---- components/ModalContent/RevokeTokenModal.tsx | 30 ++-- components/ModalContent/UploadFileModal.tsx | 67 ++++---- components/Navbar.tsx | 10 +- components/NoLinksFound.tsx | 8 +- components/PreserverdFormatRow.tsx | 1 - components/ProfileDropdown.tsx | 17 +- components/RadioButton.tsx | 8 - components/ReadableView.tsx | 8 +- components/SettingsSidebar.tsx | 48 +++--- components/Sidebar.tsx | 8 +- components/ToggleDarkMode.tsx | 6 +- layouts/AuthRedirect.tsx | 1 - layouts/CenteredForm.tsx | 13 +- pages/register.tsx | 8 +- public/locales/en/common.json | 156 +++++++++++++++++- 41 files changed, 677 insertions(+), 637 deletions(-) delete mode 100644 components/LinkViews/LinkComponents/LinkGroupedIconURL.tsx delete mode 100644 components/Loader.tsx diff --git a/components/Announcement.tsx b/components/Announcement.tsx index caf1b73..3186833 100644 --- a/components/Announcement.tsx +++ b/components/Announcement.tsx @@ -1,5 +1,6 @@ import Link from "next/link"; import React, { MouseEventHandler } from "react"; +import { Trans } from "next-i18next"; type Props = { toggleAnnouncementBar: MouseEventHandler; @@ -13,15 +14,17 @@ export default function Announcement({ toggleAnnouncementBar }: Props) {

- See what's new in{" "} - - Linkwarden {announcementId} - - ! + , + ]} + />

- diff --git a/components/InstallApp.tsx b/components/InstallApp.tsx index b8bcf84..6fa4a61 100644 --- a/components/InstallApp.tsx +++ b/components/InstallApp.tsx @@ -1,5 +1,6 @@ import { isPWA } from "@/lib/client/utils"; import React, { useState } from "react"; +import { Trans } from "next-i18next"; type Props = {}; @@ -25,15 +26,16 @@ const InstallApp = (props: Props) => { />

- Install Linkwarden to your home screen for a faster access and - enhanced experience.{" "} - - Learn more - + , + ]} + />

diff --git a/components/ModalContent/BulkEditLinksModal.tsx b/components/ModalContent/BulkEditLinksModal.tsx index 07b3914..5f3d31a 100644 --- a/components/ModalContent/BulkEditLinksModal.tsx +++ b/components/ModalContent/BulkEditLinksModal.tsx @@ -5,12 +5,14 @@ import useLinkStore from "@/store/links"; import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; import toast from "react-hot-toast"; import Modal from "../Modal"; +import { useTranslation } from "next-i18next"; type Props = { onClose: Function; }; export default function BulkEditLinksModal({ onClose }: Props) { + const { t } = useTranslation(); const { updateLinks, selectedLinks, setSelectedLinks } = useLinkStore(); const [submitLoader, setSubmitLoader] = useState(false); const [removePreviousTags, setRemovePreviousTags] = useState(false); @@ -20,7 +22,6 @@ export default function BulkEditLinksModal({ onClose }: Props) { const setCollection = (e: any) => { const collectionId = e?.value || null; - console.log(updatedValues); setUpdatedValues((prevValues) => ({ ...prevValues, collectionId })); }; @@ -33,7 +34,7 @@ export default function BulkEditLinksModal({ onClose }: Props) { if (!submitLoader) { setSubmitLoader(true); - const load = toast.loading("Updating..."); + const load = toast.loading(t("updating")); const response = await updateLinks( selectedLinks, @@ -44,7 +45,7 @@ export default function BulkEditLinksModal({ onClose }: Props) { toast.dismiss(load); if (response.ok) { - toast.success(`Updated!`); + toast.success(t("updated")); setSelectedLinks([]); onClose(); } else toast.error(response.data as string); @@ -57,13 +58,15 @@ export default function BulkEditLinksModal({ onClose }: Props) { return (

- Edit {selectedLinks.length} Link{selectedLinks.length > 1 ? "s" : ""} + {selectedLinks.length === 1 + ? t("edit_link") + : t("edit_links", { count: selectedLinks.length })}

-

Move to Collection

+

{t("move_to_collection")}

-

Add Tags

+

{t("add_tags")}

@@ -84,7 +87,7 @@ export default function BulkEditLinksModal({ onClose }: Props) { checked={removePreviousTags} onChange={(e) => setRemovePreviousTags(e.target.checked)} /> - Remove previous tags + {t("remove_previous_tags")}
@@ -94,7 +97,7 @@ export default function BulkEditLinksModal({ onClose }: Props) { className="btn btn-accent dark:border-violet-400 text-white" onClick={submit} > - Save Changes + {t("save_changes")}
diff --git a/components/ModalContent/DeleteCollectionModal.tsx b/components/ModalContent/DeleteCollectionModal.tsx index 6548553..504d3a3 100644 --- a/components/ModalContent/DeleteCollectionModal.tsx +++ b/components/ModalContent/DeleteCollectionModal.tsx @@ -7,6 +7,7 @@ import { useRouter } from "next/router"; import usePermissions from "@/hooks/usePermissions"; import Modal from "../Modal"; import Button from "../ui/Button"; +import { useTranslation } from "next-i18next"; type Props = { onClose: Function; @@ -17,42 +18,40 @@ export default function DeleteCollectionModal({ onClose, activeCollection, }: Props) { + const { t } = useTranslation(); const [collection, setCollection] = useState(activeCollection); + const [submitLoader, setSubmitLoader] = useState(false); + const { removeCollection } = useCollectionStore(); + const router = useRouter(); + const [inputField, setInputField] = useState(""); + const permissions = usePermissions(collection.id as number); useEffect(() => { setCollection(activeCollection); }, []); - const [submitLoader, setSubmitLoader] = useState(false); - const { removeCollection } = useCollectionStore(); - const router = useRouter(); - const [inputField, setInputField] = useState(""); - - const permissions = usePermissions(collection.id as number); - const submit = async () => { - if (permissions === true) if (collection.name !== inputField) return null; - + if (permissions === true && collection.name !== inputField) return; if (!submitLoader) { setSubmitLoader(true); if (!collection) return null; setSubmitLoader(true); - const load = toast.loading("Deleting..."); + const load = toast.loading(t("deleting_collection")); - let response; - - response = await removeCollection(collection.id as any); + let response = await removeCollection(collection.id as number); toast.dismiss(load); if (response.ok) { - toast.success(`Deleted.`); + toast.success(t("deleted")); onClose(); router.push("/collections"); - } else toast.error(response.data as string); + } else { + toast.error(response.data as string); + } setSubmitLoader(false); } @@ -61,7 +60,7 @@ export default function DeleteCollectionModal({ return (

- {permissions === true ? "Delete" : "Leave"} Collection + {permissions === true ? t("delete_collection") : t("leave_collection")}

@@ -69,32 +68,26 @@ export default function DeleteCollectionModal({
{permissions === true ? ( <> -
-

- To confirm, type " - {collection.name} - " in the box below: -

- - setInputField(e.target.value)} - placeholder={`Type "${collection.name}" Here.`} - className="w-3/4 mx-auto" - /> -
+

{t("confirm_deletion_prompt", { name: collection.name })}

+ setInputField(e.target.value)} + placeholder={t("type_name_placeholder", { + name: collection.name, + })} + className="w-3/4 mx-auto" + />
- Warning: Deleting this collection will permanently erase - all its contents, and it will become inaccessible to everyone, - including members with previous access. + {t("warning")}: + {t("deletion_warning")}
) : ( -

Click the button below to leave the current collection.

+

{t("leave_prompt")}

)}
diff --git a/components/ModalContent/DeleteLinkModal.tsx b/components/ModalContent/DeleteLinkModal.tsx index b884dab..92de104 100644 --- a/components/ModalContent/DeleteLinkModal.tsx +++ b/components/ModalContent/DeleteLinkModal.tsx @@ -5,6 +5,7 @@ import toast from "react-hot-toast"; import Modal from "../Modal"; import { useRouter } from "next/router"; import Button from "../ui/Button"; +import { useTranslation } from "next-i18next"; type Props = { onClose: Function; @@ -12,11 +13,10 @@ type Props = { }; export default function DeleteLinkModal({ onClose, activeLink }: Props) { + const { t } = useTranslation(); const [link, setLink] = useState(activeLink); - const { removeLink } = useLinkStore(); - const router = useRouter(); useEffect(() => { @@ -24,13 +24,13 @@ export default function DeleteLinkModal({ onClose, activeLink }: Props) { }, []); const deleteLink = async () => { - const load = toast.loading("Deleting..."); + const load = toast.loading(t("deleting")); const response = await removeLink(link.id as number); toast.dismiss(load); - response.ok && toast.success(`Link Deleted.`); + response.ok && toast.success(t("deleted")); if (router.pathname.startsWith("/links/[id]")) { router.push("/dashboard"); @@ -41,28 +41,25 @@ export default function DeleteLinkModal({ onClose, activeLink }: Props) { return ( -

Delete Link

+

{t("delete_link")}

-

Are you sure you want to delete this Link?

+

{t("link_deletion_confirmation_message")}

- Warning: This action is irreversible! + {t("warning")}: {t("irreversible_warning")}
-

- Hold the Shift key while clicking - 'Delete' to bypass this confirmation in the future. -

+

{t("shift_key_tip")}

diff --git a/components/ModalContent/DeleteUserModal.tsx b/components/ModalContent/DeleteUserModal.tsx index 3c4c1a5..73a81ed 100644 --- a/components/ModalContent/DeleteUserModal.tsx +++ b/components/ModalContent/DeleteUserModal.tsx @@ -2,6 +2,7 @@ import toast from "react-hot-toast"; import Modal from "../Modal"; import useUserStore from "@/store/admin/users"; import Button from "../ui/Button"; +import { useTranslation } from "next-i18next"; type Props = { onClose: Function; @@ -9,39 +10,40 @@ type Props = { }; export default function DeleteUserModal({ onClose, userId }: Props) { + const { t } = useTranslation(); const { removeUser } = useUserStore(); const deleteUser = async () => { - const load = toast.loading("Deleting..."); + const load = toast.loading(t("deleting_user")); const response = await removeUser(userId); toast.dismiss(load); - response.ok && toast.success(`User Deleted.`); + response.ok && toast.success(t("user_deleted")); onClose(); }; return ( -

Delete User

+

{t("delete_user")}

-

Are you sure you want to remove this user?

+

{t("confirm_user_deletion")}

- Warning: This action is irreversible! + {t("warning")}: {t("irreversible_action_warning")}
diff --git a/components/ModalContent/EditCollectionModal.tsx b/components/ModalContent/EditCollectionModal.tsx index fbbf53e..b2105f5 100644 --- a/components/ModalContent/EditCollectionModal.tsx +++ b/components/ModalContent/EditCollectionModal.tsx @@ -5,6 +5,7 @@ import toast from "react-hot-toast"; import { HexColorPicker } from "react-colorful"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import Modal from "../Modal"; +import { useTranslation } from "next-i18next"; type Props = { onClose: Function; @@ -15,6 +16,7 @@ export default function EditCollectionModal({ onClose, activeCollection, }: Props) { + const { t } = useTranslation(); const [collection, setCollection] = useState(activeCollection); @@ -28,16 +30,14 @@ export default function EditCollectionModal({ setSubmitLoader(true); - const load = toast.loading("Updating..."); + const load = toast.loading(t("updating_collection")); - let response; - - response = await updateCollection(collection as any); + let response = await updateCollection(collection as any); toast.dismiss(load); if (response.ok) { - toast.success(`Updated!`); + toast.success(t("updated")); onClose(); } else toast.error(response.data as string); @@ -47,29 +47,35 @@ export default function EditCollectionModal({ return ( -

Edit Collection Info

+

{t("edit_collection_info")}

-

Name

+

{t("name")}

setCollection({ ...collection, name: e.target.value }) } />
-

Color

-
+

{t("color")}

+
+ + setCollection({ ...collection, color }) + } + />
- Reset + {t("reset")}
- setCollection({ ...collection, color: e })} - />
-

Description

+

{t("description")}