feat: add i18n to main menu & docs: update Chinese README (#130)

* docs: update Chinese README

* feat: add i18n to main menu

* feat: add i18n for 3 components in fossflow-lib (ConnectorHintTooltip, HelpDialog, ImportHintTooltip)
This commit is contained in:
Apricity12138
2025-09-12 05:00:32 +08:00
committed by GitHub
parent 69aa2b3f66
commit a001da7edb
10 changed files with 473 additions and 119 deletions

View File

@@ -4,6 +4,19 @@
<a href="../README.md">English</a> | <a href="README.cn.md">简体中文</a>
</p>
<b>嗨!</b> 我是 Stan如果您使用过 FossFLOW 并觉得它对您有帮助,<b>我会非常感激您能捐助一点点 :)</b> 我全职工作,抽时间来维护这个项目已经很不容易了。
如果我为您实现了某个功能,或者修复了某个 bug能得到您的支持将非常棒 :) 如果不能,也没关系,这个软件将永远免费!
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/P5P61KBXA3)
<img width="30" height="30" alt="image" src="https://github.com/user-attachments/assets/dc6ec9ca-48d7-4047-94cf-5c4f7ed63b84" /> <b> https://buymeacoffee.com/stan.smith </b>
感谢,
-Stan
------------------------------------------------------------------------------------------------------------------------------
FossFLOW 是一款功能强大的、开源的渐进式 Web 应用PWA专为创建精美的等距图表而设计。它基于 React 和 Isoflow现已 fork 并以 fossflow 名称发布到 NPM库构建完全在浏览器中运行并支持离线使用。
![Screenshot_20250630_160954](https://github.com/user-attachments/assets/e7f254ad-625f-4b8a-8efc-5293b5be9d55)

View File

@@ -6,6 +6,7 @@ import { IsoflowProps } from 'src/types';
import { setWindowCursor, modelFromModelStore } from 'src/utils';
import { useModelStore, ModelProvider } from 'src/stores/modelStore';
import { SceneProvider } from 'src/stores/sceneStore';
import { LocaleProvider } from 'src/stores/localeStore';
import { GlobalStyles } from 'src/styles/GlobalStyles';
import { Renderer } from 'src/components/Renderer/Renderer';
import { UiOverlay } from 'src/components/UiOverlay/UiOverlay';
@@ -84,13 +85,15 @@ const App = ({
export const Isoflow = (props: IsoflowProps) => {
return (
<ThemeProvider theme={theme}>
<ModelProvider>
<SceneProvider>
<UiStateProvider>
<App {...props} />
</UiStateProvider>
</SceneProvider>
</ModelProvider>
<LocaleProvider locale={props.locale || enUS}>
<ModelProvider>
<SceneProvider>
<UiStateProvider>
<App {...props} />
</UiStateProvider>
</SceneProvider>
</ModelProvider>
</LocaleProvider>
</ThemeProvider>
);
};

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Box, IconButton, Paper, Typography, useTheme } from '@mui/material';
import { Close as CloseIcon } from '@mui/icons-material';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { useTranslation } from 'src/stores/localeStore';
const STORAGE_KEY = 'fossflow_connector_hint_dismissed';
@@ -10,6 +11,7 @@ interface Props {
}
export const ConnectorHintTooltip = ({ toolMenuRef }: Props) => {
const { t } = useTranslation('connectorHintTooltip');
const theme = useTheme();
const connectorInteractionMode = useUiStateStore((state) => state.connectorInteractionMode);
const mode = useUiStateStore((state) => state.mode);
@@ -85,30 +87,28 @@ export const ConnectorHintTooltip = ({ toolMenuRef }: Props) => {
</IconButton>
<Typography variant="subtitle2" gutterBottom sx={{ fontWeight: 600 }}>
{connectorInteractionMode === 'click' ? 'Tip: Creating Connectors' : 'Tip: Connector Tools'}
{connectorInteractionMode === 'click' ? t('tipCreatingConnectors') : t('tipConnectorTools')}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
{connectorInteractionMode === 'click' ? (
<>
<strong>Click</strong> on the first node or point, then <strong>click</strong> on
the second node or point to create a connection.
<strong>{t('clickInstructionStart')}</strong> {t('clickInstructionMiddle')} <strong>{t('clickInstructionStart')}</strong> {t('clickInstructionEnd')}
{mode.type === 'CONNECTOR' && mode.isConnecting && (
<Box component="span" sx={{ display: 'block', mt: 1, color: 'primary.main' }}>
Now click on the target to complete the connection.
{t('nowClickTarget')}
</Box>
)}
</>
) : (
<>
<strong>Drag</strong> from the first node to the second node to create a connection.
<strong>{t('dragStart')}</strong> {t('dragEnd')}
</>
)}
</Typography>
<Typography variant="body2" color="text.secondary">
To reroute a connector, <strong>left-click</strong> on any point
along the connector line and drag to create or move anchor points.
{t('rerouteStart')} <strong>{t('rerouteMiddle')}</strong> {t('rerouteEnd')}
</Typography>
</Paper>
</Box>

View File

@@ -19,6 +19,7 @@ import {
import { Close as CloseIcon } from '@mui/icons-material';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { DialogTypeEnum } from 'src/types/ui';
import { useTranslation } from 'src/stores/localeStore';
interface ShortcutItem {
action: string;
@@ -26,83 +27,9 @@ interface ShortcutItem {
description: string;
}
const keyboardShortcuts: ShortcutItem[] = [
{
action: 'Undo',
shortcut: 'Ctrl+Z',
description: 'Undo the last action'
},
{
action: 'Redo',
shortcut: 'Ctrl+Y',
description: 'Redo the last undone action'
},
{
action: 'Redo (Alternative)',
shortcut: 'Ctrl+Shift+Z',
description: 'Alternative redo shortcut'
},
{
action: 'Help',
shortcut: 'F1',
description: 'Open help dialog with keyboard shortcuts'
},
{
action: 'Zoom In',
shortcut: 'Mouse Wheel Up',
description: 'Zoom in on the canvas'
},
{
action: 'Zoom Out',
shortcut: 'Mouse Wheel Down',
description: 'Zoom out from the canvas'
},
{
action: 'Pan Canvas',
shortcut: 'Left-click + Drag',
description: 'Pan the canvas when in Pan mode'
},
{
action: 'Context Menu',
shortcut: 'Right-click',
description: 'Open context menu for items or empty space'
}
];
const mouseInteractions: ShortcutItem[] = [
{
action: 'Select Tool',
shortcut: 'Click Select button',
description: 'Switch to selection mode'
},
{
action: 'Pan Tool',
shortcut: 'Click Pan button',
description: 'Switch to pan mode for moving canvas'
},
{
action: 'Add Item',
shortcut: 'Click Add item button',
description: 'Open icon picker to add new items'
},
{
action: 'Draw Rectangle',
shortcut: 'Click Rectangle button',
description: 'Switch to rectangle drawing mode'
},
{
action: 'Create Connector',
shortcut: 'Click Connector button',
description: 'Switch to connector mode'
},
{
action: 'Add Text',
shortcut: 'Click Text button',
description: 'Create a new text box'
}
];
export const HelpDialog = () => {
const { t } = useTranslation('helpDialog');
const dialog = useUiStateStore((state) => {
return state.dialog;
});
@@ -116,6 +43,82 @@ export const HelpDialog = () => {
setDialog(null);
};
const keyboardShortcuts = [
{
action: t('undoAction'),
shortcut: 'Ctrl+Z',
description: t('undoDescription')
},
{
action: t('redoAction'),
shortcut: 'Ctrl+Y',
description: t('redoDescription')
},
{
action: t('redoAltAction'),
shortcut: 'Ctrl+Shift+Z',
description: t('redoAltDescription')
},
{
action: t('helpAction'),
shortcut: 'F1',
description: t('helpDescription')
},
{
action: t('zoomInAction'),
shortcut: t('zoomInShortcut'),
description: t('zoomInDescription')
},
{
action: t('zoomOutAction'),
shortcut: t('zoomOutShortcut'),
description: t('zoomOutDescription')
},
{
action: t('panCanvasAction'),
shortcut: t('panCanvasShortcut'),
description: t('panCanvasDescription')
},
{
action: t('contextMenuAction'),
shortcut: t('contextMenuShortcut'),
description: t('contextMenuDescription')
}
];
const mouseInteractions = [
{
action: t('selectToolAction'),
shortcut: t('selectToolShortcut'),
description: t('selectToolDescription')
},
{
action: t('panToolAction'),
shortcut: t('panToolShortcut'),
description: t('panToolDescription')
},
{
action: t('addItemAction'),
shortcut: t('addItemShortcut'),
description: t('addItemDescription')
},
{
action: t('drawRectangleAction'),
shortcut: t('drawRectangleShortcut'),
description: t('drawRectangleDescription')
},
{
action: t('createConnectorAction'),
shortcut: t('createConnectorShortcut'),
description: t('createConnectorDescription')
},
{
action: t('addTextAction'),
shortcut: t('addTextShortcut'),
description: t('addTextDescription')
}
];
return (
<Dialog
open={isOpen}
@@ -131,7 +134,7 @@ export const HelpDialog = () => {
<DialogTitle>
<Box display="flex" alignItems="center" justifyContent="space-between">
<Typography variant="h6" component="div">
Keyboard Shortcuts & Help
{t('title')}
</Typography>
<Button
onClick={handleClose}
@@ -153,15 +156,15 @@ export const HelpDialog = () => {
<DialogContent>
<Box sx={{ mb: 3 }}>
<Typography variant="h6" gutterBottom>
Keyboard Shortcuts
{t('keyboardShortcuts')}
</Typography>
<TableContainer component={Paper} variant="outlined">
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Action</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Shortcut</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Description</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('action')}</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('shortcut')}</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('description')}</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -194,15 +197,15 @@ export const HelpDialog = () => {
<Box>
<Typography variant="h6" gutterBottom>
Mouse Interactions
{t('mouseInteractions')}
</Typography>
<TableContainer component={Paper} variant="outlined">
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Action</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Method</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Description</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('action')}</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('method')}</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>{t('description')}</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -233,16 +236,14 @@ export const HelpDialog = () => {
<Box sx={{ mt: 3, p: 2, bgcolor: 'info.light', borderRadius: 1 }}>
<Typography variant="body2" color="info.contrastText">
<strong>Note:</strong> Keyboard shortcuts are disabled when typing
in input fields, text areas, or content-editable elements to prevent
conflicts.
<strong>{t('note')}</strong> {t('noteContent')}
</Typography>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} variant="contained">
Close
{t('close')}
</Button>
</DialogActions>
</Dialog>

View File

@@ -1,10 +1,12 @@
import React, { useState, useEffect } from 'react';
import { Box, IconButton, Paper, Typography } from '@mui/material';
import { Close as CloseIcon, FolderOpen as FolderOpenIcon } from '@mui/icons-material';
import { useTranslation } from 'src/stores/localeStore';
const STORAGE_KEY = 'fossflow_import_hint_dismissed';
export const ImportHintTooltip = () => {
const { t } = useTranslation('importHintTooltip');
const [isDismissed, setIsDismissed] = useState(true);
useEffect(() => {
@@ -59,13 +61,12 @@ export const ImportHintTooltip = () => {
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
<FolderOpenIcon sx={{ mr: 1, color: 'info.main' }} />
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
Import Diagrams
{t('title')}
</Typography>
</Box>
<Typography variant="body2" color="text.secondary">
To import diagrams, click the <strong>menu button</strong> () in the top left corner,
then select <strong>"Open"</strong> to load your diagram files.
{t('instructionStart')} <strong>{t('menuButton')}</strong> {t('instructionMiddle')} <strong>{t('openButton')}</strong> {t('instructionEnd')}
</Typography>
</Paper>
</Box>

View File

@@ -25,6 +25,7 @@ import { useModelStore } from 'src/stores/modelStore';
import { useHistory } from 'src/hooks/useHistory';
import { DialogTypeEnum } from 'src/types/ui';
import { MenuItem } from './MenuItem';
import { useTranslation } from 'src/stores/localeStore';
export const MainMenu = () => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -43,6 +44,8 @@ export const MainMenu = () => {
const initialDataManager = useInitialDataManager();
const { undo, redo, canUndo, canRedo, clearHistory } = useHistory();
const { t } = useTranslation('mainMenu');
const onToggleMenu = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
@@ -183,7 +186,7 @@ export const MainMenu = () => {
Icon={<UndoIcon />}
disabled={!canUndo}
>
Undo
{t('undo')}
</MenuItem>
<MenuItem
@@ -191,7 +194,7 @@ export const MainMenu = () => {
Icon={<RedoIcon />}
disabled={!canRedo}
>
Redo
{t('redo')}
</MenuItem>
{(canUndo || canRedo) && sectionVisibility.actions && <Divider />}
@@ -199,38 +202,38 @@ export const MainMenu = () => {
{/* File Actions */}
{mainMenuOptions.includes('ACTION.OPEN') && (
<MenuItem onClick={onOpenModel} Icon={<FolderOpenIcon />}>
Open
{t('open')}
</MenuItem>
)}
{mainMenuOptions.includes('EXPORT.JSON') && (
<MenuItem onClick={onExportAsJSON} Icon={<ExportJsonIcon />}>
Export as JSON
{t('exportJson')}
</MenuItem>
)}
{mainMenuOptions.includes('EXPORT.JSON') && (
<MenuItem onClick={onExportAsCompactJSON} Icon={<ExportJsonIcon />}>
Export as Compact JSON
{t('exportCompactJson')}
</MenuItem>
)}
{mainMenuOptions.includes('EXPORT.PNG') && (
<MenuItem onClick={onExportAsImage} Icon={<ExportImageIcon />}>
Export as image
{t('exportImage')}
</MenuItem>
)}
{mainMenuOptions.includes('ACTION.CLEAR_CANVAS') && (
<MenuItem onClick={onClearCanvas} Icon={<DeleteOutlineIcon />}>
Clear the canvas
{t('clearCanvas')}
</MenuItem>
)}
<Divider />
<MenuItem onClick={onOpenSettings} Icon={<SettingsIcon />}>
Settings
{t('settings')}
</MenuItem>
{sectionVisibility.links && (
@@ -244,7 +247,7 @@ export const MainMenu = () => {
}}
Icon={<GitHubIcon />}
>
GitHub
{t('gitHub')}
</MenuItem>
)}
</>

View File

@@ -1,7 +1,93 @@
import { LocaleProps } from '../types/isoflowProps';
const locale: LocaleProps = {
"exampleText": "This is an example text"
common: {
exampleText: "This is an example text"
},
mainMenu: {
undo: "Undo",
redo: "Redo",
open: "Open",
exportJson: "Export as JSON",
exportCompactJson: "Export as Compact JSON",
exportImage: "Export as image",
clearCanvas: "Clear the canvas",
settings: "Settings",
gitHub: "GitHub"
},
helpDialog: {
title: "Keyboard Shortcuts & Help",
close: "Close",
keyboardShortcuts: "Keyboard Shortcuts",
mouseInteractions: "Mouse Interactions",
action: "Action",
shortcut: "Shortcut",
method: "Method",
description: "Description",
note: "Note:",
noteContent: "Keyboard shortcuts are disabled when typing in input fields, text areas, or content-editable elements to prevent conflicts.",
// Keyboard shortcuts
undoAction: "Undo",
undoDescription: "Undo the last action",
redoAction: "Redo",
redoDescription: "Redo the last undone action",
redoAltAction: "Redo (Alternative)",
redoAltDescription: "Alternative redo shortcut",
helpAction: "Help",
helpDescription: "Open help dialog with keyboard shortcuts",
zoomInAction: "Zoom In",
zoomInShortcut: "Mouse Wheel Up",
zoomInDescription: "Zoom in on the canvas",
zoomOutAction: "Zoom Out",
zoomOutShortcut: "Mouse Wheel Down",
zoomOutDescription: "Zoom out from the canvas",
panCanvasAction: "Pan Canvas",
panCanvasShortcut: "Left-click + Drag",
panCanvasDescription: "Pan the canvas when in Pan mode",
contextMenuAction: "Context Menu",
contextMenuShortcut: "Right-click",
contextMenuDescription: "Open context menu for items or empty space",
// Mouse interactions
selectToolAction: "Select Tool",
selectToolShortcut: "Click Select button",
selectToolDescription: "Switch to selection mode",
panToolAction: "Pan Tool",
panToolShortcut: "Click Pan button",
panToolDescription: "Switch to pan mode for moving canvas",
addItemAction: "Add Item",
addItemShortcut: "Click Add item button",
addItemDescription: "Open icon picker to add new items",
drawRectangleAction: "Draw Rectangle",
drawRectangleShortcut: "Click Rectangle button",
drawRectangleDescription: "Switch to rectangle drawing mode",
createConnectorAction: "Create Connector",
createConnectorShortcut: "Click Connector button",
createConnectorDescription: "Switch to connector mode",
addTextAction: "Add Text",
addTextShortcut: "Click Text button",
addTextDescription: "Create a new text box"
},
connectorHintTooltip: {
tipCreatingConnectors: "Tip: Creating Connectors",
tipConnectorTools: "Tip: Connector Tools",
clickInstructionStart: "Click",
clickInstructionMiddle: "on the first node or point, then",
clickInstructionEnd: "on the second node or point to create a connection.",
nowClickTarget: "Now click on the target to complete the connection.",
dragStart: "Drag",
dragEnd: "from the first node to the second node to create a connection.",
rerouteStart: "To reroute a connector,",
rerouteMiddle: "left-click",
rerouteEnd: "on any point along the connector line and drag to create or move anchor points."
},
importHintTooltip: {
title: "Import Diagrams",
instructionStart: "To import diagrams, click the",
menuButton: "menu button",
instructionMiddle: "(☰) in the top left corner, then select",
openButton: "\"Open\"",
instructionEnd: "to load your diagram files."
}
};
export default locale;

View File

@@ -1,7 +1,93 @@
import { LocaleProps } from '../types/isoflowProps';
const locale: LocaleProps = {
"exampleText": "这是一段示例文本"
common: {
exampleText: "这是一段示例文本"
},
mainMenu: {
undo: "撤销",
redo: "重做",
open: "打开",
exportJson: "导出为 JSON",
exportCompactJson: "导出为紧凑 JSON",
exportImage: "导出为图片",
clearCanvas: "清空画布",
settings: "设置",
gitHub: "GitHub"
},
helpDialog: {
title: "键盘快捷键和帮助",
close: "关闭",
keyboardShortcuts: "键盘快捷键",
mouseInteractions: "鼠标交互",
action: "操作",
shortcut: "快捷键",
method: "方法",
description: "描述",
note: "注意:",
noteContent: "在输入框、文本区域或可编辑内容元素中键入时,键盘快捷键会被禁用,以防止冲突。",
// Keyboard shortcuts
undoAction: "撤销",
undoDescription: "撤销上一个操作",
redoAction: "重做",
redoDescription: "重做上一个撤销的操作",
redoAltAction: "重做(备选)",
redoAltDescription: "备选重做快捷键",
helpAction: "帮助",
helpDescription: "打开包含键盘快捷键的帮助对话框",
zoomInAction: "放大",
zoomInShortcut: "鼠标滚轮向上",
zoomInDescription: "放大画布",
zoomOutAction: "缩小",
zoomOutShortcut: "鼠标滚轮向下",
zoomOutDescription: "缩小画布",
panCanvasAction: "平移画布",
panCanvasShortcut: "左键拖拽",
panCanvasDescription: "在平移模式下移动画布",
contextMenuAction: "上下文菜单",
contextMenuShortcut: "右键点击",
contextMenuDescription: "为项目或空白区域打开上下文菜单",
// Mouse interactions
selectToolAction: "选择工具",
selectToolShortcut: "点击选择按钮",
selectToolDescription: "切换到选择模式",
panToolAction: "平移工具",
panToolShortcut: "点击平移按钮",
panToolDescription: "切换到平移模式以移动画布",
addItemAction: "添加项目",
addItemShortcut: "点击添加项目按钮",
addItemDescription: "打开图标选择器以添加新项目",
drawRectangleAction: "绘制矩形",
drawRectangleShortcut: "点击矩形按钮",
drawRectangleDescription: "切换到矩形绘制模式",
createConnectorAction: "创建连接器",
createConnectorShortcut: "点击连接器按钮",
createConnectorDescription: "切换到连接器模式",
addTextAction: "添加文本",
addTextShortcut: "点击文本按钮",
addTextDescription: "创建新的文本框"
},
connectorHintTooltip: {
tipCreatingConnectors: "提示:创建连接器",
tipConnectorTools: "提示:连接器工具",
clickInstructionStart: "点击",
clickInstructionMiddle: "第一个节点或点,然后",
clickInstructionEnd: "第二个节点或点来创建连接。",
nowClickTarget: "现在点击目标以完成连接。",
dragStart: "拖拽",
dragEnd: "从第一个节点到第二个节点来创建连接。",
rerouteStart: "要重新规划连接器线路,请",
rerouteMiddle: "左键点击",
rerouteEnd: "连接器线上的任何点并拖拽以创建或移动锚点。"
},
importHintTooltip: {
title: "导入图表",
instructionStart: "要导入图表,请点击左上角的",
menuButton: "菜单按钮",
instructionMiddle: "(☰),然后选择",
openButton: "\"打开\"",
instructionEnd: "来加载您的图表文件。"
}
};
export default locale;

View File

@@ -0,0 +1,75 @@
import React, { createContext, useContext, ReactNode } from 'react';
import { LocaleProps } from '../types/isoflowProps';
import enUS from '../i18n/en-US';
const LocaleContext = createContext<LocaleProps>(enUS);
interface LocaleProviderProps {
locale: LocaleProps;
children: ReactNode;
}
export const LocaleProvider: React.FC<LocaleProviderProps> = ({ locale, children }) => {
return (
<LocaleContext.Provider value={locale}>
{children}
</LocaleContext.Provider>
);
};
export const useLocale = (): LocaleProps => {
const context = useContext(LocaleContext);
if (!context) {
throw new Error('useLocale must be used within a LocaleProvider');
}
return context;
};
// Generic type helper for nested object access
type NestedKeyOf<ObjectType extends object> = {
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
? `${Key}.${NestedKeyOf<ObjectType[Key]>}`
: `${Key}`;
}[keyof ObjectType & (string | number)];
// Overloaded useTranslation function
export function useTranslation(): {
t: (key: NestedKeyOf<LocaleProps>) => string;
};
export function useTranslation<K extends keyof LocaleProps>(
namespace: K
): {
t: (key: keyof LocaleProps[K]) => string;
};
export function useTranslation<K extends keyof LocaleProps>(namespace?: K) {
const locale = useLocale();
if (namespace) {
// Return scoped translation function for specific namespace
const namespaceData = locale[namespace];
const t = (key: keyof LocaleProps[K]): string => {
const value = namespaceData[key];
return typeof value === 'string' ? value : String(key);
};
return { t };
} else {
// Return global translation function with dot notation
const t = (key: NestedKeyOf<LocaleProps>): string => {
const parts = key.split('.');
let current: any = locale;
for (const part of parts) {
if (current && typeof current === 'object' && part in current) {
current = current[part];
} else {
return key; // Return key if path not found
}
}
return typeof current === 'string' ? current : key;
};
return { t };
}
}

View File

@@ -8,8 +8,94 @@ export type InitialData = Model & {
};
export interface LocaleProps {
exampleText: string;
// other locale keys
common: {
exampleText: string;
};
mainMenu: {
undo: string;
redo: string;
open: string;
exportJson: string;
exportCompactJson: string;
exportImage: string;
clearCanvas: string;
settings: string;
gitHub: string;
};
helpDialog: {
title: string;
close: string;
keyboardShortcuts: string;
mouseInteractions: string;
action: string;
shortcut: string;
method: string;
description: string;
note: string;
noteContent: string;
// Keyboard shortcuts
undoAction: string;
undoDescription: string;
redoAction: string;
redoDescription: string;
redoAltAction: string;
redoAltDescription: string;
helpAction: string;
helpDescription: string;
zoomInAction: string;
zoomInShortcut: string;
zoomInDescription: string;
zoomOutAction: string;
zoomOutShortcut: string;
zoomOutDescription: string;
panCanvasAction: string;
panCanvasShortcut: string;
panCanvasDescription: string;
contextMenuAction: string;
contextMenuShortcut: string;
contextMenuDescription: string;
// Mouse interactions
selectToolAction: string;
selectToolShortcut: string;
selectToolDescription: string;
panToolAction: string;
panToolShortcut: string;
panToolDescription: string;
addItemAction: string;
addItemShortcut: string;
addItemDescription: string;
drawRectangleAction: string;
drawRectangleShortcut: string;
drawRectangleDescription: string;
createConnectorAction: string;
createConnectorShortcut: string;
createConnectorDescription: string;
addTextAction: string;
addTextShortcut: string;
addTextDescription: string;
};
connectorHintTooltip: {
tipCreatingConnectors: string;
tipConnectorTools: string;
clickInstructionStart: string;
clickInstructionMiddle: string;
clickInstructionEnd: string;
nowClickTarget: string;
dragStart: string;
dragEnd: string;
rerouteStart: string;
rerouteMiddle: string;
rerouteEnd: string;
};
importHintTooltip: {
title: string;
instructionStart: string;
menuButton: string;
instructionMiddle: string;
openButton: string;
instructionEnd: string;
};
// other namespaces can be added here
}
export interface IsoflowProps {