Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi language Support #101

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
## Dev Workflow

1. Link the `package/walletkit` using `yarn link`
2. In `package/walletkit` run `yarn build` (This will watch the ts files for changes and will also build it)
3. In `package/example` link this walletkit instead of installing it by `npm link @gokiprotocol/walletkit`
4. `yarn run` to get the example started running!
5. DEV

---

## Demo

![walletkit-multilang](https://user-images.githubusercontent.com/22261173/137582726-9e0478dd-3168-4006-b77b-bef67843a5a4.gif)


---

## TODO

1. Get a better fallback UI for suspense
2. Anything more?

---

## To Use

Get the package from the `release` branch. [Here](https://github.com/Aadhinana/walletkit/tree/release)

---

## Source

# walletkit 🔑

[![NPM](https://img.shields.io/npm/v/@gokiprotocol/walletkit)](https://www.npmjs.com/package/@gokiprotocol/walletkit)
[![License](https://img.shields.io/npm/l/@gokiprotocol/walletkit)](/LICENSE)

![Banner](/images/banner.png)

WalletKit is a React library that allows a Solana dApp to display a modal for connecting wallets.

It is intended to be used with [use-solana](https://github.com/saber-hq/saber-common/tree/master/packages/use-solana).
Expand All @@ -14,7 +44,3 @@ It is intended to be used with [use-solana](https://github.com/saber-hq/saber-co
```bash
yarn add @gokiprotocol/walletkit
```

## Usage

Check out the [example app](/packages/example) to understand how to use this library.
46 changes: 46 additions & 0 deletions packages/example/public/locales/hn/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"connect_wallet": "वॉलेट कनेक्ट करें",
"modal": {
"walletStepIntro": {
"instruction": "{{appName}} का उपयोग करने के लिए, आपको एक सोलाना वॉलेट कनेक्ट करना होगा।",
"detailsOne": {
"title": "आप अपने क्रिप्टो को नियंत्रित करते हैं",
"description": "गैर-कस्टोडियल वॉलेट का उपयोग करने से आप तीसरे पक्ष पर भरोसा किए बिना अपने क्रिप्टो को नियंत्रित कर सकते हैं।"
},
"detailsTwo": {
"title": "जल्दी और सस्ते में लेन-देन करें",
"description": "सोलाना की मापनीयता सुनिश्चित करती है कि लेनदेन $0.01 से कम और बिजली की तेज गति से बने रहें।"
}
},
"walletStepSelect": {
"heading": "अपना वॉलेट चुनें",
"showUninstalledWallet": "अनइंस्टॉल किए गए वॉलेट दिखाएं",
"hideUninstalledWallet": "अनइंस्टॉल किए गए वॉलेट छिपाएं"
},
"walletStepConnecting": {
"connecting": {
"header": "कनेक्ट हो रहा है...",
"instructions": "कृपया अपना {{walletName}} वॉलेट अनलॉक करें।"
},
"footer": {
"title": "परेशानी हो रही है?"
}
},
"walletStepRedirect": {
"title": "आपको रीडायरेक्ट किया जा रहा है",
"ix1": "{{infoName}} वॉलेट उपयोग करने के लिए, पहले आपको {{infoName}} वॉलेट इंस्टॉल करना है",
"ix2": "सावधान रहे! ध्यान रखे कि आप केवल आधिकारिक वेबसाइट <strong>({{providerURL}})</strong> से इंस्टॉल करें"
}
},
"buttons": {
"continue": "आगे बड़े",
"goBack": "वापस जाओ",
"refresh": "ताज़ा करना"
},
"footer": {
"title": "पहली बार सोलाना का उपयोग कर रहे हैं?",
"button": "और अधिक जानें",
"finishedInstalling": "हो गया इंस्टॉल?"
},
"changeLanguage": "भाषा बदलें"
}
3 changes: 3 additions & 0 deletions packages/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const App: React.FC = () => {
app={{
name: "My App",
}}
langOption={{
"hn": { nativeName: "Hindi" },
}}
>
<Body />
</WalletKitProvider>
Expand Down
7 changes: 6 additions & 1 deletion packages/walletkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"url": "git+https://github.com/GokiProtocol/walletkit.git"
},
"scripts": {
"build": "tsc"
"build": "tsc",
"build:dev": "tsc -w"
},
"bugs": {
"url": "https://github.com/GokiProtocol/walletkit/issues"
Expand All @@ -32,8 +33,12 @@
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@reach/dialog": "^0.16.0",
"i18next": "^21.3.1",
"i18next-browser-languagedetector": "^6.1.2",
"i18next-http-backend": "^1.3.1",
"polished": "^4.1.3",
"react-device-detect": "^2.0.0",
"react-i18next": "^11.12.0",
"react-spring": "^9.2.6",
"react-use-gesture": "^9.1.3",
"unstated-next": "^1.1.0"
Expand Down
37 changes: 24 additions & 13 deletions packages/walletkit/src/WalletKitProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { UseSolanaArgs } from "@saberhq/use-solana";
import { SolanaProvider } from "@saberhq/use-solana";
import React, { useContext, useMemo, useState } from "react";
import React, { Suspense, useContext, useMemo, useState } from "react";
import { I18nextProvider } from "react-i18next";

import {
ModalStep,
WalletSelectorModal,
} from "./components/WalletSelectorModal";
import type { WalletKitArgs } from "./types";
import I18n from "./i18n";
import type { LangOption, WalletKitArgs } from "./types";

export interface WalletKit {
connect: () => void;
Expand All @@ -15,12 +17,14 @@ export interface WalletKit {
const WalletKitContext = React.createContext<WalletKit | null>(null);

interface Props extends WalletKitArgs, UseSolanaArgs {
langOption?: LangOption;
children: React.ReactNode;
}

export const WalletKitProvider: React.FC<Props> = ({
children,
app,
langOption,
initialStep = ModalStep.Intro,
...solanaProviderArgs
}: Props) => {
Expand All @@ -30,18 +34,25 @@ export const WalletKitProvider: React.FC<Props> = ({
return { connect: () => setShowWalletSelector(true) };
}, []);

const l: LangOption = { en: { nativeName: "Englilsh" }, ...langOption };

return (
<SolanaProvider {...solanaProviderArgs}>
<WalletKitContext.Provider value={kit}>
<WalletSelectorModal
app={app}
initialStep={initialStep}
isOpen={showWalletSelector}
onDismiss={() => setShowWalletSelector(false)}
/>
{children}
</WalletKitContext.Provider>
</SolanaProvider>
<Suspense fallback="loading..">
<I18nextProvider i18n={I18n}>
<SolanaProvider {...solanaProviderArgs}>
<WalletKitContext.Provider value={kit}>
<WalletSelectorModal
app={app}
initialStep={initialStep}
isOpen={showWalletSelector}
onDismiss={() => setShowWalletSelector(false)}
langOption={l}
/>
{children}
</WalletKitContext.Provider>
</SolanaProvider>
</I18nextProvider>
</Suspense>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { css } from "@emotion/react";
import styled from "@emotion/styled";
import lighten from "polished/lib/color/lighten";
import { useTranslation } from "react-i18next";

import { useWalletKit } from "../../WalletKitProvider";

Expand Down Expand Up @@ -56,6 +57,7 @@ export const ConnectWalletButton: React.FC<Props> = ({
...buttonProps
}: Props) => {
const { connect } = useWalletKit();
const { t } = useTranslation();
return (
<Button variant={variant} {...buttonProps} onClick={connect}>
<Logomark
Expand All @@ -64,7 +66,10 @@ export const ConnectWalletButton: React.FC<Props> = ({
width: 16px;
`}
/>
<span>Connect Wallet</span>
<span>
{t("connect_wallet", "Connect Wallet")}
{/* Connect Wallet */}
</span>
</Button>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import styled from "@emotion/styled";
import type { ChangeEventHandler } from "react";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";

import type { LangOption } from "../../types";

interface Props
extends React.DetailedHTMLProps<
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> {
langOption?: LangOption;
}

export const LanguageToggle: React.FC<Props> = ({ langOption }: Props) => {
const { t, i18n } = useTranslation();

const [lang, setLang] = useState<string>(i18n.language);

const handleSelectLanguage: ChangeEventHandler<HTMLSelectElement> = (
e: React.ChangeEvent<HTMLSelectElement>
) => {
setLang(e.target.value);
i18n.changeLanguage(e.target.value).catch((e) => console.log(e));
};

return (
<BottomArea>
<label>{t("changeLanguage", "Change Language")}</label>
<select id="language" value={lang} onChange={handleSelectLanguage}>
{Object.keys(langOption!).map((lng) => (
<option
key={lng}
value={lng}
style={{
border: "1px solid #dfdfdf",
boxSizing: "border-box",
borderRadius: "4px",
padding: "0 4px",
}}
>
{langOption![lng]!.nativeName}
</option>
))}
</select>
</BottomArea>
);
};

export const BottomArea = styled.div`
font-size: 14px;
line-height: 15px;
color: #696969;
margin: 0 10px;

display: flex;
justify-content: space-around;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from "@emotion/styled";
import { useSolana, WalletType } from "@saberhq/use-solana";
import { useCallback, useEffect, useState } from "react";
import { isMobile } from "react-device-detect";
import { useTranslation } from "react-i18next";

import { BottomArea, FooterText } from "../ButtonWithFooter";
import type { ProviderInfo } from "../WalletStepSelect";
Expand Down Expand Up @@ -30,6 +31,7 @@ export const WalletStepConnecting: React.FC<Props> = ({
);
const { activate, connected, wallet } = useSolana();
const [error, setError] = useState<string | null>(null);
const { t } = useTranslation();

const isManualConnect =
isMobile &&
Expand Down Expand Up @@ -70,7 +72,12 @@ export const WalletStepConnecting: React.FC<Props> = ({
<ConnectingWrapper>
{error ? (
<ConnectingHeader>
<Connecting>Error connecting wallet</Connecting>
<Connecting>
{t(
"modal.walletStepConnecting.error.header",
"Error Connecting Wallet"
)}
</Connecting>
<ConnectingInstructions>{error}</ConnectingInstructions>
<ConnectingInstructions>
<a
Expand All @@ -85,13 +92,18 @@ export const WalletStepConnecting: React.FC<Props> = ({
void doActivate();
}}
>
Retry
{t("buttons.retry", "Retry")}
</a>
</ConnectingInstructions>
</ConnectingHeader>
) : (
<ConnectingHeader>
<Connecting>Connecting...</Connecting>
<Connecting>
{t(
"modal.walletStepConnecting.connecting.header",
"Connecting..."
)}
</Connecting>
{isManualConnect ? (
<ConnectingInstructions>
Please{" "}
Expand All @@ -113,7 +125,11 @@ export const WalletStepConnecting: React.FC<Props> = ({
</ConnectingInstructions>
) : (
<ConnectingInstructions>
Please unlock your {walletProviderInfo.name} wallet.
{t(
"modal.walletStepConnecting.connecting.instructions",
"Please unlock your {{ walletName }} wallet",
{ walletName: walletProviderInfo.name }
)}
</ConnectingInstructions>
)}
</ConnectingHeader>
Expand All @@ -127,7 +143,7 @@ export const WalletStepConnecting: React.FC<Props> = ({
</AppIconsWrapper>
<BottomArea>
<FooterText>
Having trouble?{" "}
{t("modal.walletStepConnecting.footer.title", "Having trouble?")}{" "}
<a
href="#"
onClick={(e) => {
Expand All @@ -136,7 +152,7 @@ export const WalletStepConnecting: React.FC<Props> = ({
onBack?.();
}}
>
Go back
{t("buttons.goBack", "Go Back")}
</a>
</FooterText>
</BottomArea>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import styled from "@emotion/styled";

interface Props {
icon: React.ReactNode;
title: string;
description: string;
title: React.ReactNode | string;
description: React.ReactNode | string;
}

export const Detail: React.FC<Props> = ({
Expand Down
Loading