diff --git a/apps/web/src/i18n/index.tsx b/apps/web/src/i18n/index.tsx index 4bad77f98e..68324f7193 100644 --- a/apps/web/src/i18n/index.tsx +++ b/apps/web/src/i18n/index.tsx @@ -11,6 +11,7 @@ import { } from 'react'; import { de } from './locales/de'; import { en } from './locales/en'; +import { id } from './locales/id'; import { esES } from './locales/es-ES'; import { fa } from './locales/fa'; import { ar } from './locales/ar'; @@ -34,6 +35,7 @@ type DictKey = keyof Dict; const DICTS: Record = { 'en': en, + 'id': id, 'de': de, 'zh-CN': zhCN, 'zh-TW': zhTW, diff --git a/apps/web/src/i18n/locales/id.ts b/apps/web/src/i18n/locales/id.ts new file mode 100644 index 0000000000..4dbc067884 --- /dev/null +++ b/apps/web/src/i18n/locales/id.ts @@ -0,0 +1,971 @@ +import type { Dict } from '../types'; + +export const id: Dict = { + 'common.cancel': 'Batal', + 'common.save': 'Simpan', + 'common.close': 'Tutup', + 'common.delete': 'Hapus', + 'common.rename': 'Ganti nama', + 'common.preview': 'Pratinjau', + 'common.share': 'Bagikan', + 'common.search': 'Cari', + 'common.searchEllipsis': 'Cari...', + 'common.loading': 'Memuat...', + 'common.all': 'Semua', + 'common.none': 'Tidak ada', + 'common.default': 'Default', + 'common.installed': 'terpasang', + 'common.notInstalled': 'belum terpasang', + 'common.active': 'aktif', + 'common.offline': 'offline', + 'common.selected': 'dipilih', + 'common.create': 'Buat', + 'common.openPreview': 'Buka pratinjau', + 'common.exitFullscreen': 'Keluar layar penuh', + 'common.fullscreen': 'Layar penuh', + 'common.openInNewTab': 'Buka di tab baru', + 'common.exportPdf': 'Ekspor sebagai PDF', + 'common.exportZip': 'Unduh sebagai .zip', + 'common.exportHtml': 'Ekspor sebagai HTML mandiri', + 'common.justNow': 'baru saja', + 'common.minutesAgo': '{n}m lalu', + 'common.hoursAgo': '{n}j lalu', + 'common.daysAgo': '{n}h lalu', + 'common.now': 'sekarang', + 'common.minutesShort': '{n}m', + 'common.hoursShort': '{n}j', + 'common.daysShort': '{n}h', + 'common.untitled': 'Tanpa judul', + + 'app.brand': 'Open Design', + 'app.brandPill': 'Pratinjau Riset', + 'app.brandSubtitle': 'oleh Nexu Labs', + 'app.welcomeLoading': 'Memuat workspace...', + + 'settings.welcomeKicker': 'Selamat datang', + 'settings.welcomeTitle': 'Siapkan Open Design', + 'settings.welcomeSubtitle': 'Pilih cara menjalankan generasi. Ini bisa diubah kapan saja dari tombol Settings di bar atas.', + 'settings.kicker': 'Pengaturan', + 'settings.title': 'Eksekusi & model', + 'settings.subtitle': 'Pilih antara CLI code-agent lokal dan Anthropic API (BYOK). API key hanya disimpan di browser ini.', + 'settings.modeAria': 'Mode eksekusi', + 'settings.protocolAria': 'Protokol API', + 'settings.modeDaemon': 'CLI lokal', + 'settings.modeDaemonHelp': 'Jalankan lewat code-agent CLI di komputer ini', + 'settings.modeDaemonOffline': 'Daemon tidak berjalan', + 'settings.modeDaemonOfflineMeta': 'daemon offline', + 'settings.modeDaemonInstalledMeta': '{count} terpasang', + 'settings.modeApi': 'Anthropic API', + 'settings.modeApiMeta': 'BYOK', + 'settings.codeAgent': 'Code agent', + 'settings.codeAgentHint': 'Terdeteksi dari PATH. Pilih CLI yang ingin dipakai untuk menjalankan generasi.', + 'settings.rescan': 'Pindai ulang', + 'settings.rescanTitle': 'Pindai ulang PATH', + 'settings.rescanRunning': 'Memindai...', + 'settings.rescanSuccess': 'Pemindaian selesai. {count} tersedia.', + 'settings.rescanFailed': 'Pemindaian gagal. Periksa daemon lalu coba lagi.', + 'settings.noAgentsDetected': + 'Belum ada agent terdeteksi. Pasang salah satu dari Claude Code, Codex, Devin for Terminal, Gemini CLI, OpenCode, Cursor Agent, Qwen, atau GitHub Copilot CLI, lalu klik pindai ulang.', + 'settings.apiSection': 'Anthropic API', + 'settings.quickFillProvider': 'Provider isi cepat', + 'settings.customProvider': 'Provider kustom', + 'settings.apiKey': 'API key', + 'settings.showKey': 'Tampilkan key', + 'settings.hideKey': 'Sembunyikan key', + 'settings.show': 'Tampilkan', + 'settings.hide': 'Sembunyikan', + 'settings.model': 'Model', + 'settings.suggestedModelsHint': 'Ini model yang disarankan untuk protokol ini. Provider kamu mungkin mendukung model lain.', + 'settings.baseUrl': 'Base URL', + 'settings.baseUrlInvalid': + 'Masukkan URL publik http:// atau https:// yang valid. Localhost diizinkan; IP jaringan privat diblokir.', + 'settings.azureDeploymentModel': 'Nama deployment', + 'settings.azureDeploymentModelHint': + 'Untuk Azure OpenAI, field ini digunakan sebagai nama deployment di /openai/deployments/. Masukkan nama deployment yang kamu buat di Azure.', + 'settings.apiVersion': 'Versi API', + 'settings.maxTokens': 'Token maks (opsional)', + 'settings.maxTokensHint': + 'Batas panjang respons. Setiap model punya default sendiri; kosongkan untuk memakainya, atau isi angka untuk menimpa.', + 'settings.apiHint': + 'Panggilan dikirim langsung dari browser ini ke base URL yang kamu atur. Tanpa proxy. Key tidak keluar dari localStorage.', + 'settings.skipForNow': 'Lewati dulu', + 'settings.getStarted': 'Mulai', + 'settings.envConfigure': 'Atur mode eksekusi', + 'settings.localCli': 'CLI lokal', + 'settings.anthropicApi': 'Anthropic API', + 'settings.noAgentSelected': 'belum ada agent dipilih', + 'settings.language': 'Bahasa', + 'settings.languageHint': 'Ganti bahasa antarmuka. Disimpan di browser ini.', + 'settings.appearance': 'Tampilan', + 'settings.appearanceHint': 'Pilih terang, gelap atau ikuti pengaturan sistem.', + 'settings.themeSystem': 'Sistem', + 'settings.themeLight': 'Terang', + 'settings.themeDark': 'Gelap', + 'settings.modelPicker': 'Model', + 'settings.reasoningPicker': 'Kekuatan penalaran', + 'settings.modelPickerHint': + 'Diambil dari CLI jika tersedia. "Default" mengikuti konfigurasi CLI; "Custom..." untuk mengetik model id sendiri.', + 'settings.cliEnvTitle': 'Lokasi konfigurasi CLI', + 'settings.cliEnvHint': 'Atur direktori konfigurasi non-rahasia untuk menjalankan aplikasi paket dan deteksi agent.', + 'settings.cliEnvClaudeConfigDir': 'Direktori konfigurasi Claude Code', + 'settings.cliEnvCodexHome': 'Home Codex', + 'settings.modelCustom': 'Kustom (isi di bawah)...', + 'settings.modelCustomLabel': 'ID model kustom', + 'settings.modelCustomPlaceholder': 'mis. anthropic/claude-sonnet-4-6', + 'settings.mediaProviders': 'Provider media', + 'settings.mediaProvidersHint': 'API key untuk generasi gambar, video, dan audio. Disimpan lokal dan disinkronkan ke daemon lokal.', + 'settings.mediaProviderApiKey': 'API key', + 'settings.mediaProviderBaseUrl': 'Base URL', + 'settings.mediaProviderConfigured': 'Sudah diatur', + 'settings.mediaProviderUnset': 'Belum diatur', + 'settings.mediaProviderClear': 'Bersihkan', + 'settings.mediaProviderPlaceholder': 'Tempel API key', + 'settings.mediaProviderBaseUrlPlaceholder': 'Timpa base URL default', + 'settings.about': 'Tentang', + 'settings.aboutHint': 'Detail versi dan runtime', + 'settings.appVersion': 'Versi', + 'settings.appChannel': 'Channel', + 'settings.appRuntime': 'Runtime', + 'settings.appPlatform': 'Platform', + 'settings.appArchitecture': 'Arsitektur', + 'settings.runtimePackaged': 'Aplikasi paket', + 'settings.runtimeDevelopment': 'Development', + 'settings.versionUnavailable': 'Detail versi tidak tersedia saat daemon offline.', + + 'entry.tabDesigns': 'Desain', + 'entry.tabExamples': 'Contoh', + 'entry.tabDesignSystems': 'Sistem desain', + 'entry.tabConnectors': 'Konektor', + 'entry.openSettingsTitle': 'Pengaturan', + 'entry.openSettingsAria': 'Buka pengaturan', + 'entry.resizeAria': 'Ubah ukuran sidebar', + 'entry.loadingWorkspace': 'Memuat workspace...', + 'entry.tabImageTemplates': 'Templat gambar', + 'entry.tabVideoTemplates': 'Templat video', + + 'promptTemplates.searchPlaceholder': 'Cari templat...', + 'promptTemplates.countLabel': '{n} hasil', + 'promptTemplates.emptyImage': 'Belum ada templat prompt gambar.', + 'promptTemplates.emptyVideo': 'Belum ada templat prompt video.', + 'promptTemplates.emptyNoMatch': 'Tidak ada templat yang cocok dengan pencarianmu.', + 'promptTemplates.attributionFooter': 'Diadaptasi dari library prompt publik. Tiap kartu menautkan ke author asli.', + 'promptTemplates.openPreviewTitle': 'Buka prompt dan pratinjau', + 'promptTemplates.sourcePrefix': 'Sumber:', + 'promptTemplates.fetchError': 'Tidak bisa memuat isi templat ini.', + 'promptTemplates.promptLabel': 'Isi prompt', + 'promptTemplates.copyPrompt': 'Salin prompt', + 'promptTemplates.copyDone': 'Tersalin!', + 'promptTemplates.modelHint': 'Model disarankan: {model}', + 'promptTemplates.openSource': 'Lihat asli', + 'promptTemplates.openFullscreen': 'Buka pratinjau layar penuh', + 'promptTemplates.closeFullscreen': 'Tutup pratinjau layar penuh', + 'promptTemplates.allSources': 'Semua sumber', + 'promptTemplates.sourceFilterAria': 'Filter berdasarkan sumber', + 'promptTemplates.retry': 'Coba lagi', + + 'connectors.title': 'Konektor', + 'connectors.subtitle': 'Sumber data lokal dan mendatang yang bisa mendukung live artifact.', + 'connectors.account': 'Akun', + 'connectors.noAccount': 'Belum terhubung', + 'connectors.tools': 'Alat', + 'connectors.connect': 'Hubungkan', + 'connectors.disconnect': 'Putuskan', + 'connectors.configure': 'Konfigurasikan', + 'connectors.unavailable': 'Tidak tersedia', + 'connectors.phaseStubTitle': 'API konektor hadir di Fase 3; ini adalah area pratinjau.', + 'connectors.statusAvailable': 'Tersedia', + 'connectors.statusConnected': 'Terhubung', + 'connectors.statusError': 'Error', + 'connectors.statusDisabled': 'Nonaktif', + 'connectors.gateTitle': 'Konfigurasikan API key Composio', + 'connectors.gateBody': + 'Konektor membutuhkan API key Composio. Tambahkan di Pengaturan untuk membuka integrasi yang tersedia.', + 'connectors.gateAction': 'Buka pengaturan', + 'connectors.aboutLabel': 'Tentang', + 'connectors.detailsLabel': 'Detail', + 'connectors.statusLabel': 'Status', + 'connectors.categoryLabel': 'Kategori', + 'connectors.providerLabel': 'Provider', + 'connectors.toolsSection': 'Alat', + 'connectors.toolsLoading': 'Memuat alat...', + 'connectors.noToolsAvailable': 'Belum ada alat tersedia. Hubungkan untuk melihat apa yang disediakan integrasi ini.', + 'connectors.openDetailsAria': 'Buka detail {name}', + 'connectors.toolsBadgeNone': 'Tidak ada alat', + 'connectors.toolsBadgeOne': '{n} alat', + 'connectors.toolsBadgeMany': '{n} alat', + 'connectors.searchPlaceholder': 'Cari konektor...', + 'connectors.searchAriaLabel': 'Cari konektor berdasarkan nama, provider, atau alat', + 'connectors.searchClear': 'Bersihkan pencarian', + 'connectors.emptyNoMatchTitle': 'Tidak ada konektor yang cocok dengan "{query}"', + 'connectors.emptyNoMatchBody': 'Coba kata kunci lain, atau bersihkan pencarian untuk melihat seluruh katalog.', + 'connectors.emptyNoMatchAction': 'Bersihkan pencarian', + + 'newproj.tabPrototype': 'Prototype', + 'newproj.tabLiveArtifact': 'Live artifact', + 'newproj.tabDeck': 'Slide deck', + 'newproj.tabTemplate': 'Dari templat', + 'newproj.tabOther': 'Lainnya', + 'newproj.titlePrototype': 'Prototype baru', + 'newproj.titleLiveArtifact': 'Live artifact baru', + 'newproj.titleDeck': 'Slide deck baru', + 'newproj.titleTemplate': 'Mulai dari templat', + 'newproj.titleImage': 'Gambar baru', + 'newproj.titleVideo': 'Video baru', + 'newproj.titleAudio': 'Audio baru', + 'newproj.titleOther': 'Proyek baru', + 'newproj.namePlaceholder': 'Nama proyek', + 'newproj.fidelityLabel': 'Fidelity', + 'newproj.fidelityWireframe': 'Wireframe', + 'newproj.fidelityHigh': 'High fidelity', + 'newproj.toggleSpeakerNotes': 'Gunakan catatan pembicara', + 'newproj.toggleSpeakerNotesHint': 'Kurangi teks di slide; simpan poin bicara di catatan.', + 'newproj.toggleAnimations': 'Sertakan animasi', + 'newproj.toggleAnimationsHint': 'Tambahkan motion, hover, dan transisi di atas templat.', + 'newproj.templateLabel': 'Templat', + 'newproj.noTemplatesTitle': 'Belum ada templat', + 'newproj.noTemplatesBody': 'Buka proyek apa pun, lalu pakai menu Share di penampil berkas untuk mengubahnya menjadi templat.', + 'newproj.savedTemplate': 'Templat tersimpan', + 'newproj.fileSingular': 'berkas', + 'newproj.filePlural': 'berkas', + 'newproj.create': 'Buat', + 'newproj.createLiveArtifact': 'Buat live artifact', + 'newproj.createFromTemplate': 'Buat dari templat', + 'newproj.createDisabledTitle': 'Simpan proyek sebagai templat dulu.', + 'newproj.importClaudeZip': 'Impor ZIP Claude Design', + 'newproj.importClaudeZipTitle': 'Impor file .zip hasil ekspor Claude Design', + 'newproj.importingClaudeZip': 'Mengimpor...', + 'newproj.privacyFooter': 'Secara default hanya kamu yang bisa melihat proyekmu.', + 'newproj.designSystem': 'Sistem desain', + 'newproj.dsNoneFreeform': 'Tidak ada - bebas', + 'newproj.dsNoneSubtitleEmpty': 'Tanpa token sistem, pilih palet sendiri', + 'newproj.dsNoneSubtitleSelected': 'Lewati token sistem. Agent memilih paletnya sendiri.', + 'newproj.dsCategoryFallback': 'Sistem desain', + 'newproj.dsSearch': 'Cari sistem desain...', + 'newproj.dsModeAria': 'Mode pilihan', + 'newproj.dsModeSingle': 'Tunggal', + 'newproj.dsModeMulti': 'Multi', + 'newproj.dsNoneTitle': 'Tidak ada - bebas', + 'newproj.dsNoneSub': 'Lewati token sistem. Agent memilih paletnya sendiri.', + 'newproj.dsEmpty': 'Tidak ada sistem desain yang cocok dengan "{query}".', + 'newproj.dsFootSingular': 'hanya sebagai inspirasi.', + 'newproj.dsFootPlural': 'hanya sebagai inspirasi.', + 'newproj.dsFootClear': 'Bersihkan', + 'newproj.dsBadgeDefault': 'DEFAULT', + 'newproj.dsPrimaryFallback': 'Utama', + 'newproj.surfaceImage': 'Gambar', + 'newproj.surfaceVideo': 'Video', + 'newproj.surfaceAudio': 'Audio', + 'newproj.modelLabel': 'Model', + 'newproj.aspectLabel': 'Aspek', + 'newproj.imageStyleLabel': 'Catatan gaya', + 'newproj.imageStylePlaceholder': 'Foto editorial, cahaya siang lembut, palet kalem', + 'newproj.videoLengthLabel': 'Durasi', + 'newproj.videoLengthSeconds': '{n}d', + 'newproj.audioKindLabel': 'Jenis audio', + 'newproj.audioKindMusic': 'Musik', + 'newproj.audioKindSpeech': 'Speech / TTS', + 'newproj.audioKindSfx': 'SFX', + 'newproj.audioDurationLabel': 'Durasi', + 'newproj.audioDurationSeconds': '{n}d', + 'newproj.voiceLabel': 'Suara', + 'newproj.voicePlaceholder': 'ID suara provider, opsional', + 'newproj.connectorsLabel': 'Konektor', + 'newproj.connectorsHint': 'Sumber data yang bisa diambil artifact ini.', + 'newproj.connectorsEmptyTitle': 'Belum ada konektor dikonfigurasi', + 'newproj.connectorsEmptyBody': 'Hubungkan sumber data agar live artifact dapat mengambil angka nyata, bukan placeholder.', + 'newproj.connectorsEmptyCta': 'Atur konektor ->', + 'newproj.connectorsLoading': 'Memuat konektor...', + 'newproj.connectorsCountOne': '{n} terhubung', + 'newproj.connectorsCountMany': '{n} terhubung', + 'newproj.connectorsManage': 'Kelola', + 'newproj.promptTemplateLabel': 'Templat referensi', + 'newproj.promptTemplateNoneTitle': 'Tidak ada - tulis sendiri', + 'newproj.promptTemplateNoneSub': 'Lewati galeri, jelaskan brief sendiri', + 'newproj.promptTemplateRefSub': 'Templat referensi', + 'newproj.promptTemplateSearch': 'Cari templat...', + 'newproj.promptTemplateEmpty': 'Belum ada templat untuk tipe ini.', + 'newproj.promptTemplateBodyLabel': 'Prompt (bisa diedit)', + 'newproj.promptTemplateOptimizeHint': 'Edit prompt sebelum membuat proyek agar sesuai dengan kebutuhanmu.', + 'newproj.promptTemplateBodyEmpty': 'Prompt kosong - agent tidak menerima referensi templat.', + + 'designs.subRecent': 'Terbaru', + 'designs.subYours': 'Desainmu', + 'designs.filterAria': 'Filter proyek', + 'designs.searchPlaceholder': 'Cari...', + 'designs.emptyNoProjects': 'Belum ada proyek. Buat satu dari panel kiri.', + 'designs.emptyNoMatch': 'Tidak ada proyek yang cocok dengan pencarianmu.', + 'designs.deleteTitle': 'Hapus proyek', + 'designs.deleteConfirm': 'Hapus "{name}"?', + 'designs.cardFreeform': 'Bebas', + 'designs.badgeLive': 'Live', + 'designs.liveArtifactBadgesAria': 'Badge live artifact', + 'designs.liveCount': '{n} live', + 'designs.statusLive': 'Live artifact', + 'designs.statusArchived': 'Diarsipkan', + 'designs.statusError': 'Error', + 'designs.statusRefreshing': 'Memperbarui...', + 'designs.statusRefreshFailed': 'Refresh gagal', + 'designs.statusRefreshed': 'Diperbarui', + 'designs.status.notStarted': 'Belum dimulai', + 'designs.status.queued': 'Dalam antrean', + 'designs.status.running': 'Berjalan', + 'designs.status.awaitingInput': 'Menunggu input', + 'designs.status.succeeded': 'Selesai', + 'designs.status.failed': 'Gagal', + 'designs.status.canceled': 'Dibatalkan', + 'designs.viewToggleAria': 'Mode tampilan', + 'designs.viewGrid': 'Tampilan grid', + 'designs.viewKanban': 'Tampilan kanban', + 'designs.kanbanEmptyColumn': 'Tidak ada desain', + 'designs.deleteAria': 'Hapus proyek {name}', + + 'examples.typeLabel': 'Tipe', + 'examples.surfaceLabel': 'Surface', + 'examples.surfaceWeb': 'Web', + 'examples.surfaceImage': 'Gambar', + 'examples.surfaceVideo': 'Video', + 'examples.surfaceAudio': 'Audio', + 'examples.scenarioLabel': 'Skenario', + 'examples.modeAll': 'Semua', + 'examples.modePrototypeDesktop': 'Prototype - desktop', + 'examples.modePrototypeMobile': 'Prototype - mobile', + 'examples.modeDeck': 'Slide', + 'examples.modeDocument': 'Dokumen & templat', + 'examples.modeOrbit': 'Orbit', + 'examples.scenarioGeneral': 'Umum', + 'examples.scenarioEngineering': 'Engineering', + 'examples.scenarioProduct': 'Produk', + 'examples.scenarioDesign': 'Desain', + 'examples.scenarioMarketing': 'Marketing', + 'examples.scenarioSales': 'Sales', + 'examples.scenarioFinance': 'Keuangan', + 'examples.scenarioHr': 'HR', + 'examples.scenarioOperations': 'Operasi', + 'examples.scenarioSupport': 'Support', + 'examples.scenarioLegal': 'Legal', + 'examples.scenarioEducation': 'Edukasi', + 'examples.scenarioPersonal': 'Personal', + 'examples.searchPlaceholder': 'Cari contoh...', + 'examples.searchAria': 'Cari contoh berdasarkan nama', + 'examples.emptyNoSkills': 'Tidak ada skill tersedia. Apakah daemon berjalan?', + 'examples.emptyNoMatch': 'Tidak ada contoh yang cocok dengan filter ini.', + 'examples.openPreview': 'Buka pratinjau', + 'examples.loadingPreview': 'Memuat pratinjau...', + 'examples.hoverPreview': 'Arahkan kursor untuk pratinjau', + 'examples.usePrompt': 'Gunakan prompt ini', + 'examples.previewModalTitle': 'Buka pratinjau penuh', + 'examples.shareTitle': 'Bagikan contoh ini', + 'examples.shareLoadFirst': 'Arahkan kursor dulu untuk memuat pratinjau', + 'examples.shareMenu': 'Bagikan', + 'examples.exportPdfAllSlides': 'Ekspor PDF (semua slide)', + 'examples.exportPptxLocked': 'Ekspor PPTX... (buka templat dulu)', + 'examples.tagSlideDeck': 'Slide deck', + 'examples.tagTemplate': 'Templat', + 'examples.tagDesignSystem': 'Sistem desain', + 'examples.tagMobilePrototype': 'Prototype mobile', + 'examples.tagDesktopPrototype': 'Prototype desktop', + 'examples.tagImage': 'Gambar', + 'examples.tagVideo': 'Video', + 'examples.tagAudio': 'Audio', + 'examples.previewLabel': 'Pratinjau', + + 'ds.surfaceLabel': 'Surface', + 'ds.surfaceWeb': 'Web', + 'ds.surfaceImage': 'Gambar', + 'ds.surfaceVideo': 'Video', + 'ds.surfaceAudio': 'Audio', + 'ds.searchPlaceholder': 'Cari sistem desain...', + 'ds.emptyNoMatch': 'Tidak ada sistem desain yang cocok.', + 'ds.badgeDefault': 'Default', + 'ds.preview': 'Pratinjau', + 'ds.previewTitle': 'Pratinjau sistem desain', + 'ds.categoryAll': 'Semua', + 'ds.categoryUncategorized': 'Tanpa kategori', + 'ds.showcase': 'Showcase', + 'ds.tokens': 'Token', + 'ds.specToggle': 'Spesifikasi', + 'ds.specLoading': 'Memuat spesifikasi...', + + 'avatar.title': 'Akun & pengaturan', + 'avatar.localCli': 'CLI lokal', + 'avatar.anthropicApi': 'Anthropic API', + 'avatar.useLocal': 'Gunakan CLI lokal', + 'avatar.useApi': 'Gunakan Anthropic API', + 'avatar.codeAgent': 'Code agent', + 'avatar.rescan': 'Pindai ulang PATH', + 'avatar.settings': 'Pengaturan', + 'avatar.backToProjects': 'Kembali ke proyek', + 'avatar.metaActive': 'aktif', + 'avatar.metaOffline': 'offline', + 'avatar.metaSelected': 'dipilih', + 'avatar.noAgentSelected': 'Belum ada agent dipilih', + 'avatar.modelSection': 'Model', + 'avatar.modelLabel': 'Model', + 'avatar.reasoningLabel': 'Penalaran', + 'avatar.customSuffix': '(kustom)', + + 'project.backToProjects': 'Kembali ke proyek', + 'project.metaFreeform': 'Bebas', + 'project.resizeChatPanel': 'Ubah ukuran panel chat', + + 'chat.tabChat': 'Chat', + 'chat.tabComments': 'Komentar', + 'chat.commentsSoon': 'Komentar - segera hadir', + 'chat.comments.attached': 'Dilampirkan ke chat', + 'chat.comments.emptyAttached': 'Tidak ada komentar terlampir.', + 'chat.comments.saved': 'Komentar tersimpan', + 'chat.comments.emptySaved': 'Tidak ada komentar tersimpan.', + 'chat.comments.add': 'Tambah', + 'chat.comments.addAll': 'Tambah semua', + 'chat.comments.remove': 'Hapus', + 'chat.comments.placeholder': 'Komentari elemen ini...', + 'chat.comments.addSend': 'Tambah & kirim', + 'chat.comments.updateSend': 'Perbarui & kirim', + 'chat.comments.removeAttachment': 'Hapus lampiran komentar', + 'chat.comments.removeAttachmentAria': 'Hapus lampiran komentar untuk {name}', + 'chat.conversationsTitle': 'Percakapan', + 'chat.conversationsAria': 'Buka percakapan', + 'chat.newConversation': 'Percakapan baru', + 'chat.newConversationsTitle': 'Mulai percakapan baru', + 'chat.conversationsHeading': 'Percakapan', + 'chat.new': 'Baru', + 'chat.emptyConversations': 'Belum ada percakapan.', + 'chat.deleteConversation': 'Hapus percakapan', + 'chat.deleteConversationConfirm': 'Hapus "{title}"? Semua pesannya ikut dihapus.', + 'chat.untitledConversation': 'Percakapan tanpa judul', + 'chat.startTitle': 'Mulai percakapan', + 'chat.startHint': 'Jelaskan apa yang ingin kamu buat. Agent akan menulis file dan menampilkan pratinjau di sini.', + 'chat.fillInputTitle': 'Isi brief dulu', + 'chat.jumpToLatest': 'Lompat ke terbaru', + 'chat.scrollToLatest': 'Scroll ke terbaru', + 'chat.you': 'Kamu', + 'chat.openFile': 'Buka {name}', + 'chat.composerPlaceholder': 'Jelaskan desain, perubahan, atau artifact yang kamu inginkan...', + 'chat.composerHint': 'Tekan Enter untuk kirim, Shift+Enter untuk baris baru.', + 'chat.cliSettingsTitle': 'Pengaturan CLI', + 'chat.cliSettingsAria': 'Buka pengaturan CLI', + 'chat.attachTitle': 'Lampirkan', + 'chat.attachAria': 'Lampirkan file atau konteks', + 'chat.importTitle': 'Impor', + 'chat.importLabel': 'Impor konteks', + 'chat.importComingSoon': 'Segera hadir', + 'chat.importSoon': 'Segera', + 'chat.importFig': 'File desain', + 'chat.importGitHub': 'GitHub', + 'chat.importWeb': 'Web', + 'chat.importFolder': 'Tautkan folder kode', + 'chat.importSkills': 'Skills', + 'chat.importProject': 'Proyek', + 'chat.linkedFolderRemoveAria': 'Hapus folder tertaut {path}', + 'chat.linkedFolderNotFound': 'Folder tidak ada', + 'chat.linkedFolderAlready': 'Folder ini sudah tertaut', + 'chat.linkedFolderPickError': 'Tidak bisa membuka pemilih folder', + 'chat.send': 'Kirim', + 'chat.stop': 'Stop', + 'chat.removeAria': 'Hapus {name}', + 'chat.example1Title': 'Pitch editorial', + 'chat.example1Tag': 'Majalah', + 'chat.example1Prompt': 'Buat pitch deck bergaya majalah untuk seed round startup AI.', + 'chat.example2Title': 'Dashboard analitik SaaS', + 'chat.example2Tag': 'Data', + 'chat.example2Prompt': + 'Buat dashboard analitik padat untuk SaaS developer tools dengan KPI, grafik MRR, peta heatmap penggunaan, kohort retensi, dan feed event real-time.', + 'chat.example3Title': 'Laporan tahunan long-scroll', + 'chat.example3Tag': 'Editorial', + 'chat.example3Prompt': 'Buat laporan tahunan long-scroll dengan hero editorial, angka utama, timeline, dan visualisasi data.', + + 'preview.shareMenu': 'Bagikan', + 'preview.openInNewTab': 'Buka di tab baru', + 'preview.exit': 'Keluar', + 'preview.fullscreen': 'Layar penuh', + 'preview.closeTitle': 'Tutup pratinjau', + 'preview.loading': 'Memuat {label}...', + 'preview.showSidebar': 'Tampilkan {label}', + 'preview.hideSidebar': 'Sembunyikan {label}', + + 'misc.savedTemplate': 'Templat tersimpan', + 'misc.primary': 'Utama', + 'misc.designSystem': 'Sistem desain', + + 'workspace.designFiles': 'File desain', + 'workspace.focusMode': 'Fokus workspace', + 'workspace.showChat': 'Tampilkan chat', + 'workspace.closeTab': 'Tutup tab', + 'workspace.deleteFileConfirm': 'Hapus "{name}" dari folder proyek?', + 'workspace.openFromDesignFiles': 'Buka file dari', + 'workspace.designFilesLink': 'File desain', + 'workspace.loadingSketch': 'Memuat sketsa...', + + 'designFiles.title': 'File desain', + 'designFiles.upload': 'Upload file', + 'designFiles.pasteText': 'Tempel sebagai file teks', + 'designFiles.newSketch': 'Sketsa baru', + 'designFiles.empty': 'Belum ada file desain.', + 'designFiles.refresh': 'Refresh', + 'designFiles.delete': 'Hapus', + 'designFiles.searchPlaceholder': 'Cari file...', + 'designFiles.up': 'Naik', + 'designFiles.back': 'Kembali', + 'designFiles.crumbs': 'Proyek', + 'designFiles.rowMenu': 'Menu baris', + 'designFiles.openInTab': 'Buka di tab', + 'designFiles.download': 'Unduh', + 'designFiles.downloadSelected': 'Unduh {n} sebagai ZIP', + 'designFiles.clearSelection': 'Bersihkan', + 'designFiles.selectAll': 'Pilih semua', + 'designFiles.dropTitle': 'Lepaskan file di sini', + 'designFiles.dropDesc': 'Upload file desain, gambar, dokumen, atau aset lain ke proyek ini.', + 'designFiles.upload.title': 'Upload file', + 'designFiles.paste.title': 'Tempel teks sebagai file', + 'designFiles.upload.label': 'Upload', + 'designFiles.paste.label': 'Tempel', + 'designFiles.previewOpen': 'Buka', + 'designFiles.previewClose': 'Tutup pratinjau', + 'designFiles.modified': 'Diubah {time} - {size}', + 'designFiles.weeksAgo': '{n} minggu lalu', + 'designFiles.sectionPages': 'Halaman', + 'designFiles.sectionScripts': 'Skrip', + 'designFiles.sectionImages': 'Gambar', + 'designFiles.sectionSketches': 'Sketsa', + 'designFiles.sectionLiveArtifacts': 'Live artifact', + 'designFiles.sectionOther': 'Lainnya', + 'designFiles.showMore': 'Tampilkan +{n} lagi', + 'designFiles.kindHtml': 'Halaman HTML', + 'designFiles.kindImage': 'Gambar', + 'designFiles.kindSketch': 'Sketsa', + 'designFiles.kindText': 'Teks', + 'designFiles.kindCode': 'Skrip', + 'designFiles.kindPdf': 'PDF', + 'designFiles.kindDocument': 'Dokumen', + 'designFiles.kindPresentation': 'Presentasi', + 'designFiles.kindSpreadsheet': 'Spreadsheet', + 'designFiles.kindLiveArtifact': 'Live artifact', + 'designFiles.kindBinary': 'Biner', + + 'quickSwitcher.placeholder': 'Buka file...', + 'quickSwitcher.empty': 'Tidak ada file di proyek ini', + 'quickSwitcher.noMatches': 'Tidak ada yang cocok', + 'quickSwitcher.navigate': 'navigasi', + 'quickSwitcher.open': 'buka', + 'quickSwitcher.close': 'tutup', + + 'pasteDialog.title': 'Tempel teks', + 'pasteDialog.hint': 'Disimpan ke folder proyek. Pilih nama apa saja.', + 'pasteDialog.fileNameLabel': 'Nama berkas', + 'pasteDialog.namePlaceholder': 'catatan.txt', + 'pasteDialog.contentLabel': 'Konten', + 'pasteDialog.contentPlaceholder': 'Tempel apa saja...', + 'pasteDialog.save': 'Simpan', + 'pasteDialog.cancel': 'Batal', + + 'sketch.save': 'Simpan', + 'sketch.cancel': 'Batal', + 'sketch.saving': 'Menyimpan...', + 'sketch.tooltipDirty': 'Ada perubahan belum disimpan', + 'sketch.tooltipClean': 'Tersimpan', + + 'fileViewer.empty': 'Pilih file untuk dilihat.', + 'fileViewer.loading': 'Memuat file...', + 'fileViewer.exportPptx': 'Ekspor PPTX', + 'fileViewer.openInNewTab': 'Buka di tab baru', + 'fileViewer.copyPath': 'Salin path', + 'fileViewer.copied': 'Tersalin', + 'fileViewer.share': 'Bagikan', + 'fileViewer.binaryMeta': 'Biner - {size}', + 'fileViewer.binaryNote': 'Berkas biner ({size} byte). Unduh atau buka dari disk untuk memeriksanya.', + 'fileViewer.pdfMeta': 'PDF - {size}', + 'fileViewer.documentMeta': 'Dokumen', + 'fileViewer.presentationMeta': 'Presentasi', + 'fileViewer.spreadsheetMeta': 'Spreadsheet', + 'fileViewer.previewUnavailable': 'Pratinjau tidak tersedia untuk file ini.', + 'fileViewer.download': 'Unduh', + 'fileViewer.open': 'Buka', + 'fileViewer.imageMeta': 'Gambar - {size}', + 'fileViewer.reactMeta': 'Komponen React - {size}', + 'fileViewer.sketchMeta': 'Sketsa - {size}', + 'fileViewer.markdownStreamingMeta': 'Memuat pratinjau...', + 'fileViewer.markdownErrorMeta': 'Pratinjau mungkin belum lengkap (error generasi).', + 'fileViewer.markdownStreamingStatus': 'Memuat... menampilkan markdown sebagian.', + 'fileViewer.markdownErrorStatus': 'Error generasi. Menampilkan konten terakhir yang tersedia.', + 'fileViewer.videoMeta': 'Video - {size}', + 'fileViewer.audioMeta': 'Audio - {size}', + 'fileViewer.reload': 'Muat ulang', + 'fileViewer.reloadDisk': 'Muat ulang dari disk', + 'fileViewer.copy': 'Salin', + 'fileViewer.copyTitle': 'Salin konten', + 'fileViewer.saveDisabled': 'Tidak ada perubahan untuk disimpan', + 'fileViewer.save': 'Simpan', + 'fileViewer.preview': 'Pratinjau', + 'fileViewer.source': 'Sumber', + 'fileViewer.tweaks': 'Tweaks', + 'fileViewer.comment': 'Komentar', + 'fileViewer.edit': 'Edit', + 'fileViewer.draw': 'Gambar', + + 'manualEdit.layers': 'Lapisan', + 'manualEdit.editableCount': '{count} dapat diedit', + 'manualEdit.title': 'Editor manual', + 'manualEdit.selectLayer': 'Pilih lapisan', + 'manualEdit.empty': 'Klik elemen di pratinjau atau pilih lapisan.', + 'manualEdit.noClass': 'tanpa class', + 'manualEdit.tabsAria': 'Tab edit manual', + 'manualEdit.tabContent': 'Konten', + 'manualEdit.tabStyle': 'Gaya', + 'manualEdit.tabAttributes': 'Atribut', + 'manualEdit.tabHtml': 'HTML', + 'manualEdit.tabSource': 'Sumber', + 'manualEdit.attributesJson': 'JSON atribut', + 'manualEdit.selectedHtml': 'HTML elemen terpilih', + 'manualEdit.fullSource': 'Sumber artifact lengkap', + 'manualEdit.applyContent': 'Terapkan konten', + 'manualEdit.applyStyle': 'Terapkan gaya', + 'manualEdit.applyAttributes': 'Terapkan atribut', + 'manualEdit.applyHtml': 'Terapkan HTML', + 'manualEdit.applySource': 'Terapkan sumber', + 'manualEdit.invalidAttributes': 'JSON atribut tidak valid.', + 'manualEdit.changes': 'Perubahan', + 'manualEdit.undo': 'Undo', + 'manualEdit.redo': 'Redo', + 'manualEdit.noChanges': 'Belum ada edit manual.', + 'manualEdit.imageUrl': 'URL gambar', + 'manualEdit.altText': 'Teks alt', + 'manualEdit.label': 'Label', + 'manualEdit.text': 'Teks', + 'manualEdit.href': 'Href', + 'manualEdit.textColor': 'Warna teks', + 'manualEdit.background': 'Latar belakang', + 'manualEdit.fontSize': 'Ukuran font', + 'manualEdit.weight': 'Bobot', + 'manualEdit.align': 'Rata', + 'manualEdit.padding': 'Padding', + 'manualEdit.margin': 'Margin', + 'manualEdit.radius': 'Radius', + 'manualEdit.border': 'Border', + 'manualEdit.width': 'Lebar', + 'manualEdit.minHeight': 'Tinggi minimum', + + 'fileViewer.zoomOut': 'Perkecil', + 'fileViewer.zoomIn': 'Perbesar', + 'fileViewer.resetZoom': 'Atur ulang zoom', + 'fileViewer.reloadAria': 'Muat ulang file', + 'fileViewer.previousSlide': 'Slide sebelumnya', + 'fileViewer.nextSlide': 'Slide berikutnya', + 'fileViewer.slideNavAria': 'Navigasi slide', + 'fileViewer.present': 'Presentasikan', + 'fileViewer.presentInTab': 'Presentasikan di tab', + 'fileViewer.presentFullscreen': 'Presentasi layar penuh', + 'fileViewer.presentNewTab': 'Presentasi di tab baru', + 'fileViewer.exitPresentation': 'Keluar presentasi', + 'fileViewer.shareLabel': 'Bagikan', + 'fileViewer.exportPdf': 'Ekspor PDF', + 'fileViewer.exportPdfAllSlides': 'Ekspor PDF semua slide', + 'fileViewer.exportPptxBusy': 'Mengekspor PPTX...', + 'fileViewer.exportPptxHint': 'Buat deck terlebih dahulu untuk mengekspor PPTX.', + 'fileViewer.exportPptxNa': 'PPTX tidak tersedia', + 'fileViewer.exportZip': 'Ekspor ZIP', + 'fileViewer.exportHtml': 'Ekspor HTML', + 'fileViewer.exportMd': 'Ekspor Markdown', + 'fileViewer.exportJsx': 'Ekspor JSX', + 'fileViewer.exportReactHtml': 'Ekspor React HTML', + 'fileViewer.saveAsTemplate': 'Simpan sebagai templat', + 'fileViewer.savingTemplate': 'Menyimpan templat...', + 'fileViewer.savedTemplate': 'Disimpan sebagai "{name}"', + 'fileViewer.savedTemplateFail': 'Gagal menyimpan templat', + 'fileViewer.templateNamePrompt': 'Nama templat', + 'fileViewer.templateNameDefault': 'Templat baru', + 'fileViewer.templateDescPrompt': 'Deskripsi templat', + + 'liveArtifact.refresh.button': 'Refresh', + 'liveArtifact.refresh.buttonTitle': 'Refresh live artifact ini', + 'liveArtifact.refresh.loadingTitle': 'Memuat live artifact...', + 'liveArtifact.refresh.noSourceTitle': 'Belum ada sumber refresh yang tersedia.', + 'liveArtifact.refresh.running': 'Memperbarui...', + 'liveArtifact.refresh.runningMessage': 'Memperbarui data dan pratinjau. Ini bisa butuh waktu sebentar.', + 'liveArtifact.refresh.runningAction': 'Pratinjau sebelumnya tetap terlihat sampai refresh berhasil.', + 'liveArtifact.refresh.successOne': 'Refresh selesai. Data diperbarui.', + 'liveArtifact.refresh.successMany': 'Refresh selesai. Data diperbarui.', + 'liveArtifact.refresh.successAction': 'Pratinjau sudah dimuat ulang dengan data committed terbaru.', + 'liveArtifact.refresh.previousFailure': 'Refresh sebelumnya gagal: {message}', + 'liveArtifact.refresh.failureAction': 'Periksa riwayat refresh, perbaiki sumber atau masalah izin, lalu coba lagi.', + 'liveArtifact.refresh.networkFailure': 'Permintaan refresh gagal. Periksa koneksi lalu coba lagi.', + 'liveArtifact.refresh.genericFailure': 'Refresh gagal.', + 'liveArtifact.refresh.statusNever': 'Tidak bisa di-refresh', + 'liveArtifact.refresh.statusReady': 'Siap di-refresh', + 'liveArtifact.refresh.statusSucceeded': 'Sudah terbaru', + 'liveArtifact.refresh.statusFailed': 'Refresh gagal', + + 'fileViewer.deployToVercel': 'Deploy ke Vercel', + 'fileViewer.redeployToVercel': 'Deploy ulang ke Vercel', + 'fileViewer.deployingToVercel': 'Deploying ke Vercel...', + 'fileViewer.preparingPublicLink': 'Menyiapkan link publik...', + 'fileViewer.copyDeployLink': 'Salin link deploy', + 'fileViewer.deployModalTitle': 'Deploy ke Vercel', + 'fileViewer.deployModalSubtitle': 'Masukkan token Vercel untuk membuat link publik.', + 'fileViewer.vercelToken': 'Token Vercel', + 'fileViewer.vercelTokenGetLink': 'Buat token', + 'fileViewer.vercelTokenPlaceholder': 'Tempel token Vercel', + 'fileViewer.vercelTokenReuseHint': 'Token disimpan lokal untuk deploy berikutnya.', + 'fileViewer.vercelTokenRequired': 'Token Vercel wajib diisi.', + 'fileViewer.vercelTeamId': 'Team ID Vercel', + 'fileViewer.vercelTeamSlug': 'Team slug Vercel', + 'fileViewer.optional': 'opsional', + 'fileViewer.vercelPreviewOnly': 'Buat preview deployment saja', + 'fileViewer.savingConfig': 'Menyimpan konfigurasi...', + 'fileViewer.deployConfigSaveFailed': 'Gagal menyimpan konfigurasi deploy.', + 'fileViewer.deployFailed': 'Deploy gagal.', + 'fileViewer.deployResultLabel': 'Hasil deploy', + 'fileViewer.deployLinkPreparingLabel': 'Link deploy sedang disiapkan', + 'fileViewer.deployLinkDelayed': 'Link publik belum siap. Coba lagi sebentar lagi.', + 'fileViewer.deployLinkProtectedLabel': 'Deployment dilindungi', + 'fileViewer.deployLinkProtected': 'Vercel meminta autentikasi untuk membuka link ini.', + 'fileViewer.retryLink': 'Coba link lagi', + + 'questionForm.submit': 'Kirim', + 'questionForm.skip': 'Lewati', + 'questionForm.locked': 'Terkunci', + + 'conv.switch': 'Ganti percakapan', + 'conv.label': 'Percakapan', + 'conv.heading': 'Percakapan', + 'conv.new': 'Baru', + 'conv.empty': 'Belum ada percakapan.', + 'conv.untitled': 'Tanpa judul', + 'conv.renameTooltip': 'Ganti nama percakapan', + 'conv.delete': 'Hapus percakapan', + 'conv.deleteConfirm': 'Hapus "{title}"? Semua pesannya ikut dihapus.', + + 'agentPicker.label': 'Agent', + 'agentPicker.modeChoose': 'Pilih mode', + 'agentPicker.localCli': 'CLI lokal', + 'agentPicker.daemonOff': 'Daemon mati', + 'agentPicker.byok': 'BYOK', + 'agentPicker.selectAgent': 'Pilih agent', + 'agentPicker.noAgents': 'Tidak ada agent', + 'agentPicker.notInstalled': 'Belum terpasang', + 'agentPicker.rescan': 'Pindai ulang', + + 'tool.openInTab': 'Buka {name} di tab', + 'tool.open': 'Buka', + 'tool.todos': 'Todo', + 'tool.write': 'Tulis', + 'tool.edit': 'Edit', + 'tool.read': 'Baca', + 'tool.bash': 'Bash', + 'tool.glob': 'Glob', + 'tool.grep': 'Grep', + 'tool.fetch': 'Fetch', + 'tool.search': 'Cari', + 'tool.lines': '{n} baris', + 'tool.changeSingular': 'perubahan', + 'tool.changePlural': 'perubahan', + 'tool.in': 'di {path}', + 'tool.hide': 'Sembunyikan', + 'tool.output': 'Output', + 'tool.running': 'Berjalan', + 'tool.error': 'Error', + 'tool.done': 'Selesai', + + 'assistant.role': 'Asisten', + 'assistant.workingLabel': 'Sedang bekerja', + 'assistant.doneLabel': 'Selesai', + 'assistant.unfinishedLabel': 'Belum selesai', + 'assistant.unfinishedSummary': '{n} tugas tersisa', + 'assistant.unfinishedMore': '+{n} lagi', + 'assistant.continueRemaining': 'Lanjutkan', + 'assistant.outTokens': '{n} keluar', + 'assistant.producedFiles': 'File yang dibuat', + 'assistant.openFile': 'Buka file', + 'assistant.downloadFile': 'Unduh file', + 'assistant.thinking': 'Berpikir...', + 'assistant.systemReminder': 'Pengingat sistem', + 'assistant.waitingFirstOutput': 'Menunggu output pertama...', + 'assistant.statusBootingAgent': 'Menyalakan agent...', + 'assistant.statusStarting': 'Memulai...', + 'assistant.statusRequesting': 'Mengirim permintaan...', + 'assistant.statusThinking': 'Berpikir...', + 'assistant.statusStreaming': 'Memuat...', + 'assistant.slowHint': 'Ini mungkin butuh waktu sebentar.', + 'assistant.verbEditing': 'mengedit', + 'assistant.verbWriting': 'menulis', + 'assistant.verbReading': 'membaca', + 'assistant.verbSearching': 'mencari', + 'assistant.verbRunning': 'menjalankan', + 'assistant.verbTodos': 'memperbarui todo', + 'assistant.verbFetching': 'mengambil', + 'assistant.verbCalling': 'memanggil', + + 'qf.answered': 'Terjawab', + 'qf.choose': 'Pilih', + 'qf.required': 'Wajib', + 'qf.lockedSubmitted': 'Jawaban terkunci setelah dikirim.', + 'qf.lockedPrev': 'Jawaban sebelumnya', + 'qf.hint': 'Pilih opsi atau isi jawaban singkat.', + 'qf.submitDefault': 'Kirim jawaban', + 'qf.submitDisabledTitle': 'Lengkapi pertanyaan wajib dulu.', + 'qf.submitTitle': 'Kirim jawaban', + 'qf.cardSelected': 'Dipilih', + 'qf.cardRefs': 'Referensi', + 'qf.cardSampleText': 'Contoh teks', + + 'sketch.toolSelect': 'Pilih', + 'sketch.toolPen': 'Pena', + 'sketch.toolText': 'Teks', + 'sketch.toolRect': 'Kotak', + 'sketch.toolArrow': 'Panah', + 'sketch.toolEraser': 'Penghapus', + 'sketch.color': 'Warna', + 'sketch.strokeSize': 'Ukuran garis', + 'sketch.undo': 'Undo', + 'sketch.clear': 'Bersihkan', + 'sketch.close': 'Tutup', + 'sketch.textPrompt': 'Teks', + + 'pet.title': 'Teman kerja', + 'pet.subtitle': 'Pilih teman kecil untuk melayang di workspace.', + 'pet.navTitle': 'Pets', + 'pet.navHint': 'Pilih teman untuk melayang di workspace.', + 'pet.tabBuiltIn': 'Bawaan', + 'pet.tabBuiltInHint': 'Pet pilihan yang disertakan dengan Open Design - pilih satu lalu adopsi.', + 'pet.builtInEmpty': 'Pet bawaan belum tersedia. Coba refresh tab Komunitas setelah daemon online.', + 'pet.tabCustom': 'Kustom', + 'pet.tabCustomHint': 'Buat sendiri dengan nama, glyph, warna, atau sprite.', + 'pet.tabCommunity': 'Komunitas', + 'pet.tabCommunityHint': 'Pet hasil hatch dari Codex - adopsi satu atau buat yang baru.', + 'pet.tabsAria': 'Sumber pet', + 'pet.adopt': 'Adopsi pet', + 'pet.adoptedBadge': 'Diadopsi', + 'pet.adoptCallout': 'Pet aktif akan muncul di workspace.', + 'pet.changePet': 'Ganti pet', + 'pet.wake': 'Bangunkan', + 'pet.tuck': 'Tidurkan', + 'pet.wakeTitle': 'Tampilkan pet', + 'pet.tuckTitle': 'Sembunyikan pet', + 'pet.settingsTitle': 'Kustomisasi pet', + 'pet.useCustom': 'Gunakan kustom', + 'pet.customTitle': 'Kustom Pet', + 'pet.customHint': 'Buat nama, simbol, dan sapaan sendiri.', + 'pet.customGreetingPlaceholder': 'Halo, aku siap membantu.', + 'pet.fieldName': 'Nama', + 'pet.fieldGlyph': 'Glyph', + 'pet.fieldGlyphHint': 'Satu karakter atau simbol singkat.', + 'pet.fieldGreeting': 'Sapaan', + 'pet.fieldAccent': 'Aksen', + 'pet.fieldAccentCustom': 'Kustom', + 'pet.overlayAria': 'Overlay pet', + 'pet.spriteAria': '{name} - geser untuk memindahkan, klik untuk chat', + 'pet.spriteTitle': 'Halo dari {name}! Klik untuk chat.', + 'pet.railAria': 'Panel pet', + 'pet.railTitle': 'Pets', + 'pet.railHint': 'Pilih teman untuk melayang di workspace.', + 'pet.railExpand': 'Perluas panel pet', + 'pet.railCollapse': 'Ciutkan panel pet', + 'pet.railHide': 'Sembunyikan panel pet', + 'pet.railShow': 'Tampilkan panel pet', + 'pet.railCustomFlavor': 'Punyamu sendiri - nama, glyph, warna.', + 'pet.railCustomize': 'Kustomisasi...', + 'pet.composerTitle': 'Pet', + 'pet.composerMenuTitle': 'Perintah pet', + 'pet.composerMenuHint': 'Kelola pet dari composer.', + 'pet.composerOpenSettings': 'Buka pengaturan pet', + 'pet.welcomeTeaserTitle': 'Tambahkan teman kecil', + 'pet.welcomeTeaserBody': 'Pet bisa menemani workspace saat agent bekerja.', + 'pet.welcomeTeaserCta': 'Pilih pet', + 'pet.imageUpload': 'Upload sprite', + 'pet.imageReplace': 'Ganti sprite', + 'pet.imageRemove': 'Gunakan emoji', + 'pet.imageHintIdle': 'PNG, JPG, WebP, GIF, atau SVG. Upload sheet? Letakkan strip horizontal dan atur jumlah frame.', + 'pet.imageHintActive': 'Sprite kamu sedang ditampilkan. Atur frame > 1 untuk menjalankan spritesheet horizontal.', + 'pet.fieldFrames': 'Frame', + 'pet.fieldFramesHint': '1 = statis. > 1 = spritesheet horizontal.', + 'pet.fieldFps': 'Kecepatan (fps)', + 'pet.fieldFpsHint': 'Seberapa cepat frame berganti.', + 'pet.atlasImport': 'Impor sprite Codex', + 'pet.atlasImportTitle': 'Impor atlas hatch-pet 8x9 / 192x208 (PNG atau WebP).', + 'pet.atlasPickerTitle': 'Pilih baris animasi', + 'pet.atlasPickerHint': + 'Pet Codex memiliki 9 baris animasi. Secara default, atlas penuh dipertahankan agar pet mengganti baris saat hover, drag, dan idle. Kamu juga bisa membekukannya ke satu loop.', + 'pet.atlasCancel': 'Buang atlas', + 'pet.atlasAdopt': 'Bekukan ke baris ini', + 'pet.atlasAdoptFull': 'Gunakan atlas penuh (animasi)', + 'pet.atlasAdoptFullTitle': 'Pertahankan semua baris agar pet bereaksi terhadap hover, arah drag, dan idle lama.', + 'pet.atlasAdoptRowTitle': 'Potong baris yang disorot menjadi satu strip loop.', + 'pet.atlasActiveHint': 'Atlas animasi aktif - pet memilih baris dari interaksimu (hover, drag, idle).', + 'pet.atlasRow.idle': 'Idle', + 'pet.atlasRow.running-right': 'Lari kanan', + 'pet.atlasRow.running-left': 'Lari kiri', + 'pet.atlasRow.waving': 'Melambai', + 'pet.atlasRow.jumping': 'Melompat', + 'pet.atlasRow.failed': 'Gagal', + 'pet.atlasRow.waiting': 'Menunggu', + 'pet.atlasRow.running': 'Berjalan', + 'pet.atlasRow.review': 'Review', + 'pet.hatchTitle': 'Hatch pet baru dengan AI', + 'pet.hatchHint': 'Gunakan skill hatch-pet bawaan di chat untuk membuat spritesheet bergaya Codex, lalu impor di sini.', + 'pet.hatchConcept': 'Konsep pet (opsional)', + 'pet.hatchConceptPlaceholder': 'mis. shiba pixel-art kecil memakai sweater nyaman', + 'pet.hatchCopy': 'Salin prompt', + 'pet.hatchCopied': 'Tersalin!', + 'pet.hatchFoot': 'Setelah skill menyimpan pet, kembali ke sini dan pilih "Impor sprite Codex".', + 'pet.slashPopoverAria': 'Perintah slash', + 'pet.slashPopoverTitle': 'Perintah', + 'pet.slashPopoverHint': 'atas/bawah untuk navigasi - enter untuk pilih - esc untuk tutup', + 'pet.slashPet': 'Toggle, adopsi, atau buka pengaturan pet.', + 'pet.slashPetWake': 'Bangunkan overlay pet melayang.', + 'pet.slashPetTuck': 'Sembunyikan pet untuk sekarang.', + 'pet.slashHatch': 'Buat pet Codex lewat skill hatch-pet.', + 'pet.slashHatchArg': '', + 'pet.codexTitle': 'Baru di-hatch', + 'pet.codexSubtitle': 'Pet yang dikemas oleh skill hatch-pet muncul di sini untuk adopsi sekali klik.', + 'pet.codexSubtitleWithDir': 'Memindai {dir} untuk pet yang dikemas oleh skill hatch-pet.', + 'pet.codexEmpty': 'Belum ada pet hasil hatch. Ketik /hatch di chat untuk membuat satu.', + 'pet.codexLoading': 'Mencari pet hasil hatch...', + 'pet.codexRefresh': 'Refresh', + 'pet.codexAdopt': 'Adopsi', + 'pet.codexAdopting': 'Mengadopsi...', + 'pet.communitySync': 'Unduh pet komunitas', + 'pet.communitySyncing': 'Mengunduh...', + 'pet.communitySyncTitle': 'Sinkronkan pet terbaru dari Codex Pet Share + j20 Hatchery ke ~/.codex/pets/.', + 'pet.communitySyncDone': 'Tersinkron {wrote} pet baru ({total} total).', + 'pet.communitySyncFailed': 'Sinkronisasi gagal: {error}', + 'pet.codexBundled': 'Bawaan', + 'pet.codexBundledTitle': 'Disertakan dengan Open Design - tidak perlu diunduh.', + + 'settings.notifications': 'Notifikasi', + 'settings.notificationsHint': 'Atur suara dan notifikasi desktop.', + 'settings.notifyCompletionSound': 'Suara saat selesai', + 'settings.notifyCompletionSoundHint': 'Putar suara ketika generasi selesai.', + 'settings.notifySuccessSound': 'Suara berhasil', + 'settings.notifyFailureSound': 'Suara gagal', + 'settings.notifyDesktop': 'Notifikasi desktop', + 'settings.notifyDesktopHint': 'Tampilkan notifikasi sistem saat generasi selesai.', + 'settings.notifyDesktopBlocked': 'Notifikasi diblokir oleh browser.', + 'settings.notifyDesktopUnsupported': 'Browser ini tidak mendukung notifikasi desktop.', + 'settings.notifyTest': 'Tes notifikasi', + 'settings.notifyTestSent': 'Notifikasi tes terkirim.', + 'settings.notifyTestFailed': 'Gagal mengirim notifikasi tes.', + 'settings.notifySoundDing': 'Ding', + 'settings.notifySoundChime': 'Chime', + 'settings.notifySoundTwoToneUp': 'Dua nada naik', + 'settings.notifySoundPluck': 'Pluck', + 'settings.notifySoundBuzz': 'Buzz', + 'settings.notifySoundTwoToneDown': 'Dua nada turun', + 'settings.notifySoundThud': 'Thud', + 'settings.library': 'Skill & Sistem Desain', + 'settings.libraryHint': 'Jelajahi, pratinjau, dan aktifkan/nonaktifkan library kontenmu', + 'settings.librarySkills': 'Skill', + 'settings.libraryDesignSystems': 'Sistem desain', + 'settings.librarySearch': 'Cari...', + 'settings.libraryAll': 'Semua', + 'settings.libraryPreview': 'Pratinjau', + 'settings.libraryPreviewClose': 'Tutup', + 'settings.libraryLoading': 'Memuat...', + 'settings.libraryNoResults': 'Tidak ada item yang cocok dengan pencarianmu.', + 'settings.libraryEnabled': 'Aktif', + 'settings.libraryDisabled': 'Nonaktif', + 'settings.libraryToggleLabel': 'Toggle', + + 'notify.successTitle': 'Pembuatan selesai', + 'notify.failureTitle': 'Pembuatan gagal', + 'notify.successBody': 'Artifact siap dilihat.', + 'notify.failureBody': 'Cek chat untuk detail error.', +}; diff --git a/apps/web/src/i18n/types.ts b/apps/web/src/i18n/types.ts index be883310ec..a73c52cb62 100644 --- a/apps/web/src/i18n/types.ts +++ b/apps/web/src/i18n/types.ts @@ -1,11 +1,12 @@ // Supported UI locales. Adding a new locale requires creating a new // dictionary in `./locales/` and registering it in `./index.tsx`. -export type Locale = 'en' | 'de' | 'zh-CN' | 'zh-TW' | 'pt-BR' | 'es-ES' | 'ru' | 'fa' | 'ar' | 'ja' | 'ko' | 'pl' | 'hu' | 'fr' | 'uk' | 'tr'; +export type Locale = 'en' | 'id' | 'de' | 'zh-CN' | 'zh-TW' | 'pt-BR' | 'es-ES' | 'ru' | 'fa' | 'ar' | 'ja' | 'ko' | 'pl' | 'hu' | 'fr' | 'uk' | 'tr'; -export const LOCALES: Locale[] = ['en', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa', 'ar', 'ja', 'ko', 'pl', 'hu', 'fr', 'uk', 'tr']; +export const LOCALES: Locale[] = ['en', 'id', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa', 'ar', 'ja', 'ko', 'pl', 'hu', 'fr', 'uk', 'tr']; export const LOCALE_LABEL: Record = { 'en': 'English', + 'id': 'Bahasa Indonesia', 'de': 'Deutsch', 'zh-CN': '简体中文', 'zh-TW': '繁體中文', diff --git a/apps/web/tests/i18n/design-files-agent-copy.test.ts b/apps/web/tests/i18n/design-files-agent-copy.test.ts index 01793b28ef..83d22d6a6d 100644 --- a/apps/web/tests/i18n/design-files-agent-copy.test.ts +++ b/apps/web/tests/i18n/design-files-agent-copy.test.ts @@ -5,6 +5,7 @@ import { en } from '../../src/i18n/locales/en'; import { esES } from '../../src/i18n/locales/es-ES'; import { fa } from '../../src/i18n/locales/fa'; import { fr } from '../../src/i18n/locales/fr'; +import { id } from '../../src/i18n/locales/id'; import { ja } from '../../src/i18n/locales/ja'; import { ptBR } from '../../src/i18n/locales/pt-BR'; import { ru } from '../../src/i18n/locales/ru'; @@ -17,6 +18,7 @@ const LOCALE_DICTS = { esES, fa, fr, + id, ja, ptBR, ru, diff --git a/apps/web/tests/i18n/design-files-dropzone-copy.test.ts b/apps/web/tests/i18n/design-files-dropzone-copy.test.ts index bb77cf162f..3b9042088a 100644 --- a/apps/web/tests/i18n/design-files-dropzone-copy.test.ts +++ b/apps/web/tests/i18n/design-files-dropzone-copy.test.ts @@ -5,6 +5,7 @@ import { en } from '../../src/i18n/locales/en'; import { esES } from '../../src/i18n/locales/es-ES'; import { fa } from '../../src/i18n/locales/fa'; import { fr } from '../../src/i18n/locales/fr'; +import { id } from '../../src/i18n/locales/id'; import { ja } from '../../src/i18n/locales/ja'; import { ptBR } from '../../src/i18n/locales/pt-BR'; import { ru } from '../../src/i18n/locales/ru'; @@ -17,6 +18,7 @@ const LOCALE_DICTS = { esES, fa, fr, + id, ja, ptBR, ru, diff --git a/apps/web/tests/i18n/locales.test.ts b/apps/web/tests/i18n/locales.test.ts index 18e044008e..c708989c9a 100644 --- a/apps/web/tests/i18n/locales.test.ts +++ b/apps/web/tests/i18n/locales.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { en } from '../../src/i18n/locales/en'; import { LOCALES, LOCALE_LABEL, type Dict, type Locale } from '../../src/i18n/types'; -const EXPECTED_LOCALES = ['en', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa', 'ar', 'ja', 'ko', 'pl', 'hu', 'fr', 'uk', 'tr']; +const EXPECTED_LOCALES = ['en', 'id', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa', 'ar', 'ja', 'ko', 'pl', 'hu', 'fr', 'uk', 'tr']; function placeholders(value: string): string[] { const names: string[] = []; @@ -28,6 +28,7 @@ async function loadDict(locale: Locale): Promise { describe('i18n locales', () => { it('registers every supported locale in the language menu', () => { expect(LOCALES).toEqual(EXPECTED_LOCALES); + expect((LOCALE_LABEL as Record).id).toBe('Bahasa Indonesia'); expect((LOCALE_LABEL as Record).de).toBe('Deutsch'); expect((LOCALE_LABEL as Record).ja).toBe('日本語'); });