mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-23 22:48:57 -05:00
* I18n basic framework construction completed * fossflow-lib i18n done Thanks to @AmazingRain
This commit is contained in:
150
package-lock.json
generated
150
package-lock.json
generated
@@ -5377,6 +5377,15 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-4.0.0.tgz",
|
||||
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -7771,6 +7780,15 @@
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
@@ -7822,6 +7840,55 @@
|
||||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.4.2",
|
||||
"resolved": "https://registry.npmmirror.com/i18next/-/i18next-25.4.2.tgz",
|
||||
"integrity": "sha512-gD4T25a6ovNXsfXY1TwHXXXLnD/K2t99jyYMCSimSCBnBRJVQr5j+VAaU83RJCPzrTGhVQ6dqIga66xO2rtd5g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com/i18next.html"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-browser-languagedetector": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz",
|
||||
"integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-http-backend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz",
|
||||
"integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-fetch": "4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
@@ -10102,6 +10169,48 @@
|
||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -11090,6 +11199,32 @@
|
||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "15.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.7.3.tgz",
|
||||
"integrity": "sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 25.4.1",
|
||||
"react": ">= 16.8.0",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz",
|
||||
@@ -12774,7 +12909,7 @@
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -13003,6 +13138,15 @@
|
||||
"d3-timer": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
|
||||
@@ -13521,9 +13665,13 @@
|
||||
"dependencies": {
|
||||
"@isoflow/isopacks": "^0.0.10",
|
||||
"fossflow": "*",
|
||||
"i18next": "^25.4.2",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-i18next": "^15.7.3",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "npm run start --workspace=packages/fossflow-app",
|
||||
"dev": "NODE_ENV=development npm run start --workspace=packages/fossflow-app",
|
||||
"dev:lib": "npm run dev --workspace=packages/fossflow-lib",
|
||||
"dev:backend": "npm run dev --workspace=packages/fossflow-backend",
|
||||
"build": "npm run build:lib && npm run build:app",
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
"dependencies": {
|
||||
"@isoflow/isopacks": "^0.0.10",
|
||||
"fossflow": "*",
|
||||
"i18next": "^25.4.2",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-i18next": "^15.7.3",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -13,5 +13,11 @@ export default defineConfig({
|
||||
// https://rsbuild.rs/guide/advanced/browser-compatibility
|
||||
polyfill: 'usage',
|
||||
assetPrefix: process.env.PUBLIC_URL || '/',
|
||||
copy: [
|
||||
{
|
||||
from: './src/i18n',
|
||||
to: 'i18n/app',
|
||||
},
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,10 +6,13 @@ import awsIsopack from '@isoflow/isopacks/dist/aws';
|
||||
import gcpIsopack from '@isoflow/isopacks/dist/gcp';
|
||||
import azureIsopack from '@isoflow/isopacks/dist/azure';
|
||||
import kubernetesIsopack from '@isoflow/isopacks/dist/kubernetes';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DiagramData, mergeDiagramData, extractSavableData } from './diagramUtils';
|
||||
import { StorageManager } from './StorageManager';
|
||||
import { DiagramManager } from './components/DiagramManager';
|
||||
import { storageManager } from './services/storageService';
|
||||
import ChangeLanguage from './components/ChangeLanguage';
|
||||
import { allLocales } from 'fossflow';
|
||||
import './App.css';
|
||||
|
||||
const icons = flattenCollections([
|
||||
@@ -451,6 +454,16 @@ function App() {
|
||||
setFossflowKey(prev => prev + 1); // Force re-render
|
||||
setHasUnsavedChanges(false);
|
||||
};
|
||||
|
||||
// i18n
|
||||
const [canI18n, setCanI18n] = useState(false);
|
||||
const { t, i18n } = useTranslation('app');
|
||||
useEffect(() => {
|
||||
// http://localhost:3000/?canI18n=1
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
// show demo
|
||||
setCanI18n(params.get('canI18n') === '1');
|
||||
}, [window.location.search]);
|
||||
|
||||
// Auto-save functionality
|
||||
useEffect(() => {
|
||||
@@ -514,28 +527,29 @@ function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<div className="toolbar">
|
||||
<button onClick={newDiagram}>New Diagram</button>
|
||||
{canI18n && <ChangeLanguage />}
|
||||
<button onClick={newDiagram}>{t('nav.newDiagram')}</button>
|
||||
{serverStorageAvailable && (
|
||||
<button
|
||||
onClick={() => setShowDiagramManager(true)}
|
||||
style={{ backgroundColor: '#2196F3', color: 'white' }}
|
||||
>
|
||||
🌐 Server Storage
|
||||
🌐 {t('nav.serverStorage')}
|
||||
</button>
|
||||
)}
|
||||
<button onClick={() => setShowSaveDialog(true)}>Save (Session Only)</button>
|
||||
<button onClick={() => setShowLoadDialog(true)}>Load (Session Only)</button>
|
||||
<button onClick={() => setShowSaveDialog(true)}>{t('nav.saveSessionOnly')}</button>
|
||||
<button onClick={() => setShowLoadDialog(true)}>{t('nav.loadSessionOnly')}</button>
|
||||
<button
|
||||
onClick={() => setShowImportDialog(true)}
|
||||
style={{ backgroundColor: '#28a745' }}
|
||||
>
|
||||
📂 Import File
|
||||
📂 {t('nav.importFile')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowExportDialog(true)}
|
||||
style={{ backgroundColor: '#007bff' }}
|
||||
>
|
||||
💾 Export File
|
||||
💾 {t('nav.exportFile')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
@@ -551,7 +565,7 @@ function App() {
|
||||
}}
|
||||
title="Save to current session only"
|
||||
>
|
||||
Quick Save (Session)
|
||||
{t('nav.quickSaveSession')}
|
||||
</button>
|
||||
<span className="current-diagram">
|
||||
{currentDiagram ? `Current: ${currentDiagram.name}` : diagramName || 'Untitled Diagram'}
|
||||
@@ -568,6 +582,7 @@ function App() {
|
||||
initialData={diagramData}
|
||||
onModelUpdated={handleModelUpdated}
|
||||
editorMode="EDITABLE"
|
||||
locale={allLocales[i18n.language as keyof typeof allLocales]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import './styles.css';
|
||||
import { supportedLanguages } from '../../i18n';
|
||||
|
||||
const ChangeLanguage = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [currentLang, setCurrentLang] = useState(i18n.language || 'en');
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const changeLanguage = (lang: string) => {
|
||||
i18n.changeLanguage(lang);
|
||||
setCurrentLang(lang);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="language-selector" ref={dropdownRef}>
|
||||
<div
|
||||
className="language-display"
|
||||
onMouseEnter={() => setIsOpen(true)}
|
||||
>
|
||||
A/文
|
||||
</div>
|
||||
{isOpen && (
|
||||
<div className="language-dropdown">
|
||||
{supportedLanguages.map(item => (
|
||||
<div
|
||||
key={item.value}
|
||||
className={`language-option ${currentLang === item.value ? 'active' : ''}`}
|
||||
onClick={() => changeLanguage(item.value)}
|
||||
>
|
||||
{item.label}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangeLanguage;
|
||||
@@ -0,0 +1,45 @@
|
||||
.language-selector {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.language-display {
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.language-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.language-option {
|
||||
padding: 8px 12px;
|
||||
transition: background-color 0.2s;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.language-option:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.language-option.active {
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
34
packages/fossflow-app/src/i18n.ts
Normal file
34
packages/fossflow-app/src/i18n.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import Backend from 'i18next-http-backend';
|
||||
|
||||
// future: add language detector
|
||||
// import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
i18n
|
||||
.use(Backend)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: 'en-US',
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
ns: ['app'],
|
||||
backend: {
|
||||
loadPath: '/i18n/{{ns}}/{{lng}}.json'
|
||||
},
|
||||
});
|
||||
|
||||
export const supportedLanguages = [
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
label: '中文',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
];
|
||||
|
||||
export default i18n;
|
||||
11
packages/fossflow-app/src/i18n/en-US.json
Normal file
11
packages/fossflow-app/src/i18n/en-US.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"nav": {
|
||||
"newDiagram": "New Diagram",
|
||||
"saveSessionOnly": "Save (Session Only)",
|
||||
"loadSessionOnly": "Load (Session Only)",
|
||||
"importFile": "Import File",
|
||||
"exportFile": "Export File",
|
||||
"quickSaveSession": "Quick Save(Session)",
|
||||
"serverStorage": "Server Storage"
|
||||
}
|
||||
}
|
||||
11
packages/fossflow-app/src/i18n/zh-CN.json
Normal file
11
packages/fossflow-app/src/i18n/zh-CN.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"nav": {
|
||||
"newDiagram": "新建图表",
|
||||
"saveSessionOnly": "保存(仅会话)",
|
||||
"loadSessionOnly": "加载(仅会话)",
|
||||
"importFile": "导入文件",
|
||||
"exportFile": "导出文件",
|
||||
"quickSaveSession": "快速保存(会话)",
|
||||
"serverStorage": "服务端存储"
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,19 @@ import reportWebVitals from './reportWebVitals';
|
||||
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import ErrorBoundaryFallbackUI from './components/ErrorBoundary';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n from './i18n';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<ErrorBoundary FallbackComponent={ErrorBoundaryFallbackUI}>
|
||||
<App />
|
||||
</ErrorBoundary>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ErrorBoundary FallbackComponent={ErrorBoundaryFallbackUI}>
|
||||
<App />
|
||||
</ErrorBoundary>
|
||||
</I18nextProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { UiOverlay } from 'src/components/UiOverlay/UiOverlay';
|
||||
import { UiStateProvider, useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { INITIAL_DATA, MAIN_MENU_OPTIONS } from 'src/config';
|
||||
import { useInitialDataManager } from 'src/hooks/useInitialDataManager';
|
||||
import enUS from 'src/i18n/en-US';
|
||||
|
||||
const App = ({
|
||||
initialData,
|
||||
@@ -21,7 +22,8 @@ const App = ({
|
||||
onModelUpdated,
|
||||
enableDebugTools = false,
|
||||
editorMode = 'EDITABLE',
|
||||
renderer
|
||||
renderer,
|
||||
locale = enUS,
|
||||
}: IsoflowProps) => {
|
||||
const uiStateActions = useUiStateStore((state) => {
|
||||
return state.actions;
|
||||
|
||||
7
packages/fossflow-lib/src/i18n/en-US.ts
Normal file
7
packages/fossflow-lib/src/i18n/en-US.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { LocaleProps } from '../types/isoflowProps';
|
||||
|
||||
const locale: LocaleProps = {
|
||||
"exampleText": "This is an example text"
|
||||
};
|
||||
|
||||
export default locale;
|
||||
9
packages/fossflow-lib/src/i18n/index.ts
Normal file
9
packages/fossflow-lib/src/i18n/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import enUS from './en-US';
|
||||
import zhCN from './zh-CN';
|
||||
|
||||
const locales = {
|
||||
'en-US': enUS,
|
||||
'zh-CN': zhCN
|
||||
};
|
||||
|
||||
export default locales;
|
||||
7
packages/fossflow-lib/src/i18n/zh-CN.ts
Normal file
7
packages/fossflow-lib/src/i18n/zh-CN.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { LocaleProps } from '../types/isoflowProps';
|
||||
|
||||
const locale: LocaleProps = {
|
||||
"exampleText": "这是一段示例文本"
|
||||
};
|
||||
|
||||
export default locale;
|
||||
@@ -6,3 +6,8 @@ export { INITIAL_DATA, INITIAL_SCENE_STATE } from 'src/config';
|
||||
export * from 'src/schemas';
|
||||
export type { IsoflowProps, InitialData } from 'src/types';
|
||||
export * from 'src/types/model';
|
||||
|
||||
// Export i18n locales
|
||||
export { default as enUS } from 'src/i18n/en-US';
|
||||
export { default as zhCN } from 'src/i18n/zh-CN';
|
||||
export { default as allLocales } from 'src/i18n';
|
||||
|
||||
@@ -7,6 +7,11 @@ export type InitialData = Model & {
|
||||
view?: string;
|
||||
};
|
||||
|
||||
export interface LocaleProps {
|
||||
exampleText: string;
|
||||
// other locale keys
|
||||
}
|
||||
|
||||
export interface IsoflowProps {
|
||||
initialData?: InitialData;
|
||||
mainMenuOptions?: MainMenuOptions;
|
||||
@@ -16,4 +21,5 @@ export interface IsoflowProps {
|
||||
enableDebugTools?: boolean;
|
||||
editorMode?: keyof typeof EditorModeEnum;
|
||||
renderer?: RendererProps;
|
||||
locale?: LocaleProps;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user