Browse Source

feat(i18n): add Bosnian locale (#12283)

Edin 2 weeks ago
parent
commit
ef09dddaa5

+ 8 - 0
packages/app/src/context/language.tsx

@@ -18,6 +18,7 @@ import { dict as ar } from "@/i18n/ar"
 import { dict as no } from "@/i18n/no"
 import { dict as br } from "@/i18n/br"
 import { dict as th } from "@/i18n/th"
+import { dict as bs } from "@/i18n/bs"
 import { dict as uiEn } from "@opencode-ai/ui/i18n/en"
 import { dict as uiZh } from "@opencode-ai/ui/i18n/zh"
 import { dict as uiZht } from "@opencode-ai/ui/i18n/zht"
@@ -33,6 +34,7 @@ import { dict as uiAr } from "@opencode-ai/ui/i18n/ar"
 import { dict as uiNo } from "@opencode-ai/ui/i18n/no"
 import { dict as uiBr } from "@opencode-ai/ui/i18n/br"
 import { dict as uiTh } from "@opencode-ai/ui/i18n/th"
+import { dict as uiBs } from "@opencode-ai/ui/i18n/bs"
 
 export type Locale =
   | "en"
@@ -50,6 +52,7 @@ export type Locale =
   | "no"
   | "br"
   | "th"
+  | "bs"
 
 type RawDictionary = typeof en & typeof uiEn
 type Dictionary = i18n.Flatten<RawDictionary>
@@ -66,6 +69,7 @@ const LOCALES: readonly Locale[] = [
   "ja",
   "pl",
   "ru",
+  "bs",
   "ar",
   "no",
   "br",
@@ -99,6 +103,7 @@ function detectLocale(): Locale {
       return "no"
     if (language.toLowerCase().startsWith("pt")) return "br"
     if (language.toLowerCase().startsWith("th")) return "th"
+    if (language.toLowerCase().startsWith("bs")) return "bs"
   }
 
   return "en"
@@ -129,6 +134,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
       if (store.locale === "no") return "no"
       if (store.locale === "br") return "br"
       if (store.locale === "th") return "th"
+      if (store.locale === "bs") return "bs"
       return "en"
     })
 
@@ -154,6 +160,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
       if (locale() === "no") return { ...base, ...i18n.flatten({ ...no, ...uiNo }) }
       if (locale() === "br") return { ...base, ...i18n.flatten({ ...br, ...uiBr }) }
       if (locale() === "th") return { ...base, ...i18n.flatten({ ...th, ...uiTh }) }
+      if (locale() === "bs") return { ...base, ...i18n.flatten({ ...bs, ...uiBs }) }
       return { ...base, ...i18n.flatten({ ...ko, ...uiKo }) }
     })
 
@@ -175,6 +182,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
       no: "language.no",
       br: "language.br",
       th: "language.th",
+      bs: "language.bs",
     }
 
     const label = (value: Locale) => t(labelKey[value])

+ 747 - 0
packages/app/src/i18n/bs.ts

@@ -0,0 +1,747 @@
+export const dict = {
+  "command.category.suggested": "Predloženo",
+  "command.category.view": "Prikaz",
+  "command.category.project": "Projekat",
+  "command.category.provider": "Provajder",
+  "command.category.server": "Server",
+  "command.category.session": "Sesija",
+  "command.category.theme": "Tema",
+  "command.category.language": "Jezik",
+  "command.category.file": "Datoteka",
+  "command.category.context": "Kontekst",
+  "command.category.terminal": "Terminal",
+  "command.category.model": "Model",
+  "command.category.mcp": "MCP",
+  "command.category.agent": "Agent",
+  "command.category.permissions": "Dozvole",
+  "command.category.workspace": "Radni prostor",
+  "command.category.settings": "Postavke",
+
+  "theme.scheme.system": "Sistem",
+  "theme.scheme.light": "Svijetlo",
+  "theme.scheme.dark": "Tamno",
+
+  "command.sidebar.toggle": "Prikaži/sakrij bočnu traku",
+  "command.project.open": "Otvori projekat",
+  "command.provider.connect": "Poveži provajdera",
+  "command.server.switch": "Promijeni server",
+  "command.settings.open": "Otvori postavke",
+  "command.session.previous": "Prethodna sesija",
+  "command.session.next": "Sljedeća sesija",
+  "command.session.previous.unseen": "Prethodna nepročitana sesija",
+  "command.session.next.unseen": "Sljedeća nepročitana sesija",
+  "command.session.archive": "Arhiviraj sesiju",
+
+  "command.palette": "Paleta komandi",
+
+  "command.theme.cycle": "Promijeni temu",
+  "command.theme.set": "Koristi temu: {{theme}}",
+  "command.theme.scheme.cycle": "Promijeni šemu boja",
+  "command.theme.scheme.set": "Koristi šemu boja: {{scheme}}",
+
+  "command.language.cycle": "Promijeni jezik",
+  "command.language.set": "Koristi jezik: {{language}}",
+
+  "command.session.new": "Nova sesija",
+  "command.file.open": "Otvori datoteku",
+  "command.tab.close": "Zatvori karticu",
+  "command.context.addSelection": "Dodaj odabir u kontekst",
+  "command.context.addSelection.description": "Dodaj odabrane linije iz trenutne datoteke",
+  "command.terminal.toggle": "Prikaži/sakrij terminal",
+  "command.fileTree.toggle": "Prikaži/sakrij stablo datoteka",
+  "command.review.toggle": "Prikaži/sakrij pregled",
+  "command.terminal.new": "Novi terminal",
+  "command.terminal.new.description": "Kreiraj novu karticu terminala",
+  "command.steps.toggle": "Prikaži/sakrij korake",
+  "command.steps.toggle.description": "Prikaži ili sakrij korake za trenutnu poruku",
+  "command.message.previous": "Prethodna poruka",
+  "command.message.previous.description": "Idi na prethodnu korisničku poruku",
+  "command.message.next": "Sljedeća poruka",
+  "command.message.next.description": "Idi na sljedeću korisničku poruku",
+  "command.model.choose": "Odaberi model",
+  "command.model.choose.description": "Odaberi drugi model",
+  "command.mcp.toggle": "Prikaži/sakrij MCP-ove",
+  "command.mcp.toggle.description": "Prikaži/sakrij MCP-ove",
+  "command.agent.cycle": "Promijeni agenta",
+  "command.agent.cycle.description": "Prebaci na sljedećeg agenta",
+  "command.agent.cycle.reverse": "Promijeni agenta unazad",
+  "command.agent.cycle.reverse.description": "Prebaci na prethodnog agenta",
+  "command.model.variant.cycle": "Promijeni nivo razmišljanja",
+  "command.model.variant.cycle.description": "Prebaci na sljedeći nivo",
+  "command.permissions.autoaccept.enable": "Automatski prihvataj izmjene",
+  "command.permissions.autoaccept.disable": "Zaustavi automatsko prihvatanje izmjena",
+  "command.workspace.toggle": "Prikaži/sakrij radne prostore",
+  "command.workspace.toggle.description": "Omogući ili onemogući više radnih prostora u bočnoj traci",
+  "command.session.undo": "Poništi",
+  "command.session.undo.description": "Poništi posljednju poruku",
+  "command.session.redo": "Vrati",
+  "command.session.redo.description": "Vrati posljednju poništenu poruku",
+  "command.session.compact": "Sažmi sesiju",
+  "command.session.compact.description": "Sažmi sesiju kako bi se smanjio kontekst",
+  "command.session.fork": "Fork iz poruke",
+  "command.session.fork.description": "Kreiraj novu sesiju iz prethodne poruke",
+  "command.session.share": "Podijeli sesiju",
+  "command.session.share.description": "Podijeli ovu sesiju i kopiraj URL u međuspremnik",
+  "command.session.unshare": "Ukini dijeljenje sesije",
+  "command.session.unshare.description": "Zaustavi dijeljenje ove sesije",
+
+  "palette.search.placeholder": "Pretraži datoteke, komande i sesije",
+  "palette.empty": "Nema rezultata",
+  "palette.group.commands": "Komande",
+  "palette.group.files": "Datoteke",
+
+  "dialog.provider.search.placeholder": "Pretraži provajdere",
+  "dialog.provider.empty": "Nema pronađenih provajdera",
+  "dialog.provider.group.popular": "Popularno",
+  "dialog.provider.group.other": "Ostalo",
+  "dialog.provider.tag.recommended": "Preporučeno",
+  "dialog.provider.opencode.note": "Kurirani modeli uključujući Claude, GPT, Gemini i druge",
+  "dialog.provider.anthropic.note": "Direktan pristup Claude modelima, uključujući Pro i Max",
+  "dialog.provider.copilot.note": "Claude modeli za pomoć pri kodiranju",
+  "dialog.provider.openai.note": "GPT modeli za brze, sposobne opšte AI zadatke",
+  "dialog.provider.google.note": "Gemini modeli za brze, strukturirane odgovore",
+  "dialog.provider.openrouter.note": "Pristup svim podržanim modelima preko jednog provajdera",
+  "dialog.provider.vercel.note": "Jedinstven pristup AI modelima uz pametno rutiranje",
+
+  "dialog.model.select.title": "Odaberi model",
+  "dialog.model.search.placeholder": "Pretraži modele",
+  "dialog.model.empty": "Nema rezultata za modele",
+  "dialog.model.manage": "Upravljaj modelima",
+  "dialog.model.manage.description": "Prilagodi koji se modeli prikazuju u izborniku modela.",
+
+  "dialog.model.unpaid.freeModels.title": "Besplatni modeli koje obezbjeđuje OpenCode",
+  "dialog.model.unpaid.addMore.title": "Dodaj još modela od popularnih provajdera",
+
+  "dialog.provider.viewAll": "Prikaži više provajdera",
+
+  "provider.connect.title": "Poveži {{provider}}",
+  "provider.connect.title.anthropicProMax": "Prijavi se putem Claude Pro/Max",
+  "provider.connect.selectMethod": "Odaberi način prijave za {{provider}}.",
+  "provider.connect.method.apiKey": "API ključ",
+  "provider.connect.status.inProgress": "Autorizacija je u toku...",
+  "provider.connect.status.waiting": "Čekanje na autorizaciju...",
+  "provider.connect.status.failed": "Autorizacija nije uspjela: {{error}}",
+  "provider.connect.apiKey.description":
+    "Unesi svoj {{provider}} API ključ da povežeš račun i koristiš {{provider}} modele u OpenCode-u.",
+  "provider.connect.apiKey.label": "{{provider}} API ključ",
+  "provider.connect.apiKey.placeholder": "API ključ",
+  "provider.connect.apiKey.required": "API ključ je obavezan",
+  "provider.connect.opencodeZen.line1":
+    "OpenCode Zen ti daje pristup kuriranom skupu pouzdanih, optimizovanih modela za coding agente.",
+  "provider.connect.opencodeZen.line2":
+    "Sa jednim API ključem dobijaš pristup modelima kao što su Claude, GPT, Gemini, GLM i drugi.",
+  "provider.connect.opencodeZen.visit.prefix": "Posjeti ",
+  "provider.connect.opencodeZen.visit.link": "opencode.ai/zen",
+  "provider.connect.opencodeZen.visit.suffix": " da preuzmeš svoj API ključ.",
+  "provider.connect.oauth.code.visit.prefix": "Posjeti ",
+  "provider.connect.oauth.code.visit.link": "ovaj link",
+  "provider.connect.oauth.code.visit.suffix":
+    " da preuzmeš autorizacijski kod i povežeš račun te koristiš {{provider}} modele u OpenCode-u.",
+  "provider.connect.oauth.code.label": "{{method}} autorizacijski kod",
+  "provider.connect.oauth.code.placeholder": "Autorizacijski kod",
+  "provider.connect.oauth.code.required": "Autorizacijski kod je obavezan",
+  "provider.connect.oauth.code.invalid": "Nevažeći autorizacijski kod",
+  "provider.connect.oauth.auto.visit.prefix": "Posjeti ",
+  "provider.connect.oauth.auto.visit.link": "ovaj link",
+  "provider.connect.oauth.auto.visit.suffix":
+    " i unesi kod ispod da povežeš račun i koristiš {{provider}} modele u OpenCode-u.",
+  "provider.connect.oauth.auto.confirmationCode": "Kod za potvrdu",
+  "provider.connect.toast.connected.title": "{{provider}} povezan",
+  "provider.connect.toast.connected.description": "{{provider}} modeli su sada dostupni za korištenje.",
+
+  "provider.disconnect.toast.disconnected.title": "{{provider}} odspojen",
+  "provider.disconnect.toast.disconnected.description": "{{provider}} modeli više nisu dostupni.",
+
+  "model.tag.free": "Besplatno",
+  "model.tag.latest": "Najnovije",
+  "model.provider.anthropic": "Anthropic",
+  "model.provider.openai": "OpenAI",
+  "model.provider.google": "Google",
+  "model.provider.xai": "xAI",
+  "model.provider.meta": "Meta",
+  "model.input.text": "tekst",
+  "model.input.image": "slika",
+  "model.input.audio": "zvuk",
+  "model.input.video": "video",
+  "model.input.pdf": "pdf",
+  "model.tooltip.allows": "Podržava: {{inputs}}",
+  "model.tooltip.reasoning.allowed": "Podržava rasuđivanje",
+  "model.tooltip.reasoning.none": "Bez rasuđivanja",
+  "model.tooltip.context": "Limit konteksta {{limit}}",
+
+  "common.search.placeholder": "Pretraži",
+  "common.goBack": "Nazad",
+  "common.goForward": "Naprijed",
+  "common.loading": "Učitavanje",
+  "common.loading.ellipsis": "...",
+  "common.cancel": "Otkaži",
+  "common.connect": "Poveži",
+  "common.disconnect": "Prekini vezu",
+  "common.submit": "Pošalji",
+  "common.save": "Sačuvaj",
+  "common.saving": "Čuvanje...",
+  "common.default": "Podrazumijevano",
+  "common.attachment": "prilog",
+
+  "prompt.placeholder.shell": "Unesi shell naredbu...",
+  "prompt.placeholder.normal": 'Pitaj bilo šta... "{{example}}"',
+  "prompt.placeholder.summarizeComments": "Sažmi komentare…",
+  "prompt.placeholder.summarizeComment": "Sažmi komentar…",
+  "prompt.mode.shell": "Shell",
+  "prompt.mode.shell.exit": "esc za izlaz",
+
+  "prompt.example.1": "Popravi TODO u bazi koda",
+  "prompt.example.2": "Koji je tehnološki stack ovog projekta?",
+  "prompt.example.3": "Popravi pokvarene testove",
+  "prompt.example.4": "Objasni kako radi autentifikacija",
+  "prompt.example.5": "Pronađi i popravi sigurnosne ranjivosti",
+  "prompt.example.6": "Dodaj jedinične testove za servis korisnika",
+  "prompt.example.7": "Refaktoriši ovu funkciju da bude čitljivija",
+  "prompt.example.8": "Šta znači ova greška?",
+  "prompt.example.9": "Pomozi mi da otklonim ovu grešku",
+  "prompt.example.10": "Generiši API dokumentaciju",
+  "prompt.example.11": "Optimizuj upite prema bazi podataka",
+  "prompt.example.12": "Dodaj validaciju ulaza",
+  "prompt.example.13": "Napravi novu komponentu za...",
+  "prompt.example.14": "Kako da deployam ovaj projekat?",
+  "prompt.example.15": "Pregledaj moj kod prema najboljim praksama",
+  "prompt.example.16": "Dodaj obradu grešaka u ovu funkciju",
+  "prompt.example.17": "Objasni ovaj regex obrazac",
+  "prompt.example.18": "Pretvori ovo u TypeScript",
+  "prompt.example.19": "Dodaj logovanje kroz cijelu bazu koda",
+  "prompt.example.20": "Koje su zavisnosti zastarjele?",
+  "prompt.example.21": "Pomozi mi da napišem migracijsku skriptu",
+  "prompt.example.22": "Implementiraj keširanje za ovaj endpoint",
+  "prompt.example.23": "Dodaj paginaciju u ovu listu",
+  "prompt.example.24": "Napravi CLI komandu za...",
+  "prompt.example.25": "Kako ovdje rade varijable okruženja?",
+
+  "prompt.popover.emptyResults": "Nema rezultata",
+  "prompt.popover.emptyCommands": "Nema komandi",
+  "prompt.dropzone.label": "Spusti slike ili PDF-ove ovdje",
+  "prompt.slash.badge.custom": "prilagođeno",
+  "prompt.slash.badge.skill": "skill",
+  "prompt.slash.badge.mcp": "mcp",
+  "prompt.context.active": "aktivno",
+  "prompt.context.includeActiveFile": "Uključi aktivnu datoteku",
+  "prompt.context.removeActiveFile": "Ukloni aktivnu datoteku iz konteksta",
+  "prompt.context.removeFile": "Ukloni datoteku iz konteksta",
+  "prompt.action.attachFile": "Priloži datoteku",
+  "prompt.attachment.remove": "Ukloni prilog",
+  "prompt.action.send": "Pošalji",
+  "prompt.action.stop": "Zaustavi",
+
+  "prompt.toast.pasteUnsupported.title": "Nepodržano lijepljenje",
+  "prompt.toast.pasteUnsupported.description": "Ovdje se mogu zalijepiti samo slike ili PDF-ovi.",
+  "prompt.toast.modelAgentRequired.title": "Odaberi agenta i model",
+  "prompt.toast.modelAgentRequired.description": "Odaberi agenta i model prije slanja upita.",
+  "prompt.toast.worktreeCreateFailed.title": "Neuspješno kreiranje worktree-a",
+  "prompt.toast.sessionCreateFailed.title": "Neuspješno kreiranje sesije",
+  "prompt.toast.shellSendFailed.title": "Neuspješno slanje shell naredbe",
+  "prompt.toast.commandSendFailed.title": "Neuspješno slanje komande",
+  "prompt.toast.promptSendFailed.title": "Neuspješno slanje upita",
+
+  "dialog.mcp.title": "MCP-ovi",
+  "dialog.mcp.description": "{{enabled}} od {{total}} omogućeno",
+  "dialog.mcp.empty": "Nema konfigurisnih MCP-ova",
+
+  "dialog.lsp.empty": "LSP-ovi se automatski otkrivaju prema tipu datoteke",
+  "dialog.plugins.empty": "Plugini su konfigurisani u opencode.json",
+
+  "mcp.status.connected": "povezano",
+  "mcp.status.failed": "neuspjelo",
+  "mcp.status.needs_auth": "potrebna autentifikacija",
+  "mcp.status.disabled": "onemogućeno",
+
+  "dialog.fork.empty": "Nema poruka za fork",
+
+  "dialog.directory.search.placeholder": "Pretraži foldere",
+  "dialog.directory.empty": "Nema pronađenih foldera",
+
+  "dialog.server.title": "Serveri",
+  "dialog.server.description": "Promijeni na koji se OpenCode server ova aplikacija povezuje.",
+  "dialog.server.search.placeholder": "Pretraži servere",
+  "dialog.server.empty": "Još nema servera",
+  "dialog.server.add.title": "Dodaj server",
+  "dialog.server.add.url": "URL servera",
+  "dialog.server.add.placeholder": "http://localhost:4096",
+  "dialog.server.add.error": "Nije moguće povezati se na server",
+  "dialog.server.add.checking": "Provjera...",
+  "dialog.server.add.button": "Dodaj server",
+  "dialog.server.default.title": "Podrazumijevani server",
+  "dialog.server.default.description":
+    "Poveži se na ovaj server pri pokretanju aplikacije umjesto pokretanja lokalnog servera. Potreban je restart.",
+  "dialog.server.default.none": "Nije odabran server",
+  "dialog.server.default.set": "Postavi trenutni server kao podrazumijevani",
+  "dialog.server.default.clear": "Očisti",
+  "dialog.server.action.remove": "Ukloni server",
+
+  "dialog.server.menu.edit": "Uredi",
+  "dialog.server.menu.default": "Postavi kao podrazumijevano",
+  "dialog.server.menu.defaultRemove": "Ukloni podrazumijevano",
+  "dialog.server.menu.delete": "Izbriši",
+  "dialog.server.current": "Trenutni server",
+  "dialog.server.status.default": "Podrazumijevano",
+
+  "dialog.project.edit.title": "Uredi projekat",
+  "dialog.project.edit.name": "Naziv",
+  "dialog.project.edit.icon": "Ikonica",
+  "dialog.project.edit.icon.alt": "Ikonica projekta",
+  "dialog.project.edit.icon.hint": "Klikni ili prevuci sliku",
+  "dialog.project.edit.icon.recommended": "Preporučeno: 128x128px",
+  "dialog.project.edit.color": "Boja",
+  "dialog.project.edit.color.select": "Odaberi boju {{color}}",
+  "dialog.project.edit.worktree.startup": "Skripta za pokretanje radnog prostora",
+  "dialog.project.edit.worktree.startup.description": "Pokreće se nakon kreiranja novog radnog prostora (worktree).",
+  "dialog.project.edit.worktree.startup.placeholder": "npr. bun install",
+
+  "context.breakdown.title": "Razlaganje konteksta",
+  "context.breakdown.note":
+    'Približna raspodjela ulaznih tokena. "Ostalo" uključuje definicije alata i dodatni overhead.',
+  "context.breakdown.system": "Sistem",
+  "context.breakdown.user": "Korisnik",
+  "context.breakdown.assistant": "Asistent",
+  "context.breakdown.tool": "Pozivi alata",
+  "context.breakdown.other": "Ostalo",
+
+  "context.systemPrompt.title": "Sistemski prompt",
+  "context.rawMessages.title": "Sirove poruke",
+
+  "context.stats.session": "Sesija",
+  "context.stats.messages": "Poruke",
+  "context.stats.provider": "Provajder",
+  "context.stats.model": "Model",
+  "context.stats.limit": "Limit konteksta",
+  "context.stats.totalTokens": "Ukupno tokena",
+  "context.stats.usage": "Korištenje",
+  "context.stats.inputTokens": "Ulazni tokeni",
+  "context.stats.outputTokens": "Izlazni tokeni",
+  "context.stats.reasoningTokens": "Tokeni za rasuđivanje",
+  "context.stats.cacheTokens": "Cache tokeni (čitanje/pisanje)",
+  "context.stats.userMessages": "Korisničke poruke",
+  "context.stats.assistantMessages": "Poruke asistenta",
+  "context.stats.totalCost": "Ukupni trošak",
+  "context.stats.sessionCreated": "Sesija kreirana",
+  "context.stats.lastActivity": "Posljednja aktivnost",
+
+  "context.usage.tokens": "Tokeni",
+  "context.usage.usage": "Korištenje",
+  "context.usage.cost": "Trošak",
+  "context.usage.clickToView": "Klikni da vidiš kontekst",
+  "context.usage.view": "Prikaži korištenje konteksta",
+
+  "language.en": "English",
+  "language.zh": "简体中文",
+  "language.zht": "繁體中文",
+  "language.ko": "한국어",
+  "language.de": "Deutsch",
+  "language.es": "Español",
+  "language.fr": "Français",
+  "language.da": "Dansk",
+  "language.ja": "日本語",
+  "language.pl": "Polski",
+  "language.ru": "Русский",
+  "language.ar": "العربية",
+  "language.no": "Norsk",
+  "language.br": "Português (Brasil)",
+  "language.bs": "Bosanski",
+  "language.th": "ไทย",
+
+  "toast.language.title": "Jezik",
+  "toast.language.description": "Prebačeno na {{language}}",
+
+  "toast.theme.title": "Tema promijenjena",
+  "toast.scheme.title": "Šema boja",
+
+  "toast.workspace.enabled.title": "Radni prostori omogućeni",
+  "toast.workspace.enabled.description": "Više worktree-ova se sada prikazuje u bočnoj traci",
+  "toast.workspace.disabled.title": "Radni prostori onemogućeni",
+  "toast.workspace.disabled.description": "Samo glavni worktree se prikazuje u bočnoj traci",
+
+  "toast.permissions.autoaccept.on.title": "Automatsko prihvatanje izmjena",
+  "toast.permissions.autoaccept.on.description": "Dozvole za izmjene i pisanje biće automatski odobrene",
+  "toast.permissions.autoaccept.off.title": "Zaustavljeno automatsko prihvatanje izmjena",
+  "toast.permissions.autoaccept.off.description": "Dozvole za izmjene i pisanje zahtijevaće odobrenje",
+
+  "toast.model.none.title": "Nije odabran model",
+  "toast.model.none.description": "Poveži provajdera da sažmeš ovu sesiju",
+
+  "toast.file.loadFailed.title": "Neuspjelo učitavanje datoteke",
+  "toast.file.listFailed.title": "Neuspješno listanje datoteka",
+
+  "toast.context.noLineSelection.title": "Nema odabranih linija",
+  "toast.context.noLineSelection.description": "Prvo odaberi raspon linija u kartici datoteke.",
+
+  "toast.session.share.copyFailed.title": "Neuspjelo kopiranje URL-a u međuspremnik",
+  "toast.session.share.success.title": "Sesija podijeljena",
+  "toast.session.share.success.description": "URL za dijeljenje je kopiran u međuspremnik!",
+  "toast.session.share.failed.title": "Neuspjelo dijeljenje sesije",
+  "toast.session.share.failed.description": "Došlo je do greške prilikom dijeljenja sesije",
+
+  "toast.session.unshare.success.title": "Dijeljenje sesije ukinuto",
+  "toast.session.unshare.success.description": "Dijeljenje sesije je uspješno ukinuto!",
+  "toast.session.unshare.failed.title": "Neuspjelo ukidanje dijeljenja",
+  "toast.session.unshare.failed.description": "Došlo je do greške prilikom ukidanja dijeljenja",
+
+  "toast.session.listFailed.title": "Neuspjelo učitavanje sesija za {{project}}",
+
+  "toast.update.title": "Dostupno ažuriranje",
+  "toast.update.description": "Nova verzija OpenCode-a ({{version}}) je dostupna za instalaciju.",
+  "toast.update.action.installRestart": "Instaliraj i restartuj",
+  "toast.update.action.notYet": "Ne još",
+
+  "error.page.title": "Nešto je pošlo po zlu",
+  "error.page.description": "Došlo je do greške prilikom učitavanja aplikacije.",
+  "error.page.details.label": "Detalji greške",
+  "error.page.action.restart": "Restartuj",
+  "error.page.action.checking": "Provjera...",
+  "error.page.action.checkUpdates": "Provjeri ažuriranja",
+  "error.page.action.updateTo": "Ažuriraj na {{version}}",
+  "error.page.report.prefix": "Molimo prijavi ovu grešku OpenCode timu",
+  "error.page.report.discord": "na Discordu",
+  "error.page.version": "Verzija: {{version}}",
+
+  "error.dev.rootNotFound":
+    "Korijenski element nije pronađen. Da li si zaboravio da ga dodaš u index.html? Ili je možda id atribut pogrešno napisan?",
+
+  "error.globalSync.connectFailed": "Nije moguće povezati se na server. Da li server radi na `{{url}}`?",
+
+  "error.chain.unknown": "Nepoznata greška",
+  "error.chain.causedBy": "Uzrok:",
+  "error.chain.apiError": "API greška",
+  "error.chain.status": "Status: {{status}}",
+  "error.chain.retryable": "Može se ponoviti: {{retryable}}",
+  "error.chain.responseBody": "Tijelo odgovora:\n{{body}}",
+  "error.chain.didYouMean": "Da li si mislio: {{suggestions}}",
+  "error.chain.modelNotFound": "Model nije pronađen: {{provider}}/{{model}}",
+  "error.chain.checkConfig": "Provjeri konfiguraciju (opencode.json) - nazive provajdera/modela",
+  "error.chain.mcpFailed": 'MCP server "{{name}}" nije uspio. Napomena: OpenCode još ne podržava MCP autentifikaciju.',
+  "error.chain.providerAuthFailed": "Autentifikacija provajdera nije uspjela ({{provider}}): {{message}}",
+  "error.chain.providerInitFailed":
+    'Neuspjelo inicijalizovanje provajdera "{{provider}}". Provjeri kredencijale i konfiguraciju.',
+  "error.chain.configJsonInvalid": "Konfiguracijska datoteka na {{path}} nije važeći JSON(C)",
+  "error.chain.configJsonInvalidWithMessage": "Konfiguracijska datoteka na {{path}} nije važeći JSON(C): {{message}}",
+  "error.chain.configDirectoryTypo":
+    'Direktorij "{{dir}}" u {{path}} nije ispravan. Preimenuj direktorij u "{{suggestion}}" ili ga ukloni. Ovo je česta greška u kucanju.',
+  "error.chain.configFrontmatterError": "Neuspjelo parsiranje frontmatter-a u {{path}}:\n{{message}}",
+  "error.chain.configInvalid": "Konfiguracijska datoteka na {{path}} nije ispravna",
+  "error.chain.configInvalidWithMessage": "Konfiguracijska datoteka na {{path}} nije ispravna: {{message}}",
+
+  "notification.permission.title": "Potrebna dozvola",
+  "notification.permission.description": "{{sessionTitle}} u {{projectName}} traži dozvolu",
+  "notification.question.title": "Pitanje",
+  "notification.question.description": "{{sessionTitle}} u {{projectName}} ima pitanje",
+  "notification.action.goToSession": "Idi na sesiju",
+
+  "notification.session.responseReady.title": "Odgovor je spreman",
+  "notification.session.error.title": "Greška sesije",
+  "notification.session.error.fallbackDescription": "Došlo je do greške",
+
+  "home.recentProjects": "Nedavni projekti",
+  "home.empty.title": "Nema nedavnih projekata",
+  "home.empty.description": "Kreni tako što ćeš otvoriti lokalni projekat",
+
+  "session.tab.session": "Sesija",
+  "session.tab.review": "Pregled",
+  "session.tab.context": "Kontekst",
+  "session.panel.reviewAndFiles": "Pregled i datoteke",
+  "session.review.filesChanged": "Izmijenjeno {{count}} datoteka",
+  "session.review.change.one": "Izmjena",
+  "session.review.change.other": "Izmjene",
+  "session.review.loadingChanges": "Učitavanje izmjena...",
+  "session.review.empty": "Još nema izmjena u ovoj sesiji",
+  "session.review.noChanges": "Nema izmjena",
+
+  "session.files.selectToOpen": "Odaberi datoteku za otvaranje",
+  "session.files.all": "Sve datoteke",
+  "session.files.binaryContent": "Binarna datoteka (sadržaj se ne može prikazati)",
+
+  "session.messages.renderEarlier": "Prikaži ranije poruke",
+  "session.messages.loadingEarlier": "Učitavanje ranijih poruka...",
+  "session.messages.loadEarlier": "Učitaj ranije poruke",
+  "session.messages.loading": "Učitavanje poruka...",
+  "session.messages.jumpToLatest": "Idi na najnovije",
+
+  "session.context.addToContext": "Dodaj {{selection}} u kontekst",
+
+  "session.new.worktree.main": "Glavna grana",
+  "session.new.worktree.mainWithBranch": "Glavna grana ({{branch}})",
+  "session.new.worktree.create": "Kreiraj novi worktree",
+  "session.new.lastModified": "Posljednja izmjena",
+
+  "session.header.search.placeholder": "Pretraži {{project}}",
+  "session.header.searchFiles": "Pretraži datoteke",
+
+  "status.popover.trigger": "Status",
+  "status.popover.ariaLabel": "Konfiguracije servera",
+  "status.popover.tab.servers": "Serveri",
+  "status.popover.tab.mcp": "MCP",
+  "status.popover.tab.lsp": "LSP",
+  "status.popover.tab.plugins": "Plugini",
+  "status.popover.action.manageServers": "Upravljaj serverima",
+
+  "session.share.popover.title": "Objavi na webu",
+  "session.share.popover.description.shared": "Ova sesija je javna na webu. Dostupna je svima koji imaju link.",
+  "session.share.popover.description.unshared": "Podijeli sesiju javno na webu. Biće dostupna svima koji imaju link.",
+  "session.share.action.share": "Podijeli",
+  "session.share.action.publish": "Objavi",
+  "session.share.action.publishing": "Objavljivanje...",
+  "session.share.action.unpublish": "Poništi objavu",
+  "session.share.action.unpublishing": "Poništavanje objave...",
+  "session.share.action.view": "Prikaži",
+  "session.share.copy.copied": "Kopirano",
+  "session.share.copy.copyLink": "Kopiraj link",
+
+  "lsp.tooltip.none": "Nema LSP servera",
+  "lsp.label.connected": "{{count}} LSP",
+
+  "prompt.loading": "Učitavanje upita...",
+  "terminal.loading": "Učitavanje terminala...",
+  "terminal.title": "Terminal",
+  "terminal.title.numbered": "Terminal {{number}}",
+  "terminal.close": "Zatvori terminal",
+  "terminal.connectionLost.title": "Veza prekinuta",
+  "terminal.connectionLost.description":
+    "Veza s terminalom je prekinuta. Ovo se može desiti kada se server restartuje.",
+
+  "common.closeTab": "Zatvori karticu",
+  "common.dismiss": "Odbaci",
+  "common.requestFailed": "Zahtjev nije uspio",
+  "common.moreOptions": "Više opcija",
+  "common.learnMore": "Saznaj više",
+  "common.rename": "Preimenuj",
+  "common.reset": "Resetuj",
+  "common.archive": "Arhiviraj",
+  "common.delete": "Izbriši",
+  "common.close": "Zatvori",
+  "common.edit": "Uredi",
+  "common.loadMore": "Učitaj još",
+  "common.key.esc": "ESC",
+
+  "sidebar.menu.toggle": "Prikaži/sakrij meni",
+  "sidebar.nav.projectsAndSessions": "Projekti i sesije",
+  "sidebar.settings": "Postavke",
+  "sidebar.help": "Pomoć",
+  "sidebar.workspaces.enable": "Omogući radne prostore",
+  "sidebar.workspaces.disable": "Onemogući radne prostore",
+  "sidebar.gettingStarted.title": "Početak",
+  "sidebar.gettingStarted.line1": "OpenCode uključuje besplatne modele, tako da možeš odmah početi.",
+  "sidebar.gettingStarted.line2": "Poveži bilo kojeg provajdera da koristiš modele, npr. Claude, GPT, Gemini itd.",
+  "sidebar.project.recentSessions": "Nedavne sesije",
+  "sidebar.project.viewAllSessions": "Prikaži sve sesije",
+
+  "app.name.desktop": "OpenCode Desktop",
+
+  "settings.section.desktop": "Desktop",
+  "settings.section.server": "Server",
+  "settings.tab.general": "Opšte",
+  "settings.tab.shortcuts": "Prečice",
+
+  "settings.general.section.appearance": "Izgled",
+  "settings.general.section.notifications": "Sistemske obavijesti",
+  "settings.general.section.updates": "Ažuriranja",
+  "settings.general.section.sounds": "Zvučni efekti",
+
+  "settings.general.row.language.title": "Jezik",
+  "settings.general.row.language.description": "Promijeni jezik prikaza u OpenCode-u",
+  "settings.general.row.appearance.title": "Izgled",
+  "settings.general.row.appearance.description": "Prilagodi kako OpenCode izgleda na tvom uređaju",
+  "settings.general.row.theme.title": "Tema",
+  "settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
+  "settings.general.row.font.title": "Font",
+  "settings.general.row.font.description": "Prilagodi monospace font koji se koristi u blokovima koda",
+
+  "settings.general.row.releaseNotes.title": "Bilješke o izdanju",
+  "settings.general.row.releaseNotes.description": 'Prikaži iskačuće prozore "Šta je novo" nakon ažuriranja',
+
+  "settings.updates.row.startup.title": "Provjeri ažuriranja pri pokretanju",
+  "settings.updates.row.startup.description": "Automatski provjerava ažuriranja kada se OpenCode pokrene",
+  "settings.updates.row.check.title": "Provjeri ažuriranja",
+  "settings.updates.row.check.description": "Ručno provjeri ažuriranja i instaliraj ako su dostupna",
+  "settings.updates.action.checkNow": "Provjeri sada",
+  "settings.updates.action.checking": "Provjera...",
+  "settings.updates.toast.latest.title": "Sve je ažurno",
+  "settings.updates.toast.latest.description": "Koristiš najnoviju verziju OpenCode-a.",
+  "font.option.ibmPlexMono": "IBM Plex Mono",
+  "font.option.cascadiaCode": "Cascadia Code",
+  "font.option.firaCode": "Fira Code",
+  "font.option.hack": "Hack",
+  "font.option.inconsolata": "Inconsolata",
+  "font.option.intelOneMono": "Intel One Mono",
+  "font.option.iosevka": "Iosevka",
+  "font.option.jetbrainsMono": "JetBrains Mono",
+  "font.option.mesloLgs": "Meslo LGS",
+  "font.option.robotoMono": "Roboto Mono",
+  "font.option.sourceCodePro": "Source Code Pro",
+  "font.option.ubuntuMono": "Ubuntu Mono",
+  "sound.option.alert01": "Upozorenje 01",
+  "sound.option.alert02": "Upozorenje 02",
+  "sound.option.alert03": "Upozorenje 03",
+  "sound.option.alert04": "Upozorenje 04",
+  "sound.option.alert05": "Upozorenje 05",
+  "sound.option.alert06": "Upozorenje 06",
+  "sound.option.alert07": "Upozorenje 07",
+  "sound.option.alert08": "Upozorenje 08",
+  "sound.option.alert09": "Upozorenje 09",
+  "sound.option.alert10": "Upozorenje 10",
+  "sound.option.bipbop01": "Bip-bop 01",
+  "sound.option.bipbop02": "Bip-bop 02",
+  "sound.option.bipbop03": "Bip-bop 03",
+  "sound.option.bipbop04": "Bip-bop 04",
+  "sound.option.bipbop05": "Bip-bop 05",
+  "sound.option.bipbop06": "Bip-bop 06",
+  "sound.option.bipbop07": "Bip-bop 07",
+  "sound.option.bipbop08": "Bip-bop 08",
+  "sound.option.bipbop09": "Bip-bop 09",
+  "sound.option.bipbop10": "Bip-bop 10",
+  "sound.option.staplebops01": "Staplebops 01",
+  "sound.option.staplebops02": "Staplebops 02",
+  "sound.option.staplebops03": "Staplebops 03",
+  "sound.option.staplebops04": "Staplebops 04",
+  "sound.option.staplebops05": "Staplebops 05",
+  "sound.option.staplebops06": "Staplebops 06",
+  "sound.option.staplebops07": "Staplebops 07",
+  "sound.option.nope01": "Ne 01",
+  "sound.option.nope02": "Ne 02",
+  "sound.option.nope03": "Ne 03",
+  "sound.option.nope04": "Ne 04",
+  "sound.option.nope05": "Ne 05",
+  "sound.option.nope06": "Ne 06",
+  "sound.option.nope07": "Ne 07",
+  "sound.option.nope08": "Ne 08",
+  "sound.option.nope09": "Ne 09",
+  "sound.option.nope10": "Ne 10",
+  "sound.option.nope11": "Ne 11",
+  "sound.option.nope12": "Ne 12",
+  "sound.option.yup01": "Da 01",
+  "sound.option.yup02": "Da 02",
+  "sound.option.yup03": "Da 03",
+  "sound.option.yup04": "Da 04",
+  "sound.option.yup05": "Da 05",
+  "sound.option.yup06": "Da 06",
+
+  "settings.general.notifications.agent.title": "Agent",
+  "settings.general.notifications.agent.description":
+    "Prikaži sistemsku obavijest kada agent završi ili zahtijeva pažnju",
+  "settings.general.notifications.permissions.title": "Dozvole",
+  "settings.general.notifications.permissions.description": "Prikaži sistemsku obavijest kada je potrebna dozvola",
+  "settings.general.notifications.errors.title": "Greške",
+  "settings.general.notifications.errors.description": "Prikaži sistemsku obavijest kada dođe do greške",
+
+  "settings.general.sounds.agent.title": "Agent",
+  "settings.general.sounds.agent.description": "Pusti zvuk kada agent završi ili zahtijeva pažnju",
+  "settings.general.sounds.permissions.title": "Dozvole",
+  "settings.general.sounds.permissions.description": "Pusti zvuk kada je potrebna dozvola",
+  "settings.general.sounds.errors.title": "Greške",
+  "settings.general.sounds.errors.description": "Pusti zvuk kada dođe do greške",
+
+  "settings.shortcuts.title": "Prečice na tastaturi",
+  "settings.shortcuts.reset.button": "Vrati na podrazumijevano",
+  "settings.shortcuts.reset.toast.title": "Prečice resetovane",
+  "settings.shortcuts.reset.toast.description": "Prečice na tastaturi su vraćene na podrazumijevane.",
+  "settings.shortcuts.conflict.title": "Prečica je već u upotrebi",
+  "settings.shortcuts.conflict.description": "{{keybind}} je već dodijeljeno za {{titles}}.",
+  "settings.shortcuts.unassigned": "Nedodijeljeno",
+  "settings.shortcuts.pressKeys": "Pritisni tastere",
+  "settings.shortcuts.search.placeholder": "Pretraži prečice",
+  "settings.shortcuts.search.empty": "Nema pronađenih prečica",
+
+  "settings.shortcuts.group.general": "Opšte",
+  "settings.shortcuts.group.session": "Sesija",
+  "settings.shortcuts.group.navigation": "Navigacija",
+  "settings.shortcuts.group.modelAndAgent": "Model i agent",
+  "settings.shortcuts.group.terminal": "Terminal",
+  "settings.shortcuts.group.prompt": "Upit",
+
+  "settings.providers.title": "Provajderi",
+  "settings.providers.description": "Postavke provajdera će se ovdje moći podešavati.",
+  "settings.providers.section.connected": "Povezani provajderi",
+  "settings.providers.connected.empty": "Nema povezanih provajdera",
+  "settings.providers.section.popular": "Popularni provajderi",
+  "settings.providers.tag.environment": "Okruženje",
+  "settings.providers.tag.config": "Konfiguracija",
+  "settings.providers.tag.custom": "Prilagođeno",
+  "settings.providers.tag.other": "Ostalo",
+  "settings.models.title": "Modeli",
+  "settings.models.description": "Postavke modela će se ovdje moći podešavati.",
+  "settings.agents.title": "Agenti",
+  "settings.agents.description": "Postavke agenata će se ovdje moći podešavati.",
+  "settings.commands.title": "Komande",
+  "settings.commands.description": "Postavke komandi će se ovdje moći podešavati.",
+  "settings.mcp.title": "MCP",
+  "settings.mcp.description": "MCP postavke će se ovdje moći podešavati.",
+
+  "settings.permissions.title": "Dozvole",
+  "settings.permissions.description": "Kontroliši koje alate server smije koristiti po defaultu.",
+  "settings.permissions.section.tools": "Alati",
+  "settings.permissions.toast.updateFailed.title": "Neuspjelo ažuriranje dozvola",
+
+  "settings.permissions.action.allow": "Dozvoli",
+  "settings.permissions.action.ask": "Pitaj",
+  "settings.permissions.action.deny": "Zabrani",
+
+  "settings.permissions.tool.read.title": "Čitanje",
+  "settings.permissions.tool.read.description": "Čitanje datoteke (podudara se s putanjom datoteke)",
+  "settings.permissions.tool.edit.title": "Uređivanje",
+  "settings.permissions.tool.edit.description":
+    "Mijenjanje datoteka, uključujući izmjene, pisanja, patch-eve i multi-izmjene",
+  "settings.permissions.tool.glob.title": "Glob",
+  "settings.permissions.tool.glob.description": "Podudaranje datoteka pomoću glob šablona",
+  "settings.permissions.tool.grep.title": "Grep",
+  "settings.permissions.tool.grep.description": "Pretraživanje sadržaja datoteka pomoću regularnih izraza",
+  "settings.permissions.tool.list.title": "Lista",
+  "settings.permissions.tool.list.description": "Listanje datoteka unutar direktorija",
+  "settings.permissions.tool.bash.title": "Bash",
+  "settings.permissions.tool.bash.description": "Pokretanje shell komandi",
+  "settings.permissions.tool.task.title": "Zadatak",
+  "settings.permissions.tool.task.description": "Pokretanje pod-agenta",
+  "settings.permissions.tool.skill.title": "Vještina",
+  "settings.permissions.tool.skill.description": "Učitaj vještinu po nazivu",
+  "settings.permissions.tool.lsp.title": "LSP",
+  "settings.permissions.tool.lsp.description": "Pokreni upite jezičnog servera",
+  "settings.permissions.tool.todoread.title": "Čitanje liste zadataka",
+  "settings.permissions.tool.todoread.description": "Čitanje liste zadataka",
+  "settings.permissions.tool.todowrite.title": "Ažuriranje liste zadataka",
+  "settings.permissions.tool.todowrite.description": "Ažuriraj listu zadataka",
+  "settings.permissions.tool.webfetch.title": "Web preuzimanje",
+  "settings.permissions.tool.webfetch.description": "Preuzmi sadržaj sa URL-a",
+  "settings.permissions.tool.websearch.title": "Web pretraga",
+  "settings.permissions.tool.websearch.description": "Pretražuj web",
+  "settings.permissions.tool.codesearch.title": "Pretraga koda",
+  "settings.permissions.tool.codesearch.description": "Pretraži kod na webu",
+  "settings.permissions.tool.external_directory.title": "Vanjski direktorij",
+  "settings.permissions.tool.external_directory.description": "Pristup datotekama izvan direktorija projekta",
+  "settings.permissions.tool.doom_loop.title": "Beskonačna petlja",
+  "settings.permissions.tool.doom_loop.description": "Otkriva ponovljene pozive alata sa identičnim unosom",
+
+  "session.delete.failed.title": "Neuspjelo brisanje sesije",
+  "session.delete.title": "Izbriši sesiju",
+  "session.delete.confirm": 'Izbriši sesiju "{{name}}"?',
+  "session.delete.button": "Izbriši sesiju",
+
+  "workspace.new": "Novi radni prostor",
+  "workspace.type.local": "lokalno",
+  "workspace.type.sandbox": "sandbox",
+  "workspace.create.failed.title": "Neuspješno kreiranje radnog prostora",
+  "workspace.delete.failed.title": "Neuspješno brisanje radnog prostora",
+  "workspace.resetting.title": "Resetovanje radnog prostora",
+  "workspace.resetting.description": "Ovo može potrajati minut.",
+  "workspace.reset.failed.title": "Neuspješno resetovanje radnog prostora",
+  "workspace.reset.success.title": "Radni prostor resetovan",
+  "workspace.reset.success.description": "Radni prostor sada odgovara podrazumijevanoj grani.",
+  "workspace.error.stillPreparing": "Radni prostor se još priprema",
+  "workspace.status.checking": "Provjera neobjedinjenih promjena...",
+  "workspace.status.error": "Nije moguće provjeriti git status.",
+  "workspace.status.clean": "Nisu pronađene neobjedinjene promjene.",
+  "workspace.status.dirty": "Pronađene su neobjedinjene promjene u ovom radnom prostoru.",
+  "workspace.delete.title": "Izbriši radni prostor",
+  "workspace.delete.confirm": 'Izbriši radni prostor "{{name}}"?',
+  "workspace.delete.button": "Izbriši radni prostor",
+  "workspace.reset.title": "Resetuj radni prostor",
+  "workspace.reset.confirm": 'Resetuj radni prostor "{{name}}"?',
+  "workspace.reset.button": "Resetuj radni prostor",
+  "workspace.reset.archived.none": "Nijedna aktivna sesija neće biti arhivirana.",
+  "workspace.reset.archived.one": "1 sesija će biti arhivirana.",
+  "workspace.reset.archived.many": "Biće arhivirano {{count}} sesija.",
+  "workspace.reset.note": "Ovo će resetovati radni prostor da odgovara podrazumijevanoj grani.",
+}

+ 1 - 0
packages/app/src/i18n/en.ts

@@ -343,6 +343,7 @@ export const dict = {
   "language.ar": "العربية",
   "language.no": "Norsk",
   "language.br": "Português (Brasil)",
+  "language.bs": "Bosanski",
   "language.th": "ไทย",
 
   "toast.language.title": "Language",

+ 32 - 0
packages/desktop/src/i18n/bs.ts

@@ -0,0 +1,32 @@
+export const dict = {
+  "desktop.menu.checkForUpdates": "Provjeri ažuriranja...",
+  "desktop.menu.installCli": "Instaliraj CLI...",
+  "desktop.menu.reloadWebview": "Ponovo učitavanje webview-a",
+  "desktop.menu.restart": "Restartuj",
+
+  "desktop.dialog.chooseFolder": "Odaberi folder",
+  "desktop.dialog.chooseFile": "Odaberi datoteku",
+  "desktop.dialog.saveFile": "Sačuvaj datoteku",
+
+  "desktop.updater.checkFailed.title": "Provjera ažuriranja nije uspjela",
+  "desktop.updater.checkFailed.message": "Nije moguće provjeriti ažuriranja",
+  "desktop.updater.none.title": "Nema dostupnog ažuriranja",
+  "desktop.updater.none.message": "Već koristiš najnoviju verziju OpenCode-a",
+  "desktop.updater.downloadFailed.title": "Ažuriranje nije uspjelo",
+  "desktop.updater.downloadFailed.message": "Neuspjelo preuzimanje ažuriranja",
+  "desktop.updater.downloaded.title": "Ažuriranje preuzeto",
+  "desktop.updater.downloaded.prompt":
+    "Verzija {{version}} OpenCode-a je preuzeta. Želiš li da je instaliraš i ponovo pokreneš aplikaciju?",
+  "desktop.updater.installFailed.title": "Ažuriranje nije uspjelo",
+  "desktop.updater.installFailed.message": "Neuspjela instalacija ažuriranja",
+
+  "desktop.cli.installed.title": "CLI instaliran",
+  "desktop.cli.installed.message":
+    "CLI je instaliran u {{path}}\n\nRestartuj terminal da bi koristio komandu 'opencode'.",
+  "desktop.cli.failed.title": "Instalacija nije uspjela",
+  "desktop.cli.failed.message": "Neuspjela instalacija CLI-a: {{error}}",
+
+  "desktop.error.serverStartFailed.title": "OpenCode se nije mogao pokrenuti",
+  "desktop.error.serverStartFailed.description":
+    "Lokalni OpenCode server se nije mogao pokrenuti. Restartuj aplikaciju ili provjeri mrežne postavke (VPN/proxy) i pokušaj ponovo.",
+}

+ 38 - 3
packages/desktop/src/i18n/index.ts

@@ -15,6 +15,7 @@ import { dict as desktopRu } from "./ru"
 import { dict as desktopAr } from "./ar"
 import { dict as desktopNo } from "./no"
 import { dict as desktopBr } from "./br"
+import { dict as desktopBs } from "./bs"
 
 import { dict as appEn } from "../../../app/src/i18n/en"
 import { dict as appZh } from "../../../app/src/i18n/zh"
@@ -30,13 +31,45 @@ import { dict as appRu } from "../../../app/src/i18n/ru"
 import { dict as appAr } from "../../../app/src/i18n/ar"
 import { dict as appNo } from "../../../app/src/i18n/no"
 import { dict as appBr } from "../../../app/src/i18n/br"
-
-export type Locale = "en" | "zh" | "zht" | "ko" | "de" | "es" | "fr" | "da" | "ja" | "pl" | "ru" | "ar" | "no" | "br"
+import { dict as appBs } from "../../../app/src/i18n/bs"
+
+export type Locale =
+  | "en"
+  | "zh"
+  | "zht"
+  | "ko"
+  | "de"
+  | "es"
+  | "fr"
+  | "da"
+  | "ja"
+  | "pl"
+  | "ru"
+  | "ar"
+  | "no"
+  | "br"
+  | "bs"
 
 type RawDictionary = typeof appEn & typeof desktopEn
 type Dictionary = i18n.Flatten<RawDictionary>
 
-const LOCALES: readonly Locale[] = ["en", "zh", "zht", "ko", "de", "es", "fr", "da", "ja", "pl", "ru", "ar", "no", "br"]
+const LOCALES: readonly Locale[] = [
+  "en",
+  "zh",
+  "zht",
+  "ko",
+  "de",
+  "es",
+  "fr",
+  "da",
+  "ja",
+  "pl",
+  "ru",
+  "bs",
+  "ar",
+  "no",
+  "br",
+]
 
 function detectLocale(): Locale {
   if (typeof navigator !== "object") return "en"
@@ -64,6 +97,7 @@ function detectLocale(): Locale {
     )
       return "no"
     if (language.toLowerCase().startsWith("pt")) return "br"
+    if (language.toLowerCase().startsWith("bs")) return "bs"
   }
 
   return "en"
@@ -108,6 +142,7 @@ function build(locale: Locale): Dictionary {
   if (locale === "ar") return { ...base, ...i18n.flatten(appAr), ...i18n.flatten(desktopAr) }
   if (locale === "no") return { ...base, ...i18n.flatten(appNo), ...i18n.flatten(desktopNo) }
   if (locale === "br") return { ...base, ...i18n.flatten(appBr), ...i18n.flatten(desktopBr) }
+  if (locale === "bs") return { ...base, ...i18n.flatten(appBs), ...i18n.flatten(desktopBs) }
   return { ...base, ...i18n.flatten(appKo), ...i18n.flatten(desktopKo) }
 }
 

+ 108 - 0
packages/ui/src/i18n/bs.ts

@@ -0,0 +1,108 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+  "ui.sessionReview.title": "Promjene sesije",
+  "ui.sessionReview.title.lastTurn": "Promjene u posljednjem potezu",
+  "ui.sessionReview.diffStyle.unified": "Ujedinjeno",
+  "ui.sessionReview.diffStyle.split": "Podijeljeno",
+  "ui.sessionReview.expandAll": "Proširi sve",
+  "ui.sessionReview.collapseAll": "Sažmi sve",
+  "ui.sessionReview.change.added": "Dodano",
+  "ui.sessionReview.change.removed": "Uklonjeno",
+
+  "ui.lineComment.label.prefix": "Komentar na ",
+  "ui.lineComment.label.suffix": "",
+  "ui.lineComment.editorLabel.prefix": "Komentarišeš ",
+  "ui.lineComment.editorLabel.suffix": "",
+  "ui.lineComment.placeholder": "Dodaj komentar",
+  "ui.lineComment.submit": "Komentariši",
+
+  "ui.sessionTurn.steps.show": "Prikaži korake",
+  "ui.sessionTurn.steps.hide": "Sakrij korake",
+  "ui.sessionTurn.summary.response": "Odgovor",
+  "ui.sessionTurn.diff.showMore": "Prikaži još izmjena ({{count}})",
+
+  "ui.sessionTurn.retry.retrying": "ponovni pokušaj",
+  "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s",
+
+  "ui.sessionTurn.status.delegating": "Delegiranje posla",
+  "ui.sessionTurn.status.planning": "Planiranje sljedećih koraka",
+  "ui.sessionTurn.status.gatheringContext": "Prikupljanje konteksta",
+  "ui.sessionTurn.status.searchingCodebase": "Pretraživanje baze koda",
+  "ui.sessionTurn.status.searchingWeb": "Pretraživanje weba",
+  "ui.sessionTurn.status.makingEdits": "Pravljenje izmjena",
+  "ui.sessionTurn.status.runningCommands": "Pokretanje komandi",
+  "ui.sessionTurn.status.thinking": "Razmišljanje",
+  "ui.sessionTurn.status.thinkingWithTopic": "Razmišljanje - {{topic}}",
+  "ui.sessionTurn.status.gatheringThoughts": "Sređivanje misli",
+  "ui.sessionTurn.status.consideringNextSteps": "Razmatranje sljedećih koraka",
+
+  "ui.messagePart.diagnostic.error": "Greška",
+  "ui.messagePart.title.edit": "Uredi",
+  "ui.messagePart.title.write": "Napiši",
+  "ui.messagePart.option.typeOwnAnswer": "Unesi svoj odgovor",
+  "ui.messagePart.review.title": "Pregledaj svoje odgovore",
+
+  "ui.list.loading": "Učitavanje",
+  "ui.list.empty": "Nema rezultata",
+  "ui.list.clearFilter": "Očisti filter",
+  "ui.list.emptyWithFilter.prefix": "Nema rezultata za",
+  "ui.list.emptyWithFilter.suffix": "",
+
+  "ui.messageNav.newMessage": "Nova poruka",
+
+  "ui.textField.copyToClipboard": "Kopiraj u međuspremnik",
+  "ui.textField.copyLink": "Kopiraj link",
+  "ui.textField.copied": "Kopirano",
+
+  "ui.imagePreview.alt": "Pregled slike",
+
+  "ui.tool.read": "Čitanje",
+  "ui.tool.loaded": "Učitano",
+  "ui.tool.list": "Listanje",
+  "ui.tool.glob": "Glob",
+  "ui.tool.grep": "Grep",
+  "ui.tool.webfetch": "Web preuzimanje",
+  "ui.tool.shell": "Shell",
+  "ui.tool.patch": "Patch",
+  "ui.tool.todos": "Lista zadataka",
+  "ui.tool.todos.read": "Čitanje liste zadataka",
+  "ui.tool.questions": "Pitanja",
+  "ui.tool.agent": "{{type}} agent",
+
+  "ui.common.file.one": "datoteka",
+  "ui.common.file.other": "datoteke",
+  "ui.common.question.one": "pitanje",
+  "ui.common.question.other": "pitanja",
+
+  "ui.common.add": "Dodaj",
+  "ui.common.cancel": "Otkaži",
+  "ui.common.confirm": "Potvrdi",
+  "ui.common.dismiss": "Odbaci",
+  "ui.common.close": "Zatvori",
+  "ui.common.next": "Dalje",
+  "ui.common.submit": "Pošalji",
+
+  "ui.permission.deny": "Zabrani",
+  "ui.permission.allowAlways": "Uvijek dozvoli",
+  "ui.permission.allowOnce": "Dozvoli jednom",
+
+  "ui.message.expand": "Proširi poruku",
+  "ui.message.collapse": "Sažmi poruku",
+  "ui.message.copy": "Kopiraj",
+  "ui.message.copied": "Kopirano!",
+  "ui.message.attachment.alt": "prilog",
+
+  "ui.patch.action.deleted": "Obrisano",
+  "ui.patch.action.created": "Kreirano",
+  "ui.patch.action.moved": "Premješteno",
+  "ui.patch.action.patched": "Primijenjeno",
+
+  "ui.question.subtitle.answered": "{{count}} odgovoreno",
+  "ui.question.answer.none": "(nema odgovora)",
+  "ui.question.review.notAnswered": "(nije odgovoreno)",
+  "ui.question.multiHint": "(odaberi sve što važi)",
+  "ui.question.custom.placeholder": "Unesi svoj odgovor...",
+} satisfies Partial<Record<Keys, string>>