Add i18n foundation and translations (#1027)

* feat: add i18n foundation

* feat: localize sessions sidebar

* Localize multirun/scheduled tasks and fix dialog dropdown interactions

* localize git sidebar surface and add zh-CN keys

* feat(ui): localize context panel, diff/plan views, and context sidebar content

* fix(config): resolve user config home via fs/home before embedded home

* localize header/chat UI and complete model/worktree panel strings

* localize worktree + github issue/pr dialog flows

* localize settings sections and split settings i18n dictionaries

* localize additional settings sections and sidebars

* localize more settings pages and dialogs

* fix settings select trigger localization

* localize tunnel settings ui surface

* localize additional settings sections

* localize keyboard shortcuts labels in settings

* localize terminal and utility dialogs surfaces

* feat(i18n): localize remaining UI strings

* Add Ukrainian locale

* Add Spanish locale

* Add Brazilian Portuguese locale

* Polish locale translations
This commit is contained in:
Bohdan Triapitsyn
2026-04-26 14:03:39 +03:00
committed by GitHub
parent 87db2ea210
commit 7d7285655d
198 changed files with 24173 additions and 4365 deletions
@@ -15,6 +15,7 @@ import {
} from '@remixicon/react';
import { cn } from '@/lib/utils';
import type { SessionFolder } from '@/stores/useSessionFoldersStore';
import { useI18n } from '@/lib/i18n';
type Props = {
selectedCount: number;
@@ -41,15 +42,18 @@ export const BulkActionBar: React.FC<Props> = ({
onDelete,
onDone,
}) => {
const { t } = useI18n();
const canMoveToFolder = Boolean(scopeKey) && !archivedBucket;
const destructiveLabel = archivedBucket ? 'Delete' : 'Archive';
const destructiveLabel = archivedBucket
? t('sessions.sidebar.bulkActions.delete')
: t('sessions.sidebar.bulkActions.archive');
const iconButtonClass = 'inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-interactive-hover/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50';
const destructiveIconButtonClass = 'inline-flex h-7 w-7 items-center justify-center rounded-md text-destructive hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50';
return (
<div className="flex shrink-0 items-center gap-1 border-t border-border px-2.5 py-1.5">
<span className="typography-ui-label text-muted-foreground whitespace-nowrap">
{selectedCount} selected
{t('sessions.sidebar.bulkActions.selectedCount', { count: selectedCount })}
</span>
<div className="ml-auto flex items-center gap-0.5">
@@ -61,18 +65,18 @@ export const BulkActionBar: React.FC<Props> = ({
<button
type="button"
className={iconButtonClass}
aria-label="Move to folder"
aria-label={t('sessions.sidebar.bulkActions.moveToFolder')}
>
<RiFolderLine className="h-4 w-4" />
</button>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}><p>Move to folder</p></TooltipContent>
<TooltipContent side="top" sideOffset={4}><p>{t('sessions.sidebar.bulkActions.moveToFolder')}</p></TooltipContent>
</Tooltip>
<DropdownMenuContent align="end" className="min-w-[180px]">
{scopeFolders.length === 0 ? (
<DropdownMenuItem disabled className="text-muted-foreground">
No folders yet
{t('sessions.sidebar.folders.none')}
</DropdownMenuItem>
) : (
scopeFolders.map((folder) => (
@@ -84,7 +88,7 @@ export const BulkActionBar: React.FC<Props> = ({
<DropdownMenuSeparator />
<DropdownMenuItem onClick={onCreateFolderAndMove}>
<RiAddLine className="mr-1 h-4 w-4" />
New folder...
{t('sessions.sidebar.folders.newFolderEllipsis')}
</DropdownMenuItem>
{canRemoveFromFolder ? (
<DropdownMenuItem
@@ -92,7 +96,7 @@ export const BulkActionBar: React.FC<Props> = ({
className="text-destructive focus:text-destructive"
>
<RiCloseLine className="mr-1 h-4 w-4" />
Remove from folder
{t('sessions.sidebar.folders.removeFromFolder')}
</DropdownMenuItem>
) : null}
</DropdownMenuContent>
@@ -119,12 +123,12 @@ export const BulkActionBar: React.FC<Props> = ({
type="button"
onClick={onDone}
className={iconButtonClass}
aria-label="Exit selection"
aria-label={t('sessions.sidebar.header.actions.exitSelection')}
>
<RiCloseLine className="h-4 w-4" />
</button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}><p>Exit selection</p></TooltipContent>
<TooltipContent side="top" sideOffset={4}><p>{t('sessions.sidebar.header.actions.exitSelection')}</p></TooltipContent>
</Tooltip>
</div>
</div>