mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-22 09:13:18 +03:00
feat(i18n): static type on i18n (#2225)
This commit is contained in:
parent
66c3b09c67
commit
3d43e61087
1
.gitignore
vendored
1
.gitignore
vendored
@ -57,6 +57,7 @@ Thumbs.db
|
||||
.next
|
||||
out/
|
||||
storybook-static
|
||||
i18n_generated.ts
|
||||
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
|
21
.i18n-codegen.json
Normal file
21
.i18n-codegen.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "./node_modules/@magic-works/i18n-codegen/schema.json",
|
||||
"version": 1,
|
||||
"list": [
|
||||
{
|
||||
"input": "./packages/i18n/src/resources/en.json",
|
||||
"output": "./packages/i18n/src/i18n_generated",
|
||||
"parser": {
|
||||
"type": "i18next",
|
||||
"contextSeparator": "$",
|
||||
"pluralSeparator": "_"
|
||||
},
|
||||
"generator": {
|
||||
"type": "i18next/react-hooks",
|
||||
"hooks": "useAFFiNEI18N",
|
||||
"emitTS": true,
|
||||
"shouldUnescape": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -2,10 +2,12 @@
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
|
||||
import { runCli } from '@magic-works/i18n-codegen';
|
||||
import { PerfseePlugin } from '@perfsee/webpack';
|
||||
import { withSentryConfig } from '@sentry/nextjs';
|
||||
import SentryWebpackPlugin from '@sentry/webpack-plugin';
|
||||
import debugLocal from 'next-debug-local';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { blockSuiteFeatureFlags, buildFlags } from './preset.config.mjs';
|
||||
import { getCommitHash, getGitVersion } from './scripts/gitInfo.mjs';
|
||||
@ -17,6 +19,21 @@ const withVanillaExtract = createVanillaExtractPlugin();
|
||||
console.info('Build Flags', buildFlags);
|
||||
console.info('Editor Flags', blockSuiteFeatureFlags);
|
||||
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
await runCli(
|
||||
{
|
||||
config: fileURLToPath(
|
||||
new URL('../../.i18n-codegen.json', import.meta.url)
|
||||
),
|
||||
watch: false,
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const enableDebugLocal = path.isAbsolute(process.env.LOCAL_BLOCK_SUITE ?? '');
|
||||
|
||||
if (enableDebugLocal) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IconButton, Modal, ModalWrapper } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import type React from 'react';
|
||||
|
||||
@ -17,7 +17,7 @@ export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({
|
||||
open,
|
||||
onClose,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const user = useCurrentUser();
|
||||
|
||||
return (
|
||||
@ -33,8 +33,8 @@ export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({
|
||||
</IconButton>
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentTitle>{t('Enable AFFiNE Cloud')}?</ContentTitle>
|
||||
<StyleTips>{t('Enable AFFiNE Cloud Description')}</StyleTips>
|
||||
<ContentTitle>{t['Enable AFFiNE Cloud']()}?</ContentTitle>
|
||||
<StyleTips>{t['Enable AFFiNE Cloud Description']()}</StyleTips>
|
||||
{/* <StyleTips>{t('Retain cached cloud data')}</StyleTips> */}
|
||||
<div>
|
||||
<StyleButton
|
||||
@ -45,7 +45,7 @@ export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({
|
||||
onConfirm();
|
||||
}}
|
||||
>
|
||||
{user ? t('Enable') : t('Sign in and Enable')}
|
||||
{user ? t.Enable() : t['Sign in and Enable']()}
|
||||
</StyleButton>
|
||||
<StyleButton
|
||||
shape="round"
|
||||
@ -53,7 +53,7 @@ export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Not now')}
|
||||
{t['Not now']()}
|
||||
</StyleButton>
|
||||
</div>
|
||||
</Content>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MenuItem } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CopyIcon } from '@blocksuite/icons';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
@ -8,11 +8,11 @@ import { toast } from '../../../utils';
|
||||
import type { CommonMenuItemProps } from './types';
|
||||
|
||||
export const CopyLink = ({ onItemClick, onSelect }: CommonMenuItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const copyUrl = useCallback(() => {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
toast(t('Copied link to clipboard'));
|
||||
toast(t['Copied link to clipboard']());
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
@ -25,7 +25,7 @@ export const CopyLink = ({ onItemClick, onSelect }: CommonMenuItemProps) => {
|
||||
}}
|
||||
icon={<CopyIcon />}
|
||||
>
|
||||
{t('Copy Link')}
|
||||
{t['Copy Link']()}
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { MenuItem, styled } from '@affine/component';
|
||||
import type { PublicLinkDisableProps } from '@affine/component/share-menu';
|
||||
import { PublicLinkDisableModal } from '@affine/component/share-menu';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ShareIcon } from '@blocksuite/icons';
|
||||
|
||||
import type { CommonMenuItemProps } from './types';
|
||||
@ -29,7 +29,7 @@ export const DisablePublicSharing = ({
|
||||
onItemClick,
|
||||
testId,
|
||||
}: CommonMenuItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<>
|
||||
<StyledMenuItem
|
||||
@ -41,7 +41,7 @@ export const DisablePublicSharing = ({
|
||||
style={{ color: 'red' }}
|
||||
icon={<ShareIcon />}
|
||||
>
|
||||
{t('Disable Public Sharing')}
|
||||
{t['Disable Public Sharing']()}
|
||||
</StyledMenuItem>
|
||||
</>
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Menu, MenuItem } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
||||
import {
|
||||
ArrowRightSmallIcon,
|
||||
@ -15,7 +15,7 @@ export const Export = ({
|
||||
onSelect,
|
||||
onItemClick,
|
||||
}: CommonMenuItemProps<{ type: 'markdown' | 'html' }>) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
return (
|
||||
<Menu
|
||||
@ -37,7 +37,7 @@ export const Export = ({
|
||||
}}
|
||||
icon={<ExportToHtmlIcon />}
|
||||
>
|
||||
{t('Export to HTML')}
|
||||
{t['Export to HTML']()}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
data-testid="export-to-markdown"
|
||||
@ -52,7 +52,7 @@ export const Export = ({
|
||||
}}
|
||||
icon={<ExportToMarkdownIcon />}
|
||||
>
|
||||
{t('Export to Markdown')}
|
||||
{t['Export to Markdown']()}
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
@ -66,7 +66,7 @@ export const Export = ({
|
||||
onItemClick?.();
|
||||
}}
|
||||
>
|
||||
{t('Export')}
|
||||
{t.Export()}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MenuItem } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon, MoveToIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useRef, useState } from 'react';
|
||||
@ -27,7 +27,7 @@ export const MoveTo = ({
|
||||
onSelect,
|
||||
onItemClick,
|
||||
}: MoveToProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||
const open = anchorEl !== null;
|
||||
@ -44,7 +44,7 @@ export const MoveTo = ({
|
||||
endIcon={<ArrowRightSmallIcon />}
|
||||
data-testid="move-to-menu-item"
|
||||
>
|
||||
{t('Move to')}
|
||||
{t['Move to']()}
|
||||
</MenuItem>
|
||||
<PinboardMenu
|
||||
anchorEl={anchorEl}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { ConfirmProps } from '@affine/component';
|
||||
import { Confirm, MenuItem } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { DeleteTemporarilyIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
|
||||
@ -11,7 +11,7 @@ export const MoveToTrash = ({
|
||||
onItemClick,
|
||||
testId,
|
||||
}: CommonMenuItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -23,7 +23,7 @@ export const MoveToTrash = ({
|
||||
}}
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
>
|
||||
{t('Move to Trash')}
|
||||
{t['Move to Trash']()}
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
@ -35,15 +35,15 @@ const ConfirmModal = ({
|
||||
}: {
|
||||
meta: PageMeta;
|
||||
} & ConfirmProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<Confirm
|
||||
title={t('Delete page?')}
|
||||
content={t('will be moved to Trash', {
|
||||
title={t['Delete page?']()}
|
||||
content={t['will be moved to Trash']({
|
||||
title: meta.title || 'Untitled',
|
||||
})}
|
||||
confirmText={t('Delete')}
|
||||
confirmText={t.Delete()}
|
||||
confirmType="danger"
|
||||
{...confirmModalProps}
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { FlexWrapper } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useAtomValue } from 'jotai';
|
||||
@ -16,14 +16,14 @@ export const SearchContent = ({
|
||||
results: PageMeta[];
|
||||
onClick?: (dropId: string) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const record = useAtomValue(workspacePreferredModeAtom);
|
||||
|
||||
if (results.length) {
|
||||
return (
|
||||
<>
|
||||
<StyledMenuSubTitle>
|
||||
{t('Find results', { number: results.length })}
|
||||
{t['Find results']({ number: `${results.length}` })}
|
||||
</StyledMenuSubTitle>
|
||||
{results.map(meta => {
|
||||
return (
|
||||
@ -45,7 +45,7 @@ export const SearchContent = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledMenuSubTitle>{t('Find 0 result')}</StyledMenuSubTitle>
|
||||
<StyledMenuSubTitle>{t['Find 0 result']()}</StyledMenuSubTitle>
|
||||
<FlexWrapper
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { PureMenuProps } from '@affine/component';
|
||||
import { Input, PureMenu, TreeView } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { RemoveIcon, SearchIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
@ -40,7 +40,7 @@ export const PinboardMenu = ({
|
||||
() => propsMetas.filter(m => m.id !== currentMeta.id),
|
||||
[currentMeta.id, propsMetas]
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [query, setQuery] = useState('');
|
||||
const isSearching = query.length > 0;
|
||||
|
||||
@ -92,7 +92,7 @@ export const PinboardMenu = ({
|
||||
<Input
|
||||
value={query}
|
||||
onChange={setQuery}
|
||||
placeholder={t('Move page to...')}
|
||||
placeholder={t['Move page to...']()}
|
||||
height={32}
|
||||
noBorder={true}
|
||||
onClick={e => e.stopPropagation()}
|
||||
@ -121,9 +121,9 @@ export const PinboardMenu = ({
|
||||
}}
|
||||
>
|
||||
<RemoveIcon />
|
||||
{t('Remove from Pinboard')}
|
||||
{t['Remove from Pivots']()}
|
||||
</StyledPinboard>
|
||||
<p>{t('RFP')}</p>
|
||||
<p>{t['RFP']()}</p>
|
||||
</StyledMenuFooter>
|
||||
)}
|
||||
</PureMenu>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import { StyledPinboard } from '../styles';
|
||||
|
||||
export const EmptyItem = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<StyledPinboard disable={true} textWrap={true}>
|
||||
{t('Organize pages to build knowledge')}
|
||||
{t['Organize pages to build knowledge']()}
|
||||
</StyledPinboard>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MenuItem, MuiClickAwayListener, PureMenu } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
MoreVerticalIcon,
|
||||
MoveToIcon,
|
||||
@ -39,7 +39,7 @@ export const OperationButton = ({
|
||||
onMenuClose,
|
||||
onRename,
|
||||
}: OperationButtonProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const timer = useRef<ReturnType<typeof setTimeout>>();
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
@ -100,7 +100,7 @@ export const OperationButton = ({
|
||||
}}
|
||||
icon={<PlusIcon />}
|
||||
>
|
||||
{t('Add a subpage inside')}
|
||||
{t['Add a subpage inside']()}
|
||||
</MenuItem>
|
||||
{!isRoot && (
|
||||
<MenuItem
|
||||
@ -111,7 +111,7 @@ export const OperationButton = ({
|
||||
}}
|
||||
icon={<MoveToIcon />}
|
||||
>
|
||||
{t('Move to')}
|
||||
{t['Move to']()}
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isRoot && (
|
||||
@ -124,7 +124,7 @@ export const OperationButton = ({
|
||||
}}
|
||||
icon={<PenIcon />}
|
||||
>
|
||||
{t('Rename')}
|
||||
{t['Rename']()}
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isRoot && (
|
||||
@ -154,7 +154,7 @@ export const OperationButton = ({
|
||||
open={confirmModalOpen}
|
||||
meta={currentMeta}
|
||||
onConfirm={() => {
|
||||
toast(t('Moved to Trash'));
|
||||
toast(t['Moved to Trash']());
|
||||
removeToTrash(currentMeta.id);
|
||||
onDelete();
|
||||
}}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { appSidebarOpenAtom } from '@affine/component/app-sidebar';
|
||||
import { getEnvironment } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@ -21,7 +21,7 @@ export const SidebarSwitch = ({
|
||||
}: SidebarSwitchProps) => {
|
||||
const [open, setOpen] = useAtom(appSidebarOpenAtom);
|
||||
const [tooltipVisible, setTooltipVisible] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const checkIsMac = () => {
|
||||
const env = getEnvironment();
|
||||
return env.isBrowser && env.isMacOs;
|
||||
@ -34,7 +34,7 @@ export const SidebarSwitch = ({
|
||||
}, []);
|
||||
|
||||
tooltipContent =
|
||||
tooltipContent || (open ? t('Collapse sidebar') : t('Expand sidebar'));
|
||||
tooltipContent || (open ? t['Collapse sidebar']() : t['Expand sidebar']());
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IconButton, Modal, ModalWrapper } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import type React from 'react';
|
||||
|
||||
@ -15,7 +15,7 @@ export type TransformWorkspaceToAffineModalProps = {
|
||||
export const TransformWorkspaceToAffineModal: React.FC<
|
||||
TransformWorkspaceToAffineModalProps
|
||||
> = ({ open, onClose, onConform }) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const user = useCurrentUser();
|
||||
|
||||
return (
|
||||
@ -35,8 +35,8 @@ export const TransformWorkspaceToAffineModal: React.FC<
|
||||
</IconButton>
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentTitle>{t('Enable AFFiNE Cloud')}?</ContentTitle>
|
||||
<StyleTips>{t('Enable AFFiNE Cloud Description')}</StyleTips>
|
||||
<ContentTitle>{t['Enable AFFiNE Cloud']()}?</ContentTitle>
|
||||
<StyleTips>{t['Enable AFFiNE Cloud Description']()}</StyleTips>
|
||||
{/* <StyleTips>{t('Retain cached cloud data')}</StyleTips> */}
|
||||
<div>
|
||||
<StyleButton
|
||||
@ -61,7 +61,7 @@ export const TransformWorkspaceToAffineModal: React.FC<
|
||||
// setLoading(false);
|
||||
}}
|
||||
>
|
||||
{user ? t('Enable') : t('Sign in and Enable')}
|
||||
{user ? t['Enable']() : t['Sign in and Enable']()}
|
||||
</StyleButton>
|
||||
<StyleButton
|
||||
shape="round"
|
||||
@ -69,7 +69,7 @@ export const TransformWorkspaceToAffineModal: React.FC<
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Not now')}
|
||||
{t['Not now']()}
|
||||
</StyleButton>
|
||||
</div>
|
||||
</Content>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { SettingPanel, WorkspaceRegistry } from '@affine/workspace/type';
|
||||
import { settingPanel, WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { MouseEvent } from 'react';
|
||||
@ -39,6 +39,7 @@ export type WorkspaceSettingDetailProps = {
|
||||
|
||||
export type PanelProps = WorkspaceSettingDetailProps;
|
||||
|
||||
type Name = 'General' | 'Sync' | 'Collaboration' | 'Publish' | 'Export';
|
||||
const panelMap = {
|
||||
[settingPanel.General]: {
|
||||
name: 'General',
|
||||
@ -63,7 +64,7 @@ const panelMap = {
|
||||
},
|
||||
} satisfies {
|
||||
[Key in SettingPanel]: {
|
||||
name: string;
|
||||
name: Name;
|
||||
enable?: (flavour: WorkspaceFlavour) => boolean;
|
||||
ui: React.FC<PanelProps>;
|
||||
};
|
||||
@ -96,7 +97,7 @@ export const WorkspaceSettingDetail: React.FC<
|
||||
if (!(currentTab in panelMap)) {
|
||||
throw new Error('Invalid activeTab: ' + currentTab);
|
||||
}
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const workspaceId = workspace.id;
|
||||
useEffect(() => {
|
||||
if (isAffine && isOwner) {
|
||||
@ -148,7 +149,7 @@ export const WorkspaceSettingDetail: React.FC<
|
||||
data-tab-key={key}
|
||||
onClick={handleTabClick}
|
||||
>
|
||||
{t(value.name)}
|
||||
{t[value.name]()}
|
||||
</WorkspaceSettingTagItem>
|
||||
);
|
||||
})}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button, IconButton, Menu, MenuItem, Wrapper } from '@affine/component';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { PermissionType } from '@affine/workspace/affine/api';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
@ -41,7 +41,7 @@ const AffineRemoteCollaborationPanel: React.FC<
|
||||
}
|
||||
> = ({ workspace }) => {
|
||||
const [isInviteModalShow, setIsInviteModalShow] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const { members, removeMember } = useMembers(workspace.id);
|
||||
return (
|
||||
<>
|
||||
@ -49,11 +49,11 @@ const AffineRemoteCollaborationPanel: React.FC<
|
||||
<ul>
|
||||
<StyledMemberTitleContainer>
|
||||
<StyledMemberNameContainer>
|
||||
{t('Users')} (
|
||||
{t['Users']()} (
|
||||
<span data-testid="member-length">{members.length}</span>)
|
||||
</StyledMemberNameContainer>
|
||||
<StyledMemberRoleContainer>
|
||||
{t('Access level')}
|
||||
{t['Access level']()}
|
||||
</StyledMemberRoleContainer>
|
||||
<div style={{ width: '24px', paddingRight: '48px' }}></div>
|
||||
</StyledMemberTitleContainer>
|
||||
@ -91,9 +91,9 @@ const AffineRemoteCollaborationPanel: React.FC<
|
||||
<StyledMemberRoleContainer>
|
||||
{member.accepted
|
||||
? member.type !== PermissionType.Owner
|
||||
? t('Member')
|
||||
: t('Owner')
|
||||
: t('Pending')}
|
||||
? t['Member']()
|
||||
: t['Owner']()
|
||||
: t['Pending']()}
|
||||
</StyledMemberRoleContainer>
|
||||
{member.type === PermissionType.Owner ? (
|
||||
<StyledMoreVerticalDiv />
|
||||
@ -109,14 +109,14 @@ const AffineRemoteCollaborationPanel: React.FC<
|
||||
// @ts-ignore
|
||||
await removeMember(member.id);
|
||||
toast(
|
||||
t('Member has been removed', {
|
||||
t['Member has been removed']({
|
||||
name: user.name,
|
||||
})
|
||||
);
|
||||
}}
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
>
|
||||
{t('Remove from workspace')}
|
||||
{t['Remove from workspace']()}
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
@ -145,7 +145,7 @@ const AffineRemoteCollaborationPanel: React.FC<
|
||||
data-testid="invite-members"
|
||||
shape="circle"
|
||||
>
|
||||
{t('Invite Members')}
|
||||
{t['Invite Members']()}
|
||||
</Button>
|
||||
</StyledMemberButtonContainer>
|
||||
</StyledMemberContainer>
|
||||
@ -168,11 +168,11 @@ const LocalCollaborationPanel: React.FC<
|
||||
workspace: LocalWorkspace;
|
||||
}
|
||||
> = ({ workspace, onTransferWorkspace }) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Wrapper marginBottom="42px">{t('Collaboration Description')}</Wrapper>
|
||||
<Wrapper marginBottom="42px">{t['Collaboration Description']()}</Wrapper>
|
||||
|
||||
<Button
|
||||
data-testid="local-workspace-enable-cloud-button"
|
||||
@ -182,7 +182,7 @@ const LocalCollaborationPanel: React.FC<
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('Enable AFFiNE Cloud')}
|
||||
{t['Enable AFFiNE Cloud']()}
|
||||
</Button>
|
||||
{config.enableLegacyCloud ? (
|
||||
<TransformWorkspaceToAffineModal
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
MuiAvatar,
|
||||
styled,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EmailIcon } from '@blocksuite/icons';
|
||||
import type React from 'react';
|
||||
import { Suspense, useCallback, useState } from 'react';
|
||||
@ -60,7 +60,7 @@ export const InviteMemberModal = ({
|
||||
const { inviteMember } = useMembers(workspaceId);
|
||||
const [email, setEmail] = useState<string>('');
|
||||
const [showMemberPreview, setShowMemberPreview] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const inputChange = useCallback((value: string) => {
|
||||
setEmail(value);
|
||||
}, []);
|
||||
@ -77,7 +77,7 @@ export const InviteMemberModal = ({
|
||||
/>
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentTitle>{t('Invite Members')}</ContentTitle>
|
||||
<ContentTitle>{t['Invite Members']()}</ContentTitle>
|
||||
<InviteBox>
|
||||
<Input
|
||||
data-testid="invite-member-input"
|
||||
@ -90,7 +90,7 @@ export const InviteMemberModal = ({
|
||||
onBlur={useCallback(() => {
|
||||
setShowMemberPreview(false);
|
||||
}, [])}
|
||||
placeholder={t('Invite placeholder')}
|
||||
placeholder={t['Invite placeholder']()}
|
||||
/>
|
||||
{showMemberPreview && gmailReg.test(email) && (
|
||||
<Suspense fallback="loading...">
|
||||
@ -112,7 +112,7 @@ export const InviteMemberModal = ({
|
||||
onInviteSuccess();
|
||||
}}
|
||||
>
|
||||
{t('Invite')}
|
||||
{t['Invite']()}
|
||||
</Button>
|
||||
</Footer>
|
||||
</ModalWrapper>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Button, Wrapper } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
export const ExportPanel = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<>
|
||||
<Wrapper marginBottom="42px"> {t('Export Description')}</Wrapper>
|
||||
<Wrapper marginBottom="42px"> {t['Export Description']()}</Wrapper>
|
||||
<Button
|
||||
type="light"
|
||||
shape="circle"
|
||||
@ -14,7 +14,7 @@ export const ExportPanel = () => {
|
||||
window.apis.openSaveDBFileDialog();
|
||||
}}
|
||||
>
|
||||
{t('Export AFFiNE backup file')}
|
||||
{t['Export AFFiNE backup file']()}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Button, Input, Modal, ModalCloseButton } from '@affine/component';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import { useCallback, useState } from 'react';
|
||||
@ -33,11 +34,11 @@ export const WorkspaceDeleteModal = ({
|
||||
);
|
||||
const [deleteStr, setDeleteStr] = useState<string>('');
|
||||
const allowDelete = deleteStr === workspaceName;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
onDeleteWorkspace().then(() => {
|
||||
toast(t('Successfully deleted'), {
|
||||
toast(t['Successfully deleted'](), {
|
||||
portal: document.body,
|
||||
});
|
||||
});
|
||||
@ -47,7 +48,7 @@ export const WorkspaceDeleteModal = ({
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<StyledModalWrapper>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<StyledModalHeader>{t('Delete Workspace')}?</StyledModalHeader>
|
||||
<StyledModalHeader>{t['Delete Workspace']()}?</StyledModalHeader>
|
||||
{workspace.flavour === WorkspaceFlavour.LOCAL ? (
|
||||
<StyledTextContent>
|
||||
<Trans i18nKey="Delete Workspace Description">
|
||||
@ -80,7 +81,7 @@ export const WorkspaceDeleteModal = ({
|
||||
}}
|
||||
onChange={setDeleteStr}
|
||||
data-testid="delete-workspace-input"
|
||||
placeholder={t('Placeholder of delete workspace')}
|
||||
placeholder={t['Placeholder of delete workspace']()}
|
||||
value={deleteStr}
|
||||
width={315}
|
||||
height={42}
|
||||
@ -88,7 +89,7 @@ export const WorkspaceDeleteModal = ({
|
||||
</StyledInputContent>
|
||||
<StyledButtonContent>
|
||||
<Button shape="circle" onClick={onClose}>
|
||||
{t('Cancel')}
|
||||
{t['Cancel']()}
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="delete-workspace-confirm-button"
|
||||
@ -98,7 +99,7 @@ export const WorkspaceDeleteModal = ({
|
||||
shape="circle"
|
||||
style={{ marginLeft: '24px' }}
|
||||
>
|
||||
{t('Delete')}
|
||||
{t['Delete']()}
|
||||
</Button>
|
||||
</StyledButtonContent>
|
||||
</StyledModalWrapper>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button, FlexWrapper, MuiFade } from '@affine/component';
|
||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
@ -38,7 +38,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
const [input, setInput] = useState<string>(name);
|
||||
const isOwner = useIsWorkspaceOwner(workspace);
|
||||
const [showEditInput, setShowEditInput] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const handleUpdateWorkspaceName = (name: string) => {
|
||||
setName(name);
|
||||
@ -50,7 +50,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
return (
|
||||
<>
|
||||
<StyledRow>
|
||||
<StyledSettingKey>{t('Workspace Avatar')}</StyledSettingKey>
|
||||
<StyledSettingKey>{t['Workspace Avatar']()}</StyledSettingKey>
|
||||
<StyledAvatar disabled={!isOwner}>
|
||||
{isOwner ? (
|
||||
<Upload
|
||||
@ -72,7 +72,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
</StyledRow>
|
||||
|
||||
<StyledRow>
|
||||
<StyledSettingKey>{t('Workspace Name')}</StyledSettingKey>
|
||||
<StyledSettingKey>{t['Workspace Name']()}</StyledSettingKey>
|
||||
|
||||
<div style={{ position: 'relative' }}>
|
||||
<MuiFade in={!showEditInput}>
|
||||
@ -84,7 +84,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
setShowEditInput(true);
|
||||
}}
|
||||
>
|
||||
{t('Edit')}
|
||||
{t['Edit']()}
|
||||
</StyledEditButton>
|
||||
)}
|
||||
</FlexWrapper>
|
||||
@ -97,7 +97,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
width={284}
|
||||
height={38}
|
||||
value={input}
|
||||
placeholder={t('Workspace Name')}
|
||||
placeholder={t['Workspace Name']()}
|
||||
maxLength={50}
|
||||
minLength={0}
|
||||
onChange={newName => {
|
||||
@ -114,7 +114,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
setShowEditInput(false);
|
||||
}}
|
||||
>
|
||||
{t('Confirm')}
|
||||
{t['Confirm']()}
|
||||
</Button>
|
||||
<Button
|
||||
type="default"
|
||||
@ -125,7 +125,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
setShowEditInput(false);
|
||||
}}
|
||||
>
|
||||
{t('Cancel')}
|
||||
{t['Cancel']()}
|
||||
</Button>
|
||||
</FlexWrapper>
|
||||
</MuiFade>
|
||||
@ -165,29 +165,29 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<StyledSettingKey>{t('Workspace Type')}</StyledSettingKey>
|
||||
<StyledSettingKey>{t['Workspace Type']()}</StyledSettingKey>
|
||||
{isOwner ? (
|
||||
workspace.flavour === WorkspaceFlavour.LOCAL ? (
|
||||
<StyledWorkspaceInfo>
|
||||
<LocalWorkspaceIcon />
|
||||
<span>{t('Local Workspace')}</span>
|
||||
<span>{t['Local Workspace']()}</span>
|
||||
</StyledWorkspaceInfo>
|
||||
) : (
|
||||
<StyledWorkspaceInfo>
|
||||
<CloudWorkspaceIcon />
|
||||
<span>{t('Cloud Workspace')}</span>
|
||||
<span>{t['Cloud Workspace']()}</span>
|
||||
</StyledWorkspaceInfo>
|
||||
)
|
||||
) : (
|
||||
<StyledWorkspaceInfo>
|
||||
<JoinedWorkspaceIcon />
|
||||
<span>{t('Joined Workspace')}</span>
|
||||
<span>{t['Joined Workspace']()}</span>
|
||||
</StyledWorkspaceInfo>
|
||||
)}
|
||||
</StyledRow>
|
||||
|
||||
<StyledRow>
|
||||
<StyledSettingKey> {t('Delete Workspace')}</StyledSettingKey>
|
||||
<StyledSettingKey> {t['Delete Workspace']()}</StyledSettingKey>
|
||||
{isOwner ? (
|
||||
<>
|
||||
<Button
|
||||
@ -199,7 +199,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
setShowDelete(true);
|
||||
}}
|
||||
>
|
||||
{t('Delete Workspace')}
|
||||
{t['Delete Workspace']()}
|
||||
</Button>
|
||||
<WorkspaceDeleteModal
|
||||
onDeleteWorkspace={onDeleteWorkspace}
|
||||
@ -219,7 +219,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
setShowLeave(true);
|
||||
}}
|
||||
>
|
||||
{t('Leave Workspace')}
|
||||
{t['Leave Workspace']()}
|
||||
</Button>
|
||||
<WorkspaceLeave
|
||||
open={showLeave}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Modal } from '@affine/component';
|
||||
import { ModalCloseButton } from '@affine/component';
|
||||
import { Button } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import {
|
||||
StyledButtonContent,
|
||||
@ -17,7 +17,7 @@ interface WorkspaceDeleteProps {
|
||||
|
||||
export const WorkspaceLeave = ({ open, onClose }: WorkspaceDeleteProps) => {
|
||||
// const { leaveWorkSpace } = useWorkspaceHelper();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const handleLeave = async () => {
|
||||
// await leaveWorkSpace();
|
||||
onClose();
|
||||
@ -27,13 +27,13 @@ export const WorkspaceLeave = ({ open, onClose }: WorkspaceDeleteProps) => {
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<StyledModalWrapper>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<StyledModalHeader>{t('Leave Workspace')}</StyledModalHeader>
|
||||
<StyledModalHeader>{t['Leave Workspace']()}</StyledModalHeader>
|
||||
<StyledTextContent>
|
||||
{t('Leave Workspace Description')}
|
||||
{t['Leave Workspace Description']()}
|
||||
</StyledTextContent>
|
||||
<StyledButtonContent>
|
||||
<Button shape="circle" onClick={onClose}>
|
||||
{t('Cancel')}
|
||||
{t['Cancel']()}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleLeave}
|
||||
@ -41,7 +41,7 @@ export const WorkspaceLeave = ({ open, onClose }: WorkspaceDeleteProps) => {
|
||||
shape="circle"
|
||||
style={{ marginLeft: '24px' }}
|
||||
>
|
||||
{t('Leave')}
|
||||
{t['Leave']()}
|
||||
</Button>
|
||||
</StyledButtonContent>
|
||||
</StyledModalWrapper>
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
Wrapper,
|
||||
} from '@affine/component';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { Box } from '@mui/material';
|
||||
@ -41,20 +41,20 @@ const PublishPanelAffine: React.FC<PublishPanelAffineProps> = ({
|
||||
);
|
||||
}, []);
|
||||
const shareUrl = origin + '/public-workspace/' + workspace.id;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const publishWorkspace = useToggleWorkspacePublish(workspace);
|
||||
const copyUrl = useCallback(() => {
|
||||
navigator.clipboard.writeText(shareUrl);
|
||||
toast(t('Copied link to clipboard'));
|
||||
toast(t['Copied link to clipboard']());
|
||||
}, [shareUrl, t]);
|
||||
|
||||
if (workspace.public) {
|
||||
return (
|
||||
<>
|
||||
<Wrapper marginBottom="42px">{t('Published Description')}</Wrapper>
|
||||
<Wrapper marginBottom="42px">{t['Published Description']()}</Wrapper>
|
||||
|
||||
<Wrapper marginBottom="12px">
|
||||
<Content weight="500">{t('Share with link')}</Content>
|
||||
<Content weight="500">{t['Share with link']()}</Content>
|
||||
</Wrapper>
|
||||
<FlexWrapper>
|
||||
<Input
|
||||
@ -69,7 +69,7 @@ const PublishPanelAffine: React.FC<PublishPanelAffineProps> = ({
|
||||
shape="circle"
|
||||
style={{ marginLeft: '24px' }}
|
||||
>
|
||||
{t('Copy Link')}
|
||||
{t['Copy Link']()}
|
||||
</Button>
|
||||
</FlexWrapper>
|
||||
<Button
|
||||
@ -81,14 +81,14 @@ const PublishPanelAffine: React.FC<PublishPanelAffineProps> = ({
|
||||
shape="circle"
|
||||
style={{ marginTop: '38px' }}
|
||||
>
|
||||
{t('Stop publishing')}
|
||||
{t['Stop publishing']()}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Wrapper marginBottom="42px">{t('Publishing Description')}</Wrapper>
|
||||
<Wrapper marginBottom="42px">{t['Publishing Description']()}</Wrapper>
|
||||
<Button
|
||||
data-testid="publish-to-web-button"
|
||||
onClick={async () => {
|
||||
@ -97,7 +97,7 @@ const PublishPanelAffine: React.FC<PublishPanelAffineProps> = ({
|
||||
type="light"
|
||||
shape="circle"
|
||||
>
|
||||
{t('Publish to web')}
|
||||
{t['Publish to web']()}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
@ -111,7 +111,7 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
|
||||
workspace,
|
||||
onTransferWorkspace,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
@ -120,7 +120,7 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
|
||||
marginBottom: '42px',
|
||||
}}
|
||||
>
|
||||
{t('Publishing')}
|
||||
{t['Publishing']()}
|
||||
</Box>
|
||||
{/* TmpDisableAffineCloudModal */}
|
||||
|
||||
@ -132,7 +132,7 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('Enable AFFiNE Cloud')}
|
||||
{t['Enable AFFiNE Cloud']()}
|
||||
</Button>
|
||||
{config.enableLegacyCloud ? (
|
||||
<EnableAffineCloudModal
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Content, FlexWrapper, styled } from '@affine/component';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
@ -25,7 +26,7 @@ export const SyncPanel: React.FC<PanelProps> = ({ workspace }) => {
|
||||
workspace.blockSuiteWorkspace
|
||||
);
|
||||
const user = useCurrentUser();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<>
|
||||
<FlexWrapper alignItems="center" style={{ marginBottom: '12px' }}>
|
||||
@ -37,7 +38,7 @@ export const SyncPanel: React.FC<PanelProps> = ({ workspace }) => {
|
||||
/>
|
||||
<StyledWorkspaceName>{name}</StyledWorkspaceName>
|
||||
|
||||
<Content weight={500}>{t('is a Cloud Workspace')}</Content>
|
||||
<Content weight={500}>{t['is a Cloud Workspace']()}</Content>
|
||||
</FlexWrapper>
|
||||
<Trans i18nKey="Cloud Workspace Description">
|
||||
All data will be synchronised and saved to the AFFiNE account
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { Empty } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import React from 'react';
|
||||
export const PageListEmpty = (props: { listType?: string }) => {
|
||||
const { listType } = props;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const getEmptyDescription = () => {
|
||||
if (listType === 'all') {
|
||||
return t('emptyAllPages');
|
||||
return t['emptyAllPages']();
|
||||
}
|
||||
if (listType === 'favorite') {
|
||||
return t('emptyFavorite');
|
||||
return t['emptyFavorite']();
|
||||
}
|
||||
if (listType === 'trash') {
|
||||
return t('emptyTrash');
|
||||
return t['emptyTrash']();
|
||||
}
|
||||
if (listType === 'shared') {
|
||||
return t('emptySharedPages');
|
||||
return t['emptySharedPages']();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
MenuItem,
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
DeletePermanentlyIcon,
|
||||
FavoritedIcon,
|
||||
@ -44,7 +44,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
||||
onToggleTrashPage,
|
||||
}) => {
|
||||
const { id, favorite, isPublic } = pageMeta;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openDisableShared, setOpenDisableShared] = useState(false);
|
||||
|
||||
@ -65,7 +65,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
||||
onClick={() => {
|
||||
onToggleFavoritePage(id);
|
||||
toast(
|
||||
favorite ? t('Removed from Favorites') : t('Added to Favorites')
|
||||
favorite ? t['Removed from Favorites']() : t['Added to Favorites']()
|
||||
);
|
||||
}}
|
||||
icon={
|
||||
@ -76,7 +76,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
||||
)
|
||||
}
|
||||
>
|
||||
{favorite ? t('Remove from favorites') : t('Add to Favorites')}
|
||||
{favorite ? t['Remove from favorites']() : t['Add to Favorites']()}
|
||||
</MenuItem>
|
||||
{!environment.isDesktop && (
|
||||
<MenuItem
|
||||
@ -85,7 +85,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
||||
}}
|
||||
icon={<OpenInNewIcon />}
|
||||
>
|
||||
{t('Open in new tab')}
|
||||
{t['Open in new tab']()}
|
||||
</MenuItem>
|
||||
)}
|
||||
{!pageMeta.isRootPinboard && (
|
||||
@ -117,7 +117,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
||||
meta={pageMeta}
|
||||
onConfirm={() => {
|
||||
onToggleTrashPage(id, true);
|
||||
toast(t('Deleted'));
|
||||
toast(t['Moved to Trash']());
|
||||
setOpen(false);
|
||||
}}
|
||||
onClose={() => {
|
||||
@ -151,22 +151,22 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
|
||||
onRestorePage,
|
||||
}) => {
|
||||
const { id, title } = pageMeta;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<FlexWrapper>
|
||||
<Tooltip content={t('Restore it')} placement="top-start">
|
||||
<Tooltip content={t['Restore it']()} placement="top-start">
|
||||
<IconButton
|
||||
style={{ marginRight: '12px' }}
|
||||
onClick={() => {
|
||||
onRestorePage(id);
|
||||
toast(t('restored', { title: title || 'Untitled' }));
|
||||
toast(t['restored']({ title: title || 'Untitled' }));
|
||||
}}
|
||||
>
|
||||
<ResetIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip content={t('Delete permanently')} placement="top-start">
|
||||
<Tooltip content={t['Delete permanently']()} placement="top-start">
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
@ -176,14 +176,14 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Confirm
|
||||
title={t('Delete permanently?')}
|
||||
content={t("Once deleted, you can't undo this action.")}
|
||||
confirmText={t('Delete')}
|
||||
title={t['Delete permanently?']()}
|
||||
content={t['TrashButtonGroupDescription']()}
|
||||
confirmText={t['Delete']()}
|
||||
confirmType="danger"
|
||||
open={open}
|
||||
onConfirm={() => {
|
||||
onPermanentlyDeletePage(id);
|
||||
toast(t('Permanently deleted'));
|
||||
toast(t['Permanently deleted']());
|
||||
setOpen(false);
|
||||
}}
|
||||
onClose={() => {
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
TableRow,
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
FavoritedIcon,
|
||||
@ -47,10 +47,10 @@ const FavoriteTag: React.FC<FavoriteTagProps> = ({
|
||||
pageMeta: { favorite },
|
||||
onClick,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Tooltip
|
||||
content={favorite ? t('Favorited') : t('Favorite')}
|
||||
content={favorite ? t['Favorited']() : t['Favorite']()}
|
||||
placement="top-start"
|
||||
>
|
||||
<IconButton
|
||||
@ -59,7 +59,7 @@ const FavoriteTag: React.FC<FavoriteTagProps> = ({
|
||||
e.stopPropagation();
|
||||
onClick();
|
||||
toast(
|
||||
favorite ? t('Removed from Favorites') : t('Added to Favorites')
|
||||
favorite ? t['Removed from Favorites']() : t['Added to Favorites']()
|
||||
);
|
||||
}}
|
||||
style={{
|
||||
@ -106,7 +106,7 @@ export const PageList: React.FC<PageListProps> = ({
|
||||
const helper = usePageMetaHelper(blockSuiteWorkspace);
|
||||
const { removeToTrash, restoreFromTrash } =
|
||||
useBlockSuiteMetaHelper(blockSuiteWorkspace);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const theme = useTheme();
|
||||
const matches = useMediaQuery(theme.breakpoints.up('sm'));
|
||||
const isTrash = listType === 'trash';
|
||||
@ -130,14 +130,14 @@ export const PageList: React.FC<PageListProps> = ({
|
||||
<TableRow>
|
||||
{matches && (
|
||||
<>
|
||||
<TableCell proportion={0.5}>{t('Title')}</TableCell>
|
||||
<TableCell proportion={0.2}>{t('Created')}</TableCell>
|
||||
<TableCell proportion={0.5}>{t['Title']()}</TableCell>
|
||||
<TableCell proportion={0.2}>{t['Created']()}</TableCell>
|
||||
<TableCell proportion={0.2}>
|
||||
{isTrash
|
||||
? t('Moved to Trash')
|
||||
? t['Moved to Trash']()
|
||||
: isShared
|
||||
? 'Shared'
|
||||
: t('Updated')}
|
||||
: t['Updated']()}
|
||||
</TableCell>
|
||||
<TableCell proportion={0.1}></TableCell>
|
||||
</>
|
||||
@ -164,7 +164,7 @@ export const PageList: React.FC<PageListProps> = ({
|
||||
<PageIcon />
|
||||
)}
|
||||
<Content ellipsis={true} color="inherit">
|
||||
{pageMeta.title || t('Untitled')}
|
||||
{pageMeta.title || t['Untitled']()}
|
||||
</Content>
|
||||
</StyledTitleLink>
|
||||
{listType && !isTrash && (
|
||||
|
@ -1,6 +1,6 @@
|
||||
// fixme(himself65): refactor this file
|
||||
import { FlexWrapper, IconButton, Menu, MenuItem } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
FavoritedIcon,
|
||||
@ -57,7 +57,7 @@ const CommonMenu = () => {
|
||||
);
|
||||
};
|
||||
const PageMenu = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
// fixme(himself65): remove these hooks ASAP
|
||||
const [workspace] = useCurrentWorkspace();
|
||||
const [pageId] = useCurrentPageId();
|
||||
@ -83,7 +83,9 @@ const PageMenu = () => {
|
||||
onClick={() => {
|
||||
setPageMeta(pageId, { favorite: !favorite });
|
||||
toast(
|
||||
favorite ? t('Removed from Favorites') : t('Added to Favorites')
|
||||
favorite
|
||||
? t['Removed from Favorites']()
|
||||
: t['Added to Favorites']()
|
||||
);
|
||||
}}
|
||||
icon={
|
||||
@ -94,7 +96,7 @@ const PageMenu = () => {
|
||||
)
|
||||
}
|
||||
>
|
||||
{favorite ? t('Remove from favorites') : t('Add to Favorites')}
|
||||
{favorite ? t['Remove from favorites']() : t['Add to Favorites']()}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={mode === 'page' ? <EdgelessIcon /> : <PageIcon />}
|
||||
@ -106,8 +108,8 @@ const PageMenu = () => {
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{t('Convert to ')}
|
||||
{mode === 'page' ? t('Edgeless') : t('Page')}
|
||||
{t['Convert to ']()}
|
||||
{mode === 'page' ? t['Edgeless']() : t['Page']()}
|
||||
</MenuItem>
|
||||
<Export />
|
||||
{!pageMeta.isRootPinboard && (
|
||||
@ -153,7 +155,7 @@ const PageMenu = () => {
|
||||
meta={pageMeta}
|
||||
onConfirm={() => {
|
||||
removeToTrash(pageMeta.id);
|
||||
toast(t('Moved to Trash'));
|
||||
toast(t['Moved to Trash']());
|
||||
}}
|
||||
onCancel={() => {
|
||||
setOpenConfirm(false);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Button, displayFlex, Menu, MenuItem, styled } from '@affine/component';
|
||||
import { LOCALES } from '@affine/i18n';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useI18N } from '@affine/i18n';
|
||||
import { ArrowDownSmallIcon, PublishIcon } from '@blocksuite/icons';
|
||||
import type { FC, ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const LanguageMenuContent: FC = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const i18n = useI18N();
|
||||
const changeLanguage = useCallback(
|
||||
(event: string) => {
|
||||
i18n.changeLanguage(event);
|
||||
@ -32,7 +32,7 @@ const LanguageMenuContent: FC = () => {
|
||||
);
|
||||
};
|
||||
export const LanguageMenu: React.FC = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const i18n = useI18N();
|
||||
|
||||
const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { displayFlex, IconButton, styled, Tooltip } from '@affine/component';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
getLoginStorage,
|
||||
setLoginStorage,
|
||||
@ -79,7 +79,7 @@ export const SyncUser = () => {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const transformWorkspace = useTransformWorkspace();
|
||||
|
||||
if (!config.enableLegacyCloud) {
|
||||
@ -89,7 +89,7 @@ export const SyncUser = () => {
|
||||
if (status === 'offline') {
|
||||
return (
|
||||
<Tooltip
|
||||
content={t('Please make sure you are online')}
|
||||
content={t['Please make sure you are online']()}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<IconWrapper>
|
||||
@ -103,7 +103,7 @@ export const SyncUser = () => {
|
||||
return (
|
||||
<>
|
||||
<Tooltip
|
||||
content={t('Saved then enable AFFiNE Cloud')}
|
||||
content={t['Saved then enable AFFiNE Cloud']()}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<IconButton
|
||||
@ -156,7 +156,7 @@ export const SyncUser = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip content={t('Synced with AFFiNE Cloud')} placement="bottom-end">
|
||||
<Tooltip content={t['Synced with AFFiNE Cloud']()} placement="bottom-end">
|
||||
<IconWrapper>
|
||||
<CloudWorkspaceIcon />
|
||||
</IconWrapper>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Button, Confirm } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useRouter } from 'next/router';
|
||||
@ -20,7 +20,7 @@ export const TrashButtonGroup = () => {
|
||||
meta => meta.id === pageId
|
||||
);
|
||||
assertExists(pageMeta);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const router = useRouter();
|
||||
const { restoreFromTrash } = useBlockSuiteMetaHelper(blockSuiteWorkspace);
|
||||
|
||||
@ -36,7 +36,7 @@ export const TrashButtonGroup = () => {
|
||||
restoreFromTrash(pageId);
|
||||
}}
|
||||
>
|
||||
{t('Restore it')}
|
||||
{t['Restore it']()}
|
||||
</Button>
|
||||
<Button
|
||||
bold={true}
|
||||
@ -46,12 +46,12 @@ export const TrashButtonGroup = () => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('Delete permanently')}
|
||||
{t['Delete permanently']()}
|
||||
</Button>
|
||||
<Confirm
|
||||
title={t('TrashButtonGroupTitle')}
|
||||
content={t('TrashButtonGroupDescription')}
|
||||
confirmText={t('Delete')}
|
||||
title={t['TrashButtonGroupTitle']()}
|
||||
content={t['TrashButtonGroupDescription']()}
|
||||
confirmText={t['Delete']()}
|
||||
confirmType="danger"
|
||||
open={open}
|
||||
onConfirm={() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { appSidebarOpenAtom } from '@affine/component/app-sidebar';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
@ -133,7 +133,7 @@ export const Header = forwardRef<
|
||||
setShowWarning(shouldShowWarning());
|
||||
}, []);
|
||||
const [open] = useAtom(appSidebarOpenAtom);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<StyledHeaderContainer
|
||||
@ -156,7 +156,7 @@ export const Header = forwardRef<
|
||||
<Suspense>
|
||||
<SidebarSwitch
|
||||
visible={!open}
|
||||
tooltipContent={t('Expand sidebar')}
|
||||
tooltipContent={t['Expand sidebar']()}
|
||||
data-testid="sliderBar-arrowButton-expand"
|
||||
/>
|
||||
</Suspense>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { getEnvironment } from '@affine/env';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
@ -23,7 +24,7 @@ export const shouldShowWarning = () => {
|
||||
};
|
||||
|
||||
export const OSWarningMessage: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [notChrome, setNotChrome] = useState(false);
|
||||
const [notGoodVersion, setNotGoodVersion] = useState(false);
|
||||
useEffect(() => {
|
||||
@ -44,7 +45,7 @@ export const OSWarningMessage: React.FC = () => {
|
||||
</span>
|
||||
);
|
||||
} else if (notGoodVersion) {
|
||||
return <span>{t('upgradeBrowser')}</span>;
|
||||
return <span>{t['upgradeBrowser']()}</span>;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
ModalWrapper,
|
||||
styled,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
@ -35,7 +35,7 @@ export const CreateWorkspaceModal = ({
|
||||
},
|
||||
[handleCreateWorkspace, workspaceName]
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<ModalWrapper width={560} height={342} style={{ padding: '10px' }}>
|
||||
@ -49,8 +49,8 @@ export const CreateWorkspaceModal = ({
|
||||
/>
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentTitle>{t('New Workspace')}</ContentTitle>
|
||||
<p>{t('Workspace description')}</p>
|
||||
<ContentTitle>{t['New Workspace']()}</ContentTitle>
|
||||
<p>{t['Workspace description']()}</p>
|
||||
<Input
|
||||
ref={ref => {
|
||||
if (ref) {
|
||||
@ -59,7 +59,7 @@ export const CreateWorkspaceModal = ({
|
||||
}}
|
||||
data-testid="create-workspace-input"
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t('Set a Workspace name')}
|
||||
placeholder={t['Set a Workspace name']()}
|
||||
maxLength={15}
|
||||
minLength={0}
|
||||
onChange={value => {
|
||||
@ -86,7 +86,7 @@ export const CreateWorkspaceModal = ({
|
||||
handleCreateWorkspace();
|
||||
}}
|
||||
>
|
||||
{t('Create')}
|
||||
{t['Create']()}
|
||||
</Button>
|
||||
</Content>
|
||||
</ModalWrapper>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { styled } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import type React from 'react';
|
||||
import { useRef } from 'react';
|
||||
@ -17,7 +17,7 @@ export const Upload: React.FC<UploadProps> = ({
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const input_ref = useRef<HTMLInputElement>(null);
|
||||
const _chooseFile = () => {
|
||||
if (input_ref.current) {
|
||||
@ -37,7 +37,7 @@ export const Upload: React.FC<UploadProps> = ({
|
||||
};
|
||||
return (
|
||||
<UploadStyle onClick={_chooseFile}>
|
||||
{children ?? <Button>{t('Upload')}</Button>}
|
||||
{children ?? <Button>{t['Upload']()}</Button>}
|
||||
<input
|
||||
ref={input_ref}
|
||||
type="file"
|
||||
|
@ -2,7 +2,7 @@ import { FlexWrapper } from '@affine/component';
|
||||
import { IconButton } from '@affine/component';
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
|
||||
import { CloudWorkspaceIcon, SignOutIcon } from '@blocksuite/icons';
|
||||
import { useSetAtom } from 'jotai';
|
||||
@ -21,7 +21,7 @@ export type FooterProps = {
|
||||
};
|
||||
|
||||
export const Footer: React.FC<FooterProps> = ({ user, onLogin, onLogout }) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
return (
|
||||
<StyledFooter data-testid="workspace-list-modal-footer">
|
||||
@ -38,7 +38,7 @@ export const Footer: React.FC<FooterProps> = ({ user, onLogin, onLogout }) => {
|
||||
<p>{user.email}</p>
|
||||
</StyleUserInfo>
|
||||
</FlexWrapper>
|
||||
<Tooltip content={t('Sign out')} disablePortal={true}>
|
||||
<Tooltip content={t['Sign out']()} disablePortal={true}>
|
||||
<IconButton
|
||||
data-testid="workspace-list-modal-sign-out"
|
||||
onClick={() => {
|
||||
@ -69,7 +69,7 @@ export const Footer: React.FC<FooterProps> = ({ user, onLogin, onLogout }) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('Sign in')}
|
||||
{t['Sign in']()}
|
||||
</StyledSignInButton>
|
||||
)}
|
||||
</StyledFooter>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MuiFade, Tooltip } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon, NewIcon } from '@blocksuite/icons';
|
||||
import { lazy, Suspense, useState } from 'react';
|
||||
|
||||
@ -27,7 +27,7 @@ export const HelpIsland = ({
|
||||
const [spread, setShowSpread] = useState(false);
|
||||
// const { triggerShortcutsModal, triggerContactModal } = useModal();
|
||||
// const blockHub = useGlobalState(store => store.blockHub);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
//
|
||||
// useEffect(() => {
|
||||
// blockHub?.blockHubStatusUpdated.on(status => {
|
||||
@ -58,7 +58,7 @@ export const HelpIsland = ({
|
||||
style={{ height: spread ? `${showList.length * 44}px` : 0 }}
|
||||
>
|
||||
{showList.includes('whatNew') && (
|
||||
<Tooltip content={t("Discover what's new!")} placement="left-end">
|
||||
<Tooltip content={t["Discover what's new!"]()} placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-change-log-icon"
|
||||
onClick={() => {
|
||||
@ -73,7 +73,7 @@ export const HelpIsland = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
{showList.includes('contact') && (
|
||||
<Tooltip content={t('Contact Us')} placement="left-end">
|
||||
<Tooltip content={t['Contact Us']()} placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-contact-us-icon"
|
||||
onClick={() => {
|
||||
@ -86,7 +86,7 @@ export const HelpIsland = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
{showList.includes('shortcuts') && (
|
||||
<Tooltip content={t('Keyboard Shortcuts')} placement="left-end">
|
||||
<Tooltip content={t['Keyboard Shortcuts']()} placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="shortcuts-icon"
|
||||
onClick={() => {
|
||||
@ -100,7 +100,7 @@ export const HelpIsland = ({
|
||||
)}
|
||||
</StyledAnimateWrapper>
|
||||
|
||||
<Tooltip content={t('Help and Feedback')} placement="left-end">
|
||||
<Tooltip content={t['Help and Feedback']()} placement="left-end">
|
||||
<MuiFade in={!spread} data-testid="faq-icon">
|
||||
<StyledTriggerWrapper>
|
||||
<HelpIcon />
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { styled } from '@affine/component';
|
||||
import { AffineLoading } from '@affine/component/affine-loading';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { memo, Suspense } from 'react';
|
||||
|
||||
export const Loading = memo(function Loading() {
|
||||
@ -36,11 +36,11 @@ const StyledLoadingContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const PageLoading = ({ text }: { text?: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<StyledLoadingContainer>
|
||||
<Loading />
|
||||
<h1>{text ? text : t('Loading')}</h1>
|
||||
<h1>{text ? text : t['Loading']()}</h1>
|
||||
</StyledLoadingContainer>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { initPage } from '@affine/env/blocksuite';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { PageBlockModel } from '@blocksuite/blocks';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import { assertEquals, nanoid } from '@blocksuite/store';
|
||||
@ -27,7 +27,7 @@ export const Footer: React.FC<FooterProps> = ({
|
||||
router,
|
||||
}) => {
|
||||
const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const MAX_QUERY_SHOW_LENGTH = 20;
|
||||
const normalizedQuery =
|
||||
@ -60,9 +60,9 @@ export const Footer: React.FC<FooterProps> = ({
|
||||
<StyledModalFooterContent>
|
||||
<PlusIcon />
|
||||
{query ? (
|
||||
<span>{t('New Keyword Page', { query: normalizedQuery })}</span>
|
||||
<span>{t['New Keyword Page']({ query: normalizedQuery })}</span>
|
||||
) : (
|
||||
<span>{t('New Page')}</span>
|
||||
<span>{t['New Page']()}</span>
|
||||
)}
|
||||
</StyledModalFooterContent>
|
||||
</Command.Item>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { Command } from 'cmdk';
|
||||
@ -41,7 +41,7 @@ export const PublishedResults: FC<PublishedResultsProps> = ({
|
||||
// router.push('/404');
|
||||
// });
|
||||
// }, [router, dataCenter, setPublishWorkspaceName]);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useEffect(() => {
|
||||
setResults(blockSuiteWorkspace.search(query));
|
||||
//Save the Map<BlockId, PageId> obtained from the search as state
|
||||
@ -57,7 +57,7 @@ export const PublishedResults: FC<PublishedResultsProps> = ({
|
||||
{query ? (
|
||||
resultsPageMeta.length ? (
|
||||
<Command.Group
|
||||
heading={t('Find results', { number: resultsPageMeta.length })}
|
||||
heading={t['Find results']({ number: `${resultsPageMeta.length}` })}
|
||||
>
|
||||
{resultsPageMeta.map(result => {
|
||||
return (
|
||||
@ -85,7 +85,7 @@ export const PublishedResults: FC<PublishedResultsProps> = ({
|
||||
</Command.Group>
|
||||
) : (
|
||||
<StyledNotFound>
|
||||
<span>{t('Find 0 result')}</span>
|
||||
<span>{t['Find 0 result']()}</span>
|
||||
<Image
|
||||
src="/imgs/no-result.svg"
|
||||
alt="no result"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
@ -36,7 +36,7 @@ export const Results: FC<ResultsProps> = ({
|
||||
const List = useSwitchToConfig(blockSuiteWorkspace.id);
|
||||
|
||||
const recentlyViewed = useRecentlyViewed();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const results = blockSuiteWorkspace.search(query);
|
||||
|
||||
@ -61,7 +61,7 @@ export const Results: FC<ResultsProps> = ({
|
||||
return (
|
||||
<>
|
||||
{recentlyViewedItem.length > 0 && (
|
||||
<Command.Group heading={t('Recent')}>
|
||||
<Command.Group heading={t['Recent']()}>
|
||||
{recentlyViewedItem.map(recent => {
|
||||
const page = pageList.find(page => recent.id === page.id);
|
||||
assertExists(page);
|
||||
@ -87,7 +87,7 @@ export const Results: FC<ResultsProps> = ({
|
||||
})}
|
||||
</Command.Group>
|
||||
)}
|
||||
<Command.Group heading={t('Jump to')}>
|
||||
<Command.Group heading={t['Jump to']()}>
|
||||
{List.map(link => {
|
||||
return (
|
||||
<Command.Item
|
||||
@ -112,7 +112,7 @@ export const Results: FC<ResultsProps> = ({
|
||||
if (!resultsPageMeta.length) {
|
||||
return (
|
||||
<StyledNotFound>
|
||||
<span>{t('Find 0 result')}</span>
|
||||
<span>{t['Find 0 result']()}</span>
|
||||
<Image
|
||||
src="/imgs/no-result.svg"
|
||||
alt="no result"
|
||||
@ -124,7 +124,7 @@ export const Results: FC<ResultsProps> = ({
|
||||
}
|
||||
return (
|
||||
<Command.Group
|
||||
heading={t('Find results', { number: resultsPageMeta.length })}
|
||||
heading={t['Find results']({ number: `${resultsPageMeta.length}` })}
|
||||
>
|
||||
{resultsPageMeta.map(result => {
|
||||
return (
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
DeleteTemporarilyIcon,
|
||||
FavoriteIcon,
|
||||
@ -16,26 +16,26 @@ export const useSwitchToConfig = (
|
||||
href: string;
|
||||
icon: FC<SVGProps<SVGSVGElement>>;
|
||||
}[] => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t('All pages'),
|
||||
title: t['All pages'](),
|
||||
href: pathGenerator.all(workspaceId),
|
||||
icon: FolderIcon,
|
||||
},
|
||||
{
|
||||
title: t('Favorites'),
|
||||
title: t['Favorites'](),
|
||||
href: pathGenerator.favorite(workspaceId),
|
||||
icon: FavoriteIcon,
|
||||
},
|
||||
{
|
||||
title: t('Workspace Settings'),
|
||||
title: t['Workspace Settings'](),
|
||||
href: pathGenerator.setting(workspaceId),
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
title: t('Trash'),
|
||||
title: t['Trash'](),
|
||||
href: pathGenerator.trash(workspaceId),
|
||||
icon: DeleteTemporarilyIcon,
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Modal, ModalWrapper } from '@affine/component';
|
||||
import { getEnvironment } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Command } from 'cmdk';
|
||||
import type { NextRouter } from 'next/router';
|
||||
import type React from 'react';
|
||||
@ -45,7 +45,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
router,
|
||||
blockSuiteWorkspace,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [loading, startTransition] = useTransition();
|
||||
const [query, _setQuery] = useState('');
|
||||
@ -145,10 +145,10 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
}}
|
||||
placeholder={
|
||||
isPublicWorkspace
|
||||
? t('Quick search placeholder2', {
|
||||
? t['Quick search placeholder2']({
|
||||
workspace: publishWorkspaceName,
|
||||
})
|
||||
: t('Quick search placeholder')
|
||||
: t['Quick search placeholder']()
|
||||
}
|
||||
/>
|
||||
<StyledShortcut>{isMac() ? '⌘ + K' : 'Ctrl + K'}</StyledShortcut>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IconButton, Tooltip, TreeView } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
ArrowRightSmallIcon,
|
||||
CollapseIcon,
|
||||
@ -35,7 +35,7 @@ export const NavigationPath = ({
|
||||
}) => {
|
||||
const metas = useBlockSuitePageMeta(blockSuiteWorkspace);
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const [openExtend, setOpenExtend] = useState(false);
|
||||
const pageId = propsPageId ?? router.query.pageId;
|
||||
@ -59,7 +59,7 @@ export const NavigationPath = ({
|
||||
<>
|
||||
<StyledNavigationPathContainer data-testid="navigation-path">
|
||||
{openExtend ? (
|
||||
<span>{t('Navigation Path')}</span>
|
||||
<span>{t['Navigation Path']()}</span>
|
||||
) : (
|
||||
pathData.path.map((meta, index) => {
|
||||
const isLast = index === pathData.path.length - 1;
|
||||
@ -96,7 +96,9 @@ export const NavigationPath = ({
|
||||
)}
|
||||
<Tooltip
|
||||
content={
|
||||
openExtend ? t('Back to Quick Search') : t('View Navigation Path')
|
||||
openExtend
|
||||
? t['Back to Quick Search']()
|
||||
: t['View Navigation Path']()
|
||||
}
|
||||
placement="top"
|
||||
disablePortal={true}
|
||||
|
@ -1,90 +1,91 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
interface ShortcutTip {
|
||||
[x: string]: string;
|
||||
}
|
||||
export const useMacKeyboardShortcuts = (): ShortcutTip => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return {
|
||||
[t('Undo')]: '⌘+Z',
|
||||
[t('Redo')]: '⌘+⇧+Z',
|
||||
[t('Bold')]: '⌘+B',
|
||||
[t('Italic')]: '⌘+I',
|
||||
[t('Underline')]: '⌘+U',
|
||||
[t('Strikethrough')]: '⌘+⇧+S',
|
||||
[t('Inline code')]: ' ⌘+E',
|
||||
[t('Code block')]: '⌘+⌥+C',
|
||||
[t('Link')]: '⌘+K',
|
||||
[t('Quick search')]: '⌘+K',
|
||||
[t('Body text')]: '⌘+⌥+0',
|
||||
[t('Heading', { number: '1' })]: '⌘+⌥+1',
|
||||
[t('Heading', { number: '2' })]: '⌘+⌥+2',
|
||||
[t('Heading', { number: '3' })]: '⌘+⌥+3',
|
||||
[t('Heading', { number: '4' })]: '⌘+⌥+4',
|
||||
[t('Heading', { number: '5' })]: '⌘+⌥+5',
|
||||
[t('Heading', { number: '6' })]: '⌘+⌥+6',
|
||||
[t('Increase indent')]: 'Tab',
|
||||
[t('Reduce indent')]: '⇧+Tab',
|
||||
[t['Undo']()]: '⌘+Z',
|
||||
[t['Redo']()]: '⌘+⇧+Z',
|
||||
[t['Bold']()]: '⌘+B',
|
||||
[t['Italic']()]: '⌘+I',
|
||||
[t['Underline']()]: '⌘+U',
|
||||
[t['Strikethrough']()]: '⌘+⇧+S',
|
||||
[t['Inline code']()]: ' ⌘+E',
|
||||
[t['Code block']()]: '⌘+⌥+C',
|
||||
[t['Link']()]: '⌘+K',
|
||||
[t['Quick search']()]: '⌘+K',
|
||||
[t['Body text']()]: '⌘+⌥+0',
|
||||
[t['Heading']({ number: '1' })]: '⌘+⌥+1',
|
||||
[t['Heading']({ number: '2' })]: '⌘+⌥+2',
|
||||
[t['Heading']({ number: '3' })]: '⌘+⌥+3',
|
||||
[t['Heading']({ number: '4' })]: '⌘+⌥+4',
|
||||
[t['Heading']({ number: '5' })]: '⌘+⌥+5',
|
||||
[t['Heading']({ number: '6' })]: '⌘+⌥+6',
|
||||
[t['Increase indent']()]: 'Tab',
|
||||
[t['Reduce indent']()]: '⇧+Tab',
|
||||
};
|
||||
};
|
||||
|
||||
export const useMacMarkdownShortcuts = (): ShortcutTip => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return {
|
||||
[t('Bold')]: '**Text** ',
|
||||
[t('Italic')]: '*Text* ',
|
||||
[t('Underline')]: '~Text~ ',
|
||||
[t('Strikethrough')]: '~~Text~~ ',
|
||||
[t('Divider')]: '***',
|
||||
[t('Inline code')]: '`Text` ',
|
||||
[t('Code block')]: '``` Space',
|
||||
[t('Heading', { number: '1' })]: '# Text',
|
||||
[t('Heading', { number: '2' })]: '## Text',
|
||||
[t('Heading', { number: '3' })]: '### Text',
|
||||
[t('Heading', { number: '4' })]: '#### Text',
|
||||
[t('Heading', { number: '5' })]: '##### Text',
|
||||
[t('Heading', { number: '6' })]: '###### Text',
|
||||
[t['Bold']()]: '**Text** ',
|
||||
[t['Italic']()]: '*Text* ',
|
||||
[t['Underline']()]: '~Text~ ',
|
||||
[t['Strikethrough']()]: '~~Text~~ ',
|
||||
[t['Divider']()]: '***',
|
||||
[t['Inline code']()]: '`Text` ',
|
||||
[t['Code block']()]: '``` Space',
|
||||
[t['Heading']({ number: '1' })]: '# Text',
|
||||
[t['Heading']({ number: '2' })]: '## Text',
|
||||
[t['Heading']({ number: '3' })]: '### Text',
|
||||
[t['Heading']({ number: '4' })]: '#### Text',
|
||||
[t['Heading']({ number: '5' })]: '##### Text',
|
||||
[t['Heading']({ number: '6' })]: '###### Text',
|
||||
};
|
||||
};
|
||||
|
||||
export const useWindowsKeyboardShortcuts = (): ShortcutTip => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return {
|
||||
[t('Undo')]: 'Ctrl+Z',
|
||||
[t('Redo')]: 'Ctrl+Y',
|
||||
[t('Bold')]: 'Ctrl+B',
|
||||
[t('Italic')]: 'Ctrl+I',
|
||||
[t('Underline')]: 'Ctrl+U',
|
||||
[t('Strikethrough')]: 'Ctrl+Shift+S',
|
||||
[t('Inline code')]: ' Ctrl+E',
|
||||
[t('Code block')]: 'Ctrl+Alt+C',
|
||||
[t('Link')]: 'Ctrl+K',
|
||||
[t('Quick search')]: 'Ctrl+K',
|
||||
[t('Body text')]: 'Ctrl+Shift+0',
|
||||
[t('Heading', { number: '1' })]: 'Ctrl+Shift+1',
|
||||
[t('Heading', { number: '2' })]: 'Ctrl+Shift+2',
|
||||
[t('Heading', { number: '3' })]: 'Ctrl+Shift+3',
|
||||
[t('Heading', { number: '4' })]: 'Ctrl+Shift+4',
|
||||
[t('Heading', { number: '5' })]: 'Ctrl+Shift+5',
|
||||
[t('Heading', { number: '6' })]: 'Ctrl+Shift+6',
|
||||
[t('Increase indent')]: 'Tab',
|
||||
[t('Reduce indent')]: 'Shift+Tab',
|
||||
[t['Undo']()]: 'Ctrl+Z',
|
||||
[t['Redo']()]: 'Ctrl+Y',
|
||||
[t['Bold']()]: 'Ctrl+B',
|
||||
[t['Italic']()]: 'Ctrl+I',
|
||||
[t['Underline']()]: 'Ctrl+U',
|
||||
[t['Strikethrough']()]: 'Ctrl+Shift+S',
|
||||
[t['Inline code']()]: ' Ctrl+E',
|
||||
[t['Code block']()]: 'Ctrl+Alt+C',
|
||||
[t['Link']()]: 'Ctrl+K',
|
||||
[t['Quick search']()]: 'Ctrl+K',
|
||||
[t['Body text']()]: 'Ctrl+Shift+0',
|
||||
[t['Heading']({ number: '1' })]: 'Ctrl+Shift+1',
|
||||
[t['Heading']({ number: '2' })]: 'Ctrl+Shift+2',
|
||||
[t['Heading']({ number: '3' })]: 'Ctrl+Shift+3',
|
||||
[t['Heading']({ number: '4' })]: 'Ctrl+Shift+4',
|
||||
[t['Heading']({ number: '5' })]: 'Ctrl+Shift+5',
|
||||
[t['Heading']({ number: '6' })]: 'Ctrl+Shift+6',
|
||||
[t['Increase indent']()]: 'Tab',
|
||||
[t['Reduce indent']()]: 'Shift+Tab',
|
||||
};
|
||||
};
|
||||
export const useWinMarkdownShortcuts = (): ShortcutTip => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return {
|
||||
[t('Bold')]: '**Text** ',
|
||||
[t('Italic')]: '*Text* ',
|
||||
[t('Underline')]: '~Text~ ',
|
||||
[t('Strikethrough')]: '~~Text~~ ',
|
||||
[t('Divider')]: '***',
|
||||
[t('Inline code')]: '`Text` ',
|
||||
[t('Code block')]: '``` Text',
|
||||
[t('Heading', { number: '1' })]: '# Text',
|
||||
[t('Heading', { number: '2' })]: '## Text',
|
||||
[t('Heading', { number: '3' })]: '### Text',
|
||||
[t('Heading', { number: '4' })]: '#### Text',
|
||||
[t('Heading', { number: '5' })]: '##### Text',
|
||||
[t('Heading', { number: '6' })]: '###### Text',
|
||||
[t['Bold']()]: '**Text** ',
|
||||
[t['Italic']()]: '*Text* ',
|
||||
[t['Underline']()]: '~Text~ ',
|
||||
[t['Strikethrough']()]: '~~Text~~ ',
|
||||
[t['Divider']()]: '***',
|
||||
[t['Inline code']()]: '`Text` ',
|
||||
[t['Code block']()]: '``` Text',
|
||||
[t['Heading']({ number: '1' })]: '# Text',
|
||||
[t['Heading']({ number: '2' })]: '## Text',
|
||||
[t['Heading']({ number: '3' })]: '### Text',
|
||||
[t['Heading']({ number: '4' })]: '#### Text',
|
||||
[t['Heading']({ number: '5' })]: '##### Text',
|
||||
[t['Heading']({ number: '6' })]: '###### Text',
|
||||
};
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
MuiSlide,
|
||||
} from '@affine/component';
|
||||
import { getEnvironment } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
@ -32,7 +32,7 @@ const checkIsMac = () => {
|
||||
};
|
||||
|
||||
export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const macMarkdownShortcuts = useMacMarkdownShortcuts();
|
||||
const winMarkdownShortcuts = useWinMarkdownShortcuts();
|
||||
const macKeyboardShortcuts = useMacKeyboardShortcuts();
|
||||
@ -59,7 +59,7 @@ export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
<StyledModalHeader>
|
||||
<StyledTitle>
|
||||
<KeyboardIcon />
|
||||
{t('Shortcuts')}
|
||||
{t['Shortcuts']()}
|
||||
</StyledTitle>
|
||||
|
||||
<ModalCloseButton
|
||||
@ -73,7 +73,7 @@ export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
/>
|
||||
</StyledModalHeader>
|
||||
<StyledSubTitle style={{ marginTop: 0 }}>
|
||||
{t('Keyboard Shortcuts')}
|
||||
{t['Keyboard Shortcuts']()}
|
||||
</StyledSubTitle>
|
||||
{Object.entries(keyboardShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
@ -83,7 +83,7 @@ export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
</StyledListItem>
|
||||
);
|
||||
})}
|
||||
<StyledSubTitle>{t('Markdown Syntax')}</StyledSubTitle>
|
||||
<StyledSubTitle>{t['Markdown Syntax']()}</StyledSubTitle>
|
||||
{Object.entries(markdownShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<StyledListItem key={title}>
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
@ -57,7 +57,7 @@ export const WorkspaceListModal = ({
|
||||
currentWorkspaceId,
|
||||
onMoveWorkspace,
|
||||
}: WorkspaceModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
@ -71,9 +71,9 @@ export const WorkspaceListModal = ({
|
||||
>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>{t('My Workspaces')}</StyledModalTitle>
|
||||
<StyledModalTitle>{t['My Workspaces']()}</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t('Workspace description')}
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
disablePortal={true}
|
||||
>
|
||||
@ -124,8 +124,8 @@ export const WorkspaceListModal = ({
|
||||
</StyleWorkspaceAdd>
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{t('New Workspace')}</StyleWorkspaceTitle>
|
||||
<p>{t('Create Or Import')}</p>
|
||||
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle>
|
||||
<p>{t['Create Or Import']()}</p>
|
||||
</StyleWorkspaceInfo>
|
||||
</StyledCreateWorkspaceCard>
|
||||
</StyledModalContent>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import { StyledCollapseItem } from '../shared-styles';
|
||||
|
||||
export const EmptyItem = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<StyledCollapseItem disable={true} textWrap={true}>
|
||||
{t('Favorite pages for easy access')}
|
||||
{t['Favorite pages for easy access']()}
|
||||
</StyledCollapseItem>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowDownSmallIcon, FavoriteIcon } from '@blocksuite/icons';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useCallback, useState } from 'react';
|
||||
@ -26,7 +26,7 @@ export const Favorite = ({
|
||||
|
||||
const [showSubFavorite, setOpenSubFavorite] = useState(true);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -50,7 +50,7 @@ export const Favorite = ({
|
||||
}}
|
||||
>
|
||||
<FavoriteIcon />
|
||||
{t('Favorites')}
|
||||
{t['Favorites']()}
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
<FavoriteList
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ResizeIndicator,
|
||||
} from '@affine/component/app-sidebar';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import {
|
||||
DeleteTemporarilyIcon,
|
||||
@ -67,7 +67,7 @@ export const RootAppSidebar = ({
|
||||
}: RootAppSidebarProps): ReactElement => {
|
||||
const currentWorkspaceId = currentWorkspace?.id || null;
|
||||
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [isScrollAtTop, setIsScrollAtTop] = useState(true);
|
||||
const onClickNewPage = useCallback(async () => {
|
||||
const page = await createPage();
|
||||
@ -89,7 +89,7 @@ export const RootAppSidebar = ({
|
||||
data-testid="new-page-button"
|
||||
onClick={onClickNewPage}
|
||||
>
|
||||
<PlusIcon /> {t('New Page')}
|
||||
<PlusIcon /> {t['New Page']()}
|
||||
</StyledNewPageButton>
|
||||
}
|
||||
>
|
||||
@ -106,7 +106,7 @@ export const RootAppSidebar = ({
|
||||
}, [onOpenQuickSearchModal])}
|
||||
>
|
||||
<SearchIcon />
|
||||
{t('Quick search')}
|
||||
{t['Quick search']()}
|
||||
</StyledListItem>
|
||||
<StyledListItem
|
||||
active={
|
||||
@ -125,7 +125,7 @@ export const RootAppSidebar = ({
|
||||
}}
|
||||
>
|
||||
<SettingsIcon />
|
||||
<div>{t('Workspace Settings')}</div>
|
||||
<div>{t['Workspace Settings']()}</div>
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
<StyledListItem
|
||||
@ -140,7 +140,7 @@ export const RootAppSidebar = ({
|
||||
}}
|
||||
>
|
||||
<FolderIcon />
|
||||
<span data-testid="all-pages">{t('All pages')}</span>
|
||||
<span data-testid="all-pages">{t['All pages']()}</span>
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
<StyledScrollWrapper
|
||||
@ -190,7 +190,7 @@ export const RootAppSidebar = ({
|
||||
}}
|
||||
>
|
||||
<ShareIcon />
|
||||
<span data-testid="shared-pages">{t('Shared Pages')}</span>
|
||||
<span data-testid="shared-pages">{t['Shared Pages']()}</span>
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
))}
|
||||
@ -205,7 +205,7 @@ export const RootAppSidebar = ({
|
||||
pathname: currentWorkspaceId && paths.trash(currentWorkspaceId),
|
||||
}}
|
||||
>
|
||||
<DeleteTemporarilyIcon /> {t('Trash')}
|
||||
<DeleteTemporarilyIcon /> {t['Trash']()}
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
</StyledSliderBarInnerWrapper>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { DEFAULT_HELLO_WORLD_PAGE_ID } from '@affine/env';
|
||||
import { initPage } from '@affine/env/blocksuite';
|
||||
import { setUpLanguage, useTranslation } from '@affine/i18n';
|
||||
import { setUpLanguage, useI18N } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { createAffineGlobalChannel } from '@affine/workspace/affine/sync';
|
||||
import {
|
||||
rootCurrentPageIdAtom,
|
||||
@ -147,22 +148,23 @@ export const CurrentWorkspaceContext = ({
|
||||
useRouterWithWorkspaceIdDefense(router);
|
||||
const metadata = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const exist = metadata.find(m => m.id === workspaceId);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
if (!router.isReady) {
|
||||
return <PageLoading text={t('Router is Loading')} />;
|
||||
return <PageLoading text={t['Router is Loading']()} />;
|
||||
}
|
||||
if (!workspaceId) {
|
||||
return <PageLoading text={t('Finding Workspace ID')} />;
|
||||
return <PageLoading text={t['Finding Workspace ID']()} />;
|
||||
}
|
||||
if (!exist) {
|
||||
return <PageLoading text={t('Workspace Not Found')} />;
|
||||
return <PageLoading text={t['Workspace Not Found']()} />;
|
||||
}
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export const WorkspaceLayout: FC<PropsWithChildren> =
|
||||
function WorkspacesSuspense({ children }) {
|
||||
const { i18n, t } = useTranslation();
|
||||
const i18n = useI18N();
|
||||
const t = useAFFiNEI18N();
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = i18n.language;
|
||||
// todo(himself65): this is a hack, we should use a better way to set the language
|
||||
@ -239,7 +241,7 @@ export const WorkspaceLayout: FC<PropsWithChildren> =
|
||||
</AllWorkspaceContext>
|
||||
<CurrentWorkspaceContext>
|
||||
<Suspense
|
||||
fallback={<PageLoading text={t('Finding Current Workspace')} />}
|
||||
fallback={<PageLoading text={t['Finding Current Workspace']()} />}
|
||||
>
|
||||
<Provider>
|
||||
<WorkspaceLayoutInner>{children}</WorkspaceLayoutInner>
|
||||
@ -256,7 +258,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
useEffect(() => {
|
||||
logger.info('currentWorkspace: ', currentWorkspace);
|
||||
@ -371,7 +373,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
/>
|
||||
<MainContainerWrapper>
|
||||
<MainContainer className="main-container">
|
||||
<Suspense fallback={<PageLoading text={t('Page is Loading')} />}>
|
||||
<Suspense fallback={<PageLoading text={t['Page is Loading']()} />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
<StyledToolWrapper>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Button, displayFlex, styled } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/legacy/image';
|
||||
import { useRouter } from 'next/router';
|
||||
@ -24,20 +24,20 @@ export const StyledContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const NotfoundPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const router = useRouter();
|
||||
return (
|
||||
<StyledContainer data-testid="notFound">
|
||||
<Image alt="404" src="/imgs/invite-error.svg" width={360} height={270} />
|
||||
|
||||
<p>{t('404 - Page Not Found')}</p>
|
||||
<p>{t['404 - Page Not Found']()}</p>
|
||||
<Button
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
router.push('/');
|
||||
}}
|
||||
>
|
||||
{t('Back Home')}
|
||||
{t['Back Home']()}
|
||||
</Button>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { NextPage } from 'next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Suspense, useEffect } from 'react';
|
||||
@ -63,9 +63,9 @@ const IndexPageInner = () => {
|
||||
};
|
||||
|
||||
const IndexPage: NextPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Suspense fallback={<PageLoading text={t('Loading All Workspaces')} />}>
|
||||
<Suspense fallback={<PageLoading text={t['Loading All Workspaces']()} />}>
|
||||
<IndexPageInner />
|
||||
</Suspense>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Breadcrumbs, displayFlex, styled } from '@affine/component';
|
||||
import { initPage } from '@affine/env/blocksuite';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { PageIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
|
||||
@ -72,7 +72,7 @@ const PublicWorkspaceDetailPageInner = (): ReactElement => {
|
||||
[blockSuiteWorkspace.id, openPage]
|
||||
),
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [name] = useBlockSuiteWorkspaceName(blockSuiteWorkspace);
|
||||
const [avatar] = useBlockSuiteWorkspaceAvatarUrl(blockSuiteWorkspace);
|
||||
const pageTitle = blockSuiteWorkspace.meta.getPageMeta(pageId)?.title;
|
||||
@ -101,7 +101,7 @@ const PublicWorkspaceDetailPageInner = (): ReactElement => {
|
||||
href={`/public-workspace/${blockSuiteWorkspace.id}/${pageId}`}
|
||||
>
|
||||
<PageIcon fontSize={24} />
|
||||
<span>{pageTitle ? pageTitle : t('Untitled')}</span>
|
||||
<span>{pageTitle ? pageTitle : t['Untitled']()}</span>
|
||||
</StyledBreadcrumbs>
|
||||
</Breadcrumbs>
|
||||
</NavContainer>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { BlockSuiteFeatureFlags } from '@affine/env';
|
||||
import { config } from '@affine/env';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { rootCurrentPageIdAtom } from '@affine/workspace/atom';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
@ -41,7 +41,7 @@ const WorkspaceDetail: React.FC = () => {
|
||||
const { openPage } = useRouterHelper(router);
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
assertExists(currentWorkspace);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
const { setPageMeta, getPageMeta } = usePageMetaHelper(blockSuiteWorkspace);
|
||||
@ -86,7 +86,7 @@ const WorkspaceDetail: React.FC = () => {
|
||||
}
|
||||
}, [currentWorkspace]);
|
||||
if (!currentPageId) {
|
||||
return <PageLoading text={t('Loading Page')} />;
|
||||
return <PageLoading text={t['Loading Page']()} />;
|
||||
}
|
||||
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
|
||||
@ -112,16 +112,16 @@ const WorkspaceDetailPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const currentWorkspace = useAtomValue(rootCurrentWorkspaceAtom);
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useRouterAndWorkspaceWithPageIdDefense(router);
|
||||
const page = useBlockSuiteWorkspacePage(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
currentPageId
|
||||
);
|
||||
if (!router.isReady) {
|
||||
return <PageLoading text={t('Router is Loading')} />;
|
||||
return <PageLoading text={t['Router is Loading']()} />;
|
||||
} else if (!currentPageId || !page) {
|
||||
return <PageLoading text={t('Page is Loading')} />;
|
||||
return <PageLoading text={t['Page is Loading']()} />;
|
||||
}
|
||||
return <WorkspaceDetail />;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { FolderIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
@ -23,7 +23,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
@ -47,7 +47,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('All Pages')} - AFFiNE</title>
|
||||
<title>{t['All pages']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -56,7 +56,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<FolderIcon />}
|
||||
>
|
||||
{t('All pages')}
|
||||
{t['All pages']()}
|
||||
</WorkspaceTitle>
|
||||
<PageList
|
||||
onOpenPage={onClickPage}
|
||||
@ -69,7 +69,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('All Pages')} - AFFiNE</title>
|
||||
<title>{t['All pages']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -78,7 +78,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<FolderIcon />}
|
||||
>
|
||||
{t('All pages')}
|
||||
{t['All pages']()}
|
||||
</WorkspaceTitle>
|
||||
<PageList
|
||||
onOpenPage={onClickPage}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { FavoriteIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import Head from 'next/head';
|
||||
@ -18,7 +18,7 @@ const FavouritePage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
@ -39,7 +39,7 @@ const FavouritePage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('Favorites')} - AFFiNE</title>
|
||||
<title>{t['Favorites']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -48,7 +48,7 @@ const FavouritePage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<FavoriteIcon />}
|
||||
>
|
||||
{t('Favorites')}
|
||||
{t['Favorites']()}
|
||||
</WorkspaceTitle>
|
||||
<PageList
|
||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { atomWithSyncStorage } from '@affine/jotai';
|
||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||
import type { SettingPanel } from '@affine/workspace/type';
|
||||
@ -35,7 +35,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const workspaceIds = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const [currentTab, setCurrentTab] = useAtom(settingPanelAtom);
|
||||
useEffect(() => {});
|
||||
@ -101,7 +101,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
assertExists(currentWorkspace);
|
||||
const workspaceId = currentWorkspace.id;
|
||||
if (workspaceIds.length === 1 && workspaceId === workspaceIds[0].id) {
|
||||
toast(t('You cannot delete the last workspace'));
|
||||
toast(t['You cannot delete the last workspace']());
|
||||
throw new Error('You cannot delete the last workspace');
|
||||
}
|
||||
return helper.deleteWorkspace(workspaceId);
|
||||
@ -119,7 +119,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('Settings')} - AFFiNE</title>
|
||||
<title>{t['Settings']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -128,7 +128,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<SettingsIcon />}
|
||||
>
|
||||
{t('Workspace Settings')}
|
||||
{t['Workspace Settings']()}
|
||||
</WorkspaceTitle>
|
||||
<Setting
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
@ -145,7 +145,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('Settings')} - AFFiNE</title>
|
||||
<title>{t['Settings']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -154,7 +154,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<SettingsIcon />}
|
||||
>
|
||||
{t('Workspace Settings')}
|
||||
{t['Workspace Settings']()}
|
||||
</WorkspaceTitle>
|
||||
<Setting
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ShareIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import Head from 'next/head';
|
||||
@ -18,7 +18,7 @@ const SharedPages: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
@ -39,7 +39,7 @@ const SharedPages: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('Shared Pages')} - AFFiNE</title>
|
||||
<title>{t['Shared Pages']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -48,7 +48,7 @@ const SharedPages: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<ShareIcon />}
|
||||
>
|
||||
{t('Shared Pages')}
|
||||
{t['Shared Pages']()}
|
||||
</WorkspaceTitle>
|
||||
<PageList
|
||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { DeleteTemporarilyIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import Head from 'next/head';
|
||||
@ -18,7 +18,7 @@ const TrashPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
@ -42,7 +42,7 @@ const TrashPage: NextPageWithLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('Trash')} - AFFiNE</title>
|
||||
<title>{t['Trash']()} - AFFiNE</title>
|
||||
</Head>
|
||||
<WorkspaceTitle
|
||||
workspace={currentWorkspace}
|
||||
@ -51,7 +51,7 @@ const TrashPage: NextPageWithLayout = () => {
|
||||
isPublic={false}
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
>
|
||||
{t('Trash')}
|
||||
{t['Trash']()}
|
||||
</WorkspaceTitle>
|
||||
<PageList
|
||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||
|
@ -30,7 +30,7 @@
|
||||
"test:unit": "vitest --run",
|
||||
"test:unit:ui": "vitest --ui",
|
||||
"test:unit:coverage": "vitest run --coverage",
|
||||
"postinstall": "husky install",
|
||||
"postinstall": "i18n-codegen gen && husky install",
|
||||
"notify": "node scripts/notify.mjs"
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -44,6 +44,7 @@
|
||||
"@commitlint/config-conventional": "^17.6.1",
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"@magic-works/i18n-codegen": "^0.5.0",
|
||||
"@perfsee/sdk": "^1.6.0",
|
||||
"@playwright/test": "^1.33.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
|
@ -5,6 +5,7 @@ import * as path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import * as p from '@clack/prompts';
|
||||
import { runCli } from '@magic-works/i18n-codegen';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@ -80,6 +81,14 @@ if (dev.server === 'local') {
|
||||
console.log('You might need setup OctoBase dev server first.');
|
||||
}
|
||||
|
||||
runCli(
|
||||
{
|
||||
watch: true,
|
||||
cwd: root,
|
||||
},
|
||||
console.error
|
||||
);
|
||||
|
||||
spawn('yarn', ['dev'], {
|
||||
env,
|
||||
cwd,
|
||||
|
@ -1,9 +1,23 @@
|
||||
import { runCli } from '@magic-works/i18n-codegen';
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { mergeConfig } from 'vite';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||
|
||||
runCli(
|
||||
{
|
||||
config: fileURLToPath(
|
||||
new URL('../../../.i18n-codegen.json', import.meta.url)
|
||||
),
|
||||
watch: false,
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
|
||||
export default {
|
||||
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
staticDirs: ['../../../apps/web/public'],
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon, NewIcon } from '@blocksuite/icons';
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
@ -20,7 +20,7 @@ type ChangeLogProps = {
|
||||
export const ChangeLog = (props: ChangeLogProps) => {
|
||||
const { onCloseWhatsNew } = props;
|
||||
const [isClose, setIsClose] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const handleClose = () => {
|
||||
setIsClose(true);
|
||||
onCloseWhatsNew();
|
||||
@ -47,7 +47,7 @@ export const ChangeLog = (props: ChangeLogProps) => {
|
||||
}}
|
||||
>
|
||||
<NewIcon className={iconStyle} />
|
||||
{t("Discover what's new!")}
|
||||
{t["Discover what's new!"]()}
|
||||
</div>
|
||||
<IconButton
|
||||
className={iconButtonStyle}
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ModalCloseButton,
|
||||
ModalWrapper,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import {
|
||||
DiscordIcon,
|
||||
@ -64,17 +64,17 @@ export const ContactModal = ({
|
||||
onClose,
|
||||
logoSrc,
|
||||
}: ContactModalProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const topLinkList = [
|
||||
{
|
||||
icon: <LogoIcon />,
|
||||
title: t('Official Website'),
|
||||
title: t['Official Website'](),
|
||||
subTitle: 'AFFiNE.pro',
|
||||
link: 'https://affine.pro',
|
||||
},
|
||||
{
|
||||
icon: <DocIcon />,
|
||||
title: t('Check Our Docs'),
|
||||
title: t['Check Our Docs'](),
|
||||
subTitle: 'Open Source',
|
||||
link: 'https://community.affine.pro',
|
||||
},
|
||||
@ -109,7 +109,7 @@ export const ContactModal = ({
|
||||
})}
|
||||
</FlexWrapper>
|
||||
<StyledSubTitle>
|
||||
{t('Get in touch! Join our communities.')}
|
||||
{t['Get in touch! Join our communities.']()}
|
||||
</StyledSubTitle>
|
||||
<FlexWrapper justifyContent="center">
|
||||
{linkList.map(({ icon, title, link }) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
||||
import { ExportToHtmlIcon, ExportToMarkdownIcon } from '@blocksuite/icons';
|
||||
import type { FC } from 'react';
|
||||
@ -16,11 +16,11 @@ import type { ShareMenuProps } from './ShareMenu';
|
||||
|
||||
export const Export: FC<ShareMenuProps> = props => {
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<div className={menuItemStyle}>
|
||||
<div className={descriptionStyle}>
|
||||
{t('Export Shared Pages Description')}
|
||||
{t['Export Shared Pages Description']()}
|
||||
</div>
|
||||
<div className={actionsStyle}>
|
||||
<Button
|
||||
@ -33,7 +33,7 @@ export const Export: FC<ShareMenuProps> = props => {
|
||||
}}
|
||||
>
|
||||
<ExportToHtmlIcon className={svgStyle} />
|
||||
{t('Export to HTML')}
|
||||
{t['Export to HTML']()}
|
||||
</Button>
|
||||
<Button
|
||||
className={exportButtonStyle}
|
||||
@ -45,7 +45,7 @@ export const Export: FC<ShareMenuProps> = props => {
|
||||
}}
|
||||
>
|
||||
<ExportToMarkdownIcon className={svgStyle} />
|
||||
{t('Export to Markdown')}
|
||||
{t['Export to Markdown']()}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { prefixUrl } from '@affine/env';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useBlockSuiteWorkspacePageIsPublic } from '@toeverything/hooks/use-block-suite-workspace-page-is-public';
|
||||
@ -23,17 +24,17 @@ import {
|
||||
} from './styles';
|
||||
|
||||
export const LocalSharePage: FC<ShareMenuProps> = props => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<div className={menuItemStyle}>
|
||||
<div className={descriptionStyle}>{t('Shared Pages Description')}</div>
|
||||
<div className={descriptionStyle}>{t['Shared Pages Description']()}</div>
|
||||
<StyledButton
|
||||
data-testid="share-menu-enable-affine-cloud-button"
|
||||
onClick={() => {
|
||||
props.onEnableAffineCloud(props.workspace as LocalWorkspace);
|
||||
}}
|
||||
>
|
||||
{t('Enable AFFiNE Cloud')}
|
||||
{t['Enable AFFiNE Cloud']()}
|
||||
</StyledButton>
|
||||
</div>
|
||||
);
|
||||
@ -44,7 +45,7 @@ export const AffineSharePage: FC<ShareMenuProps> = props => {
|
||||
props.currentPage
|
||||
);
|
||||
const [showDisable, setShowDisable] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const sharingUrl = useMemo(() => {
|
||||
return `${prefixUrl}public-workspace/${props.workspace.id}/${props.currentPage.id}`;
|
||||
}, [props.workspace.id, props.currentPage.id]);
|
||||
@ -53,13 +54,13 @@ export const AffineSharePage: FC<ShareMenuProps> = props => {
|
||||
}, [setIsPublic]);
|
||||
const onClickCopyLink = useCallback(() => {
|
||||
navigator.clipboard.writeText(sharingUrl);
|
||||
toast(t('Copied link to clipboard'));
|
||||
toast(t['Copied link to clipboard']());
|
||||
}, [sharingUrl, t]);
|
||||
|
||||
return (
|
||||
<div className={menuItemStyle}>
|
||||
<div className={descriptionStyle}>
|
||||
{t('Create Shared Link Description')}
|
||||
{t['Create Shared Link Description']()}
|
||||
</div>
|
||||
<div className={inputButtonRowStyle}>
|
||||
<StyledInput
|
||||
@ -72,7 +73,7 @@ export const AffineSharePage: FC<ShareMenuProps> = props => {
|
||||
data-testid="affine-share-create-link"
|
||||
onClick={onClickCreateLink}
|
||||
>
|
||||
{t('Create')}
|
||||
{t['Create']()}
|
||||
</StyledButton>
|
||||
)}
|
||||
{isPublic && (
|
||||
@ -80,7 +81,7 @@ export const AffineSharePage: FC<ShareMenuProps> = props => {
|
||||
data-testid="affine-share-copy-link"
|
||||
onClick={onClickCopyLink}
|
||||
>
|
||||
{t('Copy Link')}
|
||||
{t['Copy Link']()}
|
||||
</StyledButton>
|
||||
)}
|
||||
</div>
|
||||
@ -100,7 +101,7 @@ export const AffineSharePage: FC<ShareMenuProps> = props => {
|
||||
{isPublic && (
|
||||
<>
|
||||
<StyledDisableButton onClick={() => setShowDisable(true)}>
|
||||
{t('Disable Public Link')}
|
||||
{t['Disable Public Link']()}
|
||||
</StyledDisableButton>
|
||||
<PublicLinkDisableModal
|
||||
page={props.currentPage}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { FC } from 'react';
|
||||
@ -8,11 +8,11 @@ import type { ShareMenuProps } from './ShareMenu';
|
||||
import { StyledButton } from './styles';
|
||||
|
||||
const ShareLocalWorkspace: FC<ShareMenuProps<LocalWorkspace>> = props => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<div className={menuItemStyle}>
|
||||
<div className={descriptionStyle}>
|
||||
{t('Share Menu Public Workspace Description1')}
|
||||
{t['Share Menu Public Workspace Description1']()}
|
||||
</div>
|
||||
<StyledButton
|
||||
data-testid="share-menu-enable-affine-cloud-button"
|
||||
@ -20,7 +20,7 @@ const ShareLocalWorkspace: FC<ShareMenuProps<LocalWorkspace>> = props => {
|
||||
props.onOpenWorkspaceSettings(props.workspace);
|
||||
}}
|
||||
>
|
||||
{t('Open Workspace Settings')}
|
||||
{t['Open Workspace Settings']()}
|
||||
</StyledButton>
|
||||
</div>
|
||||
);
|
||||
@ -28,13 +28,13 @@ const ShareLocalWorkspace: FC<ShareMenuProps<LocalWorkspace>> = props => {
|
||||
|
||||
const ShareAffineWorkspace: FC<ShareMenuProps<AffineWorkspace>> = props => {
|
||||
const isPublicWorkspace = props.workspace.public;
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<div className={menuItemStyle}>
|
||||
<div className={descriptionStyle}>
|
||||
{isPublicWorkspace
|
||||
? t('Share Menu Public Workspace Description2')
|
||||
: t('Share Menu Public Workspace Description1')}
|
||||
? t['Share Menu Public Workspace Description2']()
|
||||
: t['Share Menu Public Workspace Description1']()}
|
||||
</div>
|
||||
<StyledButton
|
||||
data-testid="share-menu-publish-to-web-button"
|
||||
@ -42,7 +42,7 @@ const ShareAffineWorkspace: FC<ShareMenuProps<AffineWorkspace>> = props => {
|
||||
props.onOpenWorkspaceSettings(props.workspace);
|
||||
}}
|
||||
>
|
||||
{t('Open Workspace Settings')}
|
||||
{t['Open Workspace Settings']()}
|
||||
</StyledButton>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { useBlockSuiteWorkspacePageIsPublic } from '@toeverything/hooks/use-block-suite-workspace-page-is-public';
|
||||
import { useCallback } from 'react';
|
||||
@ -24,7 +24,7 @@ export const PublicLinkDisableModal = ({
|
||||
open,
|
||||
onClose,
|
||||
}: PublicLinkDisableProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [, setIsPublic] = useBlockSuiteWorkspacePageIsPublic(page);
|
||||
const handleDisable = useCallback(() => {
|
||||
setIsPublic(false);
|
||||
@ -37,20 +37,20 @@ export const PublicLinkDisableModal = ({
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<StyledModalWrapper>
|
||||
<ModalCloseButton onClick={onClose} top={12} right={12} />
|
||||
<StyledModalHeader>{t('Disable Public Link ?')}</StyledModalHeader>
|
||||
<StyledModalHeader>{t['Disable Public Link ?']()}</StyledModalHeader>
|
||||
|
||||
<StyledTextContent>
|
||||
{t('Disable Public Link Description')}
|
||||
{t['Disable Public Link Description']()}
|
||||
</StyledTextContent>
|
||||
|
||||
<StyledButtonContent>
|
||||
<StyledButton onClick={onClose}>{t('Cancel')}</StyledButton>
|
||||
<StyledButton onClick={onClose}>{t['Cancel']()}</StyledButton>
|
||||
<StyledDangerButton
|
||||
data-testid="disable-public-link-confirm-button"
|
||||
onClick={handleDisable}
|
||||
style={{ marginLeft: '24px' }}
|
||||
>
|
||||
{t('Disable')}
|
||||
{t['Disable']()}
|
||||
</StyledDangerButton>
|
||||
</StyledButtonContent>
|
||||
</StyledModalWrapper>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { PermissionType } from '@affine/workspace/affine/api';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
@ -46,7 +46,7 @@ const PublishIcon = () => {
|
||||
};
|
||||
|
||||
const WorkspaceType: FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
let isOwner = true;
|
||||
if (workspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
isOwner = workspace.permission === PermissionType.Owner;
|
||||
@ -56,22 +56,22 @@ const WorkspaceType: FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
|
||||
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t('Local Workspace')}>
|
||||
<p title={t['Local Workspace']()}>
|
||||
<LocalWorkspaceIcon />
|
||||
<span>{t('Local Workspace')}</span>
|
||||
<span>{t['Local Workspace']()}</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return isOwner ? (
|
||||
<p title={t('Cloud Workspace')}>
|
||||
<p title={t['Cloud Workspace']()}>
|
||||
<CloudWorkspaceIcon />
|
||||
<span>{t('Cloud Workspace')}</span>
|
||||
<span>{t['Cloud Workspace']()}</span>
|
||||
</p>
|
||||
) : (
|
||||
<p title={t('Joined Workspace')}>
|
||||
<p title={t['Joined Workspace']()}>
|
||||
<JoinedWorkspaceIcon />
|
||||
<span>{t('Joined Workspace')}</span>
|
||||
<span>{t['Joined Workspace']()}</span>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
@ -89,7 +89,7 @@ export const WorkspaceCard: FC<WorkspaceCardProps> = ({
|
||||
onSettingClick,
|
||||
currentWorkspaceId,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
|
||||
return (
|
||||
@ -106,15 +106,15 @@ export const WorkspaceCard: FC<WorkspaceCardProps> = ({
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<WorkspaceType workspace={workspace} />
|
||||
{workspace.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<p title={t('Available Offline')}>
|
||||
<p title={t['Available Offline']()}>
|
||||
<LocalDataIcon />
|
||||
<span>{t('Available Offline')}</span>
|
||||
<span>{t['Available Offline']()}</span>
|
||||
</p>
|
||||
)}
|
||||
{workspace.flavour === WorkspaceFlavour.AFFINE && workspace.public && (
|
||||
<p title={t('Published to Web')}>
|
||||
<p title={t['Published to Web']()}>
|
||||
<PublishIcon />
|
||||
<span>{t('Published to Web')}</span>
|
||||
<span>{t['Published to Web']()}</span>
|
||||
</p>
|
||||
)}
|
||||
</StyleWorkspaceInfo>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import { Button } from '../button';
|
||||
import type { ModalProps } from '../modal';
|
||||
@ -38,7 +38,7 @@ export const Confirm = ({
|
||||
cancelButtonTestId = '',
|
||||
confirmButtonTestId = '',
|
||||
}: ConfirmProps) => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Modal open={open} disablePortal={false}>
|
||||
<StyledModalWrapper>
|
||||
@ -60,7 +60,7 @@ export const Confirm = ({
|
||||
style={{ marginRight: '24px' }}
|
||||
data-testid={cancelButtonTestId}
|
||||
>
|
||||
{cancelText === 'Cancel' ? t('Cancel') : cancelText}
|
||||
{cancelText === 'Cancel' ? t['Cancel']() : cancelText}
|
||||
</Button>
|
||||
<Button
|
||||
type={confirmType}
|
||||
@ -102,7 +102,7 @@ export const Confirm = ({
|
||||
}}
|
||||
data-testid={cancelButtonTestId}
|
||||
>
|
||||
{cancelText === 'Cancel' ? t('Cancel') : cancelText}
|
||||
{cancelText === 'Cancel' ? t['Cancel']() : cancelText}
|
||||
</Button>
|
||||
</StyledColumnButtonWrapper>
|
||||
)}
|
||||
|
@ -6,7 +6,7 @@
|
||||
- Replace literal text with translation keys
|
||||
|
||||
```tsx
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
// src/resources/en.json
|
||||
// {
|
||||
@ -15,7 +15,7 @@ import { useTranslation } from '@affine/i18n';
|
||||
// };
|
||||
|
||||
const App = () => {
|
||||
const { t } = useTranslation();
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const changeLanguage = (language: string) => {
|
||||
i18n.changeLanguage(language);
|
||||
@ -25,12 +25,8 @@ const App = () => {
|
||||
<div>
|
||||
<div>{t('Text')}</div>
|
||||
|
||||
<button onClick={() => changeLanguage('en')}>
|
||||
{t('Switch to language', { language: 'en' })}
|
||||
</button>
|
||||
<button onClick={() => changeLanguage('zh-Hans')}>
|
||||
{t('Switch to language', { language: 'zh-Hans' })}
|
||||
</button>
|
||||
<button onClick={() => changeLanguage('en')}>{t('Switch to language', { language: 'en' })}</button>
|
||||
<button onClick={() => changeLanguage('zh-Hans')}>{t('Switch to language', { language: 'zh-Hans' })}</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -4,7 +4,8 @@
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": "./src/index.ts",
|
||||
"./hooks": "./src/i18n_generated"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "dist/src/index.js",
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
I18nextProvider,
|
||||
initReactI18next,
|
||||
Trans,
|
||||
useTranslation,
|
||||
useTranslation as useRootTranslation,
|
||||
} from 'react-i18next';
|
||||
|
||||
import { LOCALES } from './resources';
|
||||
@ -38,7 +38,11 @@ declare module 'react-i18next' {
|
||||
|
||||
const STORAGE_KEY = 'i18n_lng';
|
||||
|
||||
export { I18nextProvider, LOCALES, Trans, useTranslation };
|
||||
export { I18nextProvider, LOCALES, Trans };
|
||||
export function useI18N() {
|
||||
const { i18n } = useRootTranslation();
|
||||
return i18n;
|
||||
}
|
||||
|
||||
const resources = LOCALES.reduce<Resource>(
|
||||
(acc, { tag, res }) => ({ ...acc, [tag]: { translation: res } }),
|
||||
|
@ -8,6 +8,8 @@
|
||||
"It takes up more space on your device": {
|
||||
"": "It takes up more space on your device."
|
||||
},
|
||||
"Synced with AFFiNE Cloud": "Synced with AFFiNE Cloud",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Export AFFiNE backup file": "Export AFFiNE backup file",
|
||||
"Saved then enable AFFiNE Cloud": "All changes are saved locally, click to enable AFFiNE Cloud.",
|
||||
"Not now": "Not now",
|
||||
@ -95,6 +97,7 @@
|
||||
"Quick search placeholder": "Quick Search...",
|
||||
"Quick search placeholder2": "Search in {{workspace}}",
|
||||
"Settings": "Settings",
|
||||
"Recent": "Recent",
|
||||
"recommendBrowser": " We recommend the <1>Chrome</1> browser for optimal experience.",
|
||||
"upgradeBrowser": "Please upgrade to the latest version of Chrome for the best experience.",
|
||||
"Invite Members": "Invite Members",
|
||||
|
19
scripts/setup/i18n.ts
Normal file
19
scripts/setup/i18n.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { runCli } from '@magic-works/i18n-codegen';
|
||||
import { beforeAll } from 'vitest';
|
||||
|
||||
beforeAll(async () => {
|
||||
await runCli(
|
||||
{
|
||||
watch: false,
|
||||
cwd: fileURLToPath(
|
||||
new URL('../../../.i18n-codegen.json', import.meta.url)
|
||||
),
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
});
|
@ -22,6 +22,7 @@
|
||||
"@affine/component/*": ["./packages/component/src/components/*/index"],
|
||||
"@affine/templates/*": ["./packages/templates/src/*"],
|
||||
"@affine/i18n": ["./packages/i18n/src"],
|
||||
"@affine/i18n/hooks": ["./packages/i18n/src/i18n_generated"],
|
||||
"@affine/debug": ["./packages/debug"],
|
||||
"@affine/jotai": ["./packages/jotai"],
|
||||
"@affine/env": ["./packages/env"],
|
||||
|
@ -5,5 +5,5 @@
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vitest.config.ts"]
|
||||
"include": ["vitest.config.ts", "scripts"]
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ export default defineConfig({
|
||||
test: {
|
||||
setupFiles: [
|
||||
resolve(rootDir, './scripts/setup/lit.ts'),
|
||||
resolve(rootDir, './scripts/setup/i18n.ts'),
|
||||
resolve(rootDir, './scripts/setup/search.ts'),
|
||||
resolve(rootDir, './scripts/setup/lottie-web.ts'),
|
||||
],
|
||||
|
43
yarn.lock
43
yarn.lock
@ -5075,6 +5075,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@magic-works/i18n-codegen@npm:^0.5.0":
|
||||
version: 0.5.0
|
||||
resolution: "@magic-works/i18n-codegen@npm:0.5.0"
|
||||
dependencies:
|
||||
chokidar: ^3.5.3
|
||||
i18next-translation-parser: ^1.0.1
|
||||
yargs: ^17.7.0
|
||||
peerDependencies:
|
||||
typescript: ^4.8 || ^5
|
||||
bin:
|
||||
i18n-codegen: dist/cli.js
|
||||
checksum: 6b730f322dbf90b55256ca818546252b43b9c86e051d3de697f09b64b12b09812af468b185f64546f0cb53ef07815b91dfaa9d0ed2de0b3a58fb2f81a4dc67a9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@malept/cross-spawn-promise@npm:^1.0.0, @malept/cross-spawn-promise@npm:^1.1.0":
|
||||
version: 1.1.1
|
||||
resolution: "@malept/cross-spawn-promise@npm:1.1.1"
|
||||
@ -9431,6 +9446,7 @@ __metadata:
|
||||
"@commitlint/config-conventional": ^17.6.1
|
||||
"@faker-js/faker": ^7.6.0
|
||||
"@istanbuljs/schema": ^0.1.3
|
||||
"@magic-works/i18n-codegen": ^0.5.0
|
||||
"@perfsee/sdk": ^1.6.0
|
||||
"@playwright/test": ^1.33.0
|
||||
"@testing-library/react": ^14.0.0
|
||||
@ -15536,6 +15552,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-parse-stringify2@github:locize/html-parse-stringify2":
|
||||
version: 2.0.1
|
||||
resolution: "html-parse-stringify2@https://github.com/locize/html-parse-stringify2.git#commit=d463109433b2c49c74a081044f54b2a6a1ccad7c"
|
||||
dependencies:
|
||||
void-elements: ^2.0.1
|
||||
checksum: 4416c04f907ec14e4dac96b32094dd98a8633264f1d8b1128243c20d0e720dc79dfd5ccaac5ee4d80b7f845e676a248bfbe323fe86c096ea020c0e33d754d0b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-parse-stringify@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "html-parse-stringify@npm:3.0.1"
|
||||
@ -15703,6 +15728,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next-translation-parser@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "i18next-translation-parser@npm:1.0.1"
|
||||
dependencies:
|
||||
html-parse-stringify2: "github:locize/html-parse-stringify2"
|
||||
checksum: c208e0335a7fc3f3e298811d4d512c86bfdf5e5d7048081ed1a1f41940e775efa7c330b8147fde97e46b0876d02c30d9b9213c672198add39215599cd019b802
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next@npm:^22.4.15":
|
||||
version: 22.4.15
|
||||
resolution: "i18next@npm:22.4.15"
|
||||
@ -24739,6 +24773,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"void-elements@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "void-elements@npm:2.0.1"
|
||||
checksum: 700c07ba9cfa2dff88bb23974b3173118f9ad8107143db9e5d753552be15cf93380954d4e7f7d7bc80e7306c35c3a7fb83ab0ce4d4dcc18abf90ca8b31452126
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vscode-oniguruma@npm:^1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "vscode-oniguruma@npm:1.7.0"
|
||||
@ -25437,7 +25478,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs@npm:^17.0.0, yargs@npm:^17.0.1, yargs@npm:^17.3.1, yargs@npm:^17.7.1":
|
||||
"yargs@npm:^17.0.0, yargs@npm:^17.0.1, yargs@npm:^17.3.1, yargs@npm:^17.7.0, yargs@npm:^17.7.1":
|
||||
version: 17.7.2
|
||||
resolution: "yargs@npm:17.7.2"
|
||||
dependencies:
|
||||
|
Loading…
Reference in New Issue
Block a user