Internationalization: 7 languages with live switching

Custom signal-based runtime (no i18n dependency): shared src/shared/i18n
dictionaries, ui I18nService.t() reactive by construction so language
switches live, and a backend i18n.ts for native menus + thrown errors.
Every user-facing string keyed across templates, toasts, dialogs, file
kinds, columns, macOS menu/context menus, and errors. Language picker in
Options (auto-detects OS locale, falls back to English); switching
relabels the webview and native chrome instantly. English/Spanish/French/
German fully drafted; Chinese/Japanese/Basque drafted, flagged for native
review. Docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 15:52:54 +02:00
co-authored by Claude Fable 5
parent d8cfc54049
commit a0f56822cd
43 changed files with 2755 additions and 322 deletions
+301
View File
@@ -0,0 +1,301 @@
// Basque (Euskara) translations. Fall back to English for missing keys.
// TODO(i18n): AI draft — REQUIRES native-speaker review (Basque is error-prone
// for machine/AI translation; treat every string as provisional).
export const eu = {
common: {
cancel: "Utzi",
save: "Gorde",
close: "Itxi",
delete: "Ezabatu",
rename: "Berrizendatu",
create: "Sortu",
apply: "Aplikatu",
choose: "Aukeratu…",
connect: "Konektatu",
local: "Lokala",
},
app: {
notConnectedTitle: "Ez dago aplikaziora konektatuta",
notConnectedBody: "Orri hau nabigatzaile arrunt batean exekutatzen ari da. Ireki mahaigaineko aplikazioa erabiltzeko.",
managerOpen: "Konexio-kudeatzailea irekita dago.",
showConnections: "Erakutsi konexioak",
},
tabBar: {
connections: "Konexioak",
manageConnections: "Kudeatu konexioak",
newTab: "Fitxa berria ({mod}T)",
closeTab: "Itxi fitxa ({mod}W)",
options: "Aukerak",
},
options: {
title: "Aukerak",
language: "Hizkuntza",
system: "Sistema",
theme: { label: "Gaia", system: "Sistema", light: "Argia", dark: "Iluna" },
tone: { label: "Tonua", dark: "Iluna", darker: "Ilunagoa" },
accent: { label: "Azentua" },
accentNames: {
graphite: "Grafitoa",
blue: "Urdina",
indigo: "Indigoa",
purple: "Morea",
rose: "Arrosa",
orange: "Laranja",
green: "Berdea",
teal: "Turkesa",
},
fileIcons: { label: "Fitxategi-ikonoak", plain: "Soila", multi: "Koloretsua" },
interface: { label: "Interfazea", compact: "Trinkoa", default: "Lehenetsia", large: "Handia" },
speedUnit: { label: "Abiadura-unitatea" },
transfers: { label: "Transferentziak", single: "Banaka", multi: "Anitz" },
atOnce: "Aldi berean",
editor: { label: "Editorea", builtin: "Barnekoa", custom: "Pertsonalizatua" },
systemDefault: "Sistemaren lehenetsia",
resetDefault: "Berrezarri lehenetsira",
finishedTransfers: { label: "Amaitutako transferentziak", autoClear: "Garbitu", keep: "Mantendu" },
},
kinds: {
folder: "Karpeta",
symlink: "Esteka sinbolikoa",
file: "Fitxategia",
image: "Irudia",
audio: "Audioa",
video: "Bideoa",
archive: "Artxiboa",
code: "Kodea",
document: "Dokumentua",
},
columns: {
name: "Izena",
size: "Tamaina",
mtime: "Aldatze-data",
kind: "Mota",
rights: "Baimenak",
owner: "Jabea",
group: "Taldea",
},
panel: {
choosePanel: "Aukeratu panel honek zer erakusten duen",
copy: "Kopiatu",
copyToRight: "Kopiatu eskuineko panelera (F5)",
copyToLeft: "Kopiatu ezkerreko panelera (F5)",
edit: "Editatu",
editFile: "Editatu fitxategia (F4)",
rename: "Berrizendatu (F2)",
newFolder: "Karpeta berria (F7)",
newFile: "Fitxategi berria",
permissions: "Baimenak",
delete: "Ezabatu",
deleteHint: "Ezabatu (F8 / Del)",
parentDir: "Karpeta gurasoa (Atzera-tekla)",
refresh: "Freskatu",
clearFilter: "Garbitu iragazkia (Esc)",
sshConfig: "~/.ssh/config",
connectingTo: "{name}(e)ra konektatzen…",
emptyDir: "Karpeta hutsa",
noMatches: "Bat-etortzerik ez",
matches: { one: "bat-etortze {count} · Esc", other: "{count} bat-etortze · Esc" },
},
connMgr: {
title: "Konexioak",
importWinscp: "Inportatu WinSCPtik…",
importWinscpHint: "Inportatu saioak WinSCP.ini esportazio batetik",
newConnection: "Konexioa",
newConnectionHint: "Konexio berria",
newStack: "Taldea",
newStackHint: "Talde berria",
expand: "Zabaldu",
collapse: "Tolestu",
renameStack: "Berrizendatu taldea",
deleteStack: "Ezabatu taldea",
openStack: "Ireki taldea fitxetan",
empty: "hutsik",
connectionsHeader: "Konexioak",
noneTitle: "Oraindik ez dago gordetako konexiorik.",
noneBody: "Sortu bat edo inportatu zure WinSCP saioak.",
name: "Izena",
namePlaceholder: "nire zerbitzaria",
host: "Ostalaria",
port: "Ataka",
stack: "Taldea",
stackNone: "(bat ere ez)",
username: "Erabiltzailea",
remotePath: "Urruneko bidea (aukerakoa)",
remotePathPlaceholder: "hasierako karpeta",
auth: "Autentifikazioa",
authPassword: "Pasahitza",
authKey: "Gako pribatua",
password: "Pasahitza",
privateKeyFile: "Gako pribatuaren fitxategia",
passphrase: "Pasaesaldia (aukerakoa)",
localDir: "Karpeta lokala (aukerakoa)",
localDirPlaceholder: "~/proiektuak/nire-zerbitzaria",
localDirHint: "Beste panela hemen irekiko da Lokalean dagoenean eta nabigatu ez denean.",
more: "Gehiago…",
less: "Gutxiago…",
selectPrompt: "Hautatu konexio bat edo sortu berri bat.",
newStackTitle: "Talde berria",
newStackPrompt: "taldearen izena",
renameStackTitle: "Berrizendatu taldea",
deleteStackTitle: "Ezabatu taldea",
deleteStackBody: 'Ezabatu "{name}" taldea? Bere konexioak mantendu egingo dira, taldekatu gabe.',
deleteConnectionTitle: "Ezabatu konexioa",
deleteConnectionBody: 'Ezabatu "{name}"?',
},
editor: {
noFileTitle: "Ez dago editatzeko fitxategirik",
noFileBody: "Leiho hau editore-testuingururik gabe ireki da. Ireki fitxategiak aplikaziotik.",
wrap: "Doitu",
wrapHint: "Doitu lerro luzeak — lerro-zenbakiak ezkutatzen ditu ({alt}Z)",
findHint: "Bilatu ({mod}F)",
findPlaceholder: "Bilatu fitxategian",
prevMatch: "Aurreko bat-etortzea (⇧↵)",
nextMatch: "Hurrengo bat-etortzea (↵)",
closeHint: "Itxi (Esc)",
disconnected: "{name}(e)tik deskonektatuta — gordetzeak huts egingo du, baina zure testua leiho honetan gordeta dago.",
cantOpen: "Ezin da {name} ireki",
closeWindow: "Itxi leihoa",
shortcuts: "{mod}S gorde · {mod}F bilatu · {mod}W itxi",
lines: { one: "lerro {count}", other: "{count} lerro" },
close: "Itxi",
save: "Gorde",
saveChangesTitle: 'Gorde "{name}"(r)en aldaketak?',
saveChangesBody: "Zure aldaketak galduko dira gordetzen ez badituzu.",
dontSave: "Ez gorde",
countLabel: "{total}(e)tik {current}",
noMatches: "Bat-etortzerik ez",
},
transfer: {
summary: "{active} aktibo · {finished} amaituta",
clearFinished: "Garbitu amaituak",
cancel: "Utzi",
dismiss: "Baztertu",
showDetails: "Erakutsi transferentzien xehetasunak",
copying: "{name} kopiatzen · %{percent}{speed}",
queued: "{count} ilaran",
failed: { one: "transferentzia {count}(e)k huts egin du", other: "{count} transferentziak huts egin dute" },
finished: "Transferentziak amaituta",
ready: "Prest",
items: "{count} elementu",
selected: "{count} hautatuta",
queuedState: "Ilaran",
scanning: "Aztertzen…",
failedState: "Huts egin du",
cancelled: "Bertan behera utzita",
completedFiles: { one: "fitxategi {count} · {size}", other: "{count} fitxategi · {size}" },
left: "{eta} geratzen da",
},
dialogs: {
chmodTitle: "Baimenak",
chmodItems: "{count} elementu",
read: "Irakurri",
write: "Idatzi",
execute: "Exekutatu",
roleOwner: "Jabea",
roleGroup: "Taldea",
roleOthers: "Besteak",
octal: "Zortzitarra",
mergeFolder: "Batu karpeta",
replace: "Ordeztu",
merge: "Batu",
mergeAll: "Batu guztiak",
replaceAll: "Ordeztu guztiak",
skip: "Saltatu",
skipAll: "Saltatu guztiak",
ofTotal: "{total}(e)tik {index}",
overwriteDirBody: "Helmugan izen bereko karpeta bat dago jada. Batzeak barneko fitxategiak ordeztu ditzake.",
overwriteFileBody: "Helmugan izen bereko fitxategi bat dago jada.",
source: "Iturburua",
destination: "Helmuga",
newer: "berriagoa",
},
toasts: {
movedToTrash: '"{name}" zakarrontzira eraman da',
editingExternal: "{name} editatzen — gordetzean automatikoki igotzen da",
nothingToCopy: "Ez dago kopiatzeko ezer (esteka sinbolikoak saltatu egiten dira)",
nothingToCopyAllSkipped: "Ez dago kopiatzeko ezer — gatazkan zeuden elementu guztiak saltatu dira",
sameFolder: "Bi panelek karpeta bera erakusten dute",
sameFile: '"{name}" saltatu da — fitxategi bera da',
typeMismatch: '"{name}" saltatu da — beste mota bateko elementu bat dago bidean',
transferFailed: '"{name}" transferentziak huts egin du: {error}',
unknownError: "errore ezezaguna",
saved: "{name} gorde da",
disconnectedReason: "{title}: deskonektatuta ({reason})",
imported: { one: "konexio {count} inportatu da", other: "{count} konexio inportatu dira" },
importedIntoStacks: { one: " talde berri {count}ean", other: " {count} talde berritan" },
importedSkipped: " ({skipped} saltatuta)",
leftoverTitle: "Geratutako editatutako fitxategiak",
leftoverMore: ", +{count} gehiago",
leftoverBody: {
one: "Aurreko saio batek editatutako aldi baterako fitxategi {count} utzi zuen ({names}). Garbitu?",
other: "Aurreko saio batek editatutako aldi baterako {count} fitxategi utzi zituen ({names}). Garbitu?",
},
leftoverClear: "Garbitu",
},
fileActions: {
deleteTitle: "Ezabatu",
deleteBody: "Ezabatu {what}? Karpetak errekurtsiboki ezabatzen dira. Ezin da desegin.",
deleteConfirm: "Ezabatu",
renameTitle: 'Berrizendatu "{name}"',
renameConfirm: "Berrizendatu",
newFolderTitle: "Karpeta berria",
newFolderPlaceholder: "karpetaren izena",
newFileTitle: "Fitxategi berria",
newFilePlaceholder: "fitxategiaren izena",
createConfirm: "Sortu",
itemsCount: "{count} elementu",
},
menu: {
about: "{app} (r)i buruz",
quit: "Irten",
file: "Fitxategia",
newTab: "Fitxa berria",
closeTab: "Itxi fitxa",
newFolder: "Karpeta berria",
newFile: "Fitxategi berria",
editFile: "Editatu fitxategia",
connect: "Konektatu",
connectionManager: "Konexio-kudeatzailea…",
edit: "Editatu",
view: "Ikusi",
refresh: "Freskatu",
window: "Leihoa",
},
ctx: {
size: "Tamaina",
modified: "Aldatze-data",
kind: "Mota",
rights: "Baimenak",
owner: "Jabea",
group: "Taldea",
revealFinder: "Erakutsi Finder-en",
revealExplorer: "Erakutsi Explorer-en",
revealFileManager: "Erakutsi fitxategi-kudeatzailean",
moveToTrash: "Eraman zakarrontzira",
moveToRecycleBin: "Eraman birziklatze-ontzira",
newFolder: "Karpeta berria",
newFile: "Fitxategi berria",
refresh: "Freskatu",
open: "Ireki",
openDefault: "Ireki lehenetsitako aplikazioarekin",
edit: "Editatu",
copyToOther: "Kopiatu beste panelera",
rename: "Berrizendatu",
permissions: "Baimenak",
copyPath: "Kopiatu bidea",
delete: "Ezabatu",
columns: "Zutabeak",
trashTooltip: "Finder-en «Jarri berriro» ez dago erabilgarri hemendik zakarrontzira botatako elementuentzat",
},
errors: {
sshAgentUnavailable: "ssh-agent ez dago erabilgarri (SSH_AUTH_SOCK ez dago ezarrita)",
identityFileNotFound: "identitate-fitxategia ez da aurkitu: {path}",
sessionNotConnected: '"{id}" saioa ez dago konektatuta',
localCannotDisconnect: "Saio lokala ezin da deskonektatu",
notADirectory: '"{path}" badago eta ez da karpeta bat',
sameFileTransfer: '"{name}": iturburua eta helmuga fitxategi bera dira',
sameFileNoName: "Iturburua eta helmuga fitxategi bera dira",
folderOntoItself: "Ezin da karpeta bat bere gainean kopiatu",
folderIntoItself: "Ezin da karpeta bat bere barnean kopiatu",
},
} as const;