diff --git a/packages/features/package.json b/packages/features/package.json index 6edb4f80..388e1a99 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -50,6 +50,8 @@ "cmdk": "1.0.0", "dayjs": "1.11.12", "easy-mesh-gradient": "0.0.5", + "i18next": "^23.14.0", + "i18next-browser-languagedetector": "^8.0.0", "immer": "10.1.1", "js-beautify": "1.15.1", "lucide-react": "0.417.0", @@ -62,6 +64,7 @@ "react-dom": "18.3.1", "react-error-boundary": "4.0.13", "react-hook-form": "7.52.1", + "react-i18next": "^15.0.1", "react-mixpanel-browser": "4.1.0", "react-qr-code": "2.0.15", "react-router": "6.25.1", diff --git a/packages/features/src/@types/i18next.d.ts b/packages/features/src/@types/i18next.d.ts new file mode 100644 index 00000000..d76f574f --- /dev/null +++ b/packages/features/src/@types/i18next.d.ts @@ -0,0 +1,13 @@ +import "i18next" +import resources from "./resources" +const { ns1, ns2 } = resources + +declare module "i18next" { + interface CustomTypeOptions { + defaultNS: "ns1" + resources: { + ns1: typeof ns1 + ns2: typeof ns2 + } + } +} diff --git a/packages/features/src/@types/resources.ts b/packages/features/src/@types/resources.ts new file mode 100644 index 00000000..f2aa9c24 --- /dev/null +++ b/packages/features/src/@types/resources.ts @@ -0,0 +1,9 @@ +import ns1 from "../i18n/locales/en/en.json" +import ns2 from "../i18n/locales/tr/tr.json" + +const resources = { + ns1, + ns2, +} as const + +export default resources diff --git a/packages/features/src/address-book/components/new-address-form.tsx b/packages/features/src/address-book/components/new-address-form.tsx index da9837e5..915cda71 100644 --- a/packages/features/src/address-book/components/new-address-form.tsx +++ b/packages/features/src/address-book/components/new-address-form.tsx @@ -3,6 +3,8 @@ import { PlusIcon } from "lucide-react" import { useForm } from "react-hook-form" import { useNavigate } from "react-router-dom" +import i18next from "i18next" + import { useAddressBookStore } from "@/common/store/address-book" import { FormError } from "@/components/form-error" @@ -26,6 +28,8 @@ export const NewAddressForm = () => { addContact(data) return navigate("/contacts") } + + const { t } = i18next return (
{ htmlFor="contactName" className={cn(errors.name && "text-destructive")} > - Contact's Name + {t("contactName")} { htmlFor="contactAddress" className={cn(errors.address && "text-destructive")} > - Receiver Address + {t("receiverAddress")} { data-testid="newAddress/createButton" > - Create Contact + {t("createContact")} ) diff --git a/packages/features/src/address-book/views/address-book.tsx b/packages/features/src/address-book/views/address-book.tsx index 50bc2156..c1b64760 100644 --- a/packages/features/src/address-book/views/address-book.tsx +++ b/packages/features/src/address-book/views/address-book.tsx @@ -1,10 +1,10 @@ +import { truncateString } from "@/common/lib/string" import type { Contact } from "@/common/types" import { AppLayout } from "@/components/app-layout" - -import { truncateString } from "@/common/lib/string" import { MenuBar } from "@/components/menu-bar" import { Copy, Plus, TrashIcon } from "lucide-react" import type { MouseEvent } from "react" +import { useTranslation } from "react-i18next" import { Link } from "react-router-dom" import { toast } from "sonner" @@ -25,11 +25,12 @@ export const AddressBookView = ({ navigator.clipboard.writeText(address) toast.success("Address copied") } + const { t } = useTranslation() return (
-

Address book

+

{t("addressBook")}

-

Add new contact

+

{t("addNewContact")}

{contacts.map((contact, index) => { diff --git a/packages/features/src/address-book/views/new-address.tsx b/packages/features/src/address-book/views/new-address.tsx index 2157637c..0d6461d2 100644 --- a/packages/features/src/address-book/views/new-address.tsx +++ b/packages/features/src/address-book/views/new-address.tsx @@ -5,6 +5,7 @@ import { MenuBar } from "@/components/menu-bar" import { zodResolver } from "@hookform/resolvers/zod" import clsx from "clsx" import { useForm } from "react-hook-form" +import { useTranslation } from "react-i18next" import { useLocation } from "react-router-dom" import { NewAddressFormSchema } from "../components/new-address-form.schema" @@ -30,11 +31,14 @@ export const NewAddressView = ({ onGoBack, onSubmit }: NewAddressViewProps) => { useEffect(() => { setValue("address", location.state?.address || "") }, []) + + const { t } = useTranslation() + return (
-

New contact

+

{t("newContact")}

{ disabled={disableSubmit} data-testid="submitForm" > - Add contact + {t("addContact")}
diff --git a/packages/features/src/components/address-dropdown.tsx b/packages/features/src/components/address-dropdown.tsx index 51d2074d..c0f5a602 100644 --- a/packages/features/src/components/address-dropdown.tsx +++ b/packages/features/src/components/address-dropdown.tsx @@ -2,6 +2,7 @@ import { truncateString } from "@/common/lib/string" import { useVault } from "@palladxyz/vault" import clsx from "clsx" import { CopyIcon, ExternalLinkIcon, UserPlusIcon } from "lucide-react" +import { useTranslation } from "react-i18next" import { Link } from "react-router-dom" import { toast } from "sonner" @@ -34,6 +35,8 @@ export const AddressDropdown = ({ ) window.open(url, "_blank")?.focus() } + const { t } = useTranslation() + return (
  • @@ -71,7 +74,7 @@ export const AddressDropdown = ({ className="flex gap-2" > - Create Contact + {t("createContact")}
  • diff --git a/packages/features/src/components/fee-picker.tsx b/packages/features/src/components/fee-picker.tsx index bb6cede2..e242f628 100644 --- a/packages/features/src/components/fee-picker.tsx +++ b/packages/features/src/components/fee-picker.tsx @@ -1,5 +1,6 @@ import { TransactionFee } from "@/common/lib/const" import { clsx } from "clsx" +import { useTranslation } from "react-i18next" type TransactionFeeShortProps = { feeValue: keyof typeof TransactionFee @@ -10,13 +11,14 @@ export const TransactionFeeShort = ({ feeValue, onClick, }: TransactionFeeShortProps) => { + const { t } = useTranslation() return ( ) @@ -28,6 +30,7 @@ type FeePickerProps = { } export const FeePicker = ({ feeValue, setValue }: FeePickerProps) => { + const { t } = useTranslation() return (
    diff --git a/packages/features/src/components/from-to.tsx b/packages/features/src/components/from-to.tsx index 4e3d239b..1f0e70da 100644 --- a/packages/features/src/components/from-to.tsx +++ b/packages/features/src/components/from-to.tsx @@ -1,4 +1,5 @@ import { ArrowRightIcon } from "lucide-react" +import { useTranslation } from "react-i18next" import { AddressDropdown } from "./address-dropdown" type FromToProps = { @@ -9,17 +10,18 @@ type FromToProps = { } export const FromTo = ({ tx }: FromToProps) => { + const { t } = useTranslation() return (
    -
    From
    +
    {t("from")}
    -
    To
    +
    {t("to")}
    { + const { t } = useTranslation() + const currentNetworkInfo = useVault((state) => state.getCurrentNetworkInfo()) const handleClick = () => { const elem = document.activeElement as HTMLLIElement @@ -40,13 +43,13 @@ export const HashDropdown = ({ hash, className }: HashDropdownProps) => {
  • diff --git a/packages/features/src/components/menu-drawer.tsx b/packages/features/src/components/menu-drawer.tsx index cd46e031..a522ad77 100644 --- a/packages/features/src/components/menu-drawer.tsx +++ b/packages/features/src/components/menu-drawer.tsx @@ -2,11 +2,13 @@ import Logo from "@/common/assets/logo.svg?react" import MenuIcon from "@/common/assets/menu.svg?react" import { useVault } from "@palladxyz/vault" import { ChevronDownIcon, XIcon } from "lucide-react" +import { useTranslation } from "react-i18next" import { Link, useNavigate } from "react-router-dom" export const MenuDrawer = () => { const navigate = useNavigate() const currentNetworkName = useVault((state) => state.currentNetworkName) + const { t } = useTranslation() return (
    @@ -64,7 +66,7 @@ export const MenuDrawer = () => { onClick={() => navigate("/")} data-testid="menu/activity" > - Dashboard + {t("dashboard")}
    diff --git a/packages/features/src/error-renderer/views/error.tsx b/packages/features/src/error-renderer/views/error.tsx index fe7b6c67..659766f1 100644 --- a/packages/features/src/error-renderer/views/error.tsx +++ b/packages/features/src/error-renderer/views/error.tsx @@ -1,4 +1,5 @@ import type { FallbackProps } from "react-error-boundary" +import { useTranslation } from "react-i18next" import { useMixpanel } from "react-mixpanel-browser" export const ErrorView = ({ error, resetErrorBoundary }: FallbackProps) => { @@ -11,19 +12,21 @@ export const ErrorView = ({ error, resetErrorBoundary }: FallbackProps) => { await mixpanel.track("Boundary Error", { error: stringifiedError }) resetErrorBoundary() } + const { t } = useTranslation() + return (

    Woops

    -

    An error happened.

    +

    {t("errorHappend")}

    - Check services status. + {t("checkServiceStatus")}