Skip to content

Commit

Permalink
Merge pull request #71 from Ray-D-Song/i18n
Browse files Browse the repository at this point in the history
feat: add i18n
  • Loading branch information
Ray-D-Song authored Jan 1, 2025
2 parents e5b9f77 + 573f04a commit 056aa3a
Show file tree
Hide file tree
Showing 41 changed files with 880 additions and 239 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,17 @@
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
"emblor": "^1.4.6",
"i18next": "^24.1.2",
"i18next-browser-languagedetector": "^8.0.2",
"i18next-http-backend": "^3.0.1",
"lucide-react": "^0.446.0",
"mitt": "^3.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.53.1",
"react-hot-toast": "^2.4.1",
"react-i18next": "^15.2.0",
"recharts": "^2.13.0",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
Expand Down
56 changes: 56 additions & 0 deletions packages/plugin/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"logout": "Logout",
"change-plugin-settings": "Change Plugin Settings",
"create": "Create",
"create-folder-failed": "Failed to create folder",
"create-folder-input-placeholder": "Folder name",
"create-folder-success": "Folder created",
"create-new-folder": "Create New Folder",
"auth-failed": "Authentication failed",
"get-current-tab-info-failed": "Can not get current tab info",
"block-audios": "Block Audios",
"block-scripts": "Block Scripts",
"block-videos": "Block Videos",
"compress-HTML": "Compress HTML",
"group-duplicate-images": "Group Duplicate Images",
"load-deferred-images": "Load Deferred Images",
"load-deferred-images-max-idle-time": "Load Deferred Images Max Idle Time",
"remove-alternative-fonts": "Remove Alternative Fonts",
"remove-alternative-images": "Remove Alternative Images",
"remove-alternative-medias": "Remove Alternative Medias",
"remove-hidden-elements": "Remove Hidden Elements",
"remove-imports": "Remove Imports",
"remove-unused-fonts": "Remove Unused Fonts",
"remove-unused-styles": "Remove Unused Styles",
"save-page": "Save Page",
"singlefile-settings": "Single File Settings",
"clear-finished-task-list": "Clear finished history task list",
"save": "Save",
"title": "Title",
"tag": "Tag",
"add-save-page-task-success": "Add save page task success",
"page-desc": "Page Description",
"scraping-page-data": "Scraping Page Data...",
"ai-tag-not-configured": "Please configure in website settings first",
"select-folder-placeholder": "Select a folder",
"folder-required": "Please select a folder",
"no-folder-found": "No Folder Found.",
"confirm": "Confirm",
"toggle-theme": "Toggle Theme",
"server-url": "Server URL",
"input-server-url-placeholder": "Enter the server URL",
"input-token-placeholder": "Enter the token",
"task-init": "Init",
"task-scraping": "Scraping page",
"task-done": "Done",
"task-failed": "Failed",
"task-uploading": "Uploading to server",
"folder-name-required": "Folder name is required",
"cancel": "Cancel",
"folder": "Folder",
"view-save-history": "View Save History",
"open-showcase-page": "Open Showcase Page",
"open-home-page": "Open Home Page",
"save-page-not-available": "Save Page (Not Available)",
"language": "Language:"
}
56 changes: 56 additions & 0 deletions packages/plugin/assets/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"logout": "登出",
"change-plugin-settings": "更改插件设置",
"create": "创建",
"create-folder-failed": "创建文件夹失败",
"create-folder-input-placeholder": "文件夹名称",
"create-folder-success": "文件夹创建成功",
"create-new-folder": "创建新文件夹",
"auth-failed": "认证失败",
"get-current-tab-info-failed": "获取当前标签页信息失败",
"block-audios": "拦截音频",
"block-scripts": "拦截脚本",
"block-videos": "拦截视频",
"compress-HTML": "压缩 HTML",
"group-duplicate-images": "分组重复图片",
"load-deferred-images": "加载延迟图片",
"load-deferred-images-max-idle-time": "加载延迟图片最大空闲时间(毫秒)",
"remove-alternative-fonts": "移除备选字体",
"remove-alternative-images": "移除用于备选分辨率的图片",
"remove-alternative-medias": "移除用于备选设备屏幕的样式表",
"remove-hidden-elements": "移除隐藏元素",
"remove-imports": "移除导入",
"remove-unused-fonts": "移除未使用的字体",
"remove-unused-styles": "移除未使用的样式",
"save-page": "保存页面",
"singlefile-settings": "SingleFile 设置",
"clear-finished-task-list": "清除已完成的历史任务列表",
"save": "保存",
"title": "标题",
"tag": "标签",
"add-save-page-task-success": "添加保存页面任务成功",
"page-desc": "页面描述",
"scraping-page-data": "正在抓取页面数据...",
"ai-tag-not-configured": "请现在网站中配置相关设置",
"select-folder-placeholder": "选择一个文件夹",
"folder-required": "请选择一个文件夹",
"no-folder-found": "未找到文件夹",
"confirm": "确认",
"toggle-theme": "切换主题",
"server-url": "服务器 URL",
"input-server-url-placeholder": "请输入服务器 URL",
"input-token-placeholder": "请输入Token",
"task-init": "初始化",
"task-scraping": "正在抓取页面",
"task-done": "完成",
"task-failed": "失败",
"task-uploading": "正在上传到服务器",
"folder-name-required": "请输入文件夹名称",
"cancel": "取消",
"folder": "文件夹",
"view-save-history": "查看保存历史",
"open-showcase-page": "打开 Showcase 页面",
"open-home-page": "打开首页",
"save-page-not-available": "保存页面(不可用)",
"language": "语言: "
}
31 changes: 31 additions & 0 deletions packages/plugin/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import enTranslation from '~/assets/locales/en/translation.json'
import zhCNTranslation from '~/assets/locales/zh-CN/translation.json'

i18n
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
resources: {
'en': {
translation: enTranslation,
},
'zh-CN': {
translation: zhCNTranslation,
},
},
})

export default i18n
3 changes: 2 additions & 1 deletion packages/plugin/manifest.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@
"resources": [
"lib/single-file-hooks-frames.js",
"lib/single-file.js",
"lib/single-file-extension-core.js"
"lib/single-file-extension-core.js",
"assets/locales/*"
]
}
]
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin/popup/components/FolderCombobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
PopoverContent,
PopoverTrigger,
} from '@web-archive/shared/components/popover'
import { useTranslation } from 'react-i18next'

interface ComboboxProps {
value?: string
Expand All @@ -23,6 +24,7 @@ interface ComboboxProps {
}

function FolderCombobox({ value, onValueChange, options }: ComboboxProps) {
const { t } = useTranslation()
const [open, setOpen] = React.useState(false)

return (
Expand All @@ -36,14 +38,14 @@ function FolderCombobox({ value, onValueChange, options }: ComboboxProps) {
>
{value
? options.find(option => option.value === value)?.label
: 'Select a folder'}
: t('select-folder-placeholder')}
{open ? <ChevronDown size={16} className="transform rotate-180 opacity-50" /> : <ChevronDown size={16} className="opacity-50" />}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0 w-[14.5rem]">
<Command>
<CommandList className="h-48 scrollbar-hide">
<CommandEmpty>No Folder Found.</CommandEmpty>
<CommandEmpty>{t('no-folder-found')}</CommandEmpty>
<CommandGroup>
{options.map(option => (
<CommandItem
Expand Down
14 changes: 5 additions & 9 deletions packages/plugin/popup/components/HistoryTaskList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ArrowLeft, Check, ClockAlert, Eraser, LoaderCircle } from 'lucide-react
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@web-archive/shared/components/tooltip'
import Browser from 'webextension-polyfill'
import { Button } from '@web-archive/shared/components/button'
import { useTranslation } from 'react-i18next'
import type { PageType } from '../PopupPage'
import type { SeriableSingleFileTask } from '~/background/processor'

Expand Down Expand Up @@ -41,6 +42,7 @@ function HistoryTaskList({ setActivePage }: { setActivePage: (tab: PageType) =>
}

function ClearHistoryTaskListButton() {
const { t } = useTranslation()
function handleClick() {
sendMessage('clear-finished-task-list', {})
}
Expand All @@ -58,7 +60,7 @@ function ClearHistoryTaskListButton() {
</Button>
</TooltipTrigger>
<TooltipContent side="left" sideOffset={20}>
Clear finished history task list
{t('clear-finished-task-list')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
Expand All @@ -82,19 +84,13 @@ function TaskListItem({ task }: { task: SeriableSingleFileTask }) {
)
}

const statusTextMap = {
init: 'Init',
scraping: 'Scraping page',
uploading: 'Uploading to server',
done: 'Done',
failed: 'Failed',
}
function TaskDetailText({ task }: { task: SeriableSingleFileTask }) {
const { t } = useTranslation()
const taskRunningTime = Date.now() - task.startTimeStamp
const shouldShowRunningTimeText = task.status !== 'done' && task.status !== 'failed'
const runningTimeText = shouldShowRunningTimeText ? `(${(taskRunningTime / 1000).toFixed(0)}s)` : ''

const statusText = statusTextMap[task.status]
const statusText = t(`task-${task.status}`)
const errorText = task.errorMessage ? `${task.errorMessage}` : 'Uknown error'

let renderText = statusText
Expand Down
12 changes: 7 additions & 5 deletions packages/plugin/popup/components/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { Button } from '@web-archive/shared/components/button'
import { Label } from '@web-archive/shared/components/label'
import { Input } from '@web-archive/shared/components/input'
import toast from 'react-hot-toast'
import { useTranslation } from 'react-i18next'
import { useServerUrl, useToken } from '~/popup/composable/server'
import type { PageType } from '~/popup/PopupPage'

function LoginPage({ setActivePage }: { setActivePage: (tab: PageType) => void }) {
const { t } = useTranslation()
const [serverUrl, saveServerUrl] = useServerUrl()
const [token, saveToken] = useToken()

Expand All @@ -16,18 +18,18 @@ function LoginPage({ setActivePage }: { setActivePage: (tab: PageType) => void }
setActivePage('home')
}
else {
toast.error('Authentication failed')
toast.error(t('auth-failed'))
}
})
}

return (
<div className="w-80 space-y-3 p-4 ">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="serverUrl">Server URL</Label>
<Label htmlFor="serverUrl">{t('server-url')}</Label>
<Input
id="serverUrl"
placeholder="Enter the server url"
placeholder={t('input-server-url-placeholder')}
value={serverUrl}
onChange={saveServerUrl}
/>
Expand All @@ -37,7 +39,7 @@ function LoginPage({ setActivePage }: { setActivePage: (tab: PageType) => void }
<Label htmlFor="token">Token</Label>
<Input
id="token"
placeholder="Enter the token"
placeholder={t('input-token-placeholder')}
type="password"
value={token}
onChange={saveToken}
Expand All @@ -48,7 +50,7 @@ function LoginPage({ setActivePage }: { setActivePage: (tab: PageType) => void }
className="w-full"
onClick={checkAuth}
>
Save
{t('save')}
</Button>
</div>
)
Expand Down
22 changes: 14 additions & 8 deletions packages/plugin/popup/components/NewFolderDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@ import { useState } from 'react'
import toast from 'react-hot-toast'
import { useRequest } from 'ahooks'
import { sendMessage } from 'webext-bridge/popup'
import { useTranslation } from 'react-i18next'

interface NewFolderProps {
afterSubmit: (folder: { id: number, name: string }) => void
open: boolean
setOpen: (open: boolean) => void
}

async function createFolder(name: string): Promise<{ id: number, name: string }> {
async function createFolder(name: string, errorMsg: string): Promise<{ id: number, name: string }> {
const newFolder = await sendMessage('create-folder', { name })
if (!newFolder) {
throw new Error('Failed to create folder')
throw new Error(errorMsg)
}
return newFolder
}

function NewFolderDialog({ afterSubmit, open, setOpen }: NewFolderProps) {
const { t } = useTranslation()
const [name, setName] = useState('')
const { run } = useRequest(
createFolder,
{
manual: true,
onSuccess: (folder) => {
toast.success('Folder created')
toast.success(t('create-folder-success'))
setOpen(false)
setName('')
afterSubmit(folder)
Expand All @@ -39,23 +41,27 @@ function NewFolderDialog({ afterSubmit, open, setOpen }: NewFolderProps) {
)
const handleSubmit = () => {
if (name.length === 0) {
toast.error('Folder name is required')
toast.error(t('folder-name-required'))
return
}
run(name)
run(name, t('create-folder-failed'))
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="w-64">
<DialogTitle>Create New Folder</DialogTitle>
<DialogTitle>{t('create-new-folder')}</DialogTitle>
<DialogDescription></DialogDescription>
<Input

value={name}

onChange={e => setName(e.target.value)}
onKeyDown={e => e.key === 'Enter' && handleSubmit()}
placeholder="Folder Name"

placeholder={t('create-folder-input-placeholder')}

/>
<Button onClick={handleSubmit}>Create</Button>
<Button onClick={handleSubmit}>{t('create')}</Button>
</DialogContent>
</Dialog>
)
Expand Down
Loading

0 comments on commit 056aa3a

Please sign in to comment.