Skip to content

Commit 1b0934b

Browse files
Add language support and localization features
- Added language support for multilingual interface - Updated i18n configuration and locale files (en, es) - Modified various components to support localization - Updated package dependencies for language support - Removed deprecated language-selectiondlg component - Enhanced UI components with language selection capabilities - Updated MicroPython package configuration
1 parent 43d07de commit 1b0934b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+899
-666
lines changed

package-lock.json

Lines changed: 124 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"flowbite-react": "^0.11.7",
3939
"gridstack": "^12.2.1",
4040
"i18next": "^24.2.1",
41+
"i18next-browser-languagedetector": "^8.2.0",
4142
"jszip": "^3.10.1",
4243
"markdown-it": "^14.1.0",
4344
"markdown-it-abbr": "^2.0.0",

public/micropython/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"fimware": "Micropython",
3-
"firmwareVersion": "1.25.0",
3+
"version": "1.25.0",
44
"firmwareBuild": "preview",
55
"firmwareDate": "2021-06-01",
66
"firmwareFilename": "firmware2350.uf2",

src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useEffect, useRef } from 'react';
22
import './App.css';
3-
import Navbar from './components/navbar';
4-
import XRPLayout from './components/xrplayout';
5-
import AppMgr from './managers/appmgr';
3+
import Navbar from '@components/navbar';
4+
import XRPLayout from '@components/xrplayout';
5+
import AppMgr from '@/managers/appmgr';
66

77
function App() {
88
const xrpLayoutRef = useRef();

src/components/MonacoEditor.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import { ExtensionHostKind, registerExtension } from 'vscode/extensions';
1515
import 'vscode/localExtensionHost';
1616
import { initializedAndStartLanguageClient } from '@components/lsp-client';
1717
import AppMgr, { EventType, Themes } from '@/managers/appmgr';
18-
import i18n from '@/utils/i18n';
1918
import { StorageKeys } from '@/utils/localstorage';
2019
import EditorMgr, { EditorSession } from '@/managers/editormgr';
2120
import { FontSize } from '@/utils/types';
2221
import { Constants } from '@/utils/constants';
22+
import { useTranslation } from 'react-i18next';
2323

2424
const languageId = 'python';
2525
let isClientInitalized: boolean = false;
@@ -137,6 +137,7 @@ const MonacoEditor = ({
137137
value,
138138
className,
139139
}: MonacoEditorProps) => {
140+
const { t } = useTranslation();
140141
const containerRef = useRef<HTMLDivElement | null>(null);
141142
const editor = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
142143

@@ -265,7 +266,7 @@ const MonacoEditor = ({
265266

266267
editor.current.addAction({
267268
id: 'save',
268-
label: i18n.t('save'),
269+
label: t('save'),
269270
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
270271
contextMenuGroupId: 'navigation',
271272
contextMenuOrder: 1.5,

src/components/chat/ai-chat.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import { GeminiContextLoader, createContextLoader } from '@/utils/gemini-context
55
import ChatMessageComponent from './chat-message';
66
import { IoSend, IoRefresh, IoSparkles, IoDocument, IoStop } from 'react-icons/io5';
77
import { v4 as uuidv4 } from 'uuid';
8+
import { useTranslation } from 'react-i18next';
89

910
export default function AIChat() {
11+
const { i18n } = useTranslation();
1012
const [messages, setMessages] = useState<ChatMessage[]>([]);
1113
const [inputValue, setInputValue] = useState('');
1214
const [status, setStatus] = useState<ChatStatus>(ChatStatus.IDLE);
@@ -150,13 +152,15 @@ export default function AIChat() {
150152
const terminalContext = contextLoader.current?.getCurrentTerminalContext() || '';
151153

152154
// Use the new simplified chat API - all teaching guidelines are now in backend
153-
console.log(`[AIChat] Sending message with session ${sessionId.substring(0, 8)}... (history: ${messages.length} messages)`);
155+
const currentLanguage = i18n.language || 'en';
156+
console.log(`[AIChat] Sending message with session ${sessionId.substring(0, 8)}... (history: ${messages.length} messages, language: ${currentLanguage})`);
154157
await geminiClient.current.chatWithContext(
155158
sessionId,
156159
userMessage.content,
157160
messages, // Conversation history
158161
editorContext,
159162
terminalContext,
163+
currentLanguage, // User's selected language
160164
(content: string) => {
161165
// Check if generation was aborted
162166
if (abortController.current?.signal.aborted) {

src/components/dashboard/AddWidget.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import { Dropdown, DropdownItem } from "flowbite-react";
44
import { MdSpeed } from 'react-icons/md';
55
import { FaBatteryHalf, FaBolt, FaCog, FaEye, FaGlobe, FaPlus } from 'react-icons/fa';
66
import { BsRulers } from 'react-icons/bs';
7-
import i18n from "@/utils/i18n";
87
import { FlowBiteConstants } from "@/utils/constants";
8+
import { useTranslation } from "react-i18next";
99

1010
type ActionType = 'accelerometer' | 'current' | 'encoder' | 'gyroscope' | 'rangefinder' | 'reflectance' | 'voltage';
1111

1212
const AddWidgets: React.FC = () => {
13+
const { t } = useTranslation();
1314
const { addWidget } = useGridStackContext();
1415

1516
const handleAction = (action: ActionType) => {
@@ -24,7 +25,7 @@ const AddWidgets: React.FC = () => {
2425
minW: 2,
2526
minH: 5,
2627
content: JSON.stringify({
27-
name: i18n.t('accelerometer'),
28+
name: 'Accelerometer',
2829
props: {
2930
isActive: true
3031
// Remove widgetId - we'll get it from GridStack
@@ -44,7 +45,7 @@ const AddWidgets: React.FC = () => {
4445
minW: 1,
4546
minH: 5,
4647
content: JSON.stringify({
47-
name: i18n.t('current'),
48+
name: 'Current',
4849
props: {
4950
isActive: true
5051
},
@@ -63,7 +64,7 @@ const AddWidgets: React.FC = () => {
6364
minW: 2,
6465
minH: 5,
6566
content: JSON.stringify({
66-
name: i18n.t('gyroscope'),
67+
name: 'Gyroscope',
6768
props: {
6869
isActive: true
6970
},
@@ -82,7 +83,7 @@ const AddWidgets: React.FC = () => {
8283
minW: 1,
8384
minH: 4,
8485
content: JSON.stringify({
85-
name: i18n.t('encoder'),
86+
name: 'Encoder',
8687
props: {
8788
isActive: true
8889
},
@@ -101,7 +102,7 @@ const AddWidgets: React.FC = () => {
101102
minW: 2,
102103
minH: 5,
103104
content: JSON.stringify({
104-
name: i18n.t('reflectance'),
105+
name: 'Reflectance',
105106
props: {
106107
isActive: true
107108
},
@@ -120,7 +121,7 @@ const AddWidgets: React.FC = () => {
120121
minW: 2,
121122
minH: 6,
122123
content: JSON.stringify({
123-
name: i18n.t('voltage'),
124+
name: 'Voltage',
124125
props: {
125126
isActive: true
126127
},
@@ -139,7 +140,7 @@ const AddWidgets: React.FC = () => {
139140
minW: 2,
140141
minH: 8,
141142
content: JSON.stringify({
142-
name: i18n.t('rangefinder'),
143+
name: 'Rangefinder',
143144
props: {
144145
isActive: true
145146
},
@@ -155,13 +156,13 @@ const AddWidgets: React.FC = () => {
155156
return (
156157
<div className="flex items-center mt-4 sm:mt-0">
157158
<Dropdown label={<FaPlus size={20} />} inline={true} theme={FlowBiteConstants.DropdownTheme} className="flex items-center mt-4 sm:mt-0 ">
158-
<DropdownItem icon={MdSpeed} onClick={() => handleAction('accelerometer')}>Accelerometer</DropdownItem>
159-
<DropdownItem icon={FaBolt} onClick={() => handleAction('current')}>Current</DropdownItem>
160-
<DropdownItem icon={FaGlobe} onClick={() => handleAction('gyroscope')}>Gyroscope</DropdownItem>
161-
<DropdownItem icon={FaCog} onClick={() => handleAction('encoder')}>Encoder</DropdownItem>
162-
<DropdownItem icon={FaEye} onClick={() => handleAction('reflectance')}>Reflectance</DropdownItem>
163-
<DropdownItem icon={BsRulers} onClick={() => handleAction('rangefinder')}>Rangefinder</DropdownItem>
164-
<DropdownItem icon={FaBatteryHalf} onClick={() => handleAction('voltage')}>Voltage</DropdownItem>
159+
<DropdownItem icon={MdSpeed} onClick={() => handleAction('accelerometer')}>{t('accelerometer')}</DropdownItem>
160+
<DropdownItem icon={FaBolt} onClick={() => handleAction('current')}>{t('current')}</DropdownItem>
161+
<DropdownItem icon={FaGlobe} onClick={() => handleAction('gyroscope')}>{t('gyroscope')}</DropdownItem>
162+
<DropdownItem icon={FaCog} onClick={() => handleAction('encoder')}>{t('encoders')}</DropdownItem>
163+
<DropdownItem icon={FaEye} onClick={() => handleAction('reflectance')}>{t('reflectance')}</DropdownItem>
164+
<DropdownItem icon={BsRulers} onClick={() => handleAction('rangefinder')}>{t('rangefinder')}</DropdownItem>
165+
<DropdownItem icon={FaBatteryHalf} onClick={() => handleAction('voltage')}>{t('voltage')}</DropdownItem>
165166
</Dropdown>
166167
</div>
167168
);

src/components/dashboard/sensors/Accelerometer.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { Dropdown, DropdownItem } from "flowbite-react";
77
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
88
import { FaChartLine, FaHashtag, FaCog, FaTrash } from 'react-icons/fa';
99
import { useGridStackContext } from '../lib/grid-stack-context';
10-
import i18n from '@/utils/i18n';
1110
import { FlowBiteConstants } from '@/utils/constants';
11+
import { useTranslation } from 'react-i18next';
1212

1313
// Define a type for timestamped accelerometer data
1414
interface TimestampedAccelData {
@@ -27,6 +27,7 @@ const axisColors = {
2727

2828
const Accelerometer: React.FC = () => {
2929
// State to store the history of accelerometer readings
30+
const { t } = useTranslation();
3031
const [accelHistory, setAccelHistory] = useState<TimestampedAccelData[]>([]);
3132
const { getSensorData, requestSensors, stopSensor, sensorData } = useSensorData();
3233
const { removeWidget } = useGridStackContext();
@@ -48,7 +49,7 @@ const Accelerometer: React.FC = () => {
4849
const sensorCard = item.querySelector('.sensor-card');
4950
const titleElement = sensorCard?.querySelector('h3');
5051

51-
if (titleElement?.textContent === 'Accelerometer') {
52+
if (titleElement?.textContent === t('accelerometer')) {
5253
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5354
const node = (item as any).gridstackNode;
5455
if (node && node.id) {
@@ -111,7 +112,7 @@ const Accelerometer: React.FC = () => {
111112
};
112113

113114
const sensorCardProps = {
114-
title: "Accelerometer",
115+
title: t('accelerometer'),
115116
icon: <MdSpeed size={20} />,
116117
onStart: handleStart,
117118
onStop: handleStop,
@@ -150,13 +151,13 @@ const Accelerometer: React.FC = () => {
150151
<DropdownItem onClick={() => handleAction('graph')}>
151152
<div className="flex items-center space-x-2">
152153
<FaChartLine size={16} />
153-
<span>{i18n.t('graph')}</span>
154+
<span>{t('graph')}</span>
154155
</div>
155156
</DropdownItem>
156157
<DropdownItem onClick={() => handleAction('number')}>
157158
<div className="flex items-center space-x-2">
158159
<FaHashtag size={16} />
159-
<span>{i18n.t('number')}</span>
160+
<span>{t('number')}</span>
160161
</div>
161162
</DropdownItem>
162163
</Dropdown>
@@ -171,7 +172,7 @@ const Accelerometer: React.FC = () => {
171172
</div>
172173
{!accelData ? (
173174
<div className="flex items-center justify-center w-full h-full">
174-
<div className="text-gray-500 dark:text-gray-400">{i18n.t('no-data-available')}</div>
175+
<div className="text-gray-500 dark:text-gray-400">{t('no-data-available')}</div>
175176
</div>
176177
) : (
177178
<div className="flex flex-col w-full h-full relative pt-12">
@@ -183,7 +184,7 @@ const Accelerometer: React.FC = () => {
183184
<XAxis
184185
dataKey="timestamp"
185186
tick={false}
186-
label={i18n.t('time')}
187+
label={t('time')}
187188
/>
188189
<YAxis />
189190
<Tooltip
@@ -197,7 +198,7 @@ const Accelerometer: React.FC = () => {
197198
</ResponsiveContainer>
198199

199200
<div className="text-xs text-gray-500 text-center mt-2 dark:text-gray-400">
200-
{accelHistory.length} {i18n.t('readings-stored')}
201+
{accelHistory.length} {t('readings-stored')}
201202
</div>
202203
</div>
203204
)

src/components/dashboard/sensors/Current.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { Dropdown, DropdownItem } from "flowbite-react";
77
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
88
import { FaChartLine, FaHashtag, FaCog, FaTrash } from 'react-icons/fa';
99
import { useGridStackContext } from '../lib/grid-stack-context';
10-
import i18n from '@/utils/i18n';
1110
import { FlowBiteConstants } from '@/utils/constants';
11+
import { useTranslation } from 'react-i18next';
1212

1313

1414
// Define a type for timestamped current data
@@ -39,6 +39,7 @@ const channelLabels: Record<ChannelType, string> = {
3939

4040
const Current: React.FC = () => {
4141
// State to store the history of current readings
42+
const { t } = useTranslation();
4243
const [currentHistory, setCurrentHistory] = useState<TimestampedCurrentData[]>([]);
4344
const { getSensorData, requestSensors, stopSensor, sensorData } = useSensorData();
4445
const { removeWidget } = useGridStackContext();
@@ -64,7 +65,7 @@ const Current: React.FC = () => {
6465
const sensorCard = item.querySelector('.sensor-card');
6566
const titleElement = sensorCard?.querySelector('h3');
6667

67-
if (titleElement?.textContent === 'Current') {
68+
if (titleElement?.textContent === t('current')) {
6869
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6970
const node = (item as any).gridstackNode;
7071
if (node && node.id) {
@@ -126,7 +127,7 @@ const Current: React.FC = () => {
126127
};
127128

128129
const sensorCardProps = {
129-
title: "Current",
130+
title: t('current'),
130131
icon: <FaBolt size={20} />,
131132
onStart: handleStart,
132133
onStop: handleStop,
@@ -165,13 +166,13 @@ const Current: React.FC = () => {
165166
<DropdownItem onClick={() => handleAction('graph')}>
166167
<div className="flex items-center space-x-2">
167168
<FaChartLine size={16} />
168-
<span>{i18n.t('graph')}</span>
169+
<span>{t('graph')}</span>
169170
</div>
170171
</DropdownItem>
171172
<DropdownItem onClick={() => handleAction('number')}>
172173
<div className="flex items-center space-x-2">
173174
<FaHashtag size={16} />
174-
<span>{i18n.t('number')}</span>
175+
<span>{t('number')}</span>
175176
</div>
176177
</DropdownItem>
177178
</Dropdown>
@@ -186,7 +187,7 @@ const Current: React.FC = () => {
186187
</div>
187188
{!currentData ? (
188189
<div className="flex items-center justify-center w-full h-full">
189-
<div className="text-gray-500 dark:text-gray-400">{i18n.t('no-data-available')}</div>
190+
<div className="text-gray-500 dark:text-gray-400">{t('no-data-available')}</div>
190191
</div>
191192
) : (
192193
<div className="flex flex-col w-full h-full relative pt-12">
@@ -198,21 +199,21 @@ const Current: React.FC = () => {
198199
<XAxis
199200
dataKey="timestamp"
200201
tick={false}
201-
label={i18n.t('time')}
202+
label={t('time')}
202203
/>
203204
<YAxis />
204205
<Tooltip
205206
labelFormatter={(value) => new Date(value).toLocaleTimeString()}
206207
formatter={(value) => typeof value === 'number' ? `${value.toFixed(0)} mA` : value}
207208
/>
208-
<Line type="monotone" dataKey="currL" stroke={channelColors.currL} dot={false} name={i18n.t('left')} />
209-
<Line type="monotone" dataKey="currR" stroke={channelColors.currR} dot={false} name={i18n.t('right')} />
209+
<Line type="monotone" dataKey="currL" stroke={channelColors.currL} dot={false} name={t('left')} />
210+
<Line type="monotone" dataKey="currR" stroke={channelColors.currR} dot={false} name={t('right')} />
210211
<Line type="monotone" dataKey="curr3" stroke={channelColors.curr3} dot={false} name="Ch 3" />
211212
<Line type="monotone" dataKey="curr4" stroke={channelColors.curr4} dot={false} name="Ch 4" />
212213
</LineChart>
213214
</ResponsiveContainer>
214215
<div className="text-xs text-gray-500 text-center mt-2 dark:text-gray-400">
215-
{currentHistory.length} {i18n.t('readings-stored')}
216+
{currentHistory.length} {t('readings-stored')}
216217
</div>
217218
</div>
218219
)

0 commit comments

Comments
 (0)