diff --git a/.gitignore b/.gitignore index a8c9432050..8b5acf4b1f 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ Thumbs.db .next out/ storybook-static +i18n_generated.ts /test-results/ /playwright-report/ diff --git a/.i18n-codegen.json b/.i18n-codegen.json new file mode 100644 index 0000000000..a22858e0ee --- /dev/null +++ b/.i18n-codegen.json @@ -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 + } + } + ] +} diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 0c58730d46..bed8a77a25 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -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) { diff --git a/apps/web/src/components/affine/enable-affine-cloud-modal/index.tsx b/apps/web/src/components/affine/enable-affine-cloud-modal/index.tsx index d82cf55b27..bb6631e2cf 100644 --- a/apps/web/src/components/affine/enable-affine-cloud-modal/index.tsx +++ b/apps/web/src/components/affine/enable-affine-cloud-modal/index.tsx @@ -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 = ({ open, onClose, }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const user = useCurrentUser(); return ( @@ -33,8 +33,8 @@ export const EnableAffineCloudModal: React.FC = ({ - {t('Enable AFFiNE Cloud')}? - {t('Enable AFFiNE Cloud Description')} + {t['Enable AFFiNE Cloud']()}? + {t['Enable AFFiNE Cloud Description']()} {/* {t('Retain cached cloud data')} */}
= ({ onConfirm(); }} > - {user ? t('Enable') : t('Sign in and Enable')} + {user ? t.Enable() : t['Sign in and Enable']()} = ({ onClose(); }} > - {t('Not now')} + {t['Not now']()}
diff --git a/apps/web/src/components/affine/operation-menu-items/CopyLink.tsx b/apps/web/src/components/affine/operation-menu-items/CopyLink.tsx index 7410736398..58203e1cfa 100644 --- a/apps/web/src/components/affine/operation-menu-items/CopyLink.tsx +++ b/apps/web/src/components/affine/operation-menu-items/CopyLink.tsx @@ -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={} > - {t('Copy Link')} + {t['Copy Link']()} ); }; diff --git a/apps/web/src/components/affine/operation-menu-items/DisablePublicSharing.tsx b/apps/web/src/components/affine/operation-menu-items/DisablePublicSharing.tsx index 4a7b1deab9..50deb4d81e 100644 --- a/apps/web/src/components/affine/operation-menu-items/DisablePublicSharing.tsx +++ b/apps/web/src/components/affine/operation-menu-items/DisablePublicSharing.tsx @@ -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 ( <> } > - {t('Disable Public Sharing')} + {t['Disable Public Sharing']()} ); diff --git a/apps/web/src/components/affine/operation-menu-items/Export.tsx b/apps/web/src/components/affine/operation-menu-items/Export.tsx index 4974fdc583..eb3c71dc0f 100644 --- a/apps/web/src/components/affine/operation-menu-items/Export.tsx +++ b/apps/web/src/components/affine/operation-menu-items/Export.tsx @@ -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(); return ( } > - {t('Export to HTML')} + {t['Export to HTML']()} } > - {t('Export to Markdown')} + {t['Export to Markdown']()} } @@ -66,7 +66,7 @@ export const Export = ({ onItemClick?.(); }} > - {t('Export')} + {t.Export()} ); diff --git a/apps/web/src/components/affine/operation-menu-items/MoveTo.tsx b/apps/web/src/components/affine/operation-menu-items/MoveTo.tsx index adc316fe88..318ec4364a 100644 --- a/apps/web/src/components/affine/operation-menu-items/MoveTo.tsx +++ b/apps/web/src/components/affine/operation-menu-items/MoveTo.tsx @@ -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(null); const [anchorEl, setAnchorEl] = useState(null); const open = anchorEl !== null; @@ -44,7 +44,7 @@ export const MoveTo = ({ endIcon={} data-testid="move-to-menu-item" > - {t('Move to')} + {t['Move to']()} { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return ( <> @@ -23,7 +23,7 @@ export const MoveToTrash = ({ }} icon={} > - {t('Move to Trash')} + {t['Move to Trash']()} ); @@ -35,15 +35,15 @@ const ConfirmModal = ({ }: { meta: PageMeta; } & ConfirmProps) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return ( diff --git a/apps/web/src/components/affine/pinboard/pinboard-menu/SearchContent.tsx b/apps/web/src/components/affine/pinboard/pinboard-menu/SearchContent.tsx index 6141ba32f3..ca7691951d 100644 --- a/apps/web/src/components/affine/pinboard/pinboard-menu/SearchContent.tsx +++ b/apps/web/src/components/affine/pinboard/pinboard-menu/SearchContent.tsx @@ -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 ( <> - {t('Find results', { number: results.length })} + {t['Find results']({ number: `${results.length}` })} {results.map(meta => { return ( @@ -45,7 +45,7 @@ export const SearchContent = ({ return ( <> - {t('Find 0 result')} + {t['Find 0 result']()} 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 = ({ e.stopPropagation()} @@ -121,9 +121,9 @@ export const PinboardMenu = ({ }} > - {t('Remove from Pinboard')} + {t['Remove from Pivots']()} -

{t('RFP')}

+

{t['RFP']()}

)} diff --git a/apps/web/src/components/affine/pinboard/pinboard-render/EmptyItem.tsx b/apps/web/src/components/affine/pinboard/pinboard-render/EmptyItem.tsx index f898be1134..af68c6d479 100644 --- a/apps/web/src/components/affine/pinboard/pinboard-render/EmptyItem.tsx +++ b/apps/web/src/components/affine/pinboard/pinboard-render/EmptyItem.tsx @@ -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 ( - {t('Organize pages to build knowledge')} + {t['Organize pages to build knowledge']()} ); }; diff --git a/apps/web/src/components/affine/pinboard/pinboard-render/OperationButton.tsx b/apps/web/src/components/affine/pinboard/pinboard-render/OperationButton.tsx index 7bde0670b8..40c496cb6b 100644 --- a/apps/web/src/components/affine/pinboard/pinboard-render/OperationButton.tsx +++ b/apps/web/src/components/affine/pinboard/pinboard-render/OperationButton.tsx @@ -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>(); const [anchorEl, setAnchorEl] = useState(null); @@ -100,7 +100,7 @@ export const OperationButton = ({ }} icon={} > - {t('Add a subpage inside')} + {t['Add a subpage inside']()} {!isRoot && ( } > - {t('Move to')} + {t['Move to']()} )} {!isRoot && ( @@ -124,7 +124,7 @@ export const OperationButton = ({ }} icon={} > - {t('Rename')} + {t['Rename']()} )} {!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(); }} diff --git a/apps/web/src/components/affine/sidebar-switch/index.tsx b/apps/web/src/components/affine/sidebar-switch/index.tsx index cd09c60d69..af6988e301 100644 --- a/apps/web/src/components/affine/sidebar-switch/index.tsx +++ b/apps/web/src/components/affine/sidebar-switch/index.tsx @@ -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 ( = ({ open, onClose, onConform }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const user = useCurrentUser(); return ( @@ -35,8 +35,8 @@ export const TransformWorkspaceToAffineModal: React.FC< - {t('Enable AFFiNE Cloud')}? - {t('Enable AFFiNE Cloud Description')} + {t['Enable AFFiNE Cloud']()}? + {t['Enable AFFiNE Cloud Description']()} {/* {t('Retain cached cloud data')} */}
- {user ? t('Enable') : t('Sign in and Enable')} + {user ? t['Enable']() : t['Sign in and Enable']()} - {t('Not now')} + {t['Not now']()}
diff --git a/apps/web/src/components/affine/workspace-setting-detail/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/index.tsx index d8ad7ac453..518d284b00 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/index.tsx @@ -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; }; @@ -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]()} ); })} diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx index cc63713ff4..af4e76805b 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx @@ -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<
    - {t('Users')} ( + {t['Users']()} ( {members.length}) - {t('Access level')} + {t['Access level']()}
    @@ -91,9 +91,9 @@ const AffineRemoteCollaborationPanel: React.FC< {member.accepted ? member.type !== PermissionType.Owner - ? t('Member') - : t('Owner') - : t('Pending')} + ? t['Member']() + : t['Owner']() + : t['Pending']()} {member.type === PermissionType.Owner ? ( @@ -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={} > - {t('Remove from workspace')} + {t['Remove from workspace']()} } @@ -145,7 +145,7 @@ const AffineRemoteCollaborationPanel: React.FC< data-testid="invite-members" shape="circle" > - {t('Invite Members')} + {t['Invite Members']()} @@ -168,11 +168,11 @@ const LocalCollaborationPanel: React.FC< workspace: LocalWorkspace; } > = ({ workspace, onTransferWorkspace }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const [open, setOpen] = useState(false); return ( <> - {t('Collaboration Description')} + {t['Collaboration Description']()} {config.enableLegacyCloud ? ( (''); 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 = ({ /> - {t('Invite Members')} + {t['Invite Members']()} { setShowMemberPreview(false); }, [])} - placeholder={t('Invite placeholder')} + placeholder={t['Invite placeholder']()} /> {showMemberPreview && gmailReg.test(email) && ( @@ -112,7 +112,7 @@ export const InviteMemberModal = ({ onInviteSuccess(); }} > - {t('Invite')} + {t['Invite']()} diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/export/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/export/index.tsx index 0c6ae934b0..d1a66067d4 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/export/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/export/index.tsx @@ -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 ( <> - {t('Export Description')} + {t['Export Description']()} ); diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx index a0f3dd12a2..331a779dda 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx @@ -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(''); 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 = ({ - {t('Delete Workspace')}? + {t['Delete Workspace']()}? {workspace.flavour === WorkspaceFlavour.LOCAL ? ( @@ -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 = ({ diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx index 397984c46c..dfd9a90fd7 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx @@ -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 = ({ const [input, setInput] = useState(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 = ({ return ( <> - {t('Workspace Avatar')} + {t['Workspace Avatar']()} {isOwner ? ( = ({ - {t('Workspace Name')} + {t['Workspace Name']()}
    @@ -84,7 +84,7 @@ export const GeneralPanel: React.FC = ({ setShowEditInput(true); }} > - {t('Edit')} + {t['Edit']()} )} @@ -97,7 +97,7 @@ export const GeneralPanel: React.FC = ({ 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 = ({ setShowEditInput(false); }} > - {t('Confirm')} + {t['Confirm']()} @@ -165,29 +165,29 @@ export const GeneralPanel: React.FC = ({ } }} > - {t('Workspace Type')} + {t['Workspace Type']()} {isOwner ? ( workspace.flavour === WorkspaceFlavour.LOCAL ? ( - {t('Local Workspace')} + {t['Local Workspace']()} ) : ( - {t('Cloud Workspace')} + {t['Cloud Workspace']()} ) ) : ( - {t('Joined Workspace')} + {t['Joined Workspace']()} )} - {t('Delete Workspace')} + {t['Delete Workspace']()} {isOwner ? ( <> = ({ setShowLeave(true); }} > - {t('Leave Workspace')} + {t['Leave Workspace']()} { // 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) => { - {t('Leave Workspace')} + {t['Leave Workspace']()} - {t('Leave Workspace Description')} + {t['Leave Workspace Description']()} diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx index 9f361da49b..b73b0a1735 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx @@ -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 = ({ ); }, []); 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 ( <> - {t('Published Description')} + {t['Published Description']()} - {t('Share with link')} + {t['Share with link']()} = ({ shape="circle" style={{ marginLeft: '24px' }} > - {t('Copy Link')} + {t['Copy Link']()} ); } return ( <> - {t('Publishing Description')} + {t['Publishing Description']()} ); @@ -111,7 +111,7 @@ const PublishPanelLocal: React.FC = ({ workspace, onTransferWorkspace, }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const [open, setOpen] = useState(false); return ( <> @@ -120,7 +120,7 @@ const PublishPanelLocal: React.FC = ({ marginBottom: '42px', }} > - {t('Publishing')} + {t['Publishing']()} {/* TmpDisableAffineCloudModal */} @@ -132,7 +132,7 @@ const PublishPanelLocal: React.FC = ({ setOpen(true); }} > - {t('Enable AFFiNE Cloud')} + {t['Enable AFFiNE Cloud']()} {config.enableLegacyCloud ? ( = ({ workspace }) => { workspace.blockSuiteWorkspace ); const user = useCurrentUser(); - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return ( <> @@ -37,7 +38,7 @@ export const SyncPanel: React.FC = ({ workspace }) => { /> {name}   - {t('is a Cloud Workspace')} + {t['is a Cloud Workspace']()} All data will be synchronised and saved to the AFFiNE account diff --git a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/Empty.tsx b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/Empty.tsx index b1ce9fcc81..7c2af5aaed 100644 --- a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/Empty.tsx +++ b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/Empty.tsx @@ -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'](); } }; diff --git a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/OperationCell.tsx b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/OperationCell.tsx index 4338270a11..8bcbbb8d66 100644 --- a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/OperationCell.tsx +++ b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/OperationCell.tsx @@ -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 = ({ 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 = ({ 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 = ({ ) } > - {favorite ? t('Remove from favorites') : t('Add to Favorites')} + {favorite ? t['Remove from favorites']() : t['Add to Favorites']()} {!environment.isDesktop && ( = ({ }} icon={} > - {t('Open in new tab')} + {t['Open in new tab']()} )} {!pageMeta.isRootPinboard && ( @@ -117,7 +117,7 @@ export const OperationCell: React.FC = ({ 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 = ({ onRestorePage, }) => { const { id, title } = pageMeta; - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const [open, setOpen] = useState(false); return ( - + { onRestorePage(id); - toast(t('restored', { title: title || 'Untitled' })); + toast(t['restored']({ title: title || 'Untitled' })); }} > - + { setOpen(true); @@ -176,14 +176,14 @@ export const TrashOperationCell: React.FC = ({ { onPermanentlyDeletePage(id); - toast(t('Permanently deleted')); + toast(t['Permanently deleted']()); setOpen(false); }} onClose={() => { diff --git a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/index.tsx b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/index.tsx index 11a6ced868..9c9aa0265e 100644 --- a/apps/web/src/components/blocksuite/block-suite-page-list/page-list/index.tsx +++ b/apps/web/src/components/blocksuite/block-suite-page-list/page-list/index.tsx @@ -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 = ({ pageMeta: { favorite }, onClick, }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return ( = ({ 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 = ({ 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 = ({ {matches && ( <> - {t('Title')} - {t('Created')} + {t['Title']()} + {t['Created']()} {isTrash - ? t('Moved to Trash') + ? t['Moved to Trash']() : isShared ? 'Shared' - : t('Updated')} + : t['Updated']()} @@ -164,7 +164,7 @@ export const PageList: React.FC = ({ )} - {pageMeta.title || t('Untitled')} + {pageMeta.title || t['Untitled']()} {listType && !isTrash && ( diff --git a/apps/web/src/components/blocksuite/workspace-header/header-right-items/EditorOptionMenu.tsx b/apps/web/src/components/blocksuite/workspace-header/header-right-items/EditorOptionMenu.tsx index 0115f1989a..fba8e276b2 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header-right-items/EditorOptionMenu.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header-right-items/EditorOptionMenu.tsx @@ -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']()} : } @@ -106,8 +108,8 @@ const PageMenu = () => { })); }} > - {t('Convert to ')} - {mode === 'page' ? t('Edgeless') : t('Page')} + {t['Convert to ']()} + {mode === 'page' ? t['Edgeless']() : t['Page']()} {!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); diff --git a/apps/web/src/components/blocksuite/workspace-header/header-right-items/LanguageMenu.tsx b/apps/web/src/components/blocksuite/workspace-header/header-right-items/LanguageMenu.tsx index bdf474def1..537b06750c 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header-right-items/LanguageMenu.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header-right-items/LanguageMenu.tsx @@ -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); diff --git a/apps/web/src/components/blocksuite/workspace-header/header-right-items/SyncUser.tsx b/apps/web/src/components/blocksuite/workspace-header/header-right-items/SyncUser.tsx index cabd23eef9..ce3094a8ba 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header-right-items/SyncUser.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header-right-items/SyncUser.tsx @@ -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 ( @@ -103,7 +103,7 @@ export const SyncUser = () => { return ( <> { } return ( - + diff --git a/apps/web/src/components/blocksuite/workspace-header/header-right-items/TrashButtonGroup.tsx b/apps/web/src/components/blocksuite/workspace-header/header-right-items/TrashButtonGroup.tsx index 98fba9e850..e01cd71bf6 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header-right-items/TrashButtonGroup.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header-right-items/TrashButtonGroup.tsx @@ -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']()} { diff --git a/apps/web/src/components/blocksuite/workspace-header/header.tsx b/apps/web/src/components/blocksuite/workspace-header/header.tsx index 16ca624507..25cb7a680e 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header.tsx @@ -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 ( diff --git a/apps/web/src/components/blocksuite/workspace-header/utils.tsx b/apps/web/src/components/blocksuite/workspace-header/utils.tsx index 5aecfe0ebd..212bdaa07e 100644 --- a/apps/web/src/components/blocksuite/workspace-header/utils.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/utils.tsx @@ -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 = () => { ); } else if (notGoodVersion) { - return {t('upgradeBrowser')}; + return {t['upgradeBrowser']()}; } return null; }; diff --git a/apps/web/src/components/pure/create-workspace-modal/index.tsx b/apps/web/src/components/pure/create-workspace-modal/index.tsx index 811275207e..1f6a87869d 100644 --- a/apps/web/src/components/pure/create-workspace-modal/index.tsx +++ b/apps/web/src/components/pure/create-workspace-modal/index.tsx @@ -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 ( @@ -49,8 +49,8 @@ export const CreateWorkspaceModal = ({ /> - {t('New Workspace')} -

    {t('Workspace description')}

    + {t['New Workspace']()} +

    {t['Workspace description']()}

    { 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']()}
    diff --git a/apps/web/src/components/pure/file-upload/index.tsx b/apps/web/src/components/pure/file-upload/index.tsx index d502ef5f47..dd88b651e0 100644 --- a/apps/web/src/components/pure/file-upload/index.tsx +++ b/apps/web/src/components/pure/file-upload/index.tsx @@ -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 = ({ children, ...props }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const input_ref = useRef(null); const _chooseFile = () => { if (input_ref.current) { @@ -37,7 +37,7 @@ export const Upload: React.FC = ({ }; return ( - {children ?? } + {children ?? } = ({ user, onLogin, onLogout }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const setOpen = useSetAtom(openDisableCloudAlertModalAtom); return ( @@ -38,7 +38,7 @@ export const Footer: React.FC = ({ user, onLogin, onLogout }) => {

    {user.email}

    - + { @@ -69,7 +69,7 @@ export const Footer: React.FC = ({ user, onLogin, onLogout }) => { } }} > - {t('Sign in')} + {t['Sign in']()} )} diff --git a/apps/web/src/components/pure/help-island/index.tsx b/apps/web/src/components/pure/help-island/index.tsx index 39f6669270..befb63f350 100644 --- a/apps/web/src/components/pure/help-island/index.tsx +++ b/apps/web/src/components/pure/help-island/index.tsx @@ -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') && ( - + { @@ -73,7 +73,7 @@ export const HelpIsland = ({ )} {showList.includes('contact') && ( - + { @@ -86,7 +86,7 @@ export const HelpIsland = ({ )} {showList.includes('shortcuts') && ( - + { @@ -100,7 +100,7 @@ export const HelpIsland = ({ )} - + diff --git a/apps/web/src/components/pure/loading/PageLoading.tsx b/apps/web/src/components/pure/loading/PageLoading.tsx index aaa262ff4a..c62ab1084e 100644 --- a/apps/web/src/components/pure/loading/PageLoading.tsx +++ b/apps/web/src/components/pure/loading/PageLoading.tsx @@ -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 ( -

    {text ? text : t('Loading')}

    +

    {text ? text : t['Loading']()}

    ); }; diff --git a/apps/web/src/components/pure/quick-search-modal/Footer.tsx b/apps/web/src/components/pure/quick-search-modal/Footer.tsx index 6602956eba..7bed0836c8 100644 --- a/apps/web/src/components/pure/quick-search-modal/Footer.tsx +++ b/apps/web/src/components/pure/quick-search-modal/Footer.tsx @@ -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 = ({ 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 = ({ {query ? ( - {t('New Keyword Page', { query: normalizedQuery })} + {t['New Keyword Page']({ query: normalizedQuery })} ) : ( - {t('New Page')} + {t['New Page']()} )} diff --git a/apps/web/src/components/pure/quick-search-modal/PublishedResults.tsx b/apps/web/src/components/pure/quick-search-modal/PublishedResults.tsx index 68079a1742..63d090d955 100644 --- a/apps/web/src/components/pure/quick-search-modal/PublishedResults.tsx +++ b/apps/web/src/components/pure/quick-search-modal/PublishedResults.tsx @@ -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 = ({ // router.push('/404'); // }); // }, [router, dataCenter, setPublishWorkspaceName]); - const { t } = useTranslation(); + const t = useAFFiNEI18N(); useEffect(() => { setResults(blockSuiteWorkspace.search(query)); //Save the Map obtained from the search as state @@ -57,7 +57,7 @@ export const PublishedResults: FC = ({ {query ? ( resultsPageMeta.length ? ( {resultsPageMeta.map(result => { return ( @@ -85,7 +85,7 @@ export const PublishedResults: FC = ({ ) : ( - {t('Find 0 result')} + {t['Find 0 result']()} no result = ({ 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 = ({ return ( <> {recentlyViewedItem.length > 0 && ( - + {recentlyViewedItem.map(recent => { const page = pageList.find(page => recent.id === page.id); assertExists(page); @@ -87,7 +87,7 @@ export const Results: FC = ({ })} )} - + {List.map(link => { return ( = ({ if (!resultsPageMeta.length) { return ( - {t('Find 0 result')} + {t['Find 0 result']()} no result = ({ } return ( {resultsPageMeta.map(result => { return ( diff --git a/apps/web/src/components/pure/quick-search-modal/config.ts b/apps/web/src/components/pure/quick-search-modal/config.ts index cc2b8955b7..a71969b43b 100644 --- a/apps/web/src/components/pure/quick-search-modal/config.ts +++ b/apps/web/src/components/pure/quick-search-modal/config.ts @@ -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>; }[] => { - 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, }, diff --git a/apps/web/src/components/pure/quick-search-modal/index.tsx b/apps/web/src/components/pure/quick-search-modal/index.tsx index 67165a1fcb..d7d5e97498 100644 --- a/apps/web/src/components/pure/quick-search-modal/index.tsx +++ b/apps/web/src/components/pure/quick-search-modal/index.tsx @@ -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 = ({ router, blockSuiteWorkspace, }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const inputRef = useRef(null); const [loading, startTransition] = useTransition(); const [query, _setQuery] = useState(''); @@ -145,10 +145,10 @@ export const QuickSearchModal: React.FC = ({ }} placeholder={ isPublicWorkspace - ? t('Quick search placeholder2', { + ? t['Quick search placeholder2']({ workspace: publishWorkspaceName, }) - : t('Quick search placeholder') + : t['Quick search placeholder']() } /> {isMac() ? '⌘ + K' : 'Ctrl + K'} diff --git a/apps/web/src/components/pure/quick-search-modal/navigation-path/index.tsx b/apps/web/src/components/pure/quick-search-modal/navigation-path/index.tsx index 79fe2b11e7..51e6172ea4 100644 --- a/apps/web/src/components/pure/quick-search-modal/navigation-path/index.tsx +++ b/apps/web/src/components/pure/quick-search-modal/navigation-path/index.tsx @@ -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 = ({ <> {openExtend ? ( - {t('Navigation Path')} + {t['Navigation Path']()} ) : ( pathData.path.map((meta, index) => { const isLast = index === pathData.path.length - 1; @@ -96,7 +96,9 @@ export const NavigationPath = ({ )} { - 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', }; }; diff --git a/apps/web/src/components/pure/shortcuts-modal/index.tsx b/apps/web/src/components/pure/shortcuts-modal/index.tsx index d21992db44..b73028917b 100644 --- a/apps/web/src/components/pure/shortcuts-modal/index.tsx +++ b/apps/web/src/components/pure/shortcuts-modal/index.tsx @@ -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) => { - {t('Shortcuts')} + {t['Shortcuts']()} { /> - {t('Keyboard Shortcuts')} + {t['Keyboard Shortcuts']()} {Object.entries(keyboardShortcuts).map(([title, shortcuts]) => { return ( @@ -83,7 +83,7 @@ export const ShortcutsModal = ({ open, onClose }: ModalProps) => { ); })} - {t('Markdown Syntax')} + {t['Markdown Syntax']()} {Object.entries(markdownShortcuts).map(([title, shortcuts]) => { return ( diff --git a/apps/web/src/components/pure/workspace-list-modal/index.tsx b/apps/web/src/components/pure/workspace-list-modal/index.tsx index 223a12044d..19b0089498 100644 --- a/apps/web/src/components/pure/workspace-list-modal/index.tsx +++ b/apps/web/src/components/pure/workspace-list-modal/index.tsx @@ -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 ( @@ -71,9 +71,9 @@ export const WorkspaceListModal = ({ > - {t('My Workspaces')} + {t['My Workspaces']()} @@ -124,8 +124,8 @@ export const WorkspaceListModal = ({ - {t('New Workspace')} -

    {t('Create Or Import')}

    + {t['New Workspace']()} +

    {t['Create Or Import']()}

    diff --git a/apps/web/src/components/pure/workspace-slider-bar/favorite/empty-item.tsx b/apps/web/src/components/pure/workspace-slider-bar/favorite/empty-item.tsx index abd3b6c676..96ee3f66f4 100644 --- a/apps/web/src/components/pure/workspace-slider-bar/favorite/empty-item.tsx +++ b/apps/web/src/components/pure/workspace-slider-bar/favorite/empty-item.tsx @@ -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 ( - {t('Favorite pages for easy access')} + {t['Favorite pages for easy access']()} ); }; diff --git a/apps/web/src/components/pure/workspace-slider-bar/favorite/index.tsx b/apps/web/src/components/pure/workspace-slider-bar/favorite/index.tsx index d2167e2374..82756ba3e9 100644 --- a/apps/web/src/components/pure/workspace-slider-bar/favorite/index.tsx +++ b/apps/web/src/components/pure/workspace-slider-bar/favorite/index.tsx @@ -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 = ({ }} > - {t('Favorites')} + {t['Favorites']()}
    { 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} > - {t('New Page')} + {t['New Page']()} } > @@ -106,7 +106,7 @@ export const RootAppSidebar = ({ }, [onOpenQuickSearchModal])} > - {t('Quick search')} + {t['Quick search']()} -
    {t('Workspace Settings')}
    +
    {t['Workspace Settings']()}
    - {t('All pages')} + {t['All pages']()} - {t('Shared Pages')} + {t['Shared Pages']()} ))} @@ -205,7 +205,7 @@ export const RootAppSidebar = ({ pathname: currentWorkspaceId && paths.trash(currentWorkspaceId), }} > - {t('Trash')} + {t['Trash']()} diff --git a/apps/web/src/layouts/workspace-layout.tsx b/apps/web/src/layouts/workspace-layout.tsx index 19447f4ffc..57f794462f 100644 --- a/apps/web/src/layouts/workspace-layout.tsx +++ b/apps/web/src/layouts/workspace-layout.tsx @@ -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 ; + return ; } if (!workspaceId) { - return ; + return ; } if (!exist) { - return ; + return ; } return <>{children}; }; export const WorkspaceLayout: FC = 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 = } + fallback={} > {children} @@ -256,7 +258,7 @@ export const WorkspaceLayoutInner: FC = ({ 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 = ({ children }) => { /> - }> + }> {children} diff --git a/apps/web/src/pages/404.tsx b/apps/web/src/pages/404.tsx index 0f8919e425..6301c490c6 100644 --- a/apps/web/src/pages/404.tsx +++ b/apps/web/src/pages/404.tsx @@ -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 ( 404 -

    {t('404 - Page Not Found')}

    +

    {t['404 - Page Not Found']()}

    ); diff --git a/apps/web/src/pages/index.tsx b/apps/web/src/pages/index.tsx index f5490b54d7..368f9ba258 100644 --- a/apps/web/src/pages/index.tsx +++ b/apps/web/src/pages/index.tsx @@ -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 ( - }> + }> ); diff --git a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx index 482f0a9116..8f825f338f 100644 --- a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx +++ b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx @@ -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}`} > - {pageTitle ? pageTitle : t('Untitled')} + {pageTitle ? pageTitle : t['Untitled']()} diff --git a/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx b/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx index 18c2942293..b9d4813c33 100644 --- a/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx +++ b/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx @@ -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 ; + return ; } 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 ; + return ; } else if (!currentPageId || !page) { - return ; + return ; } return ; }; diff --git a/apps/web/src/pages/workspace/[workspaceId]/all.tsx b/apps/web/src/pages/workspace/[workspaceId]/all.tsx index ea3d772c22..4dc692ccf3 100644 --- a/apps/web/src/pages/workspace/[workspaceId]/all.tsx +++ b/apps/web/src/pages/workspace/[workspaceId]/all.tsx @@ -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 ( <> - {t('All Pages')} - AFFiNE + {t['All pages']()} - AFFiNE { isPublic={false} icon={} > - {t('All pages')} + {t['All pages']()} { return ( <> - {t('All Pages')} - AFFiNE + {t['All pages']()} - AFFiNE { isPublic={false} icon={} > - {t('All pages')} + {t['All pages']()} { 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 ( <> - {t('Favorites')} - AFFiNE + {t['Favorites']()} - AFFiNE { isPublic={false} icon={} > - {t('Favorites')} + {t['Favorites']()} { 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 ( <> - {t('Settings')} - AFFiNE + {t['Settings']()} - AFFiNE { isPublic={false} icon={} > - {t('Workspace Settings')} + {t['Workspace Settings']()} { return ( <> - {t('Settings')} - AFFiNE + {t['Settings']()} - AFFiNE { isPublic={false} icon={} > - {t('Workspace Settings')} + {t['Workspace Settings']()} { 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 ( <> - {t('Shared Pages')} - AFFiNE + {t['Shared Pages']()} - AFFiNE { isPublic={false} icon={} > - {t('Shared Pages')} + {t['Shared Pages']()} { 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 ( <> - {t('Trash')} - AFFiNE + {t['Trash']()} - AFFiNE { isPublic={false} icon={} > - {t('Trash')} + {t['Trash']()} { + console.error(error); + process.exit(1); + } +); + export default { stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], staticDirs: ['../../../apps/web/public'], diff --git a/packages/component/src/components/changeLog/index.tsx b/packages/component/src/components/changeLog/index.tsx index f55f9577d7..a447f27e70 100644 --- a/packages/component/src/components/changeLog/index.tsx +++ b/packages/component/src/components/changeLog/index.tsx @@ -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) => { }} > - {t("Discover what's new!")} + {t["Discover what's new!"]()}
    { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const topLinkList = [ { icon: , - title: t('Official Website'), + title: t['Official Website'](), subTitle: 'AFFiNE.pro', link: 'https://affine.pro', }, { icon: , - 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 = ({ })} - {t('Get in touch! Join our communities.')} + {t['Get in touch! Join our communities.']()} {linkList.map(({ icon, title, link }) => { diff --git a/packages/component/src/components/share-menu/Export.tsx b/packages/component/src/components/share-menu/Export.tsx index e278e6c85f..77158c4058 100644 --- a/packages/component/src/components/share-menu/Export.tsx +++ b/packages/component/src/components/share-menu/Export.tsx @@ -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 = props => { const contentParserRef = useRef(); - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return (
    - {t('Export Shared Pages Description')} + {t['Export Shared Pages Description']()}
    diff --git a/packages/component/src/components/share-menu/SharePage.tsx b/packages/component/src/components/share-menu/SharePage.tsx index d6d2df72c4..c448b99d0a 100644 --- a/packages/component/src/components/share-menu/SharePage.tsx +++ b/packages/component/src/components/share-menu/SharePage.tsx @@ -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 = props => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return (
    -
    {t('Shared Pages Description')}
    +
    {t['Shared Pages Description']()}
    { props.onEnableAffineCloud(props.workspace as LocalWorkspace); }} > - {t('Enable AFFiNE Cloud')} + {t['Enable AFFiNE Cloud']()}
    ); @@ -44,7 +45,7 @@ export const AffineSharePage: FC = 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 = props => { }, [setIsPublic]); const onClickCopyLink = useCallback(() => { navigator.clipboard.writeText(sharingUrl); - toast(t('Copied link to clipboard')); + toast(t['Copied link to clipboard']()); }, [sharingUrl, t]); return (
    - {t('Create Shared Link Description')} + {t['Create Shared Link Description']()}
    = props => { data-testid="affine-share-create-link" onClick={onClickCreateLink} > - {t('Create')} + {t['Create']()} )} {isPublic && ( @@ -80,7 +81,7 @@ export const AffineSharePage: FC = props => { data-testid="affine-share-copy-link" onClick={onClickCopyLink} > - {t('Copy Link')} + {t['Copy Link']()} )}
    @@ -100,7 +101,7 @@ export const AffineSharePage: FC = props => { {isPublic && ( <> setShowDisable(true)}> - {t('Disable Public Link')} + {t['Disable Public Link']()} > = props => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return (
    - {t('Share Menu Public Workspace Description1')} + {t['Share Menu Public Workspace Description1']()}
    > = props => { props.onOpenWorkspaceSettings(props.workspace); }} > - {t('Open Workspace Settings')} + {t['Open Workspace Settings']()}
    ); @@ -28,13 +28,13 @@ const ShareLocalWorkspace: FC> = props => { const ShareAffineWorkspace: FC> = props => { const isPublicWorkspace = props.workspace.public; - const { t } = useTranslation(); + const t = useAFFiNEI18N(); return (
    {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']()}
    > = props => { props.onOpenWorkspaceSettings(props.workspace); }} > - {t('Open Workspace Settings')} + {t['Open Workspace Settings']()}
    ); diff --git a/packages/component/src/components/share-menu/disable-public-link/index.tsx b/packages/component/src/components/share-menu/disable-public-link/index.tsx index 0d7b945af2..19d10bf911 100644 --- a/packages/component/src/components/share-menu/disable-public-link/index.tsx +++ b/packages/component/src/components/share-menu/disable-public-link/index.tsx @@ -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 = ({ - {t('Disable Public Link ?')} + {t['Disable Public Link ?']()} - {t('Disable Public Link Description')} + {t['Disable Public Link Description']()} - {t('Cancel')} + {t['Cancel']()} - {t('Disable')} + {t['Disable']()} diff --git a/packages/component/src/components/workspace-card/index.tsx b/packages/component/src/components/workspace-card/index.tsx index 1917254b4d..730c1026d1 100644 --- a/packages/component/src/components/workspace-card/index.tsx +++ b/packages/component/src/components/workspace-card/index.tsx @@ -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 = ({ 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 = ({ workspace }) => { if (workspace.flavour === WorkspaceFlavour.LOCAL) { return ( -

    +

    - {t('Local Workspace')} + {t['Local Workspace']()}

    ); } return isOwner ? ( -

    +

    - {t('Cloud Workspace')} + {t['Cloud Workspace']()}

    ) : ( -

    +

    - {t('Joined Workspace')} + {t['Joined Workspace']()}

    ); }; @@ -89,7 +89,7 @@ export const WorkspaceCard: FC = ({ onSettingClick, currentWorkspaceId, }) => { - const { t } = useTranslation(); + const t = useAFFiNEI18N(); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); return ( @@ -106,15 +106,15 @@ export const WorkspaceCard: FC = ({ {name} {workspace.flavour === WorkspaceFlavour.LOCAL && ( -

    +

    - {t('Available Offline')} + {t['Available Offline']()}

    )} {workspace.flavour === WorkspaceFlavour.AFFINE && workspace.public && ( -

    +

    - {t('Published to Web')} + {t['Published to Web']()}

    )} diff --git a/packages/component/src/ui/confirm/Confirm.tsx b/packages/component/src/ui/confirm/Confirm.tsx index 553d0b18b3..cf97b08e55 100644 --- a/packages/component/src/ui/confirm/Confirm.tsx +++ b/packages/component/src/ui/confirm/Confirm.tsx @@ -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 ( @@ -60,7 +60,7 @@ export const Confirm = ({ style={{ marginRight: '24px' }} data-testid={cancelButtonTestId} > - {cancelText === 'Cancel' ? t('Cancel') : cancelText} + {cancelText === 'Cancel' ? t['Cancel']() : cancelText} )} diff --git a/packages/i18n/README.md b/packages/i18n/README.md index ec443f6fc8..b466a7a4d8 100644 --- a/packages/i18n/README.md +++ b/packages/i18n/README.md @@ -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 = () => {
    {t('Text')}
    - - + +
    ); }; diff --git a/packages/i18n/package.json b/packages/i18n/package.json index ab685e760b..4c3561b38d 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -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", diff --git a/packages/i18n/src/index.ts b/packages/i18n/src/index.ts index 4d8c30f3c7..d0df8fe253 100644 --- a/packages/i18n/src/index.ts +++ b/packages/i18n/src/index.ts @@ -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( (acc, { tag, res }) => ({ ...acc, [tag]: { translation: res } }), diff --git a/packages/i18n/src/resources/en.json b/packages/i18n/src/resources/en.json index f5dfce1e0a..941e1f8cc2 100644 --- a/packages/i18n/src/resources/en.json +++ b/packages/i18n/src/resources/en.json @@ -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 browser for optimal experience.", "upgradeBrowser": "Please upgrade to the latest version of Chrome for the best experience.", "Invite Members": "Invite Members", diff --git a/scripts/setup/i18n.ts b/scripts/setup/i18n.ts new file mode 100644 index 0000000000..7a7e0662a5 --- /dev/null +++ b/scripts/setup/i18n.ts @@ -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); + } + ); +}); diff --git a/tsconfig.json b/tsconfig.json index a4f0c1bf8c..a9aea18052 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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"], diff --git a/tsconfig.node.json b/tsconfig.node.json index b5376a7db7..0f6d3ad3da 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -5,5 +5,5 @@ "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, - "include": ["vitest.config.ts"] + "include": ["vitest.config.ts", "scripts"] } diff --git a/vitest.config.ts b/vitest.config.ts index 5c127c3c4a..a7718d9283 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -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'), ], diff --git a/yarn.lock b/yarn.lock index 3de02e423b..d03c3c35bb 100644 --- a/yarn.lock +++ b/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: