@@ -51,6 +51,7 @@ import {
5151 horizontalListSortingStrategy ,
5252} from "@dnd-kit/sortable" ;
5353import { SortableTab } from "@/components/ui/sortable-tab" ;
54+ import { useTranslation } from "react-i18next" ;
5455
5556interface TabItem {
5657 id : string ;
@@ -106,6 +107,7 @@ const TAB_TRIGGER_CLASS =
106107 "gap-2 group relative pr-8 bg-transparent data-[state=active]:bg-background border-b-2 border-b-transparent data-[state=active]:border-b-primary rounded-none h-9 hover:bg-muted/50 border-r border-r-border/40 last:border-r-0 shrink-0" ;
107108
108109export default function App ( ) {
110+ const { t } = useTranslation ( ) ;
109111 const resolveTableScope = ( driver : string , database ?: string ) => {
110112 const isDatabaseScoped = driver === "mysql" || driver === "clickhouse" ;
111113 return {
@@ -125,6 +127,8 @@ export default function App() {
125127 const [ aiVisible , setAiVisible ] = useState ( false ) ;
126128 const [ openSettings , setOpenSettings ] = useState ( false ) ;
127129 const [ isFullscreen , setIsFullscreen ] = useState ( false ) ;
130+ const isDefaultQueryTitle = ( title ?: string ) =>
131+ ! ! title && / ^ ( Q u e r y \( | 查 询 ( ) / . test ( title ) ;
128132 const [ queriesLastUpdated , setQueriesLastUpdated ] = useState ( 0 ) ;
129133 const [ pendingCloseTabIds , setPendingCloseTabIds ] = useState < string [ ] > ( [ ] ) ;
130134 const [ currentCloseTabId , setCurrentCloseTabId ] = useState < string | null > (
@@ -174,8 +178,8 @@ export default function App() {
174178 size = "sm"
175179 className = "h-7 w-7 p-0"
176180 onClick = { ( ) => setOpenSettings ( true ) }
177- title = "Settings (Cmd/Ctrl+,)"
178- aria-label = "Open settings"
181+ title = { t ( "app.window.settingsTooltip" ) }
182+ aria-label = { t ( "app.window.openSettings" ) }
179183 >
180184 < Settings className = "w-4 h-4" />
181185 </ Button >
@@ -187,10 +191,10 @@ export default function App() {
187191 onClick = { ( ) => setAiVisible ( ( v ) => ! v ) }
188192 title = {
189193 aiVisible
190- ? "Hide AI Panel (Cmd/Ctrl+\\)"
191- : "Show AI Panel (Cmd/Ctrl+\\)"
194+ ? t ( "app.window.hideAiPanel" )
195+ : t ( "app.window.showAiPanel" )
192196 }
193- aria-label = { aiVisible ? "Hide AI panel" : "Show AI panel" }
197+ aria-label = { aiVisible ? t ( "app.window.hideAiPanelAria" ) : t ( "app.window.showAiPanelAria" ) }
194198 >
195199 < Sparkles className = "w-4 h-4" />
196200 </ Button >
@@ -266,7 +270,7 @@ export default function App() {
266270 const newTab : TabItem = {
267271 id : newTabId ,
268272 type : "editor" ,
269- title : `Query ( ${ databaseName } )` ,
273+ title : t ( "app.tab.queryTitle" , { database : databaseName } ) ,
270274 connectionId,
271275 database : databaseName ,
272276 driver,
@@ -374,7 +378,7 @@ export default function App() {
374378 const tab = tabs . find ( ( t ) => t . id === tabId ) ;
375379 if ( ! tab || ! tab . connectionId ) {
376380 // TODO: Prompt user to select connection if missing
377- alert ( "Please select a connection first (feature pending)" ) ;
381+ alert ( t ( "app.error.selectConnectionFirst" ) ) ;
378382 return ;
379383 }
380384
@@ -489,7 +493,7 @@ export default function App() {
489493 } catch ( e ) {
490494 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
491495 console . error ( "get_table_data failed" , errorMessage ) ;
492- toast . error ( "Failed to load table data" , {
496+ toast . error ( t ( "app.error.loadTableData" ) , {
493497 description : errorMessage ,
494498 } ) ;
495499 }
@@ -517,11 +521,11 @@ export default function App() {
517521 scope : "full_table" ,
518522 filePath,
519523 } ) ;
520- toast . success ( `Export completed ( ${ result . rowCount } rows)` , {
524+ toast . success ( t ( "app.success.exportCompleted" , { count : result . rowCount } ) , {
521525 description : result . filePath ,
522526 } ) ;
523527 } catch ( e ) {
524- toast . error ( "Export failed" , {
528+ toast . error ( t ( "app.error.exportFailed" ) , {
525529 description : e instanceof Error ? e . message : String ( e ) ,
526530 } ) ;
527531 }
@@ -543,7 +547,7 @@ export default function App() {
543547 const newTab : TabItem = {
544548 id : tabId ,
545549 type : "ddl" ,
546- title : `DDL: ${ ctx . table } ` ,
550+ title : t ( "app.tab.ddlTitle" , { table : ctx . table } ) ,
547551 connectionId : ctx . connectionId ,
548552 database : ctx . database ,
549553 schema : ctx . schema ,
@@ -601,7 +605,7 @@ export default function App() {
601605 } catch ( e ) {
602606 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
603607 console . error ( "handleTableRefresh failed" , errorMessage ) ;
604- toast . error ( "Failed to refresh table" , {
608+ toast . error ( t ( "app.error.refreshTable" ) , {
605609 description : errorMessage ,
606610 } ) ;
607611 }
@@ -641,7 +645,7 @@ export default function App() {
641645 } catch ( e ) {
642646 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
643647 console . error ( "handlePageChange failed" , errorMessage ) ;
644- toast . error ( "Failed to change page" , {
648+ toast . error ( t ( "app.error.changePage" ) , {
645649 description : errorMessage ,
646650 } ) ;
647651 }
@@ -682,7 +686,7 @@ export default function App() {
682686 } catch ( e ) {
683687 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
684688 console . error ( "handlePageSizeChange failed" , errorMessage ) ;
685- toast . error ( "Failed to change page size" , {
689+ toast . error ( t ( "app.error.changePageSize" ) , {
686690 description : errorMessage ,
687691 } ) ;
688692 }
@@ -736,7 +740,7 @@ export default function App() {
736740 } catch ( e ) {
737741 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
738742 console . error ( "handleSortChange failed" , errorMessage ) ;
739- toast . error ( "Failed to sort table" , {
743+ toast . error ( t ( "app.error.sortTable" ) , {
740744 description : errorMessage ,
741745 } ) ;
742746 }
@@ -793,7 +797,7 @@ export default function App() {
793797 } catch ( e ) {
794798 const errorMessage = e instanceof Error ? e . message : String ( e ) ;
795799 console . error ( "handleFilterChange failed" , errorMessage ) ;
796- toast . error ( "Failed to filter table" , {
800+ toast . error ( t ( "app.error.filterTable" ) , {
797801 description : errorMessage ,
798802 } ) ;
799803 }
@@ -854,7 +858,7 @@ export default function App() {
854858 ) ,
855859 ) ;
856860 } catch ( e ) {
857- toast . error ( "Failed to save query" , {
861+ toast . error ( t ( "app.error.saveQuery" ) , {
858862 description : e instanceof Error ? e . message : String ( e ) ,
859863 } ) ;
860864 throw e ;
@@ -1209,13 +1213,13 @@ export default function App() {
12091213 { tab . type === "editor" && tab . isDirty && (
12101214 < span
12111215 className = "inline-block w-1.5 h-1.5 rounded-full bg-amber-500 ml-1 shrink-0"
1212- aria-label = "Unsaved changes"
1216+ aria-label = { t ( "app.tab.unsavedChanges" ) }
12131217 />
12141218 ) }
12151219 </ span >
12161220 < button
12171221 type = "button"
1218- aria-label = { `Close ${ title } ` }
1222+ aria-label = { t ( "app.tab.closeAria" , { title } ) }
12191223 className = "absolute right-1 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 p-1 hover:bg-accent rounded-sm cursor-pointer transition-opacity"
12201224 onClick = { ( e ) => {
12211225 e . stopPropagation ( ) ;
@@ -1231,12 +1235,12 @@ export default function App() {
12311235 < ContextMenuItem
12321236 onClick = { ( ) => handleCloseTab ( tab . id ) }
12331237 >
1234- Close Tab
1238+ { t ( "app.tab.closeTab" ) }
12351239 </ ContextMenuItem >
12361240 < ContextMenuItem
12371241 onClick = { ( ) => handleCloseOtherTabs ( tab . id ) }
12381242 >
1239- Close Other Tabs
1243+ { t ( "app.tab.closeOtherTabs" ) }
12401244 </ ContextMenuItem >
12411245 </ ContextMenuContent >
12421246 </ ContextMenu >
@@ -1263,7 +1267,7 @@ export default function App() {
12631267 < div className = "text-center" >
12641268 < FileCode className = "w-12 h-12 mx-auto mb-2 opacity-50" />
12651269 < p >
1266- Select a table or create a new query from the sidebar
1270+ { t ( "app.empty.hint" ) }
12671271 </ p >
12681272 </ div >
12691273 </ div >
@@ -1289,7 +1293,7 @@ export default function App() {
12891293 schemaOverview = { tab . schemaOverview }
12901294 savedQueryId = { tab . savedQueryId }
12911295 initialName = {
1292- tab . title . startsWith ( "Query (" ) ? "" : tab . title
1296+ isDefaultQueryTitle ( tab . title ) ? "" : tab . title
12931297 }
12941298 initialDescription = { tab . savedQueryDescription }
12951299 onSaveSuccess = { ( savedQuery ) => {
@@ -1413,21 +1417,20 @@ export default function App() {
14131417 >
14141418 < AlertDialogContent >
14151419 < AlertDialogHeader >
1416- < AlertDialogTitle > Unsaved changes </ AlertDialogTitle >
1420+ < AlertDialogTitle > { t ( "app.dialog.unsavedTitle" ) } </ AlertDialogTitle >
14171421 < AlertDialogDescription >
1418- This SQL tab has unsaved changes. Do you want to save before
1419- closing?
1422+ { t ( "app.dialog.unsavedDescription" ) }
14201423 </ AlertDialogDescription >
14211424 </ AlertDialogHeader >
14221425 < AlertDialogFooter >
14231426 < AlertDialogCancel onClick = { handleUnsavedCloseCancel } >
1424- Cancel
1427+ { t ( "common.cancel" ) }
14251428 </ AlertDialogCancel >
14261429 < AlertDialogAction onClick = { handleUnsavedCloseWithoutSave } >
1427- Don't Save
1430+ { t ( "app.dialog.dontSave" ) }
14281431 </ AlertDialogAction >
14291432 < AlertDialogAction onClick = { handleUnsavedCloseSave } >
1430- Save
1433+ { t ( "common.save" ) }
14311434 </ AlertDialogAction >
14321435 </ AlertDialogFooter >
14331436 </ AlertDialogContent >
@@ -1437,7 +1440,7 @@ export default function App() {
14371440 onOpenChange = { handleCloseSaveDialogOpenChange }
14381441 onSave = { handleCloseFlowSave }
14391442 initialName = {
1440- currentCloseTab && ! currentCloseTab . title . startsWith ( "Query (" )
1443+ currentCloseTab && ! isDefaultQueryTitle ( currentCloseTab . title )
14411444 ? currentCloseTab . title
14421445 : ""
14431446 }
0 commit comments