diff --git a/components/Auth.tsx b/components/Auth.tsx index af67829..16ab760 100644 --- a/components/Auth.tsx +++ b/components/Auth.tsx @@ -3,6 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Image from 'next/image' import { useRouter } from 'next/router' import { FC, useState } from 'react' +import { useTranslation } from 'next-i18next' import { matchProtectedRoute } from '../utils/protectedRouteHandler' import useLocalStorage from '../utils/useLocalStorage' @@ -14,16 +15,18 @@ const Auth: FC<{ redirect: string }> = ({ redirect }) => { const [token, setToken] = useState('') const [_, setPersistedToken] = useLocalStorage(authTokenPath, '') + const { t } = useTranslation() + return (
authenticate
-
Enter Password
+
{t('Enter Password')}

- This route (the folder itself and the files inside) is password protected. If you know the password, please - enter it below. + {t('This route (the folder itself and the files inside) is password protected. ') + + t('If you know the password, please enter it below.')}

diff --git a/components/Breadcrumb.tsx b/components/Breadcrumb.tsx index 726ccf1..f452eb1 100644 --- a/components/Breadcrumb.tsx +++ b/components/Breadcrumb.tsx @@ -2,13 +2,16 @@ import type { ParsedUrlQuery } from 'querystring' import Link from 'next/link' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { useTranslation } from 'next-i18next' const HomeCrumb = () => { + const { t } = useTranslation() + return ( - Home + {t('Home')} ) diff --git a/components/DownloadBtnGtoup.tsx b/components/DownloadBtnGtoup.tsx index 22e5fd6..fdee1a8 100644 --- a/components/DownloadBtnGtoup.tsx +++ b/components/DownloadBtnGtoup.tsx @@ -3,6 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { IconProp } from '@fortawesome/fontawesome-svg-core' import toast from 'react-hot-toast' import { useClipboard } from 'use-clipboard-copy' +import { useTranslation } from 'next-i18next' import Image from 'next/image' import { useRouter } from 'next/router' @@ -64,31 +65,33 @@ const DownloadButtonGroup: React.FC<{ downloadUrl: string }> = ({ downloadUrl }) const { asPath } = useRouter() const clipboard = useClipboard() + const { t } = useTranslation() + return (
window.open(downloadUrl)} btnColor="blue" - btnText="Download" + btnText={t('Download')} btnIcon="file-download" - btnTitle="Download the file directly through OneDrive" + btnTitle={t('Download the file directly through OneDrive')} /> {/* window.open(`/api/proxy?url=${encodeURIComponent(downloadUrl)}`)} btnColor="teal" - btnText="Proxy download" + btnText={t('Proxy download')} btnIcon="download" - btnTitle="Download the file with the stream proxied through Vercel Serverless" + btnTitle={t('Download the file with the stream proxied through Vercel Serverless')} /> */} { clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`) - toast.success('Copied direct link to clipboard.') + toast.success(t('Copied direct link to clipboard.')) }} btnColor="pink" - btnText="Copy direct link" + btnText={t('Copy direct link')} btnIcon="copy" - btnTitle="Copy the permalink to the file to the clipboard" + btnTitle={t('Copy the permalink to the file to the clipboard')} />
) diff --git a/components/FileListing.tsx b/components/FileListing.tsx index 6dbfa07..2df9202 100644 --- a/components/FileListing.tsx +++ b/components/FileListing.tsx @@ -7,6 +7,7 @@ import { FC, MouseEventHandler, SetStateAction, useEffect, useRef, useState } fr import dynamic from 'next/dynamic' import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' import useLocalStorage from '../utils/useLocalStorage' import { getPreviewType, preview } from '../utils/getPreviewType' @@ -146,6 +147,8 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { const router = useRouter() const [layout, _] = useLocalStorage('preferredLayout', layouts[0]) + const { t } = useTranslation() + const path = queryToPath(query) const { data, error, size, setSize } = useProtectedSWRInfinite(path) @@ -166,7 +169,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { if (!data) { return ( - + ) } @@ -240,13 +243,13 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { downloadMultipleFiles({ toastId, router, files, folder }) .then(() => { setTotalGenerating(false) - toast.success('Finished downloading selected files.', { + toast.success(t('Finished downloading selected files.'), { id: toastId, }) }) .catch(() => { setTotalGenerating(false) - toast.error('Failed to download selected files.', { id: toastId }) + toast.error(t('Failed to download selected files.'), { id: toastId }) }) } } @@ -256,7 +259,13 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { const files = (async function* () { for await (const { meta: c, path: p, isFolder, error } of traverseFolder(path)) { if (error) { - toast.error(`Failed to download folder ${p}: ${error.status} ${error.message} Skipped it to continue.`) + toast.error( + t('Failed to download folder {{path}}: {{status}} {{message}} Skipped it to continue.', { + path: p, + status: error.status, + message: error.message + }) + ) continue } yield { @@ -280,11 +289,11 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { }) .then(() => { setFolderGenerating({ ...folderGenerating, [id]: false }) - toast.success('Finished downloading folder.', { id: toastId }) + toast.success(t('Finished downloading folder.'), { id: toastId }) }) .catch(() => { setFolderGenerating({ ...folderGenerating, [id]: false }) - toast.error('Failed to download folder.', { id: toastId }) + toast.error(t('Failed to download folder.'), { id: toastId }) }) } @@ -312,7 +321,13 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { {!onlyOnePage && (
- - showing {size} page{size > 1 ? 's' : ''} of {isLoadingMore ? '...' : folderChildren.length} files - + {t('- showing {{count}} page(s) ', { + count: size, + totalFileNum: isLoadingMore ? '...' : folderChildren.length + }) + + (isLoadingMore + ? t('of {{count}} file(s) -', { count: folderChildren.length, context: 'loading' }) + : t('of {{count}} file(s) -', { count: folderChildren.length, context: 'loaded' }))}
- Oops, that's a four-oh-four. + + {/* eslint-disable-next-line react/no-unescaped-entities */} + Oops, that's a four-oh-four. +
{errorMsg}
- Press{' '} - F12{' '} - and open devtools for more details, or seek help at{' '} - - onedrive-vercel-index discussions - - . + + Press{' '} + + F12 + {' '} + and open devtools for more details, or seek help at{' '} + + onedrive-vercel-index discussions + + . +
diff --git a/components/MultiFileDownloader.tsx b/components/MultiFileDownloader.tsx index 85115ca..5538984 100644 --- a/components/MultiFileDownloader.tsx +++ b/components/MultiFileDownloader.tsx @@ -1,6 +1,7 @@ import { NextRouter } from 'next/router' import toast from 'react-hot-toast' import JSZip from 'jszip' +import { useTranslation } from 'next-i18next' import { fetcher } from '../utils/fetchWithSWR' import { getStoredToken } from '../utils/protectedRouteHandler' @@ -12,10 +13,12 @@ import { getStoredToken } from '../utils/protectedRouteHandler' * @returns Toast component with loading progress */ export function DownloadingToast(router: NextRouter, progress?: string) { + const { t } = useTranslation() + return (
- Downloading {progress ? `${progress}%` : 'selected files...'} + {progress ? t('Downloading {{progress}}%', { progress }) : t('Downloading selected files...')}
@@ -27,7 +30,7 @@ export function DownloadingToast(router: NextRouter, progress?: string) { className="p-2 rounded bg-red-500 hover:bg-red-400 text-white focus:outline-none focus:ring focus:ring-red-300" onClick={() => router.reload()} > - Cancel + {t('Cancel')}
) diff --git a/components/Navbar.tsx b/components/Navbar.tsx index 49fde9c..4c9ecce 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -8,6 +8,7 @@ import Link from 'next/link' import Image from 'next/image' import { useRouter } from 'next/router' import { Fragment, useEffect, useState } from 'react' +import { useTranslation } from 'next-i18next' import siteConfig from '../config/site.config' import SearchModal from './SearchModal' @@ -40,6 +41,8 @@ const Navbar = () => { setTokenPresent(storedToken()) }, []) + const { t } = useTranslation() + const clearTokens = () => { setIsOpen(false) @@ -47,7 +50,7 @@ const Navbar = () => { localStorage.removeItem(r) }) - toast.success('Cleared all tokens') + toast.success(t('Cleared all tokens')) setTimeout(() => { router.reload() }, 1000) @@ -74,7 +77,7 @@ const Navbar = () => { >
- Search ... + {t('Search ...')}
@@ -95,14 +98,20 @@ const Navbar = () => { className="flex items-center space-x-2 hover:opacity-80 dark:text-white" > - {l.name} + + { + // Append link name comments here to add translations + // t('Weibo') + t(l.name) + } + ))} {siteConfig.email && ( - Email + {t('Email')} )} @@ -111,7 +120,7 @@ const Navbar = () => { className="flex items-center space-x-2 p-2 hover:opacity-80 dark:text-white" onClick={() => setIsOpen(true)} > - Logout + {t('Logout')} )} @@ -148,12 +157,12 @@ const Navbar = () => { >
- Clear all tokens? + {t('Clear all tokens?')}

- These tokens are used to authenticate yourself into password protected folders, clearing them means - that you will need to re-enter the passwords again. + {t('These tokens are used to authenticate yourself into password protected folders, ') + + t('clearing them means that you will need to re-enter the passwords again.')}

@@ -171,14 +180,14 @@ const Navbar = () => { className="mr-3 inline-flex items-center justify-center space-x-2 rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-400 focus:outline-none focus:ring focus:ring-blue-300" onClick={() => setIsOpen(false)} > - Cancel + {t('Cancel')}
diff --git a/components/SearchModal.tsx b/components/SearchModal.tsx index f416426..23741d1 100644 --- a/components/SearchModal.tsx +++ b/components/SearchModal.tsx @@ -4,6 +4,7 @@ import { Dispatch, Fragment, SetStateAction, useState } from 'react' import AwesomeDebouncePromise from 'awesome-debounce-promise' import { useAsync } from 'react-async-hook' import useConstant from 'use-constant' +import { useTranslation } from 'next-i18next' import Link from 'next/link' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' @@ -112,12 +113,19 @@ function SearchResultItemTemplate({ function SearchResultItemLoadRemote({ result }: { result: OdSearchResult[number] }) { const { data, error }: SWRResponse = useSWR(`/api/item?id=${result.id}`, fetcher) + const { t } = useTranslation() + if (error) { return } if (!data) { return ( - + ) } @@ -159,6 +167,8 @@ export default function SearchModal({ }) { const { query, setQuery, results } = useDriveItemSearch() + const { t } = useTranslation() + const closeSearchBox = () => { setSearchOpen(false) setQuery('') @@ -199,13 +209,12 @@ export default function SearchModal({ type="text" id="search-box" className="w-full bg-transparent focus:outline-none focus-visible:outline-none" - placeholder="Search ..." + placeholder={t('Search ...')} value={query} onChange={e => setQuery(e.target.value)} />
ESC
-
- Loading ... + {t('Loading ...')}
)} {results.error && ( -
Error: {results.error.message}
+
+ {t('Error: {{message}}', { message: results.error.message })} +
)} {results.result && ( <> {results.result.length === 0 ? ( -
Nothing here.
+
{t('Nothing here.')}
) : ( results.result.map(result => ) )} diff --git a/components/SwitchLayout.tsx b/components/SwitchLayout.tsx index ebf31b6..af76888 100644 --- a/components/SwitchLayout.tsx +++ b/components/SwitchLayout.tsx @@ -2,6 +2,7 @@ import { Fragment } from 'react' import { IconProp } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Listbox, Transition } from '@headlessui/react' +import { useTranslation } from 'next-i18next' import useLocalStorage from '../utils/useLocalStorage' @@ -13,13 +14,21 @@ export const layouts: Array<{ id: number; name: 'Grid' | 'List'; icon: IconProp export const SwitchLayout = () => { const [preferredLayout, setPreferredLayout] = useLocalStorage('preferredLayout', layouts[0]) + const { t } = useTranslation() + return (
- {preferredLayout.name} + + { + // t('Grid') + // t('List') + t(preferredLayout.name) + } + @@ -39,7 +48,11 @@ export const SwitchLayout = () => { > - {layout.name} + { + // t('Grid') + // t('List') + t(layout.name) + } {layout.name === preferredLayout.name && ( diff --git a/components/previews/AudioPreview.tsx b/components/previews/AudioPreview.tsx index 5a10308..c76962a 100644 --- a/components/previews/AudioPreview.tsx +++ b/components/previews/AudioPreview.tsx @@ -3,6 +3,7 @@ import { FC, useState } from 'react' import ReactAudioPlayer from 'react-audio-player' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { useTranslation } from 'next-i18next' import DownloadButtonGroup from '../DownloadBtnGtoup' import { DownloadBtnContainer, PreviewContainer } from './Containers' @@ -19,6 +20,8 @@ enum PlayerState { const AudioPreview: FC<{ file: OdFileObject }> = ({ file }) => { const [playerStatus, setPlayerStatus] = useState(PlayerState.Loading) + const { t } = useTranslation() + return ( <> @@ -37,7 +40,7 @@ const AudioPreview: FC<{ file: OdFileObject }> = ({ file }) => {
{file.name}
- Last modified: {formatModifiedDateTime(file.lastModifiedDateTime)} + {t('Last modified:') + ' ' + formatModifiedDateTime(file.lastModifiedDateTime)}
= ({ file }) => { const { response: content, error, validating } = useAxiosGet(file['@microsoft.graph.downloadUrl']) + const { t } = useTranslation() + useEffect(() => { if (typeof window !== 'undefined') { Prism.highlightAll() @@ -27,7 +30,7 @@ const CodePreview: FC<{ file: any }> = ({ file }) => { if (validating) { return ( - + ) } diff --git a/components/previews/DefaultPreview.tsx b/components/previews/DefaultPreview.tsx index dc795b2..c6d2f19 100644 --- a/components/previews/DefaultPreview.tsx +++ b/components/previews/DefaultPreview.tsx @@ -2,6 +2,7 @@ import type { OdFileObject } from '../../types' import { FC } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { useTranslation } from 'next-i18next' import { getFileIcon } from '../../utils/getFileIcon' import { formatModifiedDateTime, humanFileSize } from '../../utils/fileDetails' @@ -10,6 +11,8 @@ import DownloadButtonGroup from '../DownloadBtnGtoup' import { DownloadBtnContainer, PreviewContainer } from './Containers' const DefaultPreview: FC<{ file: OdFileObject }> = ({ file }) => { + const { t } = useTranslation() + return (
@@ -21,22 +24,22 @@ const DefaultPreview: FC<{ file: OdFileObject }> = ({ file }) => {
-
Last modified
+
{t('Last modified')}
{formatModifiedDateTime(file.lastModifiedDateTime)}
-
File size
+
{t('File size')}
{humanFileSize(file.size)}
-
MIME type
-
{file.file?.mimeType || 'Unavailable'}
+
{t('MIME type')}
+
{file.file?.mimeType || t('Unavailable')}
-
Hashes
+
{t('Hashes')}
diff --git a/components/previews/EPUBPreview.tsx b/components/previews/EPUBPreview.tsx index f16405f..f7fb3dc 100644 --- a/components/previews/EPUBPreview.tsx +++ b/components/previews/EPUBPreview.tsx @@ -2,6 +2,7 @@ import type { OdFileObject } from '../../types' import { FC, useEffect, useRef, useState } from 'react' import { ReactReader } from 'react-reader' +import { useTranslation } from 'next-i18next' import Loading from '../Loading' import DownloadButtonGroup from '../DownloadBtnGtoup' @@ -18,6 +19,8 @@ const EPUBPreview: FC<{ file: OdFileObject }> = ({ file }) => { const [location, setLocation] = useState() const onLocationChange = (cfiStr: string) => setLocation(cfiStr) + const { t } = useTranslation() + // Fix for not valid epub files according to // https://github.com/gerhardsletten/react-reader/issues/33#issuecomment-673964947 const fixEpub = rendition => { @@ -50,7 +53,7 @@ const EPUBPreview: FC<{ file: OdFileObject }> = ({ file }) => { fixEpub(rendition)} - loadingView={} + loadingView={} location={location} locationChanged={onLocationChange} epubInitOptions={{ openAs: 'epub' }} diff --git a/components/previews/MarkdownPreview.tsx b/components/previews/MarkdownPreview.tsx index 469b5c1..b8b6815 100644 --- a/components/previews/MarkdownPreview.tsx +++ b/components/previews/MarkdownPreview.tsx @@ -5,6 +5,7 @@ import gfm from 'remark-gfm' import remarkMath from 'remark-math' import rehypeKatex from 'rehype-katex' import rehypeRaw from 'rehype-raw' +import { useTranslation } from 'next-i18next' import 'katex/dist/katex.min.css' @@ -21,6 +22,8 @@ const MarkdownPreview: FC<{ }> = ({ file, path, standalone = true }) => { const { response: content, error, validating } = useAxiosGet(file['@microsoft.graph.downloadUrl']) + const { t } = useTranslation() + // The parent folder of the markdown file, which is also the relative image folder const parentPath = path.substring(0, path.lastIndexOf('/')) // Check if the image is relative path instead of a absolute url @@ -76,7 +79,7 @@ const MarkdownPreview: FC<{ if (validating) { return ( - + ) } diff --git a/components/previews/TextPreview.tsx b/components/previews/TextPreview.tsx index 68e825b..2cc139c 100644 --- a/components/previews/TextPreview.tsx +++ b/components/previews/TextPreview.tsx @@ -1,3 +1,5 @@ +import { useTranslation } from 'next-i18next' + import FourOhFour from '../FourOhFour' import Loading from '../Loading' import DownloadButtonGroup from '../DownloadBtnGtoup' @@ -5,6 +7,8 @@ import useAxiosGet from '../../utils/fetchOnMount' import { DownloadBtnContainer, PreviewContainer } from './Containers' const TextPreview = ({ file }) => { + const { t } = useTranslation() + const { response: content, error, validating } = useAxiosGet(file['@microsoft.graph.downloadUrl']) if (error) { return ( @@ -17,7 +21,7 @@ const TextPreview = ({ file }) => { if (validating) { return ( - + ) } @@ -25,7 +29,7 @@ const TextPreview = ({ file }) => { if (!content) { return ( - + ) } diff --git a/components/previews/URLPreview.tsx b/components/previews/URLPreview.tsx index 389b82d..f091142 100644 --- a/components/previews/URLPreview.tsx +++ b/components/previews/URLPreview.tsx @@ -1,3 +1,5 @@ +import { useTranslation } from 'next-i18next' + import FourOhFour from '../FourOhFour' import Loading from '../Loading' import { DownloadButton } from '../DownloadBtnGtoup' @@ -12,6 +14,8 @@ const parseDotUrl = (content: string): string | undefined => { } const TextPreview = ({ file }) => { + const { t } = useTranslation() + const { response: content, error, validating } = useAxiosGet(file['@microsoft.graph.downloadUrl']) if (error) { return ( @@ -24,7 +28,7 @@ const TextPreview = ({ file }) => { if (validating) { return ( - + ) } @@ -32,7 +36,7 @@ const TextPreview = ({ file }) => { if (!content) { return ( - + ) } @@ -47,9 +51,9 @@ const TextPreview = ({ file }) => { window.open(parseDotUrl(content) || '')} btnColor="blue" - btnText="Open URL" + btnText={t('Open URL')} btnIcon="external-link-alt" - btnTitle={`Open URL ${parseDotUrl(content) || ''}`} + btnTitle={t('Open URL{{url}}', { url: ' ' + parseDotUrl(content) || '' })} /> diff --git a/components/previews/VideoPreview.tsx b/components/previews/VideoPreview.tsx index beafb78..89602ad 100644 --- a/components/previews/VideoPreview.tsx +++ b/components/previews/VideoPreview.tsx @@ -3,6 +3,7 @@ import { useRouter } from 'next/router' import { useClipboard } from 'use-clipboard-copy' import DPlayer from 'react-dplayer' import toast from 'react-hot-toast' +import { useTranslation } from 'next-i18next' import { useAsync } from 'react-async-hook' import { getBaseUrl } from '../../utils/getBaseUrl' @@ -17,6 +18,8 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => { const { asPath } = useRouter() const clipboard = useClipboard() + const { t } = useTranslation() + // OneDrive generates thumbnails for its video files, we pick the thumbnail with the highest resolution const thumbnail = file.thumbnails && file.thumbnails.length > 0 ? file.thumbnails[0].large.url : '' @@ -40,7 +43,7 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => { {error ? ( ) : loading && isFlv ? ( - + ) : ( = ({ file }) => { window.open(file['@microsoft.graph.downloadUrl'])} btnColor="blue" - btnText="Download" + btnText={t('Download')} btnIcon="file-download" /> {/* = ({ file }) => { window.open(`/api/proxy?url=${encodeURIComponent(file['@microsoft.graph.downloadUrl'])}`) } btnColor="teal" - btnText="Proxy download" + btnText={t('Proxy download')} btnIcon="download" /> */} { clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`) - toast.success('Copied direct link to clipboard.') + toast.success(t('Copied direct link to clipboard.')) }} btnColor="pink" - btnText="Copy direct link" + btnText={t('Copy direct link')} btnIcon="copy" /> diff --git a/i18next-parser.config.js b/i18next-parser.config.js new file mode 100644 index 0000000..439b39f --- /dev/null +++ b/i18next-parser.config.js @@ -0,0 +1,18 @@ +const path = require('path') + +const { i18n, localePath } = require('./next-i18next.config') + +module.exports = { + createOldCatalogs: false, + defaultNamespace: 'common', + defaultValue: (lng, _ns, key) => (lng === i18n.defaultLocale ? key : ''), + keySeparator: false, + namespaceSeparator: false, + pluralSeparator: '——', + contextSeparator: '——', + lineEnding: 'lf', + locales: i18n.locales, + output: path.join(localePath, '$LOCALE/$NAMESPACE.json'), + input: ['**/*.{ts,tsx}', '!**/node_modules/**'], + sort: true +} diff --git a/next-i18next.config.js b/next-i18next.config.js new file mode 100644 index 0000000..ea149e4 --- /dev/null +++ b/next-i18next.config.js @@ -0,0 +1,14 @@ +const path = require('path') + +module.exports = { + i18n: { + defaultLocale: 'en', + locales: ['en', 'zh-CN'] + }, + localePath: path.resolve('public/locales'), + reloadOnPrerender: process.env.NODE_ENV === 'development', + keySeparator: false, + namespaceSeparator: false, + pluralSeparator: '——', + contextSeparator: '——' +} diff --git a/next.config.js b/next.config.js index 0d60710..fa13553 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,8 @@ +const { i18n } = require('./next-i18next.config') + module.exports = { + i18n, reactStrictMode: true, + // Required by Next i18n with API routes, otherwise API routes 404 when fetching without trailing slash + trailingSlash: true } diff --git a/package.json b/package.json index 5e09e22..a61b285 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "build": "next build", "start": "next start", "lint": "next lint", - "format": "prettier components/**/*.tsx config/*.js pages/**/*.tsx {types,utils}/**/*.ts --write" + "format": "prettier components/**/*.tsx config/*.js pages/**/*.{ts,tsx} {types,utils}/**/*.ts --write", + "extract": "i18next" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.35", @@ -27,6 +28,7 @@ "ioredis": "^4.28.2", "jszip": "^3.7.1", "next": "^12.0.10", + "next-i18next": "^10.2.0", "nextjs-progressbar": "^0.0.13", "preview-office-docs": "^1.0.2", "prismjs": "^1.23.0", @@ -62,6 +64,7 @@ "eslint": "8.8.0", "eslint-config-next": "12.0.10", "eslint-config-prettier": "^8.3.0", + "i18next-parser": "^5.4.0", "postcss": "^8.4.5", "prettier": "^2.5.1", "prettier-plugin-tailwindcss": "^0.1.4", diff --git a/pages/[...path].tsx b/pages/[...path].tsx index 13fb508..f79b095 100644 --- a/pages/[...path].tsx +++ b/pages/[...path].tsx @@ -1,5 +1,6 @@ import Head from 'next/head' import { useRouter } from 'next/router' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import siteConfig from '../config/site.config' import Navbar from '../components/Navbar' @@ -32,3 +33,11 @@ export default function Folders() { ) } + +export async function getServerSideProps({ locale }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])) + } + } +} diff --git a/pages/_app.tsx b/pages/_app.tsx index 9e4f4eb..b512338 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -55,6 +55,7 @@ import * as Icons from '@fortawesome/free-brands-svg-icons' import type { AppProps } from 'next/app' import NextNProgress from 'nextjs-progressbar' +import { appWithTranslation } from 'next-i18next' // import all brand icons with tree-shaking so all icons can be referenced in the app const iconList = Object.keys(Icons) @@ -117,4 +118,4 @@ function MyApp({ Component, pageProps }: AppProps) { ) } -export default MyApp +export default appWithTranslation(MyApp) diff --git a/pages/index.tsx b/pages/index.tsx index 23789d8..b506ccc 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,5 @@ import Head from 'next/head' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import siteConfig from '../config/site.config' import Navbar from '../components/Navbar' @@ -29,3 +30,11 @@ export default function Home() { ) } + +export async function getServerSideProps({ locale }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])) + } + } +} diff --git a/pages/onedrive-vercel-index-oauth/step-1.tsx b/pages/onedrive-vercel-index-oauth/step-1.tsx index cf1272e..aedec41 100644 --- a/pages/onedrive-vercel-index-oauth/step-1.tsx +++ b/pages/onedrive-vercel-index-oauth/step-1.tsx @@ -1,6 +1,8 @@ import Head from 'next/head' import Image from 'next/image' import { useRouter } from 'next/router' +import { useTranslation, Trans } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import siteConfig from '../../config/site.config' import apiConfig from '../../config/api.config' @@ -11,10 +13,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' export default function OAuthStep1() { const router = useRouter() + const { t } = useTranslation() + return (
- {`OAuth Step 1 - ${siteConfig.title}`} + {t('OAuth Step 1 - {{title}}', { title: siteConfig.title })}
@@ -25,34 +29,40 @@ export default function OAuthStep1() {
-

Welcome to your new onedrive-vercel-index 🎉

+

+ {t('Welcome to your new onedrive-vercel-index 🎉')} +

-

Step 1/3: Preparations

+

{t('Step 1/3: Preparations')}

- If you have not specified a REDIS_URL - inside your Vercel env variable, go initialise one at{' '} - - Upstash - - . Docs:{' '} - - Vercel Integration - Upstash - - . + + If you have not specified a REDIS_URL + inside your Vercel env variable, go initialise one at{' '} + + Upstash + + . Docs:{' '} + + Vercel Integration - Upstash + + . +

- Authorisation is required as no valid{' '} - access_token or{' '} - refresh_token is - present on this deployed instance. Check the following configurations before proceeding with authorising - onedrive-vercel-index with your own Microsoft account. + + Authorisation is required as no valid{' '} + access_token or{' '} + refresh_token{' '} + is present on this deployed instance. Check the following configurations before proceeding with + authorising onedrive-vercel-index with your own Microsoft account. +

@@ -111,9 +121,11 @@ export default function OAuthStep1() {

- If you see anything - missing or incorrect, you need to reconfigure /config/api.json{' '} - and redeploy this instance. + + If you see anything + missing or incorrect, you need to reconfigure{' '} + /config/api.config.js and redeploy this instance. +

@@ -123,7 +135,7 @@ export default function OAuthStep1() { router.push('/onedrive-vercel-index-oauth/step-2') }} > - Proceed to OAuth + {t('Proceed to OAuth')}
@@ -134,3 +146,11 @@ export default function OAuthStep1() { ) } + +export async function getServerSideProps({ locale }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + }, + } +} diff --git a/pages/onedrive-vercel-index-oauth/step-2.tsx b/pages/onedrive-vercel-index-oauth/step-2.tsx index 967d8e7..2bb55e9 100644 --- a/pages/onedrive-vercel-index-oauth/step-2.tsx +++ b/pages/onedrive-vercel-index-oauth/step-2.tsx @@ -3,6 +3,8 @@ import Image from 'next/image' import { useRouter } from 'next/router' import { useState } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { useTranslation, Trans } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import siteConfig from '../../config/site.config' import Navbar from '../../components/Navbar' @@ -17,12 +19,14 @@ export default function OAuthStep2() { const [authCode, setAuthCode] = useState('') const [buttonLoading, setButtonLoading] = useState(false) + const { t } = useTranslation() + const oAuthUrl = generateAuthorisationUrl() return (
- {`OAuth Step 2 - ${siteConfig.title}`} + {t('OAuth Step 2 - {{title}}', { title: siteConfig.title })}
@@ -39,13 +43,17 @@ export default function OAuthStep2() { priority />
-

Welcome to your new onedrive-vercel-index 🎉

+

+ {t('Welcome to your new onedrive-vercel-index 🎉')} +

-

Step 2/3: Get authorisation code

+

{t('Step 2/3: Get authorisation code')}

- If you are not the owner of this website, - stop now, as continuing with this process may expose your personal files in OneDrive. + + If you are not the owner of this website, + stop now, as continuing with this process may expose your personal files in OneDrive. +

- The OAuth link for getting the authorisation code has been created. Click on the link above to get the{' '} - authorisation code. Your browser will - open a new tab to Microsoft's account login page. After logging in and authenticating with your - Microsoft account, you will be redirected to a blank page on localhost. Paste{' '} - the entire redirected URL down below. + + The OAuth link for getting the authorisation code has been created. Click on the link above to get the{' '} + authorisation code. Your browser will + {/* eslint-disable-next-line react/no-unescaped-entities */} + open a new tab to Microsoft's account login page. After logging in and authenticating with your + Microsoft account, you will be redirected to a blank page on localhost. Paste{' '} + the entire redirected URL down below. +

@@ -90,15 +101,15 @@ export default function OAuthStep2() { }} /> -

The authorisation code extracted is:

+

{t('The authorisation code extracted is:')}

- {authCode || Waiting for code...} + {authCode || {t('Waiting for code...')}}

{authCode - ? '✅ You can now proceed onto the next step: requesting your access token and refresh token.' - : '❌ No valid code extracted.'} + ? t('✅ You can now proceed onto the next step: requesting your access token and refresh token.') + : t('❌ No valid code extracted.')}

@@ -112,11 +123,11 @@ export default function OAuthStep2() { > {buttonLoading ? ( <> - Requesting tokens + {t('Requesting tokens')} ) : ( <> - Get tokens + {t('Get tokens')} )} @@ -129,3 +140,11 @@ export default function OAuthStep2() {
) } + +export async function getServerSideProps({ locale }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common'])), + }, + } +} diff --git a/pages/onedrive-vercel-index-oauth/step-3.tsx b/pages/onedrive-vercel-index-oauth/step-3.tsx index d27a8a5..d50c2cd 100644 --- a/pages/onedrive-vercel-index-oauth/step-3.tsx +++ b/pages/onedrive-vercel-index-oauth/step-3.tsx @@ -3,6 +3,8 @@ import Image from 'next/image' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { useTranslation, Trans } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import siteConfig from '../../config/site.config' import Navbar from '../../components/Navbar' @@ -15,6 +17,8 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro const router = useRouter() const [expiryTimeLeft, setExpiryTimeLeft] = useState(expiryTime) + const { t } = useTranslation() + useEffect(() => { if (!expiryTimeLeft) return @@ -27,7 +31,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro const [buttonContent, setButtonContent] = useState(
- Store tokens + {t('Store tokens')}
) const [buttonError, setButtonError] = useState(false) @@ -36,7 +40,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro setButtonError(false) setButtonContent(
- Storing tokens + {t('Storing tokens')}
) @@ -46,7 +50,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro setButtonError(true) setButtonContent(
- Error validating identify, restart + {t('Error validating identify, restart')}
) return @@ -55,7 +59,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro setButtonError(true) setButtonContent(
- Do not pretend to be the site owner + {t('Do not pretend to be the site owner')}
) return @@ -66,7 +70,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro setButtonError(false) setButtonContent(
- Stored! Going home... + {t('Stored! Going home...')}
) setTimeout(() => { @@ -77,7 +81,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro setButtonError(true) setButtonContent(
- Error storing the token + {t('Error storing the token')}
) }) @@ -86,7 +90,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro return (
- {`OAuth Step 3 - ${siteConfig.title}`} + {t('OAuth Step 3 - {{title}}', { title: siteConfig.title })}
@@ -103,30 +107,43 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro priority />
-

Welcome to your new onedrive-vercel-index 🎉

+

+ {t('Welcome to your new onedrive-vercel-index 🎉')} +

-

Step 3/3: Get access and refresh tokens

+

{t('Step 3/3: Get access and refresh tokens')}

{error ? (

- Whoops, looks like we got a problem: {error}. + + {t('Whoops, looks like we got a problem: {{error}}.', { + // t('No auth code present') + error: t(error), + })} +

- {description} + { + // t('Where is the auth code? Did you follow step 2 you silly donut?') + t(description) + }

{errorUri && (

- Check out{' '} - - Microsoft's official explanation - {' '} - on the error message. + + Check out{' '} + + {/* eslint-disable-next-line react/no-unescaped-entities */} + Microsoft's official explanation + {' '} + on the error message. +

)}
@@ -136,19 +153,19 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro router.push('/onedrive-vercel-index-oauth/step-1') }} > - Restart + {t('Restart')}
) : (
-

Success! The API returned what we needed.

+

{t('Success! The API returned what we needed.')}

    {accessToken && (
  1. {' '} - Acquired access_token:{' '} + {t('Acquired access_token: ')} {`${accessToken.substring(0, 60)}...`}
  2. @@ -157,7 +174,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro
  3. {' '} - Acquired refresh_token:{' '} + {t('Acquired refresh_token: ')} {`${refreshToken.substring(0, 60)}...`}
  4. @@ -165,15 +182,22 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro

- These tokens may take a few seconds to - populate after you click the button below. If you go back home and still see the welcome page telling - you to re-authenticate, revisit home and do a hard refresh. + {' '} + {t('These tokens may take a few seconds to populate after you click the button below. ') + + t('If you go back home and still see the welcome page telling you to re-authenticate, ') + + t('revisit home and do a hard refresh.')}

- Final step, click the button below to store these tokens persistently before they expire after{' '} - {Math.floor(expiryTimeLeft / 60)} minutes {expiryTimeLeft - Math.floor(expiryTimeLeft / 60) * 60}{' '} - seconds. Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes - and updates after your site goes live. + {t( + 'Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ', + { + minutes: Math.floor(expiryTimeLeft / 60), + seconds: expiryTimeLeft - Math.floor(expiryTimeLeft / 60) * 60, + } + ) + + t( + "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live." + )}

@@ -199,7 +223,7 @@ export default function OAuthStep3({ accessToken, expiryTime, refreshToken, erro ) } -export async function getServerSideProps({ query }) { +export async function getServerSideProps({ query, locale }) { const { authCode } = query // Return if no auth code is present @@ -208,6 +232,7 @@ export async function getServerSideProps({ query }) { props: { error: 'No auth code present', description: 'Where is the auth code? Did you follow step 2 you silly donut?', + ...(await serverSideTranslations(locale, ['common'])), }, } } @@ -221,6 +246,7 @@ export async function getServerSideProps({ query }) { error: response.error, description: response.errorDescription, errorUri: response.errorUri, + ...(await serverSideTranslations(locale, ['common'])), }, } } @@ -233,6 +259,7 @@ export async function getServerSideProps({ query }) { expiryTime, accessToken, refreshToken, + ...(await serverSideTranslations(locale, ['common'])), }, } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9550d51..391e159 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,10 +27,12 @@ specifiers: eslint: 8.8.0 eslint-config-next: 12.0.10 eslint-config-prettier: ^8.3.0 + i18next-parser: ^5.4.0 flv.js: ^1.6.2 ioredis: ^4.28.2 jszip: ^3.7.1 next: ^12.0.10 + next-i18next: ^10.2.0 nextjs-progressbar: ^0.0.13 postcss: ^8.4.5 prettier: ^2.5.1 @@ -75,6 +77,7 @@ dependencies: ioredis: 4.28.3 jszip: 3.7.1 next: 12.0.10_react-dom@17.0.2+react@17.0.2 + next-i18next: 10.2.0_61390be992b634a688f7c2555547b55b nextjs-progressbar: 0.0.13_next@12.0.10+react@17.0.2 preview-office-docs: 1.0.2_react@17.0.2 prismjs: 1.26.0 @@ -110,6 +113,7 @@ devDependencies: eslint: 8.8.0 eslint-config-next: 12.0.10_9534215cc73b6f260bf33f1b86e3ae0e eslint-config-prettier: 8.3.0_eslint@8.8.0 + i18next-parser: 5.4.0 postcss: 8.4.6 prettier: 2.5.1 prettier-plugin-tailwindcss: 0.1.4_prettier@2.5.1 @@ -152,7 +156,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.9 - dev: true /@eslint/eslintrc/1.0.5: resolution: {integrity: sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==} @@ -416,6 +419,13 @@ packages: '@types/unist': 2.0.6 dev: false + /@types/hoist-non-react-statics/3.3.1: + resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} + dependencies: + '@types/react': 17.0.38 + hoist-non-react-statics: 3.3.2 + dev: false + /@types/ioredis/4.28.7: resolution: {integrity: sha512-jnSGCD2/TPk02j6v6CGqaCEl0LbmLgK6jUuk/AFaSNUBV+SCHiG7E7fnwJreN6hw9GqtLAFkJs4zFbkJrz11mQ==} dependencies: @@ -447,6 +457,10 @@ packages: resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} dev: false + /@types/minimatch/3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + /@types/ms/0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: false @@ -469,7 +483,6 @@ packages: /@types/prop-types/15.7.4: resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==} - dev: true /@types/react-copy-to-clipboard/5.0.2: resolution: {integrity: sha512-O29AThfxrkUFRsZXjfSWR2yaWo0ppB1yLEnHA+Oh24oNetjBAwTDu1PmolIqdJKzsZiO4J1jn6R6TmO96uBvGg==} @@ -504,10 +517,12 @@ packages: '@types/prop-types': 15.7.4 '@types/scheduler': 0.16.2 csstype: 3.0.10 - dev: true /@types/scheduler/0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} + + /@types/symlink-or-copy/1.2.0: + resolution: {integrity: sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg==} dev: true /@types/unist/2.0.6: @@ -650,6 +665,13 @@ packages: picomatch: 2.3.1 dev: true + /append-buffer/1.0.2: + resolution: {integrity: sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=} + engines: {node: '>=0.10.0'} + dependencies: + buffer-equal: 1.0.0 + dev: true + /arg/5.0.1: resolution: {integrity: sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==} dev: true @@ -783,6 +805,10 @@ packages: engines: {node: '>=8'} dev: true + /boolbase/1.0.0: + resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=} + dev: true + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -797,6 +823,37 @@ packages: fill-range: 7.0.1 dev: true + /broccoli-node-api/1.7.0: + resolution: {integrity: sha512-QIqLSVJWJUVOhclmkmypJJH9u9s/aWH4+FH6Q6Ju5l+Io4dtwqdPUNmDfw40o6sxhbZHhqGujDJuHTML1wG8Yw==} + dev: true + + /broccoli-node-info/2.2.0: + resolution: {integrity: sha512-VabSGRpKIzpmC+r+tJueCE5h8k6vON7EIMMWu6d/FyPdtijwLQ7QvzShEw+m3mHoDzUaj/kiZsDYrS8X2adsBg==} + engines: {node: 8.* || >= 10.*} + dev: true + + /broccoli-output-wrapper/3.2.5: + resolution: {integrity: sha512-bQAtwjSrF4Nu0CK0JOy5OZqw9t5U0zzv2555EA/cF8/a8SLDTIetk9UgrtMVw7qKLKdSpOZ2liZNeZZDaKgayw==} + engines: {node: 10.* || >= 12.*} + dependencies: + fs-extra: 8.1.0 + heimdalljs-logger: 0.1.10 + symlink-or-copy: 1.3.1 + dev: true + + /broccoli-plugin/4.0.7: + resolution: {integrity: sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg==} + engines: {node: 10.* || >= 12.*} + dependencies: + broccoli-node-api: 1.7.0 + broccoli-output-wrapper: 3.2.5 + fs-merger: 3.2.1 + promise-map-series: 0.3.0 + quick-temp: 0.1.8 + rimraf: 3.0.2 + symlink-or-copy: 1.3.1 + dev: true + /browserslist/4.19.1: resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -809,6 +866,15 @@ packages: picocolors: 1.0.0 dev: true + /buffer-equal/1.0.0: + resolution: {integrity: sha1-WWFrSYME1Var1GaWayLu2j7KX74=} + engines: {node: '>=0.4.0'} + dev: true + + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -854,6 +920,29 @@ packages: resolution: {integrity: sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==} dev: false + /cheerio-select/1.5.0: + resolution: {integrity: sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==} + dependencies: + css-select: 4.2.1 + css-what: 5.1.0 + domelementtype: 2.2.0 + domhandler: 4.3.0 + domutils: 2.8.0 + dev: true + + /cheerio/1.0.0-rc.10: + resolution: {integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==} + engines: {node: '>= 6'} + dependencies: + cheerio-select: 1.5.0 + dom-serializer: 1.3.2 + domhandler: 4.3.0 + htmlparser2: 6.1.0 + parse5: 6.0.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + tslib: 2.3.1 + dev: true + /chokidar/3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -873,6 +962,28 @@ packages: resolution: {integrity: sha512-vooFaGFL6ulEP1liiaWFBmmfuPm3cY3y7T9eB83ZTnYc/oFeAKsq3NcDrOkBC8XaauEE8zHQwI7k0+JSYiVQSQ==} dev: false + /clone-buffer/1.0.0: + resolution: {integrity: sha1-4+JbIHrE5wGvch4staFnksrD3Fg=} + engines: {node: '>= 0.10'} + dev: true + + /clone-stats/1.0.0: + resolution: {integrity: sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=} + dev: true + + /clone/2.1.2: + resolution: {integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=} + engines: {node: '>=0.8'} + dev: true + + /cloneable-readable/1.1.3: + resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==} + dependencies: + inherits: 2.0.4 + process-nextick-args: 2.0.1 + readable-stream: 2.3.7 + dev: true + /clsx/1.1.1: resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==} engines: {node: '>=6'} @@ -904,6 +1015,11 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /colors/1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + dev: true + /comma-separated-tokens/2.0.2: resolution: {integrity: sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==} dev: false @@ -911,12 +1027,27 @@ packages: /commander/8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - dev: false /concat-map/0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true + /concat-stream/2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.0 + typedarray: 0.0.6 + dev: true + + /convert-source-map/1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + dev: true + /copy-to-clipboard/3.3.1: resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==} dependencies: @@ -935,7 +1066,6 @@ packages: /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: false /cors/2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} @@ -969,6 +1099,21 @@ packages: resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} dev: false + /css-select/4.2.1: + resolution: {integrity: sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==} + dependencies: + boolbase: 1.0.0 + css-what: 5.1.0 + domhandler: 4.3.0 + domutils: 2.8.0 + nth-check: 2.0.1 + dev: true + + /css-what/5.1.0: + resolution: {integrity: sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==} + engines: {node: '>= 6'} + dev: true + /cssesc/3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -977,7 +1122,6 @@ packages: /csstype/3.0.10: resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==} - dev: true /d/1.0.1: resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} @@ -990,6 +1134,9 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true + /de-indent/1.0.2: + resolution: {integrity: sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=} + dev: true /dayjs/1.10.7: resolution: {integrity: sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==} dev: false @@ -1102,6 +1249,33 @@ packages: esutils: 2.0.3 dev: true + /dom-serializer/1.3.2: + resolution: {integrity: sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==} + dependencies: + domelementtype: 2.2.0 + domhandler: 4.3.0 + entities: 2.2.0 + dev: true + + /domelementtype/2.2.0: + resolution: {integrity: sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==} + dev: true + + /domhandler/4.3.0: + resolution: {integrity: sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.2.0 + dev: true + + /domutils/2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.3.2 + domelementtype: 2.2.0 + domhandler: 4.3.0 + dev: true + /dplayer/1.26.0: resolution: {integrity: sha512-uOE0w/WdlX7N9d0ppIEcAYrcnUjY52TMX+MBL4lj9Mj+JMljVuaEc5w88HkZp5Q11VqvN/jxnM8ktx2Dr7/MgA==} dependencies: @@ -1110,6 +1284,15 @@ packages: promise-polyfill: 8.1.3 dev: false + /duplexify/3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.7 + stream-shift: 1.0.1 + dev: true + /electron-to-chromium/1.4.61: resolution: {integrity: sha512-kpzCOOFlx63C9qKRyIDEsKIUgzoe98ump7T4gU+/OLzj8gYkkWf2SIyBjhTSE0keAjMAp3i7C262YtkQOMYrGw==} dev: true @@ -1122,6 +1305,24 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /end-of-stream/1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + + /ensure-posix-path/1.1.1: + resolution: {integrity: sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==} + dev: true + + /entities/2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: true + + /eol/0.9.1: + resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} + dev: true + /epubjs/0.3.92: resolution: {integrity: sha512-+uo6Up+tieZm9TthPAWMzTzUl2KKArmGdD7UthMRivWs8o2IWDrKmVJ9P3R8f31/03bgnveTkzCQ17Qvg/6+Fw==} dependencies: @@ -1487,7 +1688,6 @@ packages: /extend/3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1551,6 +1751,12 @@ packages: resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} dev: true + /flush-write-stream/1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.7 + dev: true /flv.js/1.6.2: resolution: {integrity: sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==} dependencies: @@ -1579,6 +1785,53 @@ packages: resolution: {integrity: sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==} dev: true + /fs-extra/10.0.0: + resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.9 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.9 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: true + + /fs-merger/3.2.1: + resolution: {integrity: sha512-AN6sX12liy0JE7C2evclwoo0aCG3PFulLjrTLsJpWh/2mM+DinhpSGqYLbHBBbIW1PLRNcFhJG8Axtz8mQW3ug==} + dependencies: + broccoli-node-api: 1.7.0 + broccoli-node-info: 2.2.0 + fs-extra: 8.1.0 + fs-tree-diff: 2.0.1 + walk-sync: 2.2.0 + dev: true + + /fs-mkdirp-stream/1.0.0: + resolution: {integrity: sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=} + engines: {node: '>= 0.10'} + dependencies: + graceful-fs: 4.2.9 + through2: 2.0.5 + dev: true + + /fs-tree-diff/2.0.1: + resolution: {integrity: sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==} + engines: {node: 6.* || 8.* || >= 10.*} + dependencies: + '@types/symlink-or-copy': 1.2.0 + heimdalljs-logger: 0.1.10 + object-assign: 4.1.1 + path-posix: 1.0.0 + symlink-or-copy: 1.3.1 + dev: true + /fs.realpath/1.0.0: resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} dev: true @@ -1615,6 +1868,13 @@ packages: get-intrinsic: 1.1.1 dev: true + /glob-parent/3.1.0: + resolution: {integrity: sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=} + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + dev: true + /glob-parent/5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1629,6 +1889,22 @@ packages: is-glob: 4.0.3 dev: true + /glob-stream/6.1.0: + resolution: {integrity: sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=} + engines: {node: '>= 0.10'} + dependencies: + extend: 3.0.2 + glob: 7.2.0 + glob-parent: 3.1.0 + is-negated-glob: 1.0.0 + ordered-read-streams: 1.0.1 + pumpify: 1.5.1 + readable-stream: 2.3.7 + remove-trailing-separator: 1.1.0 + to-absolute-glob: 2.0.2 + unique-stream: 2.3.1 + dev: true + /glob/7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: @@ -1676,6 +1952,16 @@ packages: csstype: ^2.6.2 dev: false + /graceful-fs/4.2.9: + resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} + dev: true + + /gulp-sort/2.0.0: + resolution: {integrity: sha1-xnYqLx8N4KP8WVohWZ0/rI26Gso=} + dependencies: + through2: 2.0.5 + dev: true + /has-bigints/1.0.1: resolution: {integrity: sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==} dev: true @@ -1796,14 +2082,91 @@ packages: space-separated-tokens: 2.0.1 dev: false + /he/1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /heimdalljs-logger/0.1.10: + resolution: {integrity: sha512-pO++cJbhIufVI/fmB/u2Yty3KJD0TqNPecehFae0/eps0hkZ3b4Zc/PezUMOpYuHFQbA7FxHZxa305EhmjLj4g==} + dependencies: + debug: 2.6.9 + heimdalljs: 0.2.6 + dev: true + + /heimdalljs/0.2.6: + resolution: {integrity: sha512-o9bd30+5vLBvBtzCPwwGqpry2+n0Hi6H1+qwt6y+0kwRHGGF8TFIhJPmnuM0xO97zaKrDZMwO/V56fAnn8m/tA==} + dependencies: + rsvp: 3.2.1 + dev: true + + /hoist-non-react-statics/3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + /hotkeys-js/3.8.7: resolution: {integrity: sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==} dev: false + /html-escaper/2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: false + + /html-parse-stringify/3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + dependencies: + void-elements: 3.1.0 + dev: false + /html-void-elements/2.0.1: resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==} dev: false + /htmlparser2/6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + dependencies: + domelementtype: 2.2.0 + domhandler: 4.3.0 + domutils: 2.8.0 + entities: 2.2.0 + dev: true + + /i18next-fs-backend/1.1.4: + resolution: {integrity: sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA==} + dev: false + + /i18next-parser/5.4.0: + resolution: {integrity: sha512-AkMOy3NW09tnB+4CAVzHVWxhoab8q1L6E3aIugWeTZqbUVYTjb6dtW1AhiiUd4nLMOj29LaaVCkyqOhrTezp7Q==} + engines: {node: '>=12', npm: '>=6', yarn: '>=1'} + hasBin: true + dependencies: + '@babel/runtime': 7.16.7 + broccoli-plugin: 4.0.7 + cheerio: 1.0.0-rc.10 + colors: 1.4.0 + commander: 8.3.0 + concat-stream: 2.0.0 + eol: 0.9.1 + fs-extra: 10.0.0 + gulp-sort: 2.0.0 + i18next: 21.6.10 + js-yaml: 4.1.0 + rsvp: 4.8.5 + sort-keys: 4.2.0 + through2: 4.0.2 + typescript: 4.5.5 + vinyl: 2.2.1 + vinyl-fs: 3.0.3 + vue-template-compiler: 2.6.14 + dev: true + + /i18next/21.6.10: + resolution: {integrity: sha512-Xw+tEGQ61BF6SXtBlFffhM/YhJKHZf2cyDrcNK/l2dE6yVbkPkSasC3VhkAsHXX30vUJ0yG04WIUtf7UvwjOxg==} + dependencies: + '@babel/runtime': 7.16.7 + /ignore/4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} @@ -1873,6 +2236,14 @@ packages: - supports-color dev: false + /is-absolute/1.0.0: + resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} + engines: {node: '>=0.10.0'} + dependencies: + is-relative: 1.0.0 + is-windows: 1.0.2 + dev: true + /is-arrayish/0.2.1: resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=} dev: true @@ -1898,6 +2269,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-buffer/1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: true + /is-buffer/2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} @@ -1926,6 +2301,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-glob/3.1.0: + resolution: {integrity: sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1933,6 +2315,11 @@ packages: is-extglob: 2.1.1 dev: true + /is-negated-glob/1.0.0: + resolution: {integrity: sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=} + engines: {node: '>=0.10.0'} + dev: true + /is-negative-zero/2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -1950,6 +2337,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /is-plain-obj/2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + dev: true + /is-plain-obj/4.0.0: resolution: {integrity: sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==} engines: {node: '>=12'} @@ -1963,6 +2355,13 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-relative/1.0.0: + resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} + engines: {node: '>=0.10.0'} + dependencies: + is-unc-path: 1.0.0 + dev: true + /is-shared-array-buffer/1.0.1: resolution: {integrity: sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==} dev: true @@ -1981,15 +2380,35 @@ packages: has-symbols: 1.0.2 dev: true + /is-unc-path/1.0.0: + resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} + engines: {node: '>=0.10.0'} + dependencies: + unc-path-regex: 0.1.2 + dev: true + + /is-utf8/0.2.1: + resolution: {integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=} + dev: true + + /is-valid-glob/1.0.0: + resolution: {integrity: sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=} + engines: {node: '>=0.10.0'} + dev: true + /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true + /is-windows/1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: true + /isarray/1.0.0: resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=} - dev: false /isexe/2.0.0: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} @@ -2024,6 +2443,20 @@ packages: minimist: 1.2.5 dev: true + /jsonfile/4.0.0: + resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} + optionalDependencies: + graceful-fs: 4.2.9 + dev: true + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.9 + dev: true + /jsx-ast-utils/3.2.1: resolution: {integrity: sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==} engines: {node: '>=4.0'} @@ -2070,6 +2503,20 @@ packages: language-subtag-registry: 0.3.21 dev: true + /lazystream/1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.7 + dev: true + + /lead/1.0.0: + resolution: {integrity: sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=} + engines: {node: '>= 0.10'} + dependencies: + flush-write-stream: 1.1.1 + dev: true + /levn/0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -2158,6 +2605,14 @@ packages: resolution: {integrity: sha512-Ahs4oeG90tbdPWwAJkAAoHg2lRR8lAs9mZXETNPO9hYg3AkjUJBKi1NQ4aaIQZVGrig7c/3NUV1jANl8rFTeMg==} dev: false + /matcher-collection/2.0.1: + resolution: {integrity: sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==} + engines: {node: 6.* || 8.* || >= 10.*} + dependencies: + '@types/minimatch': 3.0.5 + minimatch: 3.0.4 + dev: true + /mdast-util-definitions/5.1.0: resolution: {integrity: sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ==} dependencies: @@ -2567,6 +3022,11 @@ packages: resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} dev: true + /mktemp/0.4.0: + resolution: {integrity: sha1-bQUVYRyKjITkhKogABKbmOmB/ws=} + engines: {node: '>0.9'} + dev: true + /mri/1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -2591,6 +3051,27 @@ packages: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true + /next-i18next/10.2.0_61390be992b634a688f7c2555547b55b: + resolution: {integrity: sha512-HTdXy8U8Ko8oxs+VAog0CQC7Ap/XyvRzwm/g5tF/CzqJ4dSCyWuLmvPjA9BpQ3VEIkxzCA43w1W75CnARRn1lw==} + engines: {node: '>=12'} + peerDependencies: + next: '>= 10.0.0' + react: '>= 16.8.0' + dependencies: + '@babel/runtime': 7.16.7 + '@types/hoist-non-react-statics': 3.3.1 + core-js: 3.21.0 + hoist-non-react-statics: 3.3.2 + i18next: 21.6.10 + i18next-fs-backend: 1.1.4 + next: 12.0.10_react-dom@17.0.2+react@17.0.2 + react: 17.0.2 + react-i18next: 11.15.3_f9635d5d32d7f130f7fe8a33cbdb7283 + transitivePeerDependencies: + - react-dom + - react-native + dev: false + /next-tick/1.0.0: resolution: {integrity: sha1-yobR/ogoFpsBICCOPchCS524NCw=} dev: false @@ -2653,6 +3134,13 @@ packages: resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} dev: true + /normalize-path/2.1.1: + resolution: {integrity: sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=} + engines: {node: '>=0.10.0'} + dependencies: + remove-trailing-separator: 1.1.0 + dev: true + /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2663,10 +3151,23 @@ packages: engines: {node: '>=0.10.0'} dev: true + /now-and-later/2.0.1: + resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==} + engines: {node: '>= 0.10'} + dependencies: + once: 1.4.0 + dev: true + /nprogress/0.2.0: resolution: {integrity: sha1-y480xTIT2JVyP8urkH6UIq28r7E=} dev: false + /nth-check/2.0.1: + resolution: {integrity: sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==} + dependencies: + boolbase: 1.0.0 + dev: true + /object-assign/4.1.1: resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=} engines: {node: '>=0.10.0'} @@ -2751,6 +3252,12 @@ packages: word-wrap: 1.2.3 dev: true + /ordered-read-streams/1.0.1: + resolution: {integrity: sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=} + dependencies: + readable-stream: 2.3.7 + dev: true + /p-limit/1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -2796,9 +3303,18 @@ packages: lines-and-columns: 1.2.4 dev: true + /parse5-htmlparser2-tree-adapter/6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + dependencies: + parse5: 6.0.1 + dev: true + /parse5/6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - dev: false + + /path-dirname/1.0.2: + resolution: {integrity: sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=} + dev: true /path-exists/3.0.0: resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=} @@ -2819,6 +3335,10 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-posix/1.0.0: + resolution: {integrity: sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8=} + dev: true + /path-type/4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -2943,7 +3463,11 @@ packages: /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: false + + /promise-map-series/0.3.0: + resolution: {integrity: sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA==} + engines: {node: 10.* || >= 12.*} + dev: true /promise-polyfill/8.1.3: resolution: {integrity: sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==} @@ -2960,6 +3484,21 @@ packages: resolution: {integrity: sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==} dev: false + /pump/2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /pumpify/1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + dev: true + /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -2974,6 +3513,14 @@ packages: engines: {node: '>=10'} dev: true + /quick-temp/0.1.8: + resolution: {integrity: sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg=} + dependencies: + mktemp: 0.4.0 + rimraf: 2.7.1 + underscore.string: 3.3.6 + dev: true + /react-async-hook/4.0.0_react@17.0.2: resolution: {integrity: sha512-97lgjFkOcHCTYSrsKBpsXg3iVWM0LnzedB749iP76sb3/8Ouu4nHIkCLEOrQWHVYqrYxjF05NN6GHoXWFkB3Kw==} engines: {node: '>=8', npm: '>=5'} @@ -3052,6 +3599,27 @@ packages: react-dom: 17.0.2_react@17.0.2 dev: false + /react-i18next/11.15.3_f9635d5d32d7f130f7fe8a33cbdb7283: + resolution: {integrity: sha512-RSUEM4So3Tu2JHV0JsZ5Yje+4nz66YViMfPZoywxOy0xyn3L7tE2CHvJ7Y9LUsrTU7vGmZ5bwb8PpjnkatdIxg==} + peerDependencies: + i18next: '>= 19.0.0' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@babel/runtime': 7.16.7 + html-escaper: 2.0.2 + html-parse-stringify: 3.0.1 + i18next: 21.6.10 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + dev: false + /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -3122,7 +3690,15 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: false + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -3149,7 +3725,6 @@ packages: /regenerator-runtime/0.13.9: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} - dev: true /regexp.prototype.flags/1.4.1: resolution: {integrity: sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==} @@ -3231,11 +3806,44 @@ packages: unified: 10.1.1 dev: false + /remove-bom-buffer/3.0.0: + resolution: {integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + is-utf8: 0.2.1 + dev: true + + /remove-bom-stream/1.2.0: + resolution: {integrity: sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=} + engines: {node: '>= 0.10'} + dependencies: + remove-bom-buffer: 3.0.0 + safe-buffer: 5.1.2 + through2: 2.0.5 + dev: true + + /remove-trailing-separator/1.1.0: + resolution: {integrity: sha1-wkvOKig62tW8P1jg1IJJuSN52O8=} + dev: true + + /replace-ext/1.0.1: + resolution: {integrity: sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==} + engines: {node: '>= 0.10'} + dev: true + /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} dev: true + /resolve-options/1.1.0: + resolution: {integrity: sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=} + engines: {node: '>= 0.10'} + dependencies: + value-or-function: 3.0.0 + dev: true + /resolve/1.22.0: resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} hasBin: true @@ -3257,6 +3865,13 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true + /rimraf/2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + dependencies: + glob: 7.2.0 + dev: true + /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -3264,6 +3879,15 @@ packages: glob: 7.2.0 dev: true + /rsvp/3.2.1: + resolution: {integrity: sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo=} + dev: true + + /rsvp/4.8.5: + resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} + engines: {node: 6.* || >= 7.*} + dev: true + /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -3279,7 +3903,6 @@ packages: /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: false /scheduler/0.20.2: resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} @@ -3331,6 +3954,13 @@ packages: engines: {node: '>=8'} dev: true + /sort-keys/4.2.0: + resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==} + engines: {node: '>=8'} + dependencies: + is-plain-obj: 2.1.0 + dev: true + /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -3339,10 +3969,18 @@ packages: resolution: {integrity: sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==} dev: false + /sprintf-js/1.1.2: + resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + dev: true + /standard-as-callback/2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} dev: false + /stream-shift/1.0.1: + resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} + dev: true + /string.prototype.matchall/4.0.6: resolution: {integrity: sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==} dependencies: @@ -3374,7 +4012,6 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: false /strip-ansi/6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -3442,6 +4079,10 @@ packages: react: 17.0.2 dev: false + /symlink-or-copy/1.3.1: + resolution: {integrity: sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==} + dev: true + /tailwindcss/3.0.18_833e1018ad0d7954aa80c53675939269: resolution: {integrity: sha512-ihPTpEyA5ANgZbwKlgrbfnzOp9R5vDHFWmqxB1PT8NwOGCOFVVMl+Ps1cQQ369acaqqf1BEF77roCwK0lvNmTw==} engines: {node: '>=12.13.0'} @@ -3480,6 +4121,34 @@ packages: resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} dev: true + /through2-filter/3.0.0: + resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==} + dependencies: + through2: 2.0.5 + xtend: 4.0.2 + dev: true + + /through2/2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.7 + xtend: 4.0.2 + dev: true + + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.0 + dev: true + + /to-absolute-glob/2.0.2: + resolution: {integrity: sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=} + engines: {node: '>=0.10.0'} + dependencies: + is-absolute: 1.0.0 + is-negated-glob: 1.0.0 + dev: true + /to-regex-range/5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -3487,6 +4156,13 @@ packages: is-number: 7.0.0 dev: true + /to-through/2.0.0: + resolution: {integrity: sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=} + engines: {node: '>= 0.10'} + dependencies: + through2: 2.0.5 + dev: true + /toggle-selection/1.0.6: resolution: {integrity: sha1-bkWxJj8gF/oKzH2J14sVuL932jI=} dev: false @@ -3508,6 +4184,10 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true + /tslib/2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + dev: true + /tsutils/3.21.0_typescript@4.5.5: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -3538,6 +4218,10 @@ packages: resolution: {integrity: sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==} dev: false + /typedarray/0.0.6: + resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=} + dev: true + /typescript/4.5.5: resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==} engines: {node: '>=4.2.0'} @@ -3553,6 +4237,18 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /unc-path-regex/0.1.2: + resolution: {integrity: sha1-5z3T17DXxe2G+6xrCufYxqadUPo=} + engines: {node: '>=0.10.0'} + dev: true + + /underscore.string/3.3.6: + resolution: {integrity: sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==} + dependencies: + sprintf-js: 1.1.2 + util-deprecate: 1.0.2 + dev: true + /unified/10.1.1: resolution: {integrity: sha512-v4ky1+6BN9X3pQrOdkFIPWAaeDsHPE1svRDxq7YpTc2plkIqFMwukfqM+l0ewpP9EfwARlt9pPFAeWYhHm8X9w==} dependencies: @@ -3565,6 +4261,13 @@ packages: vfile: 5.3.0 dev: false + /unique-stream/2.3.1: + resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==} + dependencies: + json-stable-stringify-without-jsonify: 1.0.1 + through2-filter: 3.0.0 + dev: true + /unist-builder/3.0.0: resolution: {integrity: sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==} dependencies: @@ -3633,6 +4336,16 @@ packages: unist-util-visit-parents: 5.1.0 dev: false + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: true + + /universalify/2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -3683,6 +4396,11 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true + /value-or-function/3.0.0: + resolution: {integrity: sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=} + engines: {node: '>= 0.10'} + dev: true + /vary/1.1.2: resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=} engines: {node: '>= 0.8'} @@ -3711,6 +4429,76 @@ packages: vfile-message: 3.1.0 dev: false + /vinyl-fs/3.0.3: + resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==} + engines: {node: '>= 0.10'} + dependencies: + fs-mkdirp-stream: 1.0.0 + glob-stream: 6.1.0 + graceful-fs: 4.2.9 + is-valid-glob: 1.0.0 + lazystream: 1.0.1 + lead: 1.0.0 + object.assign: 4.1.2 + pumpify: 1.5.1 + readable-stream: 2.3.7 + remove-bom-buffer: 3.0.0 + remove-bom-stream: 1.2.0 + resolve-options: 1.1.0 + through2: 2.0.5 + to-through: 2.0.0 + value-or-function: 3.0.0 + vinyl: 2.2.1 + vinyl-sourcemap: 1.1.0 + dev: true + + /vinyl-sourcemap/1.1.0: + resolution: {integrity: sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=} + engines: {node: '>= 0.10'} + dependencies: + append-buffer: 1.0.2 + convert-source-map: 1.8.0 + graceful-fs: 4.2.9 + normalize-path: 2.1.1 + now-and-later: 2.0.1 + remove-bom-buffer: 3.0.0 + vinyl: 2.2.1 + dev: true + + /vinyl/2.2.1: + resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==} + engines: {node: '>= 0.10'} + dependencies: + clone: 2.1.2 + clone-buffer: 1.0.0 + clone-stats: 1.0.0 + cloneable-readable: 1.1.3 + remove-trailing-separator: 1.1.0 + replace-ext: 1.0.1 + dev: true + + /void-elements/3.1.0: + resolution: {integrity: sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=} + engines: {node: '>=0.10.0'} + dev: false + + /vue-template-compiler/2.6.14: + resolution: {integrity: sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /walk-sync/2.2.0: + resolution: {integrity: sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==} + engines: {node: 8.* || >= 10.*} + dependencies: + '@types/minimatch': 3.0.5 + ensure-posix-path: 1.1.1 + matcher-collection: 2.0.1 + minimatch: 3.0.4 + dev: true + /web-namespaces/2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} dev: false diff --git a/public/locales/en/common.json b/public/locales/en/common.json new file mode 100644 index 0000000..340a306 --- /dev/null +++ b/public/locales/en/common.json @@ -0,0 +1,111 @@ +{ + "- showing {{count}} page(s) ——one": "- showing {{count}} page ", + "- showing {{count}} page(s) ——other": "- showing {{count}} pages ", + "{{count}} item(s)——one": "{{count}} item", + "{{count}} item(s)——other": "{{count}} items", + "<0> If you are not the owner of this website, stop now, as continuing with this process may expose your personal files in OneDrive.": "<0> If you are not the owner of this website, stop now, as continuing with this process may expose your personal files in OneDrive.", + "<0> If you have not specified a REDIS_URL inside your Vercel env variable, go initialise one at <3>Upstash. Docs: <6>Vercel Integration - Upstash.": "<0> If you have not specified a REDIS_URL inside your Vercel env variable, go initialise one at <3>Upstash. Docs: <6>Vercel Integration - Upstash.", + "<0> If you see anything missing or incorrect, you need to reconfigure <3>/config/api.config.js and redeploy this instance.": "<0> If you see anything missing or incorrect, you need to reconfigure <3>/config/api.config.js and redeploy this instance.", + "✅ You can now proceed onto the next step: requesting your access token and refresh token.": "✅ You can now proceed onto the next step: requesting your access token and refresh token.", + "❌ No valid code extracted.": "❌ No valid code extracted.", + "Acquired access_token: ": "Acquired access_token: ", + "Acquired refresh_token: ": "Acquired refresh_token: ", + "Actions": "Actions", + "Authorisation is required as no valid <2>access_token or <5>refresh_token is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "Authorisation is required as no valid <2>access_token or <5>refresh_token is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.", + "Cancel": "Cancel", + "Cannot preview {{path}}": "Cannot preview {{path}}", + "Check out <2>Microsoft's official explanation on the error message.": "Check out <2>Microsoft's official explanation on the error message.", + "Clear all": "Clear all", + "Clear all tokens?": "Clear all tokens?", + "Cleared all tokens": "Cleared all tokens", + "clearing them means that you will need to re-enter the passwords again.": "clearing them means that you will need to re-enter the passwords again.", + "Copied direct link to clipboard.": "Copied direct link to clipboard.", + "Copied folder permalink.": "Copied folder permalink.", + "Copied raw file permalink.": "Copied raw file permalink.", + "Copy direct link": "Copy direct link", + "Copy folder permalink": "Copy folder permalink", + "Copy raw file permalink": "Copy raw file permalink", + "Copy the permalink to the file to the clipboard": "Copy the permalink to the file to the clipboard", + "Do not pretend to be the site owner": "Do not pretend to be the site owner", + "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.", + "Download": "Download", + "Download file": "Download file", + "Download folder": "Download folder", + "Download selected files": "Download selected files", + "Download the file directly through OneDrive": "Download the file directly through OneDrive", + "Downloading {{progress}}%": "Downloading {{progress}}%", + "Downloading folder, refresh page to cancel": "Downloading folder, refresh page to cancel", + "Downloading selected files, refresh page to cancel": "Downloading selected files, refresh page to cancel", + "Downloading selected files...": "Downloading selected files...", + "Email": "Email", + "Enter Password": "Enter Password", + "Error storing the token": "Error storing the token", + "Error validating identify, restart": "Error validating identify, restart", + "Error: {{message}}": "Error: {{message}}", + "Failed to download folder {{path}}: {{status}} {{message}} Skipped it to continue.": "Failed to download folder {{path}}: {{status}} {{message}} Skipped it to continue.", + "Failed to download folder.": "Failed to download folder.", + "Failed to download selected files.": "Failed to download selected files.", + "File is empty.": "File is empty.", + "File size": "File size", + "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ", + "Finished downloading folder.": "Finished downloading folder.", + "Finished downloading selected files.": "Finished downloading selected files.", + "Get tokens": "Get tokens", + "Grid": "Grid", + "Hashes": "Hashes", + "Home": "Home", + "If you go back home and still see the welcome page telling you to re-authenticate, ": "If you go back home and still see the welcome page telling you to re-authenticate, ", + "If you know the password, please enter it below.": "If you know the password, please enter it below.", + "Last modified": "Last modified", + "Last Modified": "Last Modified", + "Last modified:": "Last modified:", + "List": "List", + "Load more": "Load more", + "Loading ...": "Loading ...", + "Loading EPUB ...": "Loading EPUB ...", + "Loading file content...": "Loading file content...", + "Loading FLV extension...": "Loading FLV extension...", + "Logout": "Logout", + "MIME type": "MIME type", + "Name": "Name", + "No more files": "No more files", + "Nothing here.": "Nothing here.", + "OAuth Step 1 - {{title}}": "OAuth Step 1 - {{title}}", + "OAuth Step 2 - {{title}}": "OAuth Step 2 - {{title}}", + "OAuth Step 3 - {{title}}": "OAuth Step 3 - {{title}}", + "of {{count}} file(s) -——loaded——one": "of {{count}} file -", + "of {{count}} file(s) -——loaded——other": "of {{count}} files -", + "of {{count}} file(s) -——loading——one": "of ... file(s) -", + "of {{count}} file(s) -——loading——other": "of ... file(s) -", + "Oops, that's a <1>four-oh-four.": "Oops, that's a <1>four-oh-four.", + "Open URL": "Open URL", + "Open URL{{url}}": "Open URL{{url}}", + "Press <2>F12 and open devtools for more details, or seek help at <6>onedrive-vercel-index discussions.": "Press <2>F12 and open devtools for more details, or seek help at <6>onedrive-vercel-index discussions.", + "Proceed to OAuth": "Proceed to OAuth", + "Requesting tokens": "Requesting tokens", + "Restart": "Restart", + "revisit home and do a hard refresh.": "revisit home and do a hard refresh.", + "Search ...": "Search ...", + "Select all files": "Select all files", + "Select file": "Select file", + "Select files": "Select files", + "Size": "Size", + "Step 1/3: Preparations": "Step 1/3: Preparations", + "Step 2/3: Get authorisation code": "Step 2/3: Get authorisation code", + "Step 3/3: Get access and refresh tokens": "Step 3/3: Get access and refresh tokens", + "Store tokens": "Store tokens", + "Stored! Going home...": "Stored! Going home...", + "Storing tokens": "Storing tokens", + "Success! The API returned what we needed.": "Success! The API returned what we needed.", + "The authorisation code extracted is:": "The authorisation code extracted is:", + "The OAuth link for getting the authorisation code has been created. Click on the link above to get the <2>authorisation code. Your browser willopen a new tab to Microsoft's account login page. After logging in and authenticating with your Microsoft account, you will be redirected to a blank page on localhost. Paste <6>the entire redirected URL down below.": "The OAuth link for getting the authorisation code has been created. Click on the link above to get the <2>authorisation code. Your browser willopen a new tab to Microsoft's account login page. After logging in and authenticating with your Microsoft account, you will be redirected to a blank page on localhost. Paste <6>the entire redirected URL down below.", + "These tokens are used to authenticate yourself into password protected folders, ": "These tokens are used to authenticate yourself into password protected folders, ", + "These tokens may take a few seconds to populate after you click the button below. ": "These tokens may take a few seconds to populate after you click the button below. ", + "This route (the folder itself and the files inside) is password protected. ": "This route (the folder itself and the files inside) is password protected. ", + "Unavailable": "Unavailable", + "Waiting for code...": "Waiting for code...", + "Weibo": "Weibo", + "Welcome to your new onedrive-vercel-index 🎉": "Welcome to your new onedrive-vercel-index 🎉", + "Where is the auth code? Did you follow step 2 you silly donut?": "Where is the auth code? Did you follow step 2 you silly donut?", + "Whoops, looks like we got a problem: {{error}}.": "Whoops, looks like we got a problem: {{error}}." +} diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json new file mode 100644 index 0000000..62236ef --- /dev/null +++ b/public/locales/zh-CN/common.json @@ -0,0 +1,107 @@ +{ + "- showing {{count}} page(s) ——other": "已显示 {{count}} 页", + "{{count}} item(s)——other": "{{count}} 个项目", + "<0> If you are not the owner of this website, stop now, as continuing with this process may expose your personal files in OneDrive.": "<0> 如果你不是这个网站的所有者,请立即停止操作,因为接下来的操作可能会暴露你的 OneDrive 私人文件。", + "<0> If you have not specified a REDIS_URL inside your Vercel env variable, go initialise one at <3>Upstash. Docs: <6>Vercel Integration - Upstash.": "<0> 如果你还没有在 Vercel 中设置环境变量 REDIS_URL,你可以从 <3>Upstash 处获取一个来使用。文档:<6>Vercel 集成 - Upstash。", + "<0> If you see anything missing or incorrect, you need to reconfigure <3>/config/api.config.js and redeploy this instance.": "<0> 如果你看到有遗漏或错误的项目,你需要重新编辑 <3>/config/api.config.js 并重新部署这个实例。", + "✅ You can now proceed onto the next step: requesting your access token and refresh token.": "✅ 你现在可以进行下一步了:获取你的 access token 和 refresh token。", + "❌ No valid code extracted.": "❌ 无法提取授权码。", + "Acquired access_token: ": "获取 access_token", + "Acquired refresh_token: ": "获取 refresh_token", + "Actions": "操作", + "Authorisation is required as no valid <2>access_token or <5>refresh_token is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "本项目还没有设置有效的 <2>access_token 和 <5>refresh_token,需要进行授权。在继续对 onedrive-vercel-index 授权你的 Microsoft 帐号前,请检查一下下方的配置信息。", + "Cancel": "取消", + "Cannot preview {{path}}": "无法预览 {{path}}", + "Check out <2>Microsoft's official explanation on the error message.": "请查阅 <2>Microsoft 官方解释 以获取详细的错误信息。", + "Clear all": "清除所有密钥", + "Clear all tokens?": "清除所有密钥?", + "Cleared all tokens": "已清除所有密钥", + "clearing them means that you will need to re-enter the passwords again.": "清除它们意味着下次访问时你需要重新输入密钥。", + "Copied direct link to clipboard.": "已复制直链到剪贴板。", + "Copied folder permalink.": "已复制文件夹永久链接。", + "Copied raw file permalink.": "已复制文件永久链接。", + "Copy direct link": "复制文件直链", + "Copy folder permalink": "复制文件夹永久链接", + "Copy raw file permalink": "复制文件永久链接", + "Copy the permalink to the file to the clipboard": "复制文件永久链接到剪贴板", + "Do not pretend to be the site owner": "你不是网站所有者", + "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "别担心,存储它们之后,onedrive-vercel-index 会在帮助你定时更新 token", + "Download": "下载", + "Download file": "下载此文件", + "Download folder": "下载此文件夹", + "Download selected files": "下载选定文件", + "Download the file directly through OneDrive": "直接从 OneDrive 下载文件", + "Downloading {{progress}}%": "已下载 {{progress}}%", + "Downloading folder, refresh page to cancel": "下载文件夹中,刷新页面以取消", + "Downloading selected files, refresh page to cancel": "下载选定文件中,刷新页面以取消", + "Downloading selected files...": "下载选定文件中…", + "Email": "电子邮件", + "Enter Password": "输入密码", + "Error storing the token": "存储 token 时出错", + "Error validating identify, restart": "校验身份出错,需要重新开始", + "Error: {{message}}": "错误:{{message}}", + "Failed to download folder {{path}}: {{status}} {{message}} Skipped it to continue.": "下载文件夹 {{path}} 失败:{{status}} {{message}} 已忽略此错误并继续下载。", + "Failed to download folder.": "下载文件夹失败。", + "Failed to download selected files.": "下载选定文件失败。", + "File is empty.": "文件为空。", + "File size": "文件大小", + "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "最后一步,在这些 tokens 于 {{minutes}} 分钟 {{seconds}} 秒后失效前,点击下方按钮以永久存储这些 tokens", + "Finished downloading folder.": "下载文件夹成功。", + "Finished downloading selected files.": "下载选定文件成功。", + "Get tokens": "获取 tokens", + "Grid": "图格", + "Hashes": "哈希值", + "Home": "首页", + "If you go back home and still see the welcome page telling you to re-authenticate, ": "如果你回到首页却仍然发现欢迎界面在提示你重新认证,", + "If you know the password, please enter it below.": "如果你知晓密码,请在下面输入。", + "Last modified": "最后修改时间", + "Last Modified": "最后修改时间", + "Last modified:": "最后修改时间:", + "List": "列表", + "Load more": "加载更多", + "Loading ...": "加载中…", + "Loading EPUB ...": "加载 EPUB 中…", + "Loading file content...": "加载文件内容中…", + "Loading FLV extension...": "加载 FLV 扩展中…", + "Logout": "注销", + "MIME type": "MIME 类型", + "Name": "文件名", + "No more files": "加载完毕", + "Nothing here.": "无内容。", + "OAuth Step 1 - {{title}}": "OAuth 第 1 步 - {{title}}", + "OAuth Step 2 - {{title}}": "OAuth 第 2 步 - {{title}}", + "OAuth Step 3 - {{title}}": "OAuth 第 3 步 - {{title}}", + "of {{count}} file(s) -——loaded——other": "共 {{count}} 个文件", + "of {{count}} file(s) -——loading——other": "共…个文件", + "Oops, that's a <1>four-oh-four.": "Oops,这里是 <1>404 页面。", + "Open URL": "打开 URL", + "Open URL{{url}}": "打开 URL{{url}}", + "Press <2>F12 and open devtools for more details, or seek help at <6>onedrive-vercel-index discussions.": "请按下 <2>F12 来打开开发者工具窗口以获取详细信息,或是到 <6>onedrive-vercel-index 社区讨论 处寻求帮助。", + "Proceed to OAuth": "继续进行 OAuth", + "Requesting tokens": "正在获取 token", + "Restart": "重新开始", + "revisit home and do a hard refresh.": "重新访问首页并刷新浏览器", + "Search ...": "搜索…", + "Select all files": "选择所有文件", + "Select file": "选择此文件", + "Select files": "选择以下文件", + "Size": "文件大小", + "Step 1/3: Preparations": "步骤 1/3:准备", + "Step 2/3: Get authorisation code": "步骤 2/3:获取授权码", + "Step 3/3: Get access and refresh tokens": "步骤 3/3:获取 access token 和 refresh token", + "Store tokens": "储存 tokens", + "Stored! Going home...": "已存储!正在返回首页…", + "Storing tokens": "正在存储 token…", + "Success! The API returned what we needed.": "成功!需要的 token 已被返回。", + "The authorisation code extracted is:": "提取出的授权码为:", + "The OAuth link for getting the authorisation code has been created. Click on the link above to get the <2>authorisation code. Your browser willopen a new tab to Microsoft's account login page. After logging in and authenticating with your Microsoft account, you will be redirected to a blank page on localhost. Paste <6>the entire redirected URL down below.": "创建出的这个 OAuth 链接是用来获取授权码的。点击上方链接以获取所需的 <2>授权码。你的浏览器将在新的标签页打开 Microsoft 帐号登录页面。在登录并验证你的 Microsoft 帐号之后,你将被重定向到一个域名为 localhost 的空白页面。请将<6>完整的重定向后的 URL 整体复制粘贴到下方。", + "These tokens are used to authenticate yourself into password protected folders, ": "这些密钥是用来验证你的身份以访问密钥保护下的文件夹的,", + "These tokens may take a few seconds to populate after you click the button below. ": "当你点击下方按钮之后,这些 tokens 可能需要几秒钟来生成出现。", + "This route (the folder itself and the files inside) is password protected. ": "此路由(此文件夹和其中的文件)是受密钥保护的。", + "Unavailable": "无", + "Waiting for code...": "等待授权码…", + "Weibo": "微博", + "Welcome to your new onedrive-vercel-index 🎉": "欢迎来到你崭新的 onedrive-vercel-index 🎉", + "Where is the auth code? Did you follow step 2 you silly donut?": "授权码呢?你遵守了第 2 步吗?你这个傻瓜甜甜圈!o( ̄ヘ ̄o#)", + "Whoops, looks like we got a problem: {{error}}.": "Whoops,看来我们遇到了一个问题:{{error}}" +}