mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 00:56:26 +08:00
refactor(i18n): new hook api (#7273)
# NEW HOOK API
`useI18n`: same as `useAFFiNEI18N`, with additional APIs
```ts
import { useI18n } from '@affine/i18n'
const i18n = useI18n()
i18n['hello world']() -> 你好世界
```
# NEW GLOBAL i18n Instance
`I18n`: use i18n capabilities outside of React
```ts
import { I18n } from '@affine/i18n'
I18n['hello world']() -> 你好世界
```
# NEW TYPES
`I18nKeys` -> all i18n keys
`I18nString` -> An i18n message (key&options)
transfer and store i18n text outside of React
```ts
const msg: I18nString = {
key: 'helloworld',
options: {
arg1: '123'
}
}
I18n.t(msg) -> 你好世界123
```
before:
```ts
registerCommand('open-page', {
name: t('command.open-page')
// ^- translation happens here,
})
```
after:
```ts
registerCommand('open-page', {
name: { key: 'command.open-page' }
// ^- store I18nString here, translate when the command render to UI
})
```
This commit is contained in:
@@ -16,8 +16,7 @@ import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { WorkspaceSubPath } from '@affine/core/shared';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
LinkIcon,
|
||||
@@ -81,7 +80,7 @@ const docToCommand = (
|
||||
run: () => void,
|
||||
getPageTitle: ReturnType<typeof useGetDocCollectionPageTitle>,
|
||||
isPageJournal: (pageId: string) => boolean,
|
||||
t: ReturnType<typeof useAFFiNEI18N>,
|
||||
t: ReturnType<typeof useI18n>,
|
||||
subTitle?: string
|
||||
): CMDKCommand => {
|
||||
const docMode = doc.mode$.value;
|
||||
@@ -122,7 +121,7 @@ function useSearchedDocCommands(
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const getPageTitle = useGetDocCollectionPageTitle(workspace.docCollection);
|
||||
const { isPageJournal } = useJournalHelper(workspace.docCollection);
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
|
||||
const [searchTime, setSearchTime] = useState<number>(0);
|
||||
|
||||
@@ -202,7 +201,7 @@ export const usePageCommands = () => {
|
||||
const query = useLiveData(quickSearch.query$);
|
||||
const navigationHelper = useNavigateHelper();
|
||||
const journalHelper = useJournalHelper(workspace.docCollection);
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
|
||||
const onSelectPage = useCallback(
|
||||
(opts: { docId: string; blockId?: string }) => {
|
||||
@@ -398,7 +397,7 @@ export const collectionToCommand = (
|
||||
collection: Collection,
|
||||
navigationHelper: ReturnType<typeof useNavigateHelper>,
|
||||
selectCollection: (id: string) => void,
|
||||
t: ReturnType<typeof useAFFiNEI18N>,
|
||||
t: ReturnType<typeof useI18n>,
|
||||
workspace: Workspace
|
||||
): CMDKCommand => {
|
||||
const label = collection.name || t['Untitled']();
|
||||
@@ -422,7 +421,7 @@ export const useCollectionsCommands = () => {
|
||||
const quickSearch = useService(QuickSearchService).quickSearch;
|
||||
const query = useLiveData(quickSearch.query$);
|
||||
const navigationHelper = useNavigateHelper();
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const selectCollection = useCallback(
|
||||
(id: string) => {
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { CommandCategory } from '@affine/core/commands';
|
||||
import { useDocEngineStatus } from '@affine/core/hooks/affine/use-doc-engine-status';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { QuickSearchService } from '@affine/core/modules/cmdk';
|
||||
import { i18nTime } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { type I18nKeys, i18nTime } from '@affine/i18n';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
@@ -32,13 +32,7 @@ import { CMDKModal } from './modal';
|
||||
import { NotFoundGroup } from './not-found';
|
||||
import type { CMDKCommand } from './types';
|
||||
|
||||
type NoParametersKeys<T> = {
|
||||
[K in keyof T]: T[K] extends () => any ? K : never;
|
||||
}[keyof T];
|
||||
|
||||
type i18nKey = NoParametersKeys<ReturnType<typeof useAFFiNEI18N>>;
|
||||
|
||||
const categoryToI18nKey: Record<CommandCategory, i18nKey> = {
|
||||
const categoryToI18nKey = {
|
||||
'affine:recent': 'com.affine.cmdk.affine.category.affine.recent',
|
||||
'affine:navigation': 'com.affine.cmdk.affine.category.affine.navigation',
|
||||
'affine:creation': 'com.affine.cmdk.affine.category.affine.creation',
|
||||
@@ -55,7 +49,7 @@ const categoryToI18nKey: Record<CommandCategory, i18nKey> = {
|
||||
'com.affine.cmdk.affine.category.editor.insert-object',
|
||||
'editor:page': 'com.affine.cmdk.affine.category.editor.page',
|
||||
'affine:results': 'com.affine.cmdk.affine.category.results',
|
||||
};
|
||||
} satisfies Record<CommandCategory, I18nKeys>;
|
||||
|
||||
const QuickSearchGroup = ({
|
||||
category,
|
||||
@@ -66,7 +60,7 @@ const QuickSearchGroup = ({
|
||||
commands: CMDKCommand[];
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const i18nKey = categoryToI18nKey[category];
|
||||
const quickSearch = useService(QuickSearchService).quickSearch;
|
||||
const query = useLiveData(quickSearch.query$);
|
||||
@@ -169,7 +163,7 @@ export const CMDKContainer = ({
|
||||
groups: ReturnType<typeof useCMDKCommandGroups>;
|
||||
onQueryChange: (query: string) => void;
|
||||
}>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const [value, setValue] = useAtom(cmdkValueAtom);
|
||||
const [opening, setOpening] = useState(open);
|
||||
const { syncing, progress } = useDocEngineStatus();
|
||||
@@ -254,7 +248,7 @@ const CMDKQuickSearchModalInner = ({
|
||||
const quickSearch = useService(QuickSearchService).quickSearch;
|
||||
const query = useLiveData(quickSearch.query$);
|
||||
const groups = useCMDKCommandGroups();
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
return (
|
||||
<CMDKContainer
|
||||
className={styles.root}
|
||||
@@ -278,7 +272,7 @@ const CMDKQuickSearchCallbackModalInner = ({
|
||||
const quickSearch = useService(QuickSearchService).quickSearch;
|
||||
const query = useLiveData(quickSearch.query$);
|
||||
const groups = useSearchCallbackCommandGroups();
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
return (
|
||||
<CMDKContainer
|
||||
className={styles.root}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { QuickSearchService } from '@affine/core/modules/cmdk';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { SearchIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCommandState } from 'cmdk';
|
||||
@@ -12,7 +12,7 @@ export const NotFoundGroup = () => {
|
||||
// hack: we know that the filtered count is 3 when there is no result (create page & edgeless & append to journal, for mode === 'cmdk')
|
||||
const renderNoResult = useCommandState(state => state.filtered.count === 3);
|
||||
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
|
||||
if (!renderNoResult) {
|
||||
return null;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useJournalRouteHelper,
|
||||
} from '@affine/core/hooks/use-journal';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
MoreHorizontalIcon,
|
||||
@@ -86,7 +86,7 @@ interface JournalBlockProps {
|
||||
}
|
||||
|
||||
const EditorJournalPanel = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const doc = useService(DocService).doc;
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const { journalDate, isJournal } = useJournalInfoHelper(
|
||||
@@ -167,7 +167,7 @@ const sortPagesByDate = (
|
||||
};
|
||||
|
||||
const DailyCountEmptyFallback = ({ name }: { name: NavItemName }) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<div className={styles.dailyCountEmpty}>
|
||||
@@ -180,7 +180,7 @@ const DailyCountEmptyFallback = ({ name }: { name: NavItemName }) => {
|
||||
const JournalDailyCountBlock = ({ date }: JournalBlockProps) => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const nodeRef = useRef<HTMLDivElement>(null);
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const [activeItem, setActiveItem] = useState<NavItemName>('createdToday');
|
||||
const docRecords = useLiveData(useService(DocsService).list.docs$);
|
||||
|
||||
@@ -345,7 +345,7 @@ const ConflictList = ({
|
||||
);
|
||||
};
|
||||
const JournalConflictBlock = ({ date }: JournalBlockProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const docRecordList = useService(DocsService).list;
|
||||
const journalHelper = useJournalHelper(workspace.docCollection);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@affine/component';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ArrowLeftSmallIcon, ArrowRightSmallIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
@@ -9,7 +9,7 @@ import { NavigatorService } from '../services/navigator';
|
||||
import * as styles from './navigation-buttons.css';
|
||||
|
||||
export const NavigationButtons = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
|
||||
const shortcuts = useGeneralShortcuts().shortcuts;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IconButton, Tooltip } from '@affine/component';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
CloseIcon,
|
||||
DualLinkIcon,
|
||||
@@ -76,7 +76,7 @@ export const DocPeekViewControls = ({
|
||||
const peekView = useService(PeekViewService).peekView;
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const { jumpToPageBlock } = useNavigateHelper();
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const { doc, workspace } = useDoc(docId);
|
||||
const controls = useMemo(() => {
|
||||
return [
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ConfirmModal, toast } from '@affine/component';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
@@ -15,7 +14,7 @@ export const DeleteTagConfirmModal = ({
|
||||
onOpenChange: (open: boolean) => void;
|
||||
selectedTagIds: string[];
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const tagService = useService(TagService);
|
||||
const tags = useLiveData(tagService.tagList.tags$);
|
||||
const selectedTags = useMemo(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MenuIcon, MenuItem } from '@affine/component';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
ExpandCloseIcon,
|
||||
MoveToLeftDuotoneIcon,
|
||||
@@ -115,7 +115,7 @@ export const SplitViewPanel = memo(function SplitViewPanel({
|
||||
});
|
||||
|
||||
const SplitViewMenu = ({ view }: { view: View }) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const t = useI18n();
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const views = useLiveData(workbench.views$);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user