feat: extract i18n text
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
deb96c5382
commit
8454691e22
|
|
@ -17,16 +17,25 @@
|
|||
"discover.select_placeholder": "Select",
|
||||
"early_access": "Early Access",
|
||||
"entry_actions.copy_link": "Copy link",
|
||||
"entry_actions.failed_to_save_to_eagle": "Failed to save to Eagle.",
|
||||
"entry_actions.failed_to_save_to_instapaper": "Failed to save to Instapaper.",
|
||||
"entry_actions.failed_to_save_to_readwise": "Failed to save to Readwise.",
|
||||
"entry_actions.link_copied": "Link copied to clipboard.",
|
||||
"entry_actions.mark_as_read": "Mark as read",
|
||||
"entry_actions.mark_as_unread": "Mark as unread",
|
||||
"entry_actions.open_in_browser": "Open in browser",
|
||||
"entry_actions.save_media_to_eagle": "Save media to Eagle",
|
||||
"entry_actions.save_to_instapaper": "Save to Instapaper",
|
||||
"entry_actions.save_to_readwise": "Save to Readwise",
|
||||
"entry_actions.saved_to_eagle": "Saved to Eagle.",
|
||||
"entry_actions.saved_to_instapaper": "Saved to Instapaper.",
|
||||
"entry_actions.saved_to_readwise": "Saved to Readwise.",
|
||||
"entry_actions.share": "Share",
|
||||
"entry_actions.star": "Star",
|
||||
"entry_actions.starred": "Starred.",
|
||||
"entry_actions.tip": "Tip",
|
||||
"entry_actions.unstar": "Unstar",
|
||||
"entry_actions.unstarred": "Unstarred.",
|
||||
"entry_column.refreshing": "Refreshing new entries...",
|
||||
"entry_content.ai_summary": "AI summary",
|
||||
"entry_content.fetching_content": "Fetching original content and processing...",
|
||||
|
|
@ -48,6 +57,21 @@
|
|||
"entry_list_header.switch_to_grid": "Switch to Grid",
|
||||
"entry_list_header.switch_to_masonry": "Switch to Masonry",
|
||||
"entry_list_header.unread": "unread",
|
||||
"feed_claim_modal.choose_verification_method": "There are three ways to choose from, you can choose one of them to verify.",
|
||||
"feed_claim_modal.claim_button": "Claim",
|
||||
"feed_claim_modal.content_instructions": "Copy the content below and post it to your latest RSS feed.",
|
||||
"feed_claim_modal.description_current": "Current description:",
|
||||
"feed_claim_modal.description_instructions": "Copy the following content and paste it into the <code /> field of your RSS feed.",
|
||||
"feed_claim_modal.failed_to_load": "Failed to load claim message",
|
||||
"feed_claim_modal.rss_format_choice": "RSS generators generally have two formats to choose from. Please copy the XML and JSON formats below as needed.",
|
||||
"feed_claim_modal.rss_instructions": "Copy the code below and paste it into your RSS generator.",
|
||||
"feed_claim_modal.rss_json_format": "JSON Format",
|
||||
"feed_claim_modal.rss_xml_format": "XML Format",
|
||||
"feed_claim_modal.rsshub_notice": "This feed is provided by RSSHub with a 1 hour cache time. Please allow up to 1 hour for changes to appear after publishing content.",
|
||||
"feed_claim_modal.tab_content": "Content",
|
||||
"feed_claim_modal.tab_description": "Description",
|
||||
"feed_claim_modal.tab_rss": "RSS Tag",
|
||||
"feed_claim_modal.verify_ownership": "To claim this feed as your own, you need to verify ownership.",
|
||||
"feed_form.add_follow": "Add follow",
|
||||
"feed_form.category": "Category",
|
||||
"feed_form.category_description": "By default, your follows will be grouped by website.",
|
||||
|
|
@ -124,6 +148,17 @@
|
|||
"signin.sign_in_to": "Sign in to",
|
||||
"sync_indicator.offline": "Offline",
|
||||
"sync_indicator.synced": "Synced with server",
|
||||
"tip_modal.amount": "Amount",
|
||||
"tip_modal.claim_feed": "Claim this feed",
|
||||
"tip_modal.create_wallet": "Create For Free",
|
||||
"tip_modal.feed_owner": "Feed Owner",
|
||||
"tip_modal.low_balance": "Your balance is not enough to cover this tip. Please adjust the amount.",
|
||||
"tip_modal.no_wallet": "You don't have a wallet yet. Please create a wallet to tip.",
|
||||
"tip_modal.tip_amount_sent": "has been sent to the author.",
|
||||
"tip_modal.tip_now": "Tip Now",
|
||||
"tip_modal.tip_sent": "Tip sent successfully! Thank you for your support.",
|
||||
"tip_modal.tip_support": "⭐ Tip to show your support!",
|
||||
"tip_modal.unclaimed_feed": "No one has claimed this feed yet. The received Power will be securely held in the blockchain contract until it is claimed.",
|
||||
"user_button.account": "Account",
|
||||
"user_button.download_desktop_app": "Download Desktop app",
|
||||
"user_button.log_out": "Log out",
|
||||
|
|
|
|||
|
|
@ -179,11 +179,11 @@
|
|||
"wallet.transactions.to": "接收自",
|
||||
"wallet.transactions.tx": "交易",
|
||||
"wallet.transactions.type": "类型",
|
||||
"wallet.transactions.types.burn": "销毁",
|
||||
"wallet.transactions.types.mint": "铸造",
|
||||
"wallet.transactions.types.purchase": "购买",
|
||||
"wallet.transactions.types.tip": "打赏",
|
||||
"wallet.transactions.types.withdraw": "提取",
|
||||
"wallet.transactions.types.burn": "burn",
|
||||
"wallet.transactions.types.mint": "mint",
|
||||
"wallet.transactions.types.purchase": "purchase",
|
||||
"wallet.transactions.types.tip": "tip",
|
||||
"wallet.transactions.types.withdraw": "withdraw",
|
||||
"wallet.transactions.you": "您",
|
||||
"wallet.withdraw.addressLabel": "您的以太坊地址",
|
||||
"wallet.withdraw.amountLabel": "数量",
|
||||
|
|
|
|||
|
|
@ -63,27 +63,31 @@ export const useEntryReadabilityToggle = ({ id, url }: { id: string; url: string
|
|||
})
|
||||
}
|
||||
}, [id, url])
|
||||
export const useCollect = (entry: Nullable<CombinedEntryModel>) =>
|
||||
useMutation({
|
||||
export const useCollect = (entry: Nullable<CombinedEntryModel>) => {
|
||||
const { t } = useTranslation()
|
||||
return useMutation({
|
||||
mutationFn: async () => entry && entryActions.markStar(entry.entries.id, true),
|
||||
|
||||
onSuccess: () => {
|
||||
toast.success("Starred.", {
|
||||
toast.success(t("entry_actions.starred"), {
|
||||
duration: 1000,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useUnCollect = (entry: Nullable<CombinedEntryModel>) =>
|
||||
useMutation({
|
||||
export const useUnCollect = (entry: Nullable<CombinedEntryModel>) => {
|
||||
const { t } = useTranslation()
|
||||
return useMutation({
|
||||
mutationFn: async () => entry && entryActions.markStar(entry.entries.id, false),
|
||||
|
||||
onSuccess: () => {
|
||||
toast.success("Unstarred.", {
|
||||
toast.success(t("entry_actions.unstarred"), {
|
||||
duration: 1000,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useRead = () =>
|
||||
useMutation({
|
||||
|
|
@ -179,11 +183,11 @@ export const useEntryActions = ({
|
|||
mediaUrls: populatedEntry.entries.media.map((m) => m.url),
|
||||
})
|
||||
if (response?.status === "success") {
|
||||
toast.success("Saved to Eagle.", {
|
||||
toast.success(t("entry_actions.saved_to_eagle"), {
|
||||
duration: 3000,
|
||||
})
|
||||
} else {
|
||||
toast.error("Failed to save to Eagle.", {
|
||||
toast.error(t("entry_actions.failed_to_save_to_eagle"), {
|
||||
duration: 3000,
|
||||
})
|
||||
}
|
||||
|
|
@ -214,7 +218,7 @@ export const useEntryActions = ({
|
|||
})
|
||||
toast.success(
|
||||
<>
|
||||
Saved to Readwise,{" "}
|
||||
{t("entry_actions.saved_to_readwise")},{" "}
|
||||
<a target="_blank" className="underline" href={data.url}>
|
||||
view
|
||||
</a>
|
||||
|
|
@ -224,7 +228,7 @@ export const useEntryActions = ({
|
|||
},
|
||||
)
|
||||
} catch {
|
||||
toast.error("Failed to save to Readwise.", {
|
||||
toast.error(t("entry_actions.failed_to_save_to_readwise"), {
|
||||
duration: 3000,
|
||||
})
|
||||
}
|
||||
|
|
@ -254,7 +258,7 @@ export const useEntryActions = ({
|
|||
})
|
||||
toast.success(
|
||||
<>
|
||||
Saved to Instapaper,{" "}
|
||||
{t("entry_actions.saved_to_instapaper")},{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
className="underline"
|
||||
|
|
@ -268,7 +272,7 @@ export const useEntryActions = ({
|
|||
},
|
||||
)
|
||||
} catch {
|
||||
toast.error("Failed to save to Instapaper.", {
|
||||
toast.error(t("entry_actions.failed_to_save_to_instapaper"), {
|
||||
duration: 3000,
|
||||
})
|
||||
}
|
||||
|
|
@ -313,7 +317,7 @@ export const useEntryActions = ({
|
|||
onClick: () => {
|
||||
if (!populatedEntry.entries.url) return
|
||||
navigator.clipboard.writeText(populatedEntry.entries.url)
|
||||
toast("Link copied to clipboard.", {
|
||||
toast(t("entry_actions.link_copied"), {
|
||||
duration: 1000,
|
||||
})
|
||||
},
|
||||
|
|
@ -375,15 +379,21 @@ export const useEntryActions = ({
|
|||
}, [
|
||||
populatedEntry,
|
||||
view,
|
||||
t,
|
||||
enableEagle,
|
||||
checkEagle.isLoading,
|
||||
checkEagle.data,
|
||||
enableReadwise,
|
||||
readwiseToken,
|
||||
enableInstapaper,
|
||||
instapaperPassword,
|
||||
instapaperUsername,
|
||||
feed?.ownerUserId,
|
||||
openTipModal,
|
||||
collect,
|
||||
uncollect,
|
||||
read,
|
||||
unread,
|
||||
feed?.ownerUserId,
|
||||
t,
|
||||
])
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import { useClaimFeedMutation } from "@renderer/queries/feed"
|
|||
import { useFeedById } from "@renderer/store/feed"
|
||||
import type { FC } from "react"
|
||||
import { useEffect } from "react"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
|
||||
export const FeedClaimModalContent: FC<{
|
||||
feedId: string
|
||||
}> = ({ feedId }) => {
|
||||
const { t } = useTranslation()
|
||||
const feed = useFeedById(feedId)
|
||||
const {
|
||||
data: claimMessage,
|
||||
|
|
@ -46,7 +48,7 @@ export const FeedClaimModalContent: FC<{
|
|||
}
|
||||
|
||||
if (error) {
|
||||
return <div>Failed to load claim message</div>
|
||||
return <div>{t("feed_claim_modal.failed_to_load")}</div>
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -56,52 +58,46 @@ export const FeedClaimModalContent: FC<{
|
|||
<FollowSummary feed={feed} />
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<p>To claim this feed as your own, you need to verify ownership.</p>
|
||||
<p>There are three ways to choose from, you can choose one of them to verify.</p>
|
||||
<p>{t("feed_claim_modal.verify_ownership")}</p>
|
||||
<p>{t("feed_claim_modal.choose_verification_method")}</p>
|
||||
<Tabs defaultValue="content" className="mt-4">
|
||||
<TabsList className="w-full justify-start">
|
||||
<TabsTrigger value="content">Content</TabsTrigger>
|
||||
<TabsTrigger value="description">Description</TabsTrigger>
|
||||
<TabsTrigger value="rss">RSS Tag</TabsTrigger>
|
||||
<TabsTrigger value="content">{t("feed_claim_modal.tab_content")}</TabsTrigger>
|
||||
<TabsTrigger value="description">{t("feed_claim_modal.tab_description")}</TabsTrigger>
|
||||
<TabsTrigger value="rss">{t("feed_claim_modal.tab_rss")}</TabsTrigger>
|
||||
</TabsList>
|
||||
<AutoResizeHeight duration={0.1}>
|
||||
<TabsContent className="mt-0 pt-3" value="content">
|
||||
<p>Copy the content below and post it to your latest RSS feed.</p>
|
||||
<p>{t("feed_claim_modal.content_instructions")}</p>
|
||||
{feed.url.startsWith("rsshub://") && (
|
||||
<p className="mt-1 leading-tight text-orange-800">
|
||||
This feed is provided by RSSHub with a 1 hour cache time. Please allow up to 1 hour
|
||||
for changes to appear after publishing content.
|
||||
{t("feed_claim_modal.rsshub_notice")}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<BaseCodeBlock>{claimMessage?.data.content || ""}</BaseCodeBlock>
|
||||
</TabsContent>
|
||||
<TabsContent className="mt-0 pt-3" value="description">
|
||||
<p className="mb-2 leading-none">
|
||||
Current description:
|
||||
{t("feed_claim_modal.description_current")}
|
||||
<span className="ml-2 text-xs text-zinc-500">{feed.description}</span>
|
||||
</p>
|
||||
<p>
|
||||
Copy the following content and paste it into the{" "}
|
||||
<code className="text-sm">{`<description />`}</code> field of your RSS feed.
|
||||
</p>
|
||||
<Trans
|
||||
i18nKey="feed_claim_modal.description_instructions"
|
||||
components={{ code: <code className="text-sm">{"<description />"}</code> }}
|
||||
/>
|
||||
{feed.url.startsWith("rsshub://") && (
|
||||
<p className="mt-1 leading-tight text-orange-800">
|
||||
This feed is provided by RSSHub with a 1 hour cache time. Please allow up to 1 hour
|
||||
for changes to appear after modifying description.
|
||||
{t("feed_claim_modal.rsshub_notice")}
|
||||
</p>
|
||||
)}
|
||||
<BaseCodeBlock>{claimMessage?.data.description || ""}</BaseCodeBlock>
|
||||
</TabsContent>
|
||||
<TabsContent className="mt-0 pt-3" value="rss">
|
||||
<div className="space-y-3">
|
||||
<p>Copy the code below and paste it into your RSS generator.</p>
|
||||
<p>{t("feed_claim_modal.rss_instructions")}</p>
|
||||
<p>{t("feed_claim_modal.rss_format_choice")}</p>
|
||||
<p>
|
||||
RSS generators generally have two formats to choose from. Please copy the XML and
|
||||
JSON formats below as needed.
|
||||
</p>
|
||||
<p>
|
||||
<b>XML Format</b>
|
||||
<b>{t("feed_claim_modal.rss_xml_format")}</b>
|
||||
</p>
|
||||
<ShikiHighLighter
|
||||
transparent
|
||||
|
|
@ -111,7 +107,7 @@ export const FeedClaimModalContent: FC<{
|
|||
language="xml"
|
||||
/>
|
||||
<p>
|
||||
<b>JSON Format</b>
|
||||
<b>{t("feed_claim_modal.rss_json_format")}</b>
|
||||
</p>
|
||||
<ShikiHighLighter
|
||||
transparent
|
||||
|
|
@ -133,7 +129,7 @@ export const FeedClaimModalContent: FC<{
|
|||
variant={isSuccess ? "outline" : "primary"}
|
||||
>
|
||||
{isSuccess && <i className="i-mgc-check-circle-filled mr-2 bg-green-500" />}
|
||||
Claim
|
||||
{t("feed_claim_modal.claim_button")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const SettingSectionTitle: FC<{
|
|||
}> = ({ title, margin }) => (
|
||||
<div
|
||||
className={cn(
|
||||
"text-sm font-medium capitalize text-gray-400 first:mt-0 dark:text-neutral-500",
|
||||
"shrink-0 text-sm font-medium capitalize text-gray-400 first:mt-0 dark:text-neutral-500",
|
||||
margin === "compact" ? "mb-2 mt-4" : "mb-4 mt-8",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
import { SettingsTitle } from "../../title"
|
||||
import { MyWalletSection } from "./my-wallet-section"
|
||||
import { TransactionsSection } from "./transaction-section"
|
||||
|
||||
export const SettingWallet = () => (
|
||||
<div className="mt-4">
|
||||
<div className="mt-4 flex grow flex-col">
|
||||
<SettingsTitle />
|
||||
|
||||
<MyWalletSection />
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ export const TransactionsSection = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div className="grow">
|
||||
<SettingSectionTitle title={t("wallet.transactions.title")} />
|
||||
|
||||
<ScrollArea.ScrollArea viewportClassName="max-h-[210px]">
|
||||
<ScrollArea.ScrollArea viewportClassName="grow">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="[&_*]:!font-semibold">
|
||||
|
|
@ -128,7 +128,7 @@ const TypeRenderer = ({
|
|||
const { t } = useTranslation("settings")
|
||||
return (
|
||||
<div
|
||||
className={cn("center rounded-full px-1.5 py-px text-xs", {
|
||||
className={cn("center rounded-full px-1.5 py-px text-xs uppercase", {
|
||||
"bg-theme-accent-700 text-white": type === "tip",
|
||||
"bg-green-700 text-white": type === "mint",
|
||||
"bg-red-700 text-white": type === "burn",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@ export const Balance = ({
|
|||
|
||||
const Content = (
|
||||
<div className={cn("tabular-nums", className)}>
|
||||
{formatted} {withSuffix && <span>Power</span>}
|
||||
{formatted}{" "}
|
||||
{withSuffix && (
|
||||
<span>
|
||||
Power <i className="i-mgc-power align-text-bottom text-accent" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useCurrentModal } from "@renderer/components/ui/modal"
|
|||
import { RadioGroup } from "@renderer/components/ui/radio-group"
|
||||
import { RadioCard } from "@renderer/components/ui/radio-group/RadioCard"
|
||||
import { UserAvatar } from "@renderer/components/user-button"
|
||||
import { useI18n } from "@renderer/hooks/common"
|
||||
import { nextFrame } from "@renderer/lib/dom"
|
||||
import { useWallet, useWalletTipMutation } from "@renderer/queries/wallet"
|
||||
import { from } from "dnum"
|
||||
|
|
@ -47,6 +48,7 @@ const TipModalContent_: FC<{
|
|||
feedId: string
|
||||
entryId: string
|
||||
}> = ({ userId, feedId, entryId }) => {
|
||||
const t = useI18n()
|
||||
const myWallet = useMyWallet()
|
||||
const myWalletData = myWallet.data?.[0]
|
||||
|
||||
|
|
@ -77,38 +79,30 @@ const TipModalContent_: FC<{
|
|||
if (!myWalletData) {
|
||||
return (
|
||||
<div className="flex w-[80vw] max-w-[350px] flex-col gap-5">
|
||||
<p className="text-sm text-theme-foreground/80">
|
||||
You don't have a wallet yet. Please create a wallet to tip.
|
||||
</p>
|
||||
<p className="text-sm text-theme-foreground/80">{t("tip_modal.no_wallet")}</p>
|
||||
<div className="flex justify-end">
|
||||
<Button variant="primary" onClick={() => nextFrame(() => settingModalPresent("wallet"))}>
|
||||
Create For Free
|
||||
{t("tip_modal.create_wallet")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// if (transactionsQuery.error) {
|
||||
// return <div>Failed to load transactions history.</div>
|
||||
// }
|
||||
|
||||
if (tipMutation.isSuccess) {
|
||||
return (
|
||||
<div className="flex w-[80vw] max-w-[350px] flex-col gap-5">
|
||||
<p className="text-sm text-theme-foreground/80">
|
||||
Tip sent successfully! Thank you for your support.
|
||||
</p>
|
||||
<p className="text-sm text-theme-foreground/80">{t("tip_modal.tip_sent")}</p>
|
||||
<p>
|
||||
<Balance className="mr-1 inline-block text-sm" withSuffix>
|
||||
{amountBigInt}
|
||||
</Balance>{" "}
|
||||
has been sent to the author.
|
||||
{t("tip_modal.tip_amount_sent")}
|
||||
</p>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button variant="primary" onClick={() => dismiss()}>
|
||||
OK
|
||||
{t.common("ok")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -119,31 +113,30 @@ const TipModalContent_: FC<{
|
|||
<div className="flex w-[80vw] max-w-[350px] flex-col gap-3">
|
||||
{userId ? (
|
||||
<>
|
||||
<p className="text-sm font-medium">Feed Owner</p>
|
||||
<p className="text-sm font-medium">{t("tip_modal.feed_owner")}</p>
|
||||
<UserAvatar className="h-8 justify-start bg-transparent p-0" userId={userId} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="leading-none">
|
||||
<span className="text-xs text-theme-foreground/80">
|
||||
No one has claimed this feed yet. The received Power will be securely held in the
|
||||
blockchain contract until it is claimed.
|
||||
{t("tip_modal.unclaimed_feed")}
|
||||
</span>
|
||||
</p>
|
||||
<div className="text-center">
|
||||
<Button variant="text" className="w-fit p-0" onClick={() => claimFeed()}>
|
||||
Claim this feed
|
||||
{t("tip_modal.claim_feed")}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Divider className="my-2" />
|
||||
<p className="text-sm text-theme-foreground/80">⭐ Tip to show your support!</p>
|
||||
<p className="text-sm text-theme-foreground/80">{t("tip_modal.tip_support")}</p>
|
||||
|
||||
<div className="flex flex-col justify-center gap-y-2">
|
||||
<div className="flex flex-row items-center gap-x-2 font-bold">
|
||||
<i className="i-mgc-power text-accent" />
|
||||
<span>Amount</span>
|
||||
<span>{t("tip_modal.amount")}</span>
|
||||
</div>
|
||||
|
||||
<RadioGroup value={amount.toString()} onValueChange={(value) => setAmount(Number(value))}>
|
||||
|
|
@ -158,7 +151,7 @@ const TipModalContent_: FC<{
|
|||
<>
|
||||
<Divider className="my-2" />
|
||||
<div className="text-xs text-red-500">
|
||||
<span>Your balance is not enough to cover this tip. Please adjust the amount.</span>
|
||||
<span>{t("tip_modal.low_balance")}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -178,7 +171,7 @@ const TipModalContent_: FC<{
|
|||
variant={tipMutation.isSuccess ? "outline" : "primary"}
|
||||
>
|
||||
{tipMutation.isSuccess && <i className="i-mgc-check-circle-filled mr-2 bg-green-500" />}
|
||||
Tip Now
|
||||
{t("tip_modal.tip_now")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue