chore: i18n

This commit is contained in:
codytseng
2024-11-19 23:02:56 +08:00
parent b36cbeb158
commit 5aefd7dbde
11 changed files with 76 additions and 27 deletions

View File

@@ -1,14 +1,16 @@
import { Button } from '@renderer/components/ui/button'
import { useSecondaryPage } from '@renderer/PageManager'
import { ChevronLeft } from 'lucide-react'
import { useTranslation } from 'react-i18next'
export default function BackButton({ hide = false }: { hide?: boolean }) {
const { t } = useTranslation()
const { pop } = useSecondaryPage()
return (
<>
{!hide && (
<Button variant="titlebar" size="titlebar" title="back" onClick={() => pop()}>
<Button variant="titlebar" size="titlebar" title={t('back')} onClick={() => pop()}>
<ChevronLeft />
</Button>
)}

View File

@@ -39,7 +39,7 @@ export default function Mentions({
</PopoverTrigger>
<PopoverContent className="w-48">
<div className="space-y-2">
<div className="text-sm font-semibold">Mentions:</div>
<div className="text-sm font-semibold">{t('Mentions')}:</div>
{pubkeys.map((pubkey, index) => (
<div key={`${pubkey}-${index}`} className="flex gap-1 items-center">
<UserAvatar userId={pubkey} size="small" />

View File

@@ -99,7 +99,7 @@ export default function PostDialog({
<DialogTitle>
{parentEvent ? (
<div className="flex gap-2 items-center max-w-full">
<div className="shrink-0">Reply to</div>
<div className="shrink-0">{t('Reply to')}</div>
<UserAvatar userId={parentEvent.pubkey} size="tiny" />
<div className="truncate">{parentEvent.content}</div>
</div>
@@ -131,7 +131,7 @@ export default function PostDialog({
</Button>
<Button type="submit" disabled={!canPost} onClick={post}>
{posting && <LoaderCircle className="animate-spin" />}
{t('Post')}
{parentEvent ? t('Reply') : t('Post')}
</Button>
</div>
</div>

View File

@@ -12,8 +12,10 @@ import { useState } from 'react'
import RelayUrls from './RelayUrl'
import { useRelaySettingsComponent } from './provider'
import { TRelayGroup } from './types'
import { useTranslation } from 'react-i18next'
export default function RelayGroup({ group }: { group: TRelayGroup }) {
const { t } = useTranslation()
const { expandedRelayGroup } = useRelaySettingsComponent()
const { temporaryRelayUrls } = useRelaySettings()
const { groupName, relayUrls } = group
@@ -34,7 +36,7 @@ export default function RelayGroup({ group }: { group: TRelayGroup }) {
</div>
<div className="flex gap-1">
<RelayUrlsExpandToggle groupName={groupName}>
{relayUrls.length} relays
{t('n relays', { n: relayUrls.length })}
</RelayUrlsExpandToggle>
<RelayGroupOptions group={group} />
</div>
@@ -71,6 +73,7 @@ function RelayGroupActiveToggle({
}
function RelayGroupName({ groupName }: { groupName: string }) {
const { t } = useTranslation()
const [newGroupName, setNewGroupName] = useState(groupName)
const [newNameError, setNewNameError] = useState<string | null>(null)
const { relayGroups, switchRelayGroup, renameRelayGroup } = useRelaySettings()
@@ -80,7 +83,7 @@ function RelayGroupName({ groupName }: { groupName: string }) {
const saveNewGroupName = () => {
if (relayGroups.find((group) => group.groupName === newGroupName)) {
return setNewNameError('already exists')
return setNewNameError(t('relay collection name already exists'))
}
const errMsg = renameRelayGroup(groupName, newGroupName)
if (errMsg) {
@@ -153,6 +156,7 @@ function RelayUrlsExpandToggle({
}
function RelayGroupOptions({ group }: { group: TRelayGroup }) {
const { t } = useTranslation()
const { deleteRelayGroup } = useRelaySettings()
const { setRenamingGroup } = useRelaySettingsComponent()
@@ -165,7 +169,7 @@ function RelayGroupOptions({ group }: { group: TRelayGroup }) {
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => setRenamingGroup(group.groupName)}>
Rename
{t('Rename')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
@@ -174,13 +178,13 @@ function RelayGroupOptions({ group }: { group: TRelayGroup }) {
)
}}
>
Copy share link
{t('Copy share link')}
</DropdownMenuItem>
<DropdownMenuItem
className="text-destructive focus:text-destructive"
onClick={() => deleteRelayGroup(group.groupName)}
>
Delete
{t('Delete')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View File

@@ -5,8 +5,10 @@ import { useRelaySettings } from '@renderer/providers/RelaySettingsProvider'
import client from '@renderer/services/client.service'
import { CircleX } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
export default function RelayUrls({ groupName }: { groupName: string }) {
const { t } = useTranslation()
const { relayGroups, updateRelayGroupRelayUrls } = useRelaySettings()
const rawRelayUrls = relayGroups.find((group) => group.groupName === groupName)?.relayUrls ?? []
const isActive = relayGroups.find((group) => group.groupName === groupName)?.isActive ?? false
@@ -46,10 +48,10 @@ export default function RelayUrls({ groupName }: { groupName: string }) {
if (newRelayUrl === '') return
const normalizedUrl = normalizeUrl(newRelayUrl)
if (relays.some(({ url }) => url === normalizedUrl)) {
return setNewRelayUrlError('already exists')
return setNewRelayUrlError(t('Relay already exists'))
}
if (!isWebsocketUrl(normalizedUrl)) {
return setNewRelayUrlError('invalid URL')
return setNewRelayUrlError(t('invalid relay URL'))
}
setRelays((pre) => [...pre, { url: normalizedUrl, isConnected: false }])
const newRelayUrls = [...relays.map(({ url }) => url), normalizedUrl]
@@ -85,13 +87,13 @@ export default function RelayUrls({ groupName }: { groupName: string }) {
<div className="mt-2 flex gap-2">
<Input
className={newRelayUrlError ? 'border-destructive' : ''}
placeholder="Add new relay URL"
placeholder={t('Add a new relay')}
value={newRelayUrl}
onKeyDown={handleRelayUrlInputKeyDown}
onChange={handleRelayUrlInputChange}
onBlur={saveNewRelayUrl}
/>
<Button onClick={saveNewRelayUrl}>Add</Button>
<Button onClick={saveNewRelayUrl}>{t('Add')}</Button>
</div>
{newRelayUrlError && <div className="text-xs text-destructive mt-1">{newRelayUrlError}</div>}
</>

View File

@@ -6,8 +6,10 @@ import { useEffect, useRef, useState } from 'react'
import { RelaySettingsComponentProvider } from './provider'
import RelayGroup from './RelayGroup'
import TemporaryRelayGroup from './TemporaryRelayGroup'
import { useTranslation } from 'react-i18next'
export default function RelaySettings() {
const { t } = useTranslation()
const { relayGroups, addRelayGroup } = useRelaySettings()
const [newGroupName, setNewGroupName] = useState('')
const [newNameError, setNewNameError] = useState<string | null>(null)
@@ -21,7 +23,7 @@ export default function RelaySettings() {
const saveRelayGroup = () => {
if (relayGroups.find((group) => group.groupName === newGroupName)) {
return setNewNameError('already exists')
return setNewNameError(t('relay collection name already exists'))
}
const errMsg = addRelayGroup(newGroupName)
if (errMsg) {
@@ -45,7 +47,7 @@ export default function RelaySettings() {
return (
<RelaySettingsComponentProvider>
<div ref={dummyRef} tabIndex={-1} style={{ position: 'absolute', opacity: 0 }}></div>
<div className="text-lg font-semibold mb-4">Relay Settings</div>
<div className="text-lg font-semibold mb-4">{t('Relay Settings')}</div>
<div className="space-y-2">
<TemporaryRelayGroup />
{relayGroups.map((group, index) => (
@@ -57,18 +59,18 @@ export default function RelaySettings() {
<Separator className="my-4" />
<div className="w-full border rounded-lg p-4">
<div className="flex justify-between items-center">
<div className="font-semibold">Add a new relay group</div>
<div className="font-semibold">{t('Add a new relay collection')}</div>
</div>
<div className="mt-2 flex gap-2">
<Input
className={newNameError ? 'border-destructive' : ''}
placeholder="Group name"
placeholder={t('Relay collection name')}
value={newGroupName}
onChange={handleNewGroupNameChange}
onKeyDown={handleNewGroupNameKeyDown}
onBlur={saveRelayGroup}
/>
<Button onClick={saveRelayGroup}>Add</Button>
<Button onClick={saveRelayGroup}>{t('Add')}</Button>
</div>
{newNameError && <div className="text-xs text-destructive mt-1">{newNameError}</div>}
</div>

View File

@@ -119,7 +119,7 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas
})}
</div>
{replies.length === 0 && !loading && !hasMore && (
<div className="text-sm text-center text-muted-foreground">no replies</div>
<div className="text-sm text-center text-muted-foreground">{t('no replies')}</div>
)}
</>
)

View File

@@ -44,6 +44,24 @@ export default {
note: 'note',
"username's following": "{{username}}'s following",
following: 'following',
Login: 'Login'
Login: 'Login',
'Follows you': 'Follows you',
'relay collection name already exists': 'relay collection name already exists',
'Relay Settings': 'Relay Settings',
'Relay collection name': 'Relay collection name',
'Add a new relay collection': 'Add a new relay collection',
Add: 'Add',
'n relays': '{{n}} relays',
Rename: 'Rename',
'Copy share link': 'Copy share link',
Delete: 'Delete',
'Relay already exists': 'Relay already exists',
'invalid relay URL': 'invalid relay URL',
'Add a new relay': 'Add a new relay',
back: 'back',
'Lost in the void': 'Lost in the void',
'Carry me home': 'Carry me home',
'no replies': 'no replies',
'Reply to': 'Reply to'
}
}

View File

@@ -1,11 +1,11 @@
export default {
translation: {
'Welcome! 🥳': '欢迎!🥳',
'Welcome! 🥳': '来都来了',
About: '关于',
'New post': '发布新笔记',
Post: '发布笔记',
'Relay settings': '中继设置',
SidebarRelays: '中继设置',
'Relay settings': '服务器设置',
SidebarRelays: '服务器',
Refresh: '刷新列表',
Profile: '个人资料',
Logout: '退出登录',
@@ -44,6 +44,24 @@ export default {
note: '笔记',
"username's following": '{{username}} 的关注',
following: '关注',
Login: '登录'
Login: '登录',
'Follows you': '关注了你',
'relay collection name already exists': '服务器组名已存在',
'Relay Settings': '服务器设置',
'Relay collection name': '服务器组名',
'Add a new relay collection': '添加新的服务器组',
Add: '添加',
'n relays': '{{n}} 个服务器',
Rename: '重命名',
'Copy share link': '复制分享链接',
Delete: '删除',
'Relay already exists': '服务器已存在',
'invalid relay URL': '无效的服务器地址',
'Add a new relay': '添加新的服务器',
back: '返回',
'Lost in the void': '迷失在虚空中',
'Carry me home': '带我回家',
'no replies': '暂无回复',
'Reply to': '回复'
}
}

View File

@@ -2,16 +2,19 @@ import { Button } from '@renderer/components/ui/button'
import SecondaryPageLayout from '@renderer/layouts/SecondaryPageLayout'
import { toHome } from '@renderer/lib/link'
import { useSecondaryPage } from '@renderer/PageManager'
import { useTranslation } from 'react-i18next'
export default function NotFoundPage() {
const { t } = useTranslation()
const { push } = useSecondaryPage()
return (
<SecondaryPageLayout hideBackButton>
<div className="text-muted-foreground w-full h-full flex flex-col items-center justify-center gap-2">
<div>Lost in the void 🌌</div>
<div>{t('Lost in the void')} 🌌</div>
<div>(404)</div>
<Button variant="secondary" onClick={() => push(toHome())}>
Carry me home
{t('Carry me home')}
</Button>
</div>
</SecondaryPageLayout>

View File

@@ -71,7 +71,7 @@ export default function ProfilePage({ id }: { id?: string }) {
<div className="flex justify-end h-8 gap-2 items-center">
{isFollowingYou && (
<div className="text-muted-foreground rounded-full bg-muted text-xs h-fit px-2">
Follows you
{t('Follows you')}
</div>
)}
<FollowButton pubkey={pubkey} />