feat: i18n for common components
This commit is contained in:
parent
3293091173
commit
1a3456e0c8
|
|
@ -1,3 +1,7 @@
|
|||
{
|
||||
"intlRelativeTime": "{{val, relativetime}}"
|
||||
"intlRelativeTime": "{{val, relativetime}}",
|
||||
"ago": "{{time}} ago",
|
||||
"joined ago": "Joined {{time}} ago",
|
||||
"like stored": "Your like has been stored on the blockchain, view it on <2>Crossbell Scan</2>",
|
||||
"mint stored": "This post has been minted to NFT by you, view it on <2>xChar</2> or <6>Crossbell Scan</6>"
|
||||
}
|
||||
|
|
@ -27,5 +27,24 @@
|
|||
"Create Character": "创建角色",
|
||||
"Submit": "提交",
|
||||
"Reply": "回复",
|
||||
"Cancel Reply": "取消回复"
|
||||
"Cancel Reply": "取消回复",
|
||||
"ago": "{{time}}前",
|
||||
"joined ago": "{{time}}前加入",
|
||||
"Mint to an NFT": "铸造为 NFT",
|
||||
"Like successfull": "点赞成功",
|
||||
"Mint successfull": "铸造成功",
|
||||
"like stored": "你的点赞已被安全地存储在区块链上,可以在 <2>Crossbell Scan</2> 上查看",
|
||||
"mint stored": "你已将此篇文章铸造成NFT, 可以在 <2>xChar</2> 或 <6>Crossbell Scan</6> 上查看",
|
||||
"Got it, thanks!": "好的,谢谢!",
|
||||
"Like List": "点赞列表",
|
||||
"Mint List": "铸造列表",
|
||||
"No Content Yet.": "暂无内容",
|
||||
"Close": "关闭",
|
||||
"Dashboard": "仪表盘",
|
||||
"Copied!": "已复制!",
|
||||
"Operator Sign": "代签名",
|
||||
"Switch Characters": "切换角色",
|
||||
"Upgrade to Wallet": "升级为钱包",
|
||||
"Disconnect": "断开连接",
|
||||
"Loading": "加载中"
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
"Blog Free": "自由创作",
|
||||
"description": "xLog,给所有人的 <2>链上</2> <6>开源</6> 博客平台。",
|
||||
"Get my xLog in 5 minutes": "5 分钟拥有自己的 xLog",
|
||||
"Features": "特点",
|
||||
"Showcase": "展示",
|
||||
"Features": "特色",
|
||||
"Showcase": "展示柜",
|
||||
"Integration": "集成",
|
||||
"Source Code": "源码",
|
||||
"Visit": "访问",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
"Home": "主页",
|
||||
"Archives": "归档",
|
||||
"About": "关于",
|
||||
"Tags": "标签",
|
||||
"load more": "还有 {{count}} 篇{{name}},点击加载更多",
|
||||
"signed and stored on the blockchain": "此{{name}}已经由它的创作者签名并安全地存储在区块链上。",
|
||||
"Write a comment on the blockchain": "在区块链上写下你的评论"
|
||||
"Write a comment on the blockchain": "在区块链上写下你的评论",
|
||||
"powered by": "由 <name/> 提供支持",
|
||||
"Showcase": "展示柜"
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import * as siteModel from "~/models/site.model"
|
|||
import type { Profile } from "~/lib/types"
|
||||
import clsx from "clsx"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export const CharacterCard: React.FC<{
|
||||
siteId?: string
|
||||
|
|
@ -18,6 +19,7 @@ export const CharacterCard: React.FC<{
|
|||
const [firstOpen, setFirstOpen] = useState("")
|
||||
const [site, setSite] = useState<Profile>()
|
||||
const date = useDate()
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
useEffect(() => {
|
||||
if (open && (firstOpen !== (siteId || address) || !site)) {
|
||||
|
|
@ -72,21 +74,23 @@ export const CharacterCard: React.FC<{
|
|||
</span>
|
||||
{site?.date_created && (
|
||||
<span className="block text-gray-500">
|
||||
Joined{" "}
|
||||
<time dateTime={date.formatToISO(site.date_created)}>
|
||||
{date.dayjs
|
||||
.duration(
|
||||
date.dayjs(site.date_created).diff(date.dayjs(), "minute"),
|
||||
"minute",
|
||||
)
|
||||
.humanize()}{" "}
|
||||
ago
|
||||
{t("joined ago", {
|
||||
time: date.dayjs
|
||||
.duration(
|
||||
date
|
||||
.dayjs(site.date_created)
|
||||
.diff(date.dayjs(), "minute"),
|
||||
"minute",
|
||||
)
|
||||
.humanize(),
|
||||
})}
|
||||
</time>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
"Loading..."
|
||||
<>{t("Loading")}...</>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { Avatar } from "../ui/Avatar"
|
|||
import { BlockchainIcon } from "~/components/icons/BlockchainIcon"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { CharacterFloatCard } from "~/components/common/CharacterFloatCard"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export const CharacterList: React.FC<{
|
||||
open: boolean
|
||||
|
|
@ -17,6 +18,8 @@ export const CharacterList: React.FC<{
|
|||
list: any[]
|
||||
title: string
|
||||
}> = ({ open, setOpen, hasMore, loadMore, list, title }) => {
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
return (
|
||||
<Modal open={open} setOpen={setOpen} title={title}>
|
||||
<div className="px-5 overflow-auto flex-1">
|
||||
|
|
@ -25,7 +28,7 @@ export const CharacterList: React.FC<{
|
|||
hasMore={hasMore}
|
||||
loader={
|
||||
<div className="text-sm py-3 text-center" key={0}>
|
||||
Loading ...
|
||||
{t("Loading")} ...
|
||||
</div>
|
||||
}
|
||||
useWindow={false}
|
||||
|
|
@ -71,14 +74,14 @@ export const CharacterList: React.FC<{
|
|||
))
|
||||
) : (
|
||||
<div className="py-3 text-center text-zinc-300">
|
||||
No Content Yet.
|
||||
{t("No Content Yet.")}
|
||||
</div>
|
||||
)}
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
<div className="h-16 border-t flex items-center px-5 py-4">
|
||||
<Button isBlock onClick={() => setOpen(false)}>
|
||||
Close
|
||||
{t("Close")}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -66,13 +66,14 @@ export const CommentItem: React.FC<{
|
|||
</UniLink>{" "}
|
||||
·{" "}
|
||||
<time dateTime={date.formatToISO(comment?.createdAt)}>
|
||||
{date.dayjs
|
||||
.duration(
|
||||
date.dayjs(comment?.createdAt).diff(date.dayjs(), "minute"),
|
||||
"minute",
|
||||
)
|
||||
.humanize()}{" "}
|
||||
ago
|
||||
{t("ago", {
|
||||
time: date.dayjs
|
||||
.duration(
|
||||
date.dayjs(comment?.createdAt).diff(date.dayjs(), "minute"),
|
||||
"minute",
|
||||
)
|
||||
.humanize(),
|
||||
})}
|
||||
</time>{" "}
|
||||
·{" "}
|
||||
<UniLink href={`${CSB_SCAN}/tx/${comment.transactionHash}`}>
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ export const ConnectButton: React.FC<{
|
|||
const dropdownLinks: HeaderLinkType[] = [
|
||||
{
|
||||
icon: <DashboardIcon />,
|
||||
label: "Writer dashboard",
|
||||
label: t("Dashboard") || "",
|
||||
url: `${SITE_URL}/dashboard`,
|
||||
},
|
||||
{
|
||||
icon: <Square2StackIcon className="w-4 h-4" />,
|
||||
label: copyLabelDisplay,
|
||||
label: t(copyLabelDisplay) || "",
|
||||
onClick: copyLabel,
|
||||
},
|
||||
...(account?.type === "wallet"
|
||||
|
|
@ -126,7 +126,7 @@ export const ConnectButton: React.FC<{
|
|||
icon: <UsersIcon className="w-4 h-4" />,
|
||||
label: (
|
||||
<>
|
||||
Operator Sign (
|
||||
{t("Operator Sign")} (
|
||||
{isOpSignEnabled ? (
|
||||
<FaceSmileIcon className="w-4 h-4" />
|
||||
) : (
|
||||
|
|
@ -154,20 +154,20 @@ export const ConnectButton: React.FC<{
|
|||
},
|
||||
{
|
||||
icon: <ArrowPathRoundedSquareIcon className="w-4 h-4" />,
|
||||
label: "Switch Characters",
|
||||
label: t("Switch Characters") || "",
|
||||
onClick: selectCharactersModal.show,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
icon: <ArrowUpCircleIcon className="w-4 h-4" />,
|
||||
label: "Upgrade to Wallet",
|
||||
label: t("Upgrade to Wallet") || "",
|
||||
onClick: upgradeAccountModal.show,
|
||||
},
|
||||
]),
|
||||
{
|
||||
icon: <ArrowRightOnRectangleIcon className="w-4 h-4" />,
|
||||
label: "Disconnect",
|
||||
label: t("Disconnect") || "",
|
||||
onClick: disconnect,
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { CharacterList } from "~/components/common/CharacterList"
|
|||
import clsx from "clsx"
|
||||
import { Tooltip } from "~/components/ui/Tooltip"
|
||||
import confetti from "canvas-confetti"
|
||||
import { Trans, useTranslation } from "next-i18next"
|
||||
|
||||
export const Reactions: React.FC<{
|
||||
className?: string
|
||||
|
|
@ -29,6 +30,7 @@ export const Reactions: React.FC<{
|
|||
}> = ({ className, size, pageId }) => {
|
||||
const toggleLikePage = useToggleLikePage()
|
||||
const mintPage = useMintPage()
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
const userSite = useAccountSites()
|
||||
const [isLikeOpen, setIsLikeOpen] = useState(false)
|
||||
|
|
@ -225,7 +227,7 @@ export const Reactions: React.FC<{
|
|||
</Button>
|
||||
)
|
||||
return size !== "sm" ? (
|
||||
<Tooltip label="Mint as an NFT" placement="top">
|
||||
<Tooltip label={t("Mint to an NFT")} placement="top">
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
|
|
@ -265,54 +267,58 @@ export const Reactions: React.FC<{
|
|||
<Modal
|
||||
open={isLikeOpen}
|
||||
setOpen={setIsLikeOpen}
|
||||
title="Like successfull"
|
||||
title={t("Like successfull") || ""}
|
||||
>
|
||||
<div className="p-5">
|
||||
Your like has been stored on the blockchain, view it on{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_SCAN}/tx/${likeStatus.transactionHash}`}
|
||||
>
|
||||
Crossbell Scan
|
||||
</UniLink>
|
||||
<Trans i18nKey="like stored">
|
||||
Your like has been stored on the blockchain, view it on{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_SCAN}/tx/${likeStatus.transactionHash}`}
|
||||
>
|
||||
Crossbell Scan
|
||||
</UniLink>
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="h-16 border-t flex items-center px-5">
|
||||
<Button isBlock onClick={() => setIsLikeOpen(false)}>
|
||||
Got it, thanks!
|
||||
{t("Got it, thanks!")}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal
|
||||
open={isMintOpen}
|
||||
setOpen={setIsMintOpen}
|
||||
title="Mint successfull"
|
||||
title={t("Mint successfull") || ""}
|
||||
>
|
||||
<div className="p-5">
|
||||
This post has been minted as NFT by you, view it on{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_XCHAR}/${userSite.data?.[0]?.username}/collections`}
|
||||
>
|
||||
xChar
|
||||
</UniLink>{" "}
|
||||
or{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_SCAN}/tx/${isMint.data?.list?.[0]?.transactionHash}`}
|
||||
>
|
||||
Crossbell Scan
|
||||
</UniLink>
|
||||
<Trans i18nKey="mint stored">
|
||||
This post has been minted to NFT by you, view it on{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_XCHAR}/${userSite.data?.[0]?.username}/collections`}
|
||||
>
|
||||
xChar
|
||||
</UniLink>{" "}
|
||||
or{" "}
|
||||
<UniLink
|
||||
className="text-accent"
|
||||
href={`${CSB_SCAN}/tx/${isMint.data?.list?.[0]?.transactionHash}`}
|
||||
>
|
||||
Crossbell Scan
|
||||
</UniLink>
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="h-16 border-t flex items-center px-5">
|
||||
<Button isBlock onClick={() => setIsMintOpen(false)}>
|
||||
Got it, thanks!
|
||||
{t("Got it, thanks!")}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<CharacterList
|
||||
open={isLikeListOpen}
|
||||
setOpen={setIsLikeListOpen}
|
||||
title="Like List"
|
||||
title={t("Like List")}
|
||||
loadMore={loadMoreLikes}
|
||||
hasMore={!!likesMutation.hasNextPage}
|
||||
list={likes}
|
||||
|
|
@ -320,7 +326,7 @@ export const Reactions: React.FC<{
|
|||
<CharacterList
|
||||
open={isMintListOpen}
|
||||
setOpen={setIsMintListOpen}
|
||||
title="Mint List"
|
||||
title={t("Mint List")}
|
||||
loadMore={loadMoreMints}
|
||||
hasMore={!!mintCursor}
|
||||
list={mintList}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from "@crossbell/notification"
|
||||
import { useUserRole } from "~/hooks/useUserRole"
|
||||
import { useAccountState, useConnectModal } from "@crossbell/connect-kit"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export function DashboardLayout({
|
||||
children,
|
||||
|
|
@ -39,6 +40,7 @@ export function DashboardLayout({
|
|||
const connectModal = useConnectModal()
|
||||
const [ready, setReady] = React.useState(false)
|
||||
const [hasPermission, setHasPermission] = React.useState(false)
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
useEffect(() => {
|
||||
if (ssrReady) {
|
||||
|
|
@ -203,7 +205,7 @@ export function DashboardLayout({
|
|||
)
|
||||
) : (
|
||||
<div className="w-screen h-screen flex justify-center items-center">
|
||||
Loading...
|
||||
{t("Loading")}...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Notes, Note } from "~/lib/types"
|
|||
import { UniLink } from "../ui/UniLink"
|
||||
import { Button } from "~/components/ui/Button"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export const SiteArchives: React.FC<{
|
||||
title?: string
|
||||
|
|
@ -23,6 +24,8 @@ export const SiteArchives: React.FC<{
|
|||
}) => {
|
||||
let currentLength = 0
|
||||
const date = useDate()
|
||||
const { t } = useTranslation("common")
|
||||
const { t: siteT } = useTranslation("site")
|
||||
|
||||
const groupedByYear = useMemo<Map<string, Note[]>>(() => {
|
||||
const map = new Map()
|
||||
|
|
@ -39,7 +42,7 @@ export const SiteArchives: React.FC<{
|
|||
}
|
||||
|
||||
return map
|
||||
}, [postPages])
|
||||
}, [postPages, date])
|
||||
|
||||
const tags = useMemo<Map<string, number>>(() => {
|
||||
const result = new Map()
|
||||
|
|
@ -67,7 +70,9 @@ export const SiteArchives: React.FC<{
|
|||
|
||||
return (
|
||||
<>
|
||||
<h2 className="text-xl font-bold page-title">{title || "Archives"}</h2>
|
||||
<h2 className="text-xl font-bold page-title">
|
||||
{title || siteT("Archives")}
|
||||
</h2>
|
||||
{!postPages[0].total && (
|
||||
<div className="mt-5">
|
||||
<EmptyState />
|
||||
|
|
@ -77,7 +82,9 @@ export const SiteArchives: React.FC<{
|
|||
<>
|
||||
{showTags && tags.size > 0 && (
|
||||
<div className="mt-5">
|
||||
<h3 className="text-lg font-bold mb-1 text-zinc-700">Tags</h3>
|
||||
<h3 className="text-lg font-bold mb-1 text-zinc-700">
|
||||
{siteT("Tags")}
|
||||
</h3>
|
||||
<div className="pt-2">
|
||||
{[...tags.keys()].map((tag) => (
|
||||
<UniLink key={tag} href={`/tag/${tag}`} className="mr-6">
|
||||
|
|
@ -108,7 +115,15 @@ export const SiteArchives: React.FC<{
|
|||
>
|
||||
<span className="text-zinc-700">{post.title}</span>
|
||||
<span className="text-zinc-400 mr-3 whitespace-nowrap">
|
||||
{formatDate(post.date_published, "MMM D")}
|
||||
{t("intlDateTime", {
|
||||
val: new Date(post.date_published),
|
||||
formatParams: {
|
||||
val: {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
},
|
||||
},
|
||||
})}
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,28 @@ import { Profile, Note } from "~/lib/types"
|
|||
import Script from "next/script"
|
||||
import Image from "next/image"
|
||||
import { Platform } from "~/components/site/Platform"
|
||||
import { Trans } from "next-i18next"
|
||||
|
||||
export const SiteFooter: React.FC<{
|
||||
site?: Profile | null
|
||||
page?: Note | null
|
||||
}> = ({ site, page }) => {
|
||||
const LogoWithLink = () => {
|
||||
return (
|
||||
<UniLink
|
||||
href={SITE_URL}
|
||||
className="hover:text-accent inline-flex items-center align-text-top mx-1"
|
||||
>
|
||||
<Image
|
||||
alt={APP_NAME}
|
||||
src={`${SITE_URL}/assets/logo.svg`}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
</UniLink>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<footer className="text-zinc-500 border-t">
|
||||
|
|
@ -18,18 +35,15 @@ export const SiteFooter: React.FC<{
|
|||
<UniLink href="/" className="hover:text-accent">
|
||||
{site?.name}
|
||||
</UniLink>{" "}
|
||||
· Powered by{" "}
|
||||
<UniLink
|
||||
href={SITE_URL}
|
||||
className="hover:text-accent inline-flex items-center align-text-top ml-1"
|
||||
>
|
||||
<Image
|
||||
alt={APP_NAME}
|
||||
src={`${SITE_URL}/assets/logo.svg`}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
</UniLink>
|
||||
·{" "}
|
||||
<Trans
|
||||
i18nKey="powered by"
|
||||
defaults={"Powered by <name/>"}
|
||||
components={{
|
||||
name: <LogoWithLink />,
|
||||
}}
|
||||
ns="site"
|
||||
/>
|
||||
</p>
|
||||
{site?.connected_accounts && (
|
||||
<div className="ml-5 -mr-5">
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import type { Asset } from "unidata.js"
|
|||
import Script from "next/script"
|
||||
import { UniMedia } from "~/components/ui/UniMedia"
|
||||
import { UniLink } from "~/components/ui/UniLink"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||
const queryClient = new QueryClient()
|
||||
|
|
@ -30,6 +31,8 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
|||
|
||||
function SiteNFTPage({ domainOrSubdomain }: { domainOrSubdomain: string }) {
|
||||
const site = useGetSite(domainOrSubdomain)
|
||||
const { t } = useTranslation("common")
|
||||
const { t: siteT } = useTranslation("site")
|
||||
|
||||
const nftsOrigin = useGetNFTs(site.data?.metadata?.owner)
|
||||
|
||||
|
|
@ -46,10 +49,10 @@ function SiteNFTPage({ domainOrSubdomain }: { domainOrSubdomain: string }) {
|
|||
type="module"
|
||||
src="https://cdn.jsdelivr.net/npm/@google/model-viewer/dist/model-viewer.min.js"
|
||||
></Script>
|
||||
<h2 className="text-xl font-bold page-title">NFT Showcase</h2>
|
||||
<h2 className="text-xl font-bold page-title">NFT {siteT("Showcase")}</h2>
|
||||
<div className="mt-8">
|
||||
{nftsOrigin.isLoading ? (
|
||||
<div>Loading...</div>
|
||||
<div>{t("Loading")}...</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-3 md:grid-cols-4 gap-10">
|
||||
{nfts
|
||||
|
|
|
|||
Loading…
Reference in New Issue