Expand AITURK Turkish settings and desktop surfaces for beta 5

This commit is contained in:
2026-09-06 05:03:32 +03:00
parent 237d1e2060
commit 5e76f58637
108 changed files with 6675 additions and 1034 deletions
+12 -12
View File
@@ -30,15 +30,15 @@ describe('I18nProvider', () => {
vi.restoreAllMocks()
})
it('defaults to English without a config client', () => {
it('defaults to Turkish without a config client', () => {
render(
<I18nProvider configClient={null}>
<LanguageProbe />
</I18nProvider>
)
expect(screen.getByTestId('locale').textContent).toBe('en')
expect(screen.getByTestId('label').textContent).toBe('Language')
expect(screen.getByTestId('locale').textContent).toBe('tr')
expect(screen.getByTestId('label').textContent).toBe('Dil')
})
it('normalizes an initial locale alias and switches translations', async () => {
@@ -76,7 +76,7 @@ describe('I18nProvider', () => {
expect(configClient.saveConfig).not.toHaveBeenCalled()
})
it('keeps English usable when config loading fails', async () => {
it('keeps Turkish usable when config loading fails', async () => {
const configClient: I18nConfigClient = {
getConfig: vi.fn().mockRejectedValue(new Error('config unavailable')),
saveConfig: vi.fn()
@@ -90,8 +90,8 @@ describe('I18nProvider', () => {
await waitFor(() => expect(screen.getByTestId('loading').textContent).toBe('false'))
expect(screen.getByTestId('locale').textContent).toBe('en')
expect(screen.getByTestId('label').textContent).toBe('Language')
expect(screen.getByTestId('locale').textContent).toBe('tr')
expect(screen.getByTestId('label').textContent).toBe('Dil')
expect(configClient.saveConfig).not.toHaveBeenCalled()
})
@@ -147,8 +147,8 @@ describe('I18nProvider', () => {
await waitFor(() => expect(screen.getByTestId('loading').textContent).toBe('false'))
expect(screen.getByTestId('locale').textContent).toBe('en')
expect(screen.getByTestId('label').textContent).toBe('Language')
expect(screen.getByTestId('locale').textContent).toBe('tr')
expect(screen.getByTestId('label').textContent).toBe('Dil')
expect(configClient.saveConfig).not.toHaveBeenCalled()
})
@@ -217,14 +217,14 @@ describe('I18nProvider', () => {
)
expect(screen.getByTestId('locale').textContent).toBe('ar')
expect(document.documentElement.dir).toBe('rtl')
expect(document.documentElement.lang).toBe('ar')
expect(window.document.documentElement.dir).toBe('rtl')
expect(window.document.documentElement.lang).toBe('ar')
fireEvent.click(screen.getByRole('button', { name: 'switch' }))
await waitFor(() => expect(screen.getByTestId('locale').textContent).toBe('en'))
expect(document.documentElement.dir).toBe('ltr')
expect(document.documentElement.lang).toBe('en')
expect(window.document.documentElement.dir).toBe('ltr')
expect(window.document.documentElement.lang).toBe('en')
})
it('rolls back the visible locale when saving fails', async () => {
+168
View File
@@ -0,0 +1,168 @@
export const EN_BILLING = {
retryAfter: (minutes: number) => ` (try again in ~${minutes} min)`,
rateLimited: (suffix: string) => `🟡 Too many charges right now${suffix}. This isn't a payment failure.`,
stripeRetry: (suffix: string) => `Stripe is having trouble — try again shortly${suffix}`,
reauthorize: (who: string) => `${who} Reconnect from Settings → Gateway to re-authorize this device.`,
noSavedCardMessage:
"💳 No saved card for terminal charges yet. Set one up on the portal (one-time credit buys don't save a reusable card).",
monthlyRemaining: (amount: string) => `🔴 Monthly spend cap reached — $${amount} headroom left.`,
chargeAdded: (amount: string) => `$${amount} added.`,
unconfirmed: (message: string) =>
`${message} Your last charge's outcome is unconfirmed - check your balance/history before retrying.`,
chargeFailed: (reason: string) => `The charge didn't go through (${reason}).`,
invalidAmount: (label: string) => `${label}: enter a dollar amount with at most 2 decimal places.`,
positiveAmount: (label: string) => `${label}: amount must be greater than $0.`,
minAmount: (label: string, amount: string) => `${label}: minimum is ${amount}.`,
maxAmount: (label: string, amount: string) => `${label}: maximum is ${amount}.`,
confirmCardMessage: 'Confirm this card for terminal charges in the portal',
confirmCardTitle: 'Card confirmation needed',
spendingApprovalMessage: 'This needs Remote Spending allowed. Start a top-up to allow it, then retry.',
spendingApprovalTitle: 'Remote Spending needs approval',
adminRevoked: 'An admin stopped remote spending for this terminal.',
userRevoked: 'You stopped remote spending for this terminal.',
spendingRevoked: 'Remote spending was stopped',
sessionRevokedMessage: 'Your session was logged out. Sign in again from Settings → Gateway.',
sessionRevokedTitle: 'Session logged out',
spendingDisabledMessage:
"Remote spending is off for this account — a billing admin can turn it on from the portal's Hermes Agent page.",
spendingDisabledTitle: 'Remote spending is off',
adminRequiredMessage: 'Adding funds needs an org admin/owner. Ask an admin, or manage on the portal.',
adminRequiredTitle: 'Admin role required',
conflictingChargeMessage: '🔴 That charge key was already used for a different amount. Start a fresh top-up.',
conflictingChargeTitle: 'Start a fresh top-up',
noSavedCard: 'No saved card',
orgDeniedMessage: "This token isn't bound to an org you can manage",
orgDeniedTitle: 'Org access denied',
monthlyReached: '🔴 Monthly spend cap reached.',
monthlyReachedTitle: 'Monthly spend cap reached',
rateLimitedTitle: 'Too many charges right now',
stripeTitle: 'Stripe is having trouble',
dailyLimitMessage: 'Daily plan-change limit reached — try again tomorrow',
dailyLimitTitle: 'Daily plan-change limit reached',
endpointMessage: 'Billing endpoint returned a non-JSON response (it may not be available on this deployment).',
endpointTitle: 'Billing endpoint unavailable',
requestTimeoutMessage: 'Billing request timed out.',
requestTimeoutTitle: 'Billing request timed out',
connectionFailedMessage: 'Billing request failed before reaching the gateway.',
connectionFailedTitle: 'Billing connection failed',
requestFailedMessage: 'Billing request failed.',
requestFailedTitle: 'Billing request failed',
creditsAdded: 'Credits added.',
chargeFailedTitle: 'Charge failed',
unconfirmedTitle: 'Charge outcome unconfirmed',
checkFailedMessage: 'Could not check the charge.',
checkFailedTitle: 'Could not check charge',
missingChargeId: 'The billing service accepted the request but did not return a charge id.',
untrackedTitle: 'Charge could not be tracked',
stillProcessingMessage: 'Charge may still settle. Check the portal before retrying.',
stillProcessingTitle: 'Still processing after 5 minutes',
bankVerification: 'Your bank requires verification (3DS). Complete it on the portal to finish this purchase.',
cardExpired: 'Your card has expired. Update it on the portal.',
cardDeclined: 'Your card was declined. Try another card on the portal.',
verificationDeniedMessage: 'Verification finished without allowing Remote Spending for this terminal.',
verificationDeniedTitle: 'Verification was not approved',
verificationDoneMessage: 'Remote Spending is allowed for this terminal.',
verificationDoneTitle: 'Verification complete',
reloadLabel: 'Reload-to',
reloadGreater: 'Reload-to amount must be greater than the threshold.',
formatDate: (date: Date) =>
new Intl.DateTimeFormat(undefined, { day: 'numeric', month: 'short', year: 'numeric' }).format(date),
monthSuffix: '/mo',
creditsMonthly: (amount: string) => `$${amount} credits/mo`,
alreadyPlan: (name: string) => `You are already on ${name} — nothing to change.`,
scheduledChange: (name: string, date: string, delta: string | null) =>
`Change to ${name} — takes effect ${date}. No charge now; you keep your current plan until then.${delta ? ` Monthly credits change: ${delta}.` : ''}`,
changesPlan: (name: string, date: string) => `Changes to ${name} on ${date}.`,
cancelsOn: (date: string) => `Cancels on ${date}.`,
renewsOn: (date: string) => `Renews ${date}`,
reconcileCard: (card: string) => `Auto-refill charges ${card} — reconcile on the portal`,
chargesBelow: (amount: string, threshold: string) =>
`Charges ${amount} automatically when your balance falls below ${threshold}.`,
remaining: (amount: string, total: string, over?: string) =>
`${amount} of ${total} left${over ? ` · ${over} over` : ''}`,
used: (amount: string, total: string) => `${amount} of ${total} used`,
resetsOn: (date: string) => `Resets ${date}`,
balanceAdded: (amount: string) => `${amount} added. Balance is refreshing.`,
usageLabel: (label: string) => `${label} usage`,
balance: 'Balance',
plan: 'Plan',
autoRefill: 'Auto-refill',
enabled: 'Enabled',
off: 'Off',
portalArrow: 'Open portal ↗',
portal: 'Open portal',
connectMessage: 'Run /portal in the TUI or open the Nous portal to connect your account.',
connectTitle: 'Connect your Nous account',
addCard: 'Add card ↗',
noCardMessage: 'Buying top-up credits and auto-refill stay disabled until a card is on file. Add one on the portal.',
noCardTitle: 'No payment method on file',
free: 'Free',
subscriptionUnavailable: 'Subscription details are unavailable; opening the portal is still available.',
noSubscription: 'No active subscription — paid models draw down top-up credits.',
changePlan: 'Change plan',
viewPlans: 'View plans',
adjustPlan: 'Adjust plan ↗',
choose: 'Choose ↗',
addPayment: 'Add payment method',
paymentMethod: 'Payment method',
update: 'Update',
manageCard: 'Manage the card used for top-ups and subscription renewals.',
buy: 'Buy',
buyDescription: 'A single charge on your card, added to your balance today.',
buyCredits: 'Buy credits now',
refillDescription: 'Keep your balance topped up when it drops below your threshold.',
manage: 'Manage',
manageRefill: 'Manage auto-refill from the portal.',
refillWhenLow: 'Refill when low',
turnOnRefill: 'Turn on auto-refill from the portal',
anotherCard: 'a different card',
reconcile: 'Reconcile ↗',
subscriptionRemaining: 'Subscription credits remaining',
subscriptionCredits: 'Subscription credits',
noExpiry: 'Does not expire',
topupCredits: 'Top-up credits',
capUsed: 'Monthly spend cap used',
defaultCeiling: 'Default ceiling',
monthlyRemoteSpending: 'Monthly remote spending',
monthlyCap: 'Monthly spend cap',
refillCard: 'auto-refill card',
customerDefault: 'customer default',
subscriptionCard: 'subscription card',
customCredit: 'Custom credit amount',
processing: 'Processing… checking settlement',
retry: 'Retry',
billing: 'Billing',
paymentCredits: 'Payment & credits',
usage: 'Usage',
invoices: 'Invoices',
undoing: 'Undoing…',
undo: 'Undo',
checkingChange: 'Checking this change…',
cannotChange: 'That change cannot be made here.',
cannotSchedule: 'This change cannot be scheduled here.',
tryAgain: 'Try again',
scheduling: 'Scheduling…',
confirmDowngrade: 'Confirm downgrade',
cancel: 'Cancel',
currentPlan: 'Current plan',
scheduled: 'Scheduled',
downgrade: 'Downgrade',
backBilling: 'Back to billing',
plans: 'Plans',
noPlans: 'No plans are available to change to right now.',
refillUpdated: 'Auto-refill updated.',
refillOff: 'Auto-refill turned off.',
threshold: 'Threshold',
reloadTo: 'Reload to',
refillThreshold: 'Auto-refill threshold',
refillAmount: 'Auto-refill reload-to amount',
turnOffQuestion: 'Turn off auto-refill?',
turnOff: 'Turn off',
disable: 'Disable',
saving: 'Saving…',
save: 'Save',
verificationPage: 'Open verification page',
dismiss: 'Dismiss',
waitingVerification: 'Waiting for verification link…',
verifyContinue: 'Verify to continue'
}
@@ -0,0 +1,105 @@
/** Settings copy formerly embedded directly in React components. */
export const EN_RUNTIME_SETTINGS = {
marketplaceThemes: 'From the VS Code Marketplace',
noMatchingThemes: (query: string) => `No installed themes match "${query}".`,
auxiliaryWarning: (count: number, tasks: string, provider: string) =>
`${count} auxiliary task${count === 1 ? '' : 's'} (${tasks}) still run on ${provider}, not your main model.`,
otherProviders: 'other providers',
pasteProviderKey: (key: string) => `Paste ${key}`,
apiKey: 'API key',
activatingProvider: 'Activating...',
activateProvider: 'Activate',
setupProvider: (provider: string) => `Set up ${provider}`,
provider: 'provider',
plugins: {
unavailable: 'Desktop plugins are unavailable',
resolveFailed: 'Could not resolve the plugins folder',
openFailed: 'Could not open the plugins folder',
unknownError: 'Unknown error',
noHome: 'The backend did not report its home directory'
},
moa: {
title: 'Mixture of Agents',
description:
'Configure named presets that appear as models under the Mixture of Agents provider. The aggregator is the acting model.',
preset: 'Preset',
enabled: 'Enabled',
setDefault: 'Set default',
newPreset: 'new preset',
addPreset: 'Add preset',
default: 'Default:',
reference: (index: number) => `Reference ${index}`,
toggleReference: (index: number, enabled: boolean) => `${enabled ? 'Enable' : 'Disable'} reference ${index}`,
addReference: 'Add reference model',
aggregator: 'Aggregator'
},
computerUse: {
linux: 'Drives your desktop via the X11/XWayland accessibility stack — no permission prompt.',
win32: 'First run may trigger a Windows SmartScreen prompt for the cua-driver UIAccess worker.',
granted: 'Granted',
notGranted: 'Not granted',
unknown: 'Unknown',
statusFailed: 'Could not read Computer Use status',
permissionsFailed: 'Could not request permissions',
approveTitle: 'Approve in System Settings',
approveBody: 'macOS will show a permission dialog attributed to CuaDriver. Approve it, then return here.',
checking: 'Checking Computer Use status…',
unsupported: (platform: string) => `Computer Use is not supported on this platform (${platform}).`,
install: 'Install the cua-driver backend below to drive this machine.',
installGrant: ' Then grant Accessibility and Screen Recording here.',
identity:
'Grants attach to CuaDrivers own identity (com.trycua.driver), so the dialog names the process that drives your Mac.',
recheck: 'Recheck',
accessibility: 'Accessibility',
accessibilityHint: 'Lets cua-driver post clicks, keystrokes, and read the accessibility tree.',
screenRecording: 'Screen Recording',
screenRecordingHint: 'Lets cua-driver capture screenshots of app windows.',
driverHealth: 'Driver health',
ready: 'Ready',
notReady: 'Not ready',
readyHint: 'Computer Use is ready. Ask the agent to capture an app and click around.',
waiting: 'Waiting for approval…',
grant: 'Grant permissions'
},
pool: {
warm: 'Warm Bot Backends',
warmHint:
'How many bot backends stay running for instant switching. Higher means faster switches and more memory (~60 MB per backend). Applies immediately.',
idle: 'Backend Idle Timeout',
idleAria: 'Backend idle timeout in milliseconds',
idleHint:
'How long an unused bot backend stays warm before it is shut down. Raise this so bots you revisit every few minutes avoid a cold start.'
},
memory: {
saveChanges: 'Save changes',
startFailed: 'Could not start the connection.',
timeout: 'Timed out — try again.',
connectionFailed: 'Connection failed.',
connectOauth: 'Connect via OAuth',
reconnect: 'Reconnect',
connect: 'Connect',
apiKeySet: 'API key set',
oauthSet: 'OAuth set',
waiting: 'Waiting for browser consent…',
loadFailed: 'Memory provider settings failed to load',
loading: 'Loading memory provider settings…',
saveFailed: (label: string) => `Failed to save ${label}`,
settings: (label: string) => `${label} settings`,
credentialStatus: (label: string, set: boolean) => `${label} ${set ? 'set' : 'not set'}`,
fullConfig: 'Full config…',
saved: (label: string) => `${label} saved`,
updated: 'Memory provider configuration updated.',
fullTitle: (label: string) => `${label} — full configuration`,
fullDescription: (label: string, profile: string) =>
`Every ${label} option for the ${profile} profile. Blank fields fall back to the resolved host or built-in default.`,
reference: (label: string) => `${label} configuration reference`,
other: 'Other',
about: (label: string) => `About ${label}`,
keepSecret: 'Leave blank to keep current value',
set: 'set'
},
themeSearch: 'Search your themes or the VS Code Marketplace…',
showOptions: 'Show options',
search: 'Search…',
noResults: 'No results found.'
}
+101
View File
@@ -0,0 +1,101 @@
/** Labels for secondary desktop surfaces and session filters. */
export const EN_SURFACES = {
pet: {
message: 'Message…',
openApp: 'Open in AITURK',
run: [
'working…',
'on it…',
'crunching…',
'tinkering…',
'cooking…',
'in the weeds…',
'wiring it up…',
'making moves…',
'heads down…',
'hammering away…'
],
review: [
'thinking…',
'reading…',
'reviewing…',
'pondering…',
'connecting dots…',
'sizing it up…',
'tracing it…',
'mulling…',
'scheming…',
'hmm…'
],
failed: ['hit a snag', 'welp', 'that broke', 'oof', 'snagged'],
waiting: ['your turn', 'all yours', 'over to you', 'balls in your court', 'awaiting orders']
},
filters: {
updated: 'Updated',
project: 'Project',
status: 'Status',
profile: 'Profile',
created: 'Created',
tokens: 'Tokens',
cost: 'Cost',
manual: 'Manual',
preview: 'Preview',
pr: 'PR',
open: 'Open',
draft: 'Draft',
merged: 'Merged',
closed: 'Closed',
noPr: 'No PR',
needsInput: 'Needs input',
working: 'Working',
unread: 'Unread',
idle: 'Idle',
filters: 'Filters',
grouping: 'Grouping',
ordering: 'Ordering',
show: 'Show',
pullRequest: 'Pull request',
inbox: 'Inbox style',
archived: 'Archived',
reset: 'Reset to defaults',
expand: 'Expand all',
collapse: 'Collapse all',
markRead: 'Mark all as read'
},
quickEntry: {
title: 'Quick Entry',
ask: 'Ask AITURK…',
disconnected: 'Not connected — open AITURK to reconnect',
sendTo: 'Send to',
target: 'Target session',
current: 'Current chat',
newSession: 'New session'
},
imageBackendTitle: 'Add an image backend to generate',
imageBackendDescription: 'Hatching a custom pet needs a provider that can ground on a reference image.',
setupImage: 'Set up image generation',
keyFrom: 'Get a key from',
removeReference: 'Remove reference',
addReference: 'Add a reference',
sessionUnavailable: "Couldn't open this session",
noPage: (path: string) => `No page at ${path}`,
logUnavailable: (message: string) => `Log unavailable: ${message}`,
stop: 'Stop',
moaPresets: 'MoA presets',
learned: 'learned',
hub: 'hub',
apiKey: 'API key',
skill: 'skill',
memory: 'memory',
mapAge: 'core = oldest · outer = newer',
editSkill: 'Edit skill…',
editMemory: 'Edit memory…',
archiveSkill: 'Archive skill',
deleteMemory: 'Delete memory',
editNode: (name: string) => `Edit ${name}`,
deleteNode: (name: string) => `Delete ${name}?`,
permanentMemory: 'This memory is removed permanently.',
timeline: 'Timeline scrubber',
pause: 'Pause',
playTimeline: 'Play timeline'
}
+5
View File
@@ -1,8 +1,11 @@
import { FIELD_DESCRIPTIONS, FIELD_LABELS } from '@/app/settings/constants'
import { EN_RUNTIME_SETTINGS } from './en-runtime-settings'
import { EN_SURFACES } from './en-surfaces'
import type { Translations } from './types'
export const en: Translations = {
surfaces: EN_SURFACES,
common: {
apply: 'Apply',
back: 'Back',
@@ -383,6 +386,7 @@ export const en: Translations = {
},
settings: {
runtime: EN_RUNTIME_SETTINGS,
closeSettings: 'Close settings',
exportConfig: 'Export config',
importConfig: 'Import config',
@@ -514,6 +518,7 @@ export const en: Translations = {
completionSoundPreview: 'Preview'
},
sections: {
browser: 'Browser',
model: 'Model',
chat: 'Chat',
appearance: 'Appearance',
+174
View File
@@ -0,0 +1,174 @@
import type { EN_BILLING } from './en-billing'
export const TR_BILLING: typeof EN_BILLING = {
retryAfter: minutes => ` (yaklaşık ${minutes} dakika sonra yeniden deneyin)`,
rateLimited: suffix => `🟡 Şu anda çok fazla tahsilat isteği var${suffix}. Bu, ödeme başarısızlığı anlamına gelmez.`,
stripeRetry: suffix => `Stripe hizmetinde sorun var. Biraz sonra yeniden deneyin${suffix}`,
reauthorize: who => `${who} Bu cihaza yeniden yetki vermek için Ayarlar → Ağ geçitleri bölümünden tekrar bağlanın.`,
noSavedCardMessage:
'💳 Terminal tahsilatları için kayıtlı kart yok. Portal üzerinden kart ekleyin. Tek seferlik kredi satın alma, kartı sonraki işlemler için kaydetmez.',
monthlyRemaining: amount => `🔴 Aylık harcama sınırına ulaşıldı. Kalan harcama payı: $${amount}.`,
chargeAdded: amount => `$${amount} eklendi.`,
unconfirmed: message =>
`${message} Son tahsilatın sonucu henüz doğrulanmadı. Yeniden denemeden önce bakiyenizi ve işlem geçmişinizi kontrol edin.`,
chargeFailed: reason => `Tahsilat tamamlanamadı (${reason}).`,
invalidAmount: label => `${label}: en fazla iki ondalık basamaklı dolar tutarı girin.`,
positiveAmount: label => `${label}: tutar $0 değerinden büyük olmalıdır.`,
minAmount: (label, amount) => `${label}: en düşük tutar ${amount}.`,
maxAmount: (label, amount) => `${label}: en yüksek tutar ${amount}.`,
confirmCardMessage: 'Terminal tahsilatlarında kullanılacak bu kartı portal üzerinden onaylayın.',
confirmCardTitle: 'Kart onayı gerekiyor',
spendingApprovalMessage:
'Uzaktan harcama izni gerekiyor. İzin vermek için bir kredi yüklemesi başlatın ve yeniden deneyin.',
spendingApprovalTitle: 'Uzaktan harcama onayı gerekiyor',
adminRevoked: 'Bir yönetici bu terminalin uzaktan harcama iznini kaldırdı.',
userRevoked: 'Bu terminalin uzaktan harcama iznini kaldırdınız.',
spendingRevoked: 'Uzaktan harcama durduruldu',
sessionRevokedMessage: 'Oturumunuz kapatıldı. Ayarlar → Ağ geçitleri bölümünden yeniden giriş yapın.',
sessionRevokedTitle: 'Oturum kapatıldı',
spendingDisabledMessage:
'Bu hesapta uzaktan harcama kapalı. Bir faturalandırma yöneticisi, portalın Hermes Agent sayfasından etkinleştirebilir.',
spendingDisabledTitle: 'Uzaktan harcama kapalı',
adminRequiredMessage:
'Bakiye eklemek için kuruluş yöneticisi veya sahibi olmalısınız. Yöneticinize başvurun ya da portal üzerinden yönetin.',
adminRequiredTitle: 'Yönetici yetkisi gerekiyor',
conflictingChargeMessage:
'🔴 Bu tahsilat anahtarı başka bir tutar için kullanılmış. Yeni bir kredi yüklemesi başlatın.',
conflictingChargeTitle: 'Yeni bir kredi yüklemesi başlatın',
noSavedCard: 'Kayıtlı kart yok',
orgDeniedMessage: 'Bu erişim anahtarı, yönetebildiğiniz bir kuruluşa bağlı değil.',
orgDeniedTitle: 'Kuruluş erişimi reddedildi',
monthlyReached: '🔴 Aylık harcama sınırına ulaşıldı.',
monthlyReachedTitle: 'Aylık harcama sınırına ulaşıldı',
rateLimitedTitle: 'Şu anda çok fazla tahsilat isteği var',
stripeTitle: 'Stripe hizmetinde sorun var',
dailyLimitMessage: 'Günlük plan değiştirme sınırına ulaşıldı. Yarın yeniden deneyin.',
dailyLimitTitle: 'Günlük plan değiştirme sınırına ulaşıldı',
endpointMessage:
'Faturalandırma hizmeti beklenen JSON yanıtını döndürmedi. Bu yayında hizmet kullanılamıyor olabilir.',
endpointTitle: 'Faturalandırma hizmetine ulaşılamıyor',
requestTimeoutMessage: 'Faturalandırma isteği zaman aşımına uğradı.',
requestTimeoutTitle: 'Faturalandırma isteği zaman aşımına uğradı',
connectionFailedMessage: 'Faturalandırma isteği ağ geçidine ulaşmadan başarısız oldu.',
connectionFailedTitle: 'Faturalandırma bağlantısı kurulamadı',
requestFailedMessage: 'Faturalandırma isteği başarısız oldu.',
requestFailedTitle: 'Faturalandırma isteği başarısız oldu',
creditsAdded: 'Krediler eklendi.',
chargeFailedTitle: 'Tahsilat başarısız oldu',
unconfirmedTitle: 'Tahsilat sonucu doğrulanamadı',
checkFailedMessage: 'Tahsilat kontrol edilemedi.',
checkFailedTitle: 'Tahsilat kontrol edilemedi',
missingChargeId: 'Faturalandırma hizmeti isteği kabul etti ancak tahsilat kimliği döndürmedi.',
untrackedTitle: 'Tahsilat takip edilemedi',
stillProcessingMessage: 'Tahsilat hâlâ tamamlanabilir. Yeniden denemeden önce portalı kontrol edin.',
stillProcessingTitle: '5 dakika sonra hâlâ işleniyor',
bankVerification:
'Bankanız 3DS doğrulaması istiyor. Satın almayı bitirmek için portal üzerinden doğrulamayı tamamlayın.',
cardExpired: 'Kartınızın süresi dolmuş. Portal üzerinden güncelleyin.',
cardDeclined: 'Kartınız reddedildi. Portal üzerinden başka bir kart deneyin.',
verificationDeniedMessage: 'Doğrulama tamamlandı ancak bu terminal için uzaktan harcama izni verilmedi.',
verificationDeniedTitle: 'Doğrulama onaylanmadı',
verificationDoneMessage: 'Bu terminal için uzaktan harcama izni verildi.',
verificationDoneTitle: 'Doğrulama tamamlandı',
reloadLabel: 'Yüklenecek tutar',
reloadGreater: 'Yüklenecek tutar eşik değerinden büyük olmalıdır.',
formatDate: (date: Date) =>
new Intl.DateTimeFormat('tr-TR', { day: 'numeric', month: 'short', year: 'numeric' }).format(date),
monthSuffix: '/ay',
creditsMonthly: amount => `Aylık $${amount} kredi`,
alreadyPlan: name => `Zaten ${name} planındasınız; değişiklik gerekmiyor.`,
scheduledChange: (name, date, delta) =>
`${name} planına geçiş ${date} tarihinde uygulanır. Şimdi tahsilat yapılmaz; o tarihe kadar mevcut planınız geçerlidir.${delta ? ` Aylık kredi değişimi: ${delta}.` : ''}`,
changesPlan: (name, date) => `${date} tarihinde ${name} planına geçilir.`,
cancelsOn: date => `${date} tarihinde iptal edilir.`,
renewsOn: date => `Yenileme: ${date}`,
reconcileCard: card => `Otomatik yüklemede ${card} kullanılıyor. Portal üzerinden kartı eşleştirin.`,
chargesBelow: (amount, threshold) =>
`Bakiyeniz ${threshold} altına düştüğünde otomatik olarak ${amount} tahsil edilir.`,
remaining: (amount, total, over) => `${total} tutarının ${amount} kadarı kaldı${over ? ` · ${over} aşım` : ''}`,
used: (amount, total) => `${total} tutarının ${amount} kadarı kullanıldı`,
resetsOn: date => `Sıfırlanma: ${date}`,
balanceAdded: amount => `${amount} eklendi. Bakiye yenileniyor.`,
usageLabel: label => `${label} kullanımı`,
balance: 'Bakiye',
plan: 'Plan',
autoRefill: 'Otomatik yükleme',
enabled: 'Etkin',
off: 'Kapalı',
portalArrow: 'Portalı aç ↗',
portal: 'Portalı aç',
connectMessage: 'Hesabınızı bağlamak için terminal arayüzünde /portal komutunu çalıştırın veya Nous portalını açın.',
connectTitle: 'Nous hesabınızı bağlayın',
addCard: 'Kart ekle ↗',
noCardMessage: 'Kredi satın alma ve otomatik yükleme için kayıtlı kart gerekir. Portal üzerinden kart ekleyin.',
noCardTitle: 'Kayıtlı ödeme yöntemi yok',
free: 'Ücretsiz',
subscriptionUnavailable: 'Abonelik ayrıntılarına ulaşılamıyor. Portal üzerinden kontrol edebilirsiniz.',
noSubscription: 'Etkin abonelik yok. Ücretli modeller yüklediğiniz kredileri kullanır.',
changePlan: 'Planı değiştir',
viewPlans: 'Planları görüntüle',
adjustPlan: 'Planı düzenle ↗',
choose: 'Seç ↗',
addPayment: 'Ödeme yöntemi ekle',
paymentMethod: 'Ödeme yöntemi',
update: 'Güncelle',
manageCard: 'Kredi yüklemeleri ve abonelik yenilemeleri için kullanılan kartı yönetin.',
buy: 'Satın al',
buyDescription: 'Kartınızdan tek seferlik tahsilat yapılır ve tutar bugün bakiyenize eklenir.',
buyCredits: 'Şimdi kredi satın al',
refillDescription: 'Bakiyeniz belirlediğiniz eşiğin altına düştüğünde otomatik kredi yükleyin.',
manage: 'Yönet',
manageRefill: 'Otomatik yüklemeyi portal üzerinden yönetin.',
refillWhenLow: 'Bakiye azaldığında yükle',
turnOnRefill: 'Otomatik yüklemeyi portal üzerinden etkinleştirin',
anotherCard: 'başka bir kart',
reconcile: 'Kartı eşleştir ↗',
subscriptionRemaining: 'Kalan abonelik kredileri',
subscriptionCredits: 'Abonelik kredileri',
noExpiry: 'Süresi dolmaz',
topupCredits: 'Yüklenen krediler',
capUsed: 'Kullanılan aylık harcama sınırı',
defaultCeiling: 'Varsayılan üst sınır',
monthlyRemoteSpending: 'Aylık uzaktan harcama',
monthlyCap: 'Aylık harcama sınırı',
refillCard: 'otomatik yükleme kartı',
customerDefault: 'müşteri varsayılanı',
subscriptionCard: 'abonelik kartı',
customCredit: 'Özel kredi tutarı',
processing: 'İşleniyor… tahsilat kontrol ediliyor',
retry: 'Yeniden dene',
billing: 'Faturalandırma',
paymentCredits: 'Ödeme ve krediler',
usage: 'Kullanım',
invoices: 'Faturalar',
undoing: 'Geri alınıyor…',
undo: 'Geri al',
checkingChange: 'Değişiklik kontrol ediliyor…',
cannotChange: 'Bu değişiklik buradan yapılamaz.',
cannotSchedule: 'Bu değişiklik buradan zamanlanamaz.',
tryAgain: 'Yeniden dene',
scheduling: 'Zamanlanıyor…',
confirmDowngrade: 'Alt plana geçişi onayla',
cancel: 'İptal',
currentPlan: 'Mevcut plan',
scheduled: 'Zamanlandı',
downgrade: 'Alt plana geç',
backBilling: 'Faturalandırmaya dön',
plans: 'Planlar',
noPlans: 'Şu anda geçiş yapılabilecek bir plan yok.',
refillUpdated: 'Otomatik yükleme güncellendi.',
refillOff: 'Otomatik yükleme kapatıldı.',
threshold: 'Eşik',
reloadTo: 'Yüklenecek tutar',
refillThreshold: 'Otomatik yükleme eşiği',
refillAmount: 'Otomatik yükleme tutarı',
turnOffQuestion: 'Otomatik yükleme kapatılsın mı?',
turnOff: 'Kapat',
disable: 'Devre dışı bırak',
saving: 'Kaydediliyor…',
save: 'Kaydet',
verificationPage: 'Doğrulama sayfasını aç',
dismiss: 'Kapat',
waitingVerification: 'Doğrulama bağlantısı bekleniyor…',
verifyContinue: 'Devam etmek için doğrulayın'
}
+166
View File
@@ -0,0 +1,166 @@
import type { Translations } from './types'
export const TR_SKILLS: Translations['skills'] = {
tabSkills: 'Beceriler',
tabToolsets: 'Araçlar',
configuringProfile: 'Yapılandırılan profil:',
tabMcp: 'MCP',
all: 'Tümü',
searchSkills: 'Becerilerde ara…',
searchToolsets: 'Araçlarda ara…',
refresh: 'Becerileri yenile',
refreshing: 'Beceriler yenileniyor',
loading: 'Yetenekler yükleniyor…',
noSkillsTitle: 'Beceri bulunamadı',
noSkillsDesc: 'Daha genel bir arama veya başka bir kategori deneyin.',
noToolsetsTitle: 'Araç grubu bulunamadı',
noToolsetsDesc: 'Daha genel bir arama deneyin.',
noDescription: 'Açıklama yok.',
configured: 'Yapılandırıldı',
needsKeys: 'Anahtar gerekiyor',
visionModelHint:
'Görsel anlama, yardımcı model ayarlarınızı kullanır. Görsel destekleyen modeli sağlayıcı bazında burada değil, model ayarlarında seçin.',
visionModelLink: 'Ayarlar → Modeller bölümünde görsel modelini seçin',
toolsetsEnabled: (enabled, total) => `${total} araç grubundan ${enabled} tanesi etkin`,
configureToolset: label => `${label} ayarları`,
toggleToolset: (label, enabled) => `${label} araç grubunu ${enabled ? 'etkinleştir' : 'devre dışı bırak'}`,
skillsLoadFailed: 'Beceriler yüklenemedi',
toolsetsRefreshFailed: 'Araç grupları yenilenemedi',
skillEnabled: 'Beceri etkinleştirildi',
skillDisabled: 'Beceri devre dışı bırakıldı',
toolsetEnabled: 'Araç grubu etkinleştirildi',
toolsetDisabled: 'Araç grubu devre dışı bırakıldı',
appliesToNewSessions: name => `${name} yeni oturumlarda geçerli olur.`,
failedToUpdate: name => `${name} güncellenemedi`,
sortMostUsed: 'En çok kullanılan',
sortAlpha: 'AZ',
sortMostUsedDesc: '↓ En çok kullanılan',
sortLeastUsedAsc: '↑ En az kullanılan',
enableAll: 'Tümünü etkinleştir',
disableAll: 'Tümünü devre dışı bırak',
disableUnused: 'Kullanılmayanları devre dışı bırak',
bulkUpdated: count => `Yeni oturumlar için ${count} öğe güncellendi.`,
bulkNoChange: 'Değiştirilecek öğe yok.',
usageCount: count => `${count} kez kullanıldı`,
provenance: { agent: 'Öğrenilen', bundled: 'Yerleşik', hub: 'Beceri merkezi' },
emptyNoneFound: noun => `${noun} bulunamadı`,
emptyNothingMatches: query => `${query}” ile eşleşen sonuç yok.`,
emptyNoneAvailable: noun => `Henüz kullanılabilir ${noun} yok.`,
changesApplyNewSessions: 'Değişiklikler yeni oturumlarda geçerli olur.',
skillUpdated: 'Beceri güncellendi',
edit: 'Düzenle',
archive: 'Arşivle',
skillArchivedTitle: 'Beceri arşivlendi',
skillArchivedMessage: 'hermes curator restore komutuyla geri yüklenebilir.',
officialCatalog: 'Kurulabilecek beceriler',
officialPill: 'Resmî',
hub: {
searchPlaceholder: 'Beceri merkezinde ara',
search: 'Ara',
searching: 'Aranıyor…',
connectingHubs: 'Beceri merkezlerine bağlanılıyor…',
connectedHubs: 'Bağlı merkezler:',
featured: 'Öne çıkan beceriler',
landingHint:
'Resmî dizin, GitHub ve topluluk kaynaklarındaki kurulabilir becerileri bulmak için merkezde arama yapın.',
noResults: 'Merkezde eşleşen beceri bulunamadı.',
resultCount: (count, ms) => `${count} sonuç${ms !== null ? ` · ${ms} ms` : ''}`,
timedOut: sources => `Zaman aşımına uğrayan kaynaklar: ${sources}`,
installed: 'Kurulu',
install: 'Kur',
installing: 'Kuruluyor…',
uninstall: 'Kaldır',
uninstalling: 'Kaldırılıyor…',
updateAll: 'Kurulu becerileri güncelle',
updating: 'Güncelleniyor…',
preview: 'Önizle',
scan: 'Tara',
scanning: 'Taranıyor…',
close: 'Kapat',
files: 'Dosyalar',
noReadme: 'Bu becerinin SKILL.md önizlemesi yok.',
trust: { builtin: 'yerleşik', trusted: 'güvenilir', community: 'topluluk' },
verdictSafe: 'Güvenli',
verdictCaution: 'Dikkat gerektiriyor',
verdictDangerous: 'Tehlikeli',
policyAllow: 'Kuruluma izin veriliyor',
policyAsk: 'Kurmadan önce inceleyin',
policyBlock: 'Kurulum ilke gereği engellendi',
findings: count => `${count} bulgu`,
noFindings: 'Güvenlik bulgusu yok.',
installStarted: name => `${name} kuruluyor…`,
uninstallStarted: name => `${name} kaldırılıyor…`,
updateStarted: 'Kurulu beceriler güncelleniyor…',
actionFailed: 'Beceri işlemi başarısız oldu',
actionLog: 'İşlem günlüğü',
alreadyInstalled: name => `${name}” zaten kurulu`,
pickerTitle: 'Beceri merkezi',
pickerBrowse: 'Tüm merkeze göz at',
pickerHide: 'Merkez tarayıcısını gizle',
pickerHint: 'Bir beceride “+ Bu ajana ekle” düğmesine basın; beceri kurulur ve yukarıdaki listede görünür.',
loadFailed: 'Beceri merkezi yüklenemedi',
previewFailed: 'Beceri önizlemesi açılamadı',
scanFailed: 'Güvenlik taraması başarısız oldu',
searchFailed: 'Merkez araması başarısız oldu'
}
}
export const TR_STARMAP: Translations['starmap'] = {
title: 'Bellek haritası',
subtitle: (nodes, clusters) => `${clusters} kategoride ${nodes} beceri`,
close: 'Bellek haritasını kapat',
refresh: 'Yenile',
memory: 'Bellek',
filterAll: 'Tümü',
filterUsed: 'Kullanılan',
filterLearned: 'Öğrenilen',
viewGraph: 'Harita',
loadFailed: 'Bellek haritası yüklenemedi',
loading: 'Yükleniyor…',
emptyTitle: 'Henüz öğrenilen bilgi yok',
emptyDesc: 'AITURK çalışmalarınız için beceriler ve anılar geliştirdikçe burada görünürler.',
share: 'Haritayı paylaş',
shareHint:
'Haritayı paylaşmak için kodu kopyalayın veya bir harita yüklemek için kod yapıştırın. Kod yalnızca yerleşimi içerir; bellek ve beceri metinlerinizi içermez.',
shareTitle: 'Haritayı içe / dışa aktar',
sharePlaceholder: 'Harita kodunu yapıştırın…',
copy: 'Harita kodunu kopyala',
copied: 'Kopyalandı!',
importMap: 'Harita içe aktar',
importBtn: 'Yükle',
importEmpty: 'Yüklemek için bir harita kodu yapıştırın.',
importSuccess: nodes => `${nodes} düğümlü harita yüklendi.`,
importedBadge: 'içe aktarılan harita',
resetToMine: 'Kendi haritama dön'
}
export const TR_AGENTS: Translations['agents'] = {
close: 'Ajanları kapat',
title: 'Alt ajan ağacı',
subtitle: 'Geçerli turdaki alt ajanların canlı etkinliği.',
emptyTitle: 'Çalışan alt ajan yok',
emptyDesc: 'Bir turda iş başka ajanlara devredildiğinde alt ajanların ilerlemesi burada görünür.',
running: 'Çalışıyor',
failed: 'Başarısız',
done: 'Tamamlandı',
streaming: 'Yanıt aktarılıyor',
files: 'Dosyalar',
moreFiles: count => `+${count} dosya daha`,
delegation: index => `Görev devri ${index}`,
workers: count => `${count} çalışan`,
workersActive: count => `${count} etkin`,
agentsCount: count => `${count} ajan`,
activeCount: count => `${count} etkin`,
failedCount: count => `${count} başarısız`,
toolsCount: count => `${count} araç`,
filesCount: count => `${count} dosya`,
updatedAgo: age => `Güncellendi: ${age}`,
ageNow: 'şimdi',
ageSeconds: seconds => `${seconds} sn önce`,
ageMinutes: minutes => `${minutes} dk önce`,
ageHours: hours => `${hours} sa önce`,
ageDays: days => `${days} gün önce`,
durationSeconds: seconds => `${seconds} sn`,
durationMinutes: (minutes, seconds) => `${minutes} dk ${seconds} sn`,
tokens: value => `${value} belirteç`
}
+246
View File
@@ -0,0 +1,246 @@
import type { Translations } from './types'
export const TR_COMMAND_CENTER: Translations['commandCenter'] = {
close: 'Komut merkezini kapat',
paletteTitle: 'Komut paleti',
back: 'Geri',
searchPlaceholder: 'Oturum, görünüm ve işlem ara',
goTo: 'Git',
goToSession: 'Oturuma git',
branches: 'Dallar',
projects: 'Projeler',
openFolder: 'Klasörü proje olarak aç…',
openFolderAt: path => `Klasörü proje olarak aç — ${path}`,
newSessionInProject: project => `${project} projesinde yeni oturum`,
commands: 'Komutlar',
startInBranch: branch => `${branch} dalında yeni sohbet`,
commandCenter: 'Komut merkezi',
appearance: 'Görünüm',
settings: 'Ayarlar',
changeTheme: 'Temayı değiştir',
changeColorMode: 'Renk modunu değiştir…',
pets: {
title: 'Maskotlar',
placeholder: 'Maskot ara…',
loading: 'Maskot galerisi yükleniyor…',
error: 'Maskot galerisine erişilemedi.',
staleBackend:
'Maskotları kullanmak için AITURK’ü yeniden başlatın; çalışan sunucu bu özelliği henüz desteklemiyor.',
empty: 'Eşleşen maskot yok.',
turnOff: 'Kapat',
turnOn: 'Aç',
installed: 'Kurulu',
generatedTag: 'Oluşturulan',
adoptFailed: 'Maskot eklenemedi.',
toggleFailed: enabled => `Maskot ${enabled ? 'açılamadı' : 'kapatılamadı'}.`,
noneAvailable: 'Kullanılabilir maskot yok; kurmak için aşağıdan birini seçin.'
},
generatePet: {
title: 'Maskot oluştur',
placeholder: 'Oluşturulacak maskotu tarif edin…',
promptHint: 'Dört görünüm taslağı oluşturmak için açıklama yazıp Entera basın.',
readyHint: 'Açıklamanızdan dört görünüm taslağı oluşturmak için Entera basın.',
generate: 'Oluştur',
generating: 'Oluşturuluyor…',
retry: 'Yeniden dene',
hatch: 'Canlandır',
spawning: 'Hazırlanıyor…',
hatching: 'Maskotunuz canlandırılıyor…',
hatchingSub: 'Hayat buluyor…',
hatched: 'Hazır!',
hatchRow: (_state, done, total) => `${total} kareden ${done}. kare çiziliyor…`,
hatchComposing: 'Kareler birleştiriliyor…',
hatchSaving: 'Neredeyse hazır…',
namePlaceholder: 'Maskotunuza ad verin',
staleBackend: 'Maskot oluşturmak için AITURK’ü güncelleyin.',
backgroundHint: 'Bu pencereyi kapatabilirsiniz; AITURK işlem tamamlanınca size haber verir.',
slowProviderHint: 'Bu işlem birkaç dakika sürebilir',
remix: 'Yeni çeşitleme',
remixConfirmTitle: 'Bu görünümden yeni çeşitlemeler oluşturulsun mu?',
remixConfirmBody:
'Bu görünüm başlangıç olarak kullanılarak yeni taslaklar oluşturulur. İşlem birkaç dakika sürebilir.',
genericError: 'Oluşturma başarısız oldu; yeniden deneyin veya bir öneri seçin.',
referenceImageTooLarge: 'Referans görsel çok büyük. 16 MBtan küçük bir görsel kullanın.',
referenceImageInvalid: 'Referans görsel okunamadı. PNG, JPG, WebP veya GIF deneyin.',
adopt: 'Ekle',
startOver: 'Baştan başla'
},
installTheme: {
title: 'Tema kur…',
pageTitle: 'Tema kur',
placeholder: 'VS Code Marketplace içinde ara…',
loading: 'Mağazada aranıyor…',
error: 'Mağazaya erişilemedi.',
empty: 'Eşleşen tema yok.',
install: 'Kur',
installing: 'Kuruluyor…',
installed: 'Kurulu',
installs: count => `${count} kurulum`
},
settingsFields: 'Ayar alanları',
mcpServers: 'MCP sunucuları',
archivedChats: 'Arşivlenmiş sohbetler',
sections: { maintenance: 'Bakım', sessions: 'Oturumlar', system: 'Sistem', usage: 'Kullanım' },
sectionDescriptions: {
maintenance: 'Tanılama, yedekler, beceri düzenleyicisi ve bellek verileri',
sessions: 'Oturumları ara ve yönet',
system: 'Durum, günlükler ve sistem işlemleri',
usage: 'Zamana göre belirteç, maliyet ve beceri kullanımı'
},
nav: {
newChat: { title: 'Yeni oturum', detail: 'Yeni bir oturum başlat' },
settings: { title: 'Ayarlar', detail: 'AITURK masaüstünü yapılandır' },
skills: { title: 'Yetenekler', detail: 'Beceriler, araçlar ve MCP sunucuları' },
messaging: { title: 'Mesajlaşma', detail: 'Telegram, Slack, Discord ve diğer platformları ayarla' },
artifacts: { title: 'Çıktılar', detail: 'Oluşturulan çıktılara göz at' }
},
sectionEntries: {
sessions: { title: 'Oturum paneli', detail: 'Oturumları ara, sabitle ve yönet' },
system: { title: 'Sistem paneli', detail: 'Ağ geçidi durumu, günlükler, yeniden başlatma ve güncelleme' },
usage: { title: 'Kullanım paneli', detail: 'Belirteç, maliyet ve beceri kullanımı' }
},
providerNavigate: 'Gezinme',
providerSessions: 'Oturumlar',
refresh: 'Yenile',
refreshing: 'Yenileniyor…',
noResults: 'Eşleşen sonuç bulunamadı.',
pinSession: 'Oturumu sabitle',
unpinSession: 'Oturum sabitlemesini kaldır',
exportSession: 'Oturumu dışa aktar',
deleteSession: 'Oturumu sil',
noSessions: 'Henüz oturum yok.',
gatewayRunning: 'Mesajlaşma ağ geçidi çalışıyor',
gatewayStopped: 'Mesajlaşma ağ geçidi durdu',
hermesActiveSessions: (version, count) => `AITURK ${version} · ${count} etkin oturum`,
restartGateway: 'Ağ geçidini yeniden başlat',
openBrowser: 'Tarayıcıyı aç',
gatewayRestartFailed: 'Ağ geçidi yeniden başlatılamadı.',
updateHermes: 'AITURK’ü güncelle',
reloadWindow: 'Pencereyi yeniden yükle',
actionRunning: 'çalışıyor',
actionDone: 'tamamlandı',
actionFailed: 'başarısız',
actionStartedWaiting: 'İşlem başladı, durum bekleniyor…',
loadingStatus: 'Durum yükleniyor…',
recentLogs: 'Son günlükler',
noLogs: 'Henüz günlük yüklenmedi.',
days: count => `${count} gün`,
statSessions: 'Oturumlar',
statApiCalls: 'API çağrıları',
statTokens: 'Girdi/çıktı belirteçleri',
statCost: 'Tahmini maliyet',
actualCost: cost => `gerçek ${cost}`,
loadingUsage: 'Kullanım yükleniyor…',
noUsage: period => `Son ${period} günde kullanım yok.`,
retry: 'Yeniden dene',
dailyTokens: 'Günlük belirteçler',
input: 'girdi',
output: 'çıktı',
noDailyActivity: 'Günlük etkinlik yok.',
topModels: 'En çok kullanılan modeller',
noModelUsage: 'Henüz model kullanımı yok.',
topSkills: 'En çok kullanılan beceriler',
noSkillActivity: 'Henüz beceri kullanımı yok.',
actions: count => `${count} işlem`,
logFile: 'Günlük dosyası',
logLevel: 'Düzey',
logSearchPlaceholder: 'Günlük satırlarını filtrele…',
maintenance: {
runOps: 'Tanılama',
doctor: 'Sağlık denetimini çalıştır',
doctorDesc: 'Kurulumu, ayarları ve sağlayıcıları denetler',
securityAudit: 'Güvenlik denetimi',
securityAuditDesc: 'Ayarları ve becerileri riskli yapılandırmalar için tarar',
backup: 'Yedek oluştur',
backupDesc: 'Ayarları, belleği, becerileri ve oturumları ZIP dosyasına alır',
debugShare: 'Tanılama raporunu paylaş',
debugShareDesc:
'Gizli bilgiler maskelenmiş raporu ve günlükleri yükleyip paylaşım bağlantıları oluşturur; 6 saat sonra otomatik silinir',
debugShareRunning: 'Tanılama raporu yükleniyor…',
debugShareLinks: 'Paylaşım bağlantıları',
debugShareFailed: 'Tanılama raporu paylaşılamadı',
copyLink: 'Bağlantıyı kopyala',
linkCopied: 'Bağlantı kopyalandı',
curator: 'Beceri düzenleyicisi',
curatorDesc: 'Ajanın oluşturduğu eski becerileri arka planda inceleyip arşivler',
curatorPaused: 'Duraklatıldı',
curatorActive: 'Etkin',
curatorDisabled: 'Devre dışı',
curatorLastRun: when => `Son çalıştırma: ${when}`,
curatorNeverRan: 'Hiç çalıştırılmadı',
pause: 'Duraklat',
resume: 'Sürdür',
runNow: 'Şimdi çalıştır',
memoryData: 'Bellek verileri',
memoryDataDesc: 'Her oturuma eklenen yerleşik bellek dosyaları',
memoryProvider: name => `Etkin sağlayıcı: ${name}`,
builtinMemory: 'yerleşik',
memoryFile: 'Ajan belleği (MEMORY.md)',
userFile: 'Kullanıcı profili (USER.md)',
bytes: size => size,
empty: 'boş',
resetMemory: 'Belleği sıfırla',
resetUser: 'Profili sıfırla',
resetAll: 'İkisini de sıfırla',
resetConfirm: target => `${target} silinsin mi? Bu işlem geri alınamaz.`,
resetDone: files => `Silindi: ${files}.`,
resetFailed: 'Bellek sıfırlanamadı',
actionStarted: name => `${name} başladı; günlük izleniyor…`,
actionFailed: name => `${name} başlatılamadı`,
running: 'Çalışıyor…',
viewLog: 'İşlem günlüğü'
}
}
export const TR_ARTIFACTS: Translations['artifacts'] = {
search: 'Çıktılarda ara…',
refresh: 'Çıktıları yenile',
refreshing: 'Çıktılar yenileniyor',
indexing: 'Son oturumların çıktıları dizine ekleniyor',
tabAll: 'Tümü',
tabImages: 'Görseller',
tabFiles: 'Dosyalar',
tabLinks: 'Bağlantılar',
noArtifactsTitle: 'Çıktı bulunamadı',
noArtifactsDesc: 'Oturumlarda oluşturulan görseller ve dosyalar burada görünür.',
failedLoad: 'Çıktılar yüklenemedi',
openFailed: 'Açılamadı',
itemsImage: 'görseller',
itemsLink: 'bağlantılar',
itemsFile: 'dosyalar',
itemsGeneric: 'öğeler',
zero: '0',
rangeOf: (start, end, total) => `${start}${end} / ${total}`,
goToPage: (itemLabel, page) => `${itemLabel}: ${page}. sayfaya git`,
colTitleLink: 'Bağlantı başlığı',
colTitleFile: 'Ad',
colTitleDefault: 'Başlık / ad',
colLocationLink: 'Adres',
colLocationFile: 'Yol',
colLocationDefault: 'Konum',
colSession: 'Oturum',
kindImage: 'görsel',
kindFile: 'dosya',
kindLink: 'bağlantı',
chat: 'Sohbet',
copyUrl: 'Adresi kopyala',
copyPath: 'Yolu kopyala'
}
export const TR_ARTIFACT_CARD: Translations['artifactCard'] = {
kind: { code: 'Kod', html: 'Etkileşimli sayfa', svg: 'Grafik' },
generating: lines => `Oluşturuluyor… ${lines} satır`,
versionBadge: count => `${count} sürüm`,
open: 'Aç'
}
export const TR_ARTIFACT_PREVIEW: Translations['artifactPreview'] = {
versionOf: (current, total) => `${current}. sürüm / ${total}`,
olderVersion: 'Önceki sürüm',
newerVersion: 'Sonraki sürüm',
latest: 'En yeni',
copyContent: 'İçeriği kopyala',
download: 'İndir',
openInBrowser: 'Tarayıcıda aç',
openInBrowserFailed: 'Tarayıcıda açılamadı',
missingTitle: 'Çıktı kullanılamıyor',
missingBody: 'Bu çıktı artık yerel kayıtlarda bulunmuyor.'
}
+228
View File
@@ -0,0 +1,228 @@
import type { TranslationOverrides } from './define-locale'
export const TR_CONNECTION_SETTINGS = {
connections: {
title: 'Kayıtlı ağ geçitleri',
intro: 'Bu cihazı ve uzaktan, SSH veya bulut bağlantısıyla erişilen ajan sunucularını yönetin.',
stagedNote:
'Ağ geçidini Oturumlar bölümünden değiştirin. Profiller, sohbetler, mesajlaşma ve zamanlanmış işler kendi ağ geçitlerinde kalır. Diğer ağ geçitlerindeki işler devam eder.',
launchModeTitle: 'Açılışta son kullanılan ağ geçidinin oturumlarına dön',
launchModeDesc: 'Kapalıysa Oturumlar, birincil ağ geçidinde açılır.',
searchPlaceholder: 'Ağ geçidi ara…',
noSearchResults: 'Eşleşen ağ geçidi yok.',
loadFailed: 'Bağlantılar yüklenemedi',
currentPill: 'Geçerli',
primaryPill: 'Birincil',
managedPill: 'Uygulama yönetiyor',
addConnection: 'Bağlantı ekle',
editConnection: 'Düzenle',
removeConnection: 'Kaldır',
removeConfirmTitle: 'Bu bağlantı kaldırılsın mı?',
removeConfirmDesc: label =>
`${label}” bu uygulamadan kaldırılacak. Sunucunun kendisi değişmez; bağlantıyı daha sonra tekrar ekleyebilirsiniz.`,
makePrimary: 'Birincil yap',
testConnection: 'Dene',
testOk: 'Erişilebilir',
testFailed: 'Bağlantı testi başarısız',
saveFailed: 'Bağlantı kaydedilemedi',
removeFailed: 'Bağlantı kaldırılamadı',
updateAll: 'Tüm kurulumları güncelle',
updateAllRunning: 'Tüm kurulumlar güncelleniyor…',
updateAllDone: 'Güncelleme istekleri gönderildi',
updateAllFailed: 'Toplu güncelleme başlatılamadı',
updateSkippedCloud: 'Hermes Cloud yönetiyor',
kindLocal: 'Yerel',
kindRemote: 'Uzak ağ geçidi',
kindCloud: 'Hermes Cloud',
kindSsh: 'SSH',
kindLocalDesc: 'Bu uygulamanın yönettiği yerel ajan ortamı.',
kindRemoteDesc: 'Yerel ağ, Tailscale veya internet üzerinden HTTP(S) ile erişilen ajan sunucusu.',
kindCloudDesc: 'Hermes Cloud hesabınız üzerinden bulunan bulut kurulumu.',
kindSshDesc: 'SSH ile erişilen ajan kurulumu.',
labelTitle: 'Ad',
labelDesc:
'Zorunludur ve benzersiz olmalıdır. Kurulumun göründüğü her yerde bu ad kullanılır; örneğin “Ev sunucusu” veya “İş bilgisayarı”.',
labelPlaceholder: 'Ev sunucusu',
urlTitle: 'Ağ geçidi adresi',
sshHostTitle: 'SSH sunucusu',
headersTitle: 'Ek ağ geçidi başlıkları',
headersDesc:
'Bu ağ geçidine gönderilen her HTTP ve WebSocket isteğine eklenir. Cloudflare Access gibi erişim hizmetlerinde kullanılabilir. Değerler şifrelenir. Uygulamanın yönettiği Authorization, Cookie ve Host başlıkları yok sayılır.',
headerValuePlaceholder: 'Değer',
headerValueSaved: 'Kayıtlı değeri korumak için boş bırakın',
headerAdd: 'Başlık ekle',
headerRemove: 'Kaldır',
duplicateLocal: 'Uygulama zaten bir yerel bağlantı yönetiyor. Yalnızca bir tane olabilir.',
duplicateUrl: label => `Bu ağ geçidi adresine ait bağlantı zaten var: “${label}”.`,
duplicateSsh: label => `Bu SSH sunucusuna ait bağlantı zaten var: “${label}”.`,
sameBackendHint: label => `${label}” ile aynı sunucu`,
localAddHint: 'Yönetilen yerel bağlantı zaten bulunduğundan yeni bir yerel bağlantı eklenemez.',
cloudAddHint:
'Hermes Clouda giriş yaptığınızda ajanlarınız otomatik bulunur. Bu formu yalnızca bildiğiniz bir kurulum adresini elle kaydetmek için kullanın.',
save: 'Bağlantıyı kaydet',
saving: 'Kaydediliyor…',
cancel: 'Vazgeç',
empty: 'Henüz kayıtlı bağlantı yok.'
},
managedUpdates: {
title: 'Yönetilen güncellemeler',
intro:
'Uygulamanın yönettiği SSH kurulumlarını günceller. Oturumların durulması beklenir, uzak kaynak güncellenir ve profiller işlem kaydıyla geri yüklenir.',
sshConnection: 'Uygulamanın yönettiği SSH kurulumu',
update: 'Güncelle',
updating: 'Güncelleniyor…',
progress: 'Oturumlar bekleniyor, uzak kurulum güncelleniyor ve profiller geri yükleniyor…',
updated: 'Güncellendi',
partial: 'Güncellendi; geri yükleme başarısız',
refused: 'Reddedildi',
failed: 'Güncelleme başarısız',
alreadyRunning: 'Güncelleme zaten sürüyor',
receipt: (id, outcome) => `İşlem kaydı ${id} · ${outcome}`,
receiptVersions: (pre, post) => `${pre}${post}`,
scopesRestored: profiles => `Geri yüklenen profiller: ${profiles}`,
scopeNotRestored: (profile, error) => `${profile}” profili geri yüklenemedi: ${error}`
},
gateway: {
loading: 'Ağ geçidi ayarları yükleniyor…',
unavailableTitle: 'Ağ geçidi ayarları kullanılamıyor',
unavailableDesc: 'Masaüstü iletişim köprüsü ağ geçidi ayarlarını sunmuyor.',
title: 'Ağ geçidi bağlantısı',
envOverride: 'ortam değişkeni öncelikli',
intro:
'Varsayılan bağlantı yereldir. Başka bir makinedeki ajanı yönetmek için uzak bağlantı kullanın. Bağlantılar cihaza özeldir; profiller bağlandığınız ağ geçidinden bulunur.',
envOverrideTitle: 'Bu masaüstü oturumunu ortam değişkenleri yönetiyor.',
envOverrideDesc:
'Kayıtlı ayarları kullanmak için HERMES_DESKTOP_REMOTE_URL ve HERMES_DESKTOP_REMOTE_TOKEN ortam değişkenlerini kaldırın.',
modeTitle: 'Bağlantı modu',
localTitle: 'Yerel ağ geçidi',
localDesc: 'Bu bilgisayarda özel bir ajan sunucusu başlatır. Varsayılandır ve çevrimdışı çalışabilir.',
remoteTitle: 'Uzak ağ geçidi',
remoteDesc: 'Masaüstü arayüzünü uzaktaki bir ajan sunucusuna bağlar.',
remoteAuthHint:
'Barındırılan ağ geçitleri OAuth veya kullanıcı adı ve parola kullanır. Kendi sunucunuz oturum anahtarı kullanabilir.',
cloudTitle: 'Hermes Cloud',
cloudDesc: 'Hesabınızdaki ajanları görmek için Hermes Clouda giriş yapın. Adres yapıştırmanız gerekmez.',
cloudSignInTitle: 'Hermes Cloud',
cloudSignIn: 'Hermes Clouda giriş yap',
cloudSignedIn: 'Hermes Clouda giriş yapıldı',
cloudNeedsSignIn: 'Hesabınızdaki ajanları bulmak için Hermes Clouda giriş yapın.',
cloudSignedInDesc: 'Giriş yaptınız. Aşağıdan bir ajan seçin; oturum otomatik yenilenir.',
cloudAgentsTitle: 'Ajanlarınız',
cloudOrgPickerTitle: 'Kuruluş seçin',
cloudOrgSelect: 'Seç',
cloudOrgChange: 'Kuruluşu değiştir',
cloudOrgRole: role => `Rol: ${role}`,
cloudLoadingAgents: 'Ajanlarınız yükleniyor…',
cloudNoAgents: {
before: 'Bu hesapta ajan bulunamadı. ',
linkText: 'Nous portalında',
after: ' bir ajan oluşturup yenileyin.'
},
cloudRefresh: 'Yenile',
cloudConnect: 'Bağlan',
cloudConnecting: 'Bağlanıyor…',
cloudDiscoverFailed: 'Hermes Cloud ajanları yüklenemedi',
cloudConnectFailed: 'Ajana bağlanılamadı',
cloudSignInFailed: 'Hermes Clouda giriş yapılamadı',
cloudSignedOutTitle: 'Hermes Clouddan çıkış yapıldı',
cloudSignedOutMessage: 'Hermes Cloud oturumu temizlendi.',
cloudConnectedTitle: 'Bağlandı',
cloudConnectedPill: 'Bağlı',
cloudConnectedTo: name => `${name} ajanına bağlandı.`,
cloudAgentProvisioning: 'Hazırlanıyor…',
cloudStatusLabel: status => `Durum: ${status}`,
remoteUrlTitle: 'Uzak adres',
remoteUrlDesc: 'Uzak yönetim sunucusunun temel adresi. /hermes gibi yol önekleri desteklenir.',
probing: 'Ağ geçidinin kimlik doğrulama yöntemi denetleniyor…',
probeError: 'Ağ geçidine henüz ulaşılamadı. Adresi kontrol edin; yanıt verdiğinde giriş yöntemi görünecek.',
signedIn: 'Giriş yapıldı',
signIn: 'Giriş yap',
signOut: 'Çıkış yap',
signInWith: provider => `${provider} ile giriş yap`,
authTitle: 'Kimlik doğrulama',
authSignedInPassword: 'Bu ağ geçidi kullanıcı adı ve parola kullanıyor. Giriş yaptınız; oturum otomatik yenilenir.',
authSignedInOauth: 'Bu ağ geçidi OAuth kullanıyor. Giriş yaptınız; oturum otomatik yenilenir.',
authNeedsPassword:
'Bu ağ geçidi kullanıcı adı ve parola kullanıyor. Masaüstü uygulamasını yetkilendirmek için giriş yapın.',
authNeedsOauth: provider =>
`Bu ağ geçidi OAuth kullanıyor. Uygulamayı yetkilendirmek için ${provider} ile giriş yapın.`,
tokenTitle: 'Oturum anahtarı',
tokenDesc:
'REST ve WebSocket erişimi için yönetim panelinin oturum anahtarı. Kayıtlı anahtarı korumak için boş bırakın.',
existingToken: value => `Kayıtlı anahtar ${value}`,
savedToken: 'kayıtlı',
pasteSessionToken: 'Oturum anahtarını yapıştır',
plainTextConfirmTitle: 'Ağ geçidi anahtarı şifrelenmeden saklansın mı?',
plainTextConfirmDesc:
'Bu bilgisayarda işletim sistemi anahtar deposu bulunamadı. Anahtar bağlantı ayarları dosyasında şifrelenmeden saklanacak; aynı kullanıcı hesabıyla çalışan işlemler okuyabilir. Şifreli saklama için GNOME Keyring veya KWallet kurun ya da etkinleştirin.',
plainTextConfirmAction: 'Şifrelemeden kaydet',
plainTextStoredTitle: 'Anahtar şifrelenmeden saklanıyor',
plainTextStoredDesc:
'Güvenli depo kullanılamadığından anahtar bu bilgisayarın bağlantı ayarlarında şifrelenmeden saklanıyor. Şifrelemek için GNOME Keyring veya KWallet etkinleştirin.',
keychainEncryptionTitle: 'Kayıtlı gizli bilgileri sistem anahtar deposuyla şifrele',
keychainEncryptionDesc:
'Varsayılan olarak kapalıdır. Açıldığında bağlantı anahtarları ve giriş bilgileri Keychain, GNOME Keyring veya Windows DPAPI ile şifrelenir; sistem izin ya da parola isteyebilir. Kapalıyken yalnızca kullanıcı hesabınızın okuyabildiği dosyalarda saklanır.',
keychainEncryptionFailed: 'Gizli bilgi şifrelemesi değiştirilemedi',
testRemote: 'Uzak bağlantıyı dene',
saveForRestart: 'Sonraki açılış için kaydet',
saveAndReconnect: 'Kaydet ve yeniden bağlan',
diagnostics: 'Tanılama',
diagnosticsDesc: 'Dosya yöneticisinde desktop.log günlüğünü gösterir. Ağ geçidi başlamadığında yararlıdır.',
openLogs: 'Günlükleri aç',
incompleteTitle: 'Uzak ağ geçidi bilgileri eksik',
incompleteSignIn: 'Uzak moda geçmeden önce adresi girip giriş yapın.',
incompleteToken: 'Uzak moda geçmeden önce adresi ve oturum anahtarını girin.',
incompleteSignInTest: 'Denemeden önce uzak adresi girip giriş yapın.',
incompleteTokenTest: 'Denemeden önce uzak adresi ve oturum anahtarını girin.',
enterUrlFirst: 'Önce uzak adresi girin.',
restartingTitle: 'Ağ geçidi bağlantısı yeniden başlatılıyor',
savedTitle: 'Ağ geçidi ayarları kaydedildi',
restartingMessage: 'Arayüz açık kalacak ve kayıtlı ayarlarla yeniden bağlanacak.',
savedMessage: 'Sonraki açılış için kaydedildi.',
connectedTo: (baseUrl, version) => `${baseUrl} adresine bağlandı${version ? ` · Hermes ${version}` : ''}`,
reachableTitle: 'Uzak ağ geçidine erişildi',
signedOutTitle: 'Çıkış yapıldı',
signedOutMessage: 'Uzak ağ geçidi oturumu temizlendi.',
failedLoad: 'Ağ geçidi ayarları yüklenemedi',
signInFailed: 'Giriş yapılamadı',
signOutFailed: 'Çıkış yapılamadı',
testFailed: 'Uzak ağ geçidi testi başarısız',
applyFailed: 'Ağ geçidi ayarları uygulanamadı',
saveFailed: 'Ağ geçidi ayarları kaydedilemedi',
sshTitle: 'SSH ile bağlan',
sshDesc:
'Ajan uzaktaki bilgisayarda SSH ile başlatılır ve bu uygulamaya tünellenir. Sunucuyu elle açmanız gerekmez. Anahtar tabanlı çalışan SSH erişimi gerekir.',
sshTrustHint: 'İlk sunucu anahtarı kaydedilip sabitlenir. Daha sonra değişirse bağlantı reddedilir.',
sshHostTitle: 'Sunucu',
sshHostDesc: 'kullanıcı@sunucu veya ~/.ssh/config dosyasındaki sunucu takma adı.',
sshHostPick: 'Sunucu seçin…',
sshHostPickTitle: 'Sunucu',
sshHostPickDesc: '~/.ssh/config dosyasındaki bir sunucu veya elle girmek için Özel.',
sshHostCustom: 'Özel; elle gir…',
sshUserTitle: 'Kullanıcı',
sshUserDesc: 'Boş bırakılırsa ~/.ssh/config veya mevcut kullanıcı kullanılır.',
sshUserPlaceholder: '~/.ssh/config dosyasından',
sshPortTitle: 'Bağlantı noktası',
sshPortDesc: 'Boş bırakılırsa 22 veya ~/.ssh/config portu kullanılır.',
sshKeyTitle: 'Kimlik dosyası',
sshKeyDesc: 'Özel anahtarın yolu. Boş bırakılırsa ssh-agent veya ~/.ssh/config kullanılır.',
sshHermesPathTitle: 'Hermes yolu (isteğe bağlı)',
sshHermesPathDesc: 'Uzak hermes komutunun tam yolu. Boş bırakılırsa otomatik bulunur.',
sshHermesPathPlaceholder: 'otomatik algıla',
sshTestConnection: 'SSH bağlantısını dene',
sshConnect: 'Bağlan',
sshButtonsHint: 'Kaydet sonraki açılışta uygulanır. Bağlan hemen yeniden bağlanır.',
sshReachable: (host, platform) => `Erişilebilir: ${host} (${platform}) · Hermes bulundu`,
sshIncompleteHost: 'Bağlanmadan önce SSH sunucusunu girin.',
sshErrUnreachable: 'Sunucuya SSH üzerinden ulaşılamadı. Adresi, portu ve ağ bağlantınızı kontrol edin.',
sshErrAuth:
'SSH kimlik doğrulaması başarısız. Anahtarı ssh-add ile ssh-agenta ekleyin veya ~/.ssh/config içinde IdentityFile belirtin.',
sshErrHostKey:
'Sunucu anahtarı son bağlantıdan beri DEĞİŞTİ. Bunun beklenen bir değişiklik olduğunu doğruladıktan sonra ssh-keygen -R <sunucu> çalıştırıp yeniden bağlanın.',
sshErrNotInstalled: 'Uzak sunucuda Hermes kurulu değil. Önce sunucuya kurun veya Hermes komutunun yolunu belirtin.',
sshErrPlatform: 'Uzak platform desteklenmiyor. SSH modu Linux, macOS ve Windows sunucularını destekler.',
sshErrTimeout: 'SSH bağlantısı zaman aşımına uğradı. Sunucuya erişilemiyor veya sunucu uykuda olabilir.',
sshErrUpdateRequired: 'Masaüstünden SSH ile bağlanmadan önce uzak sunucudaki Hermesi güncelleyin.',
sshErrUnknown: 'SSH bağlantısı başarısız.'
}
} satisfies NonNullable<TranslationOverrides['settings']>
+210
View File
@@ -0,0 +1,210 @@
import type { Translations } from './types'
export const TR_UPDATES: Translations['updates'] = {
stages: {
idle: 'Hazırlanıyor…',
prepare: 'Hazırlanıyor…',
fetch: 'İndiriliyor…',
pull: 'Neredeyse hazır…',
pydeps: 'Son işlemler yapılıyor…',
update: 'AITURK güncelleniyor…',
rebuild: 'Masaüstü uygulaması yeniden derleniyor…',
restart: 'AITURK yeniden başlatılıyor…',
done: 'Güncelleme tamamlandı',
manual: 'Terminalden güncelleyin',
guiSkew: 'Masaüstü uygulamasını güncelleyin',
error: 'Güncelleme durakladı'
},
checking: 'Güncellemeler denetleniyor…',
checkFailedTitle: 'Güncellemeler denetlenemedi',
tryAgain: 'Yeniden dene',
notAvailableTitle: 'Güncelleme kullanılamıyor',
unsupportedMessage: 'Bu AITURK sürümü uygulama içinden kendini güncelleyemiyor.',
connectionRetry: 'Bağlantınızı kontrol edip yeniden deneyin.',
latestBody: 'En güncel sürümü kullanıyorsunuz.',
latestBodyBackend: 'Sunucu en güncel sürümü kullanıyor.',
allSetTitle: 'Her şey hazır',
availableTitle: 'Yeni güncelleme var',
availableBody: 'AITURK’ün yeni sürümü kurulmaya hazır.',
availableTitleBackend: 'Sunucu güncellemesi var',
availableBodyBackend: 'Bağlı AITURK sunucusunun daha yeni sürümü kurulmaya hazır.',
availableBodyNoChangelog: 'Yeni sürüm hazır. Bu kurulum türü için sürüm notları bulunmuyor.',
updateNow: 'Şimdi güncelle',
maybeLater: 'Daha sonra',
moreChanges: count => `+ ${count} değişiklik daha.`,
manualTitle: 'Terminalden güncelleyin',
manualBody:
'AITURK’ü komut satırından kurduğunuz için güncellemeler de oradan yapılır. Şu komutu terminalinize yapıştırın:',
manualPickedUp: 'AITURK sonraki açılışta yeni sürümü kullanır.',
guiSkewTitle: 'Masaüstü uygulamasını güncelleyin',
guiSkewBody:
'Sunucu güncellendi ancak masaüstü uygulama paketi değişmedi. Sürümleri eşleştirmek için AITURK masaüstü paketinizi (AppImage / .deb / .rpm) güncelleyin veya yeniden kurun.',
copy: 'Kopyala',
copied: 'Kopyalandı',
done: 'Tamam',
applyingBody:
'AITURK güncelleyicisi ayrı bir pencerede çalışır ve bitince uygulamayı otomatik açar. Güncelleme sırasında AITURK’ü kendiniz yeniden açmayın.',
applyingBodyBackend:
'Uzak sunucu güncellemeyi uygulayıp yeniden başlayacak. Hazır olduğunda AITURK otomatik bağlanır.',
applyingClose: 'Güncelleme sırasında bu pencere kapanır; ardından AITURK kendiliğinden açılır.',
errorTitle: 'Güncelleme tamamlanamadı',
errorBody: 'Şimdi yeniden deneyebilirsiniz.',
blockerTitle: 'AITURK’ü güncellemek için yerel önizlemeler kapatılsın mı?',
blockerBody:
'AITURK güncellemeden önce bu yerel önizlemeleri durdurmalı. Bu işlem dosyalarınızı değiştirmez veya silmez.',
foreignBlockerTitle: 'AITURK’ü güncellemek için diğer işlemleri kapatın',
foreignBlockerBody:
'AITURK bu işlemleri otomatik olarak güvenle kapatamıyor. İlgili uygulamayı, terminali veya servisi kapatıp güncellemeyi yeniden deneyin.',
mixedBlockerBody:
'AITURK aşağıdaki yerel önizlemeleri kapatabilir. Güncellemenin sürmesi için diğer işlemleri kendiniz kapatmalısınız.',
closePreviewsAndUpdate: 'Önizlemeleri kapat ve güncelle',
closePreviewsAndCheckAgain: 'Önizlemeleri kapat ve yeniden denetle',
localPreview: 'Yerel önizleme',
portLabel: port => `Bağlantı noktası ${port}`,
pidLabel: pid => `İşlem kimliği ${pid}`,
technicalDetails: 'Teknik ayrıntılar',
notNow: 'Şimdi değil',
clientAlsoBehindTitle: 'Masaüstü uygulaması eski sürümde',
clientAlsoBehindMessage:
'Sunucu güncel ancak masaüstü uygulaması hâlâ eski sürümde. Son düzeltmeleri almak için uygulamayı güncelleyin.',
clientAlsoBehindAction: 'Masaüstü uygulamasını güncelle',
everythingDispatched: 'Güncelleme isteği gönderildi',
everythingSkipped: 'Atlandı',
everythingRowFailed: 'Güncelleme başarısız oldu',
everythingFanoutFailedTitle: 'Diğer kurulumlar güncellenemedi',
applyStatus: {
preparing: 'Sunucu güncelleniyor…',
pulling: 'Sunucu güncelleniyor…',
restarting: 'Güncellemeyi yüklemek için sunucu yeniden başlatılıyor…',
notAvailable: 'Bu sunucu için güncelleme kullanılamıyor.',
failed: 'Sunucu güncellemesi başarısız oldu.',
noReturn:
'Sunucu yeniden çevrimiçi olmadı. Güncelleme tamamlanmamış olabilir; sunucunun çalıştığı bilgisayarı kontrol edin.'
}
}
export const TR_DESKTOP: Translations['desktop'] = {
audioReadFailed: 'Kaydedilen ses okunamadı',
sessionUnavailable: 'Oturum kullanılamıyor',
createSessionFailed: 'Yeni oturum oluşturulamadı',
promptFailed: 'İstem gönderilemedi',
providerCredentialRequired: 'İlk mesajınızı göndermeden önce sağlayıcı kimlik bilgisi ekleyin.',
emptySlashCommand: 'eğik çizgi komutu boş',
desktopCommands: 'Masaüstü komutları',
skillCommandsAvailable: count => `${count} beceri komutu kullanılabilir.`,
warningLine: message => `uyarı: ${message}`,
yoloArmed: 'Bu sohbet için YOLO etkinleştirildi',
yoloOff: 'YOLO kapalı',
yoloSystem: active => `Bu oturumda YOLO ${active ? 'açık' : 'kapalı'}`,
yoloTitle: 'YOLO',
yoloToggleFailed: 'YOLO durumu değiştirilemedi',
profileStatus: current =>
`Profil: ${current}. Başka profilde sohbet başlatmak için /profile <ad> komutunu veya “Yeni oturum” seçicisini kullanın.`,
unknownProfile: 'Bilinmeyen profil',
noProfileNamed: (target, available) => `${target}” adlı profil yok. Kullanılabilir profiller: ${available}`,
newChatsProfile: name => `Yeni sohbetler ${name} profilini kullanacak.`,
setProfileFailed: 'Profil ayarlanamadı',
sttDisabled: 'Konuşmayı metne dönüştürme ayarlarda kapalı.',
stopFailed: 'Durdurulamadı',
regenerateFailed: 'Yeniden oluşturulamadı',
editFailed: 'Düzenlenemedi',
editTurnUnavailable: 'Bu tur artık sunucu geçmişinde yok; bağlam sıkıştırılırken kaldırılmış olabilir.',
resumeFailed: 'Sürdürülemedi',
readOnlyTranscriptTitle: 'Salt okunur açıldı',
readOnlyTranscriptBody:
'Bağlı sunuculardan hiçbiri bu eski sohbeti henüz sahiplenmediği için geçmiş salt okunur açıldı. Geçmiş korunuyor; bir sunucu sahiplenene kadar mesaj gönderilemez.',
readOnlyTranscriptSendBlocked: 'Bu sohbet salt okunur açıldı; mesaj gönderimi kapalı.',
resumeStrandedTitle: 'Oturum yüklenemedi',
resumeStrandedBody:
'Oturuma bağlanılamadı ve otomatik denemeler sona erdi. Ağ geçidinin çalıştığını kontrol edip yeniden deneyin.',
resumeRetry: 'Yeniden dene',
nothingToBranch: 'Dallanacak içerik yok',
branchNeedsChat: 'Dallanmadan önce bir sohbet başlatın veya sürdürün.',
sessionBusy: 'Oturum meşgul',
branchStopCurrent: 'Sohbeti dallandırmadan önce geçerli turu durdurun.',
branchNoText: 'Bu mesajda dallanma için metin yok.',
branchTitle: n => `Taslak: Dal #${n}`,
branchFailed: 'Dallanma başarısız oldu',
deleteFailed: 'Silinemedi',
archived: 'Arşivlendi',
archiveFailed: 'Arşivlenemedi',
cwdChangeFailed: 'Çalışma dizini değiştirilemedi',
cwdStagedTitle: 'Çalışma dizini değişikliği hazır',
cwdStagedMessage:
'Çalışma dizini değişikliğini bu etkin oturuma uygulamak için masaüstü sunucusunu yeniden başlatın.',
modelSwitchFailed: 'Model değiştirilemedi',
hydrationSyncing: profile => `${profile} eşitleniyor…`,
sessionExported: 'Oturum dışa aktarıldı',
sessionExportFailed: 'Oturum dışa aktarılamadı',
imageSaved: 'Görsel kaydedildi',
downloadStarted: 'İndirme başladı',
restartToUseSaveImage: 'Görsel kaydetmeyi kullanmak için AITURK IDEyi yeniden başlatın.',
restartToSaveImages: 'Görselleri kaydetmek için AITURK IDEyi yeniden başlatın',
imageDownloadFailed: 'Görsel indirilemedi',
openImage: 'Görseli aç',
downloadImage: 'Görseli indir',
savingImage: 'Görsel kaydediliyor',
imagePreviewFailed: 'Görsel önizlemesi açılamadı',
imageAttach: 'Görsel ekleme',
imageWriteFailed: 'Görsel diske yazılamadı.',
imageAttachFailed: 'Görsel eklenemedi',
attachImages: 'Görsel ekle',
clipboard: 'Pano',
noClipboardImage: 'Panoda görsel bulunamadı',
clipboardPasteFailed: 'Panodan yapıştırılamadı',
dropFiles: 'Dosyaları bırakın',
handoff: {
pickPlatform: 'Hedef seçin',
success: platform => `${platform} platformuna devredildi. İstediğiniz zaman buradan sürdürebilirsiniz.`,
systemNote: platform => `${platform} platformuna devredildi; istediğiniz zaman buradan sürdürün.`,
failed: error => `Devir başarısız oldu: ${error}`,
timedOut: 'Ağ geçidi beklenirken zaman aşımı oluştu. `hermes gateway` çalışıyor mu?'
}
}
export const TR_TIPS: Translations['tips'] = {
close: 'Bu ipucunu bir daha gösterme',
items: {
'new-session': {
title: 'Yeni bir başlangıç',
text: 'Her yeni sohbetin kendi bağlamı, terminali ve çalışma dizini vardır.'
},
skills: {
title: 'Bir kez öğretin',
text: 'Beceriler, AITURK’ün iş gerektirdiğinde yüklediği talimat klasörleridir.'
},
messaging: {
title: 'Masanızdan uzaktayken de AITURK',
text: 'Telegram, Discord, Slack ve diğer platformları bağlayın; aynı ajan ve bellekle çalışın.'
},
artifacts: {
title: 'AITURK’ün oluşturduğu her şey',
text: 'Tüm oturumların görselleri, dosyaları ve bağlantıları tek yerde listelenir.'
},
cron: {
title: 'Otomatik çalışan görevler',
text: 'Bir istemi saatlik, gecelik veya bir cron ifadesine göre zamanlayın.'
},
'command-palette': {
title: 'Her şeye tek yerden ulaşın',
text: 'Komut paletinden oturumlara, ayarlara, becerilere ve komutlara erişin.'
},
profiles: {
title: 'Profiller birbirinden bağımsızdır',
text: 'Her profilin kendi anahtarları, belleği ve oturumları vardır.'
},
'composer-mentions': {
title: 'Dosya ekleyin, komut çalıştırın',
text: 'Sohbete dosya eklemek için @, komut çalıştırmak için / yazın.'
},
'local-setup': {
title: 'Bu bilgisayar yerel model çalıştırabilir',
text: 'Donanımınız yerel bir modeli çalıştırabilir. Yerel model sohbetleri bilgisayarınızda kalır ve API kullanım ücreti oluşturmaz.',
action: 'Kurulumu yap'
},
'right-pane': {
title: 'Çalışma paneli',
text: 'Dosyalar, terminal, değişiklik incelemesi ve uygulama içi tarayıcı sağ paneli paylaşır.'
}
}
}
+260
View File
@@ -0,0 +1,260 @@
import { defineFieldCopy } from '@/app/settings/field-copy'
export const TR_FIELD_LABELS = defineFieldCopy({
model: 'Varsayılan model',
modelContextLength: 'Bağlam penceresi',
fallbackProviders: 'Yedek modeller',
toolsets: 'Etkin araç setleri',
timezone: 'Saat dilimi',
display: { personality: 'Asistan kişiliği', showReasoning: 'Düşünme bölümleri' },
desktop: {
repoScanEnabled: 'Git depolarını otomatik bul',
repoScanRoots: 'Depo arama klasörleri',
repoScanExcludePaths: 'Arama dışında bırakılan klasörler'
},
agent: {
maxTurns: 'En fazla ajan adımı',
imageInputMode: 'Görsel ekleri',
apiMaxRetries: 'API yeniden deneme sayısı',
serviceTier: 'Hizmet düzeyi',
toolUseEnforcement: 'Araç kullanımı zorunluluğu'
},
terminal: {
cwd: 'Çalışma dizini',
backend: 'Komut çalıştırma ortamı',
timeout: 'Komut zaman aşımı',
persistentShell: 'Kalıcı kabuk oturumu',
envPassthrough: 'Aktarılacak ortam değişkenleri',
dockerImage: 'Docker imajı',
singularityImage: 'Singularity imajı',
modalImage: 'Modal imajı',
daytonaImage: 'Daytona imajı'
},
fileReadMaxChars: 'Dosya okuma sınırı',
toolOutput: {
maxBytes: 'Terminal çıktısı sınırı',
maxLines: 'Dosya sayfası satır sınırı',
maxLineLength: 'Satır uzunluğu sınırı'
},
codeExecution: { mode: 'Kod çalıştırma modu' },
approvals: { mode: 'Onay modu', timeout: 'Onay zaman aşımı', mcpReloadConfirm: 'MCP yeniden yüklemelerini onayla' },
commandAllowlist: 'İzin verilen komutlar',
security: { redactSecrets: 'Gizli bilgileri maskele', allowPrivateUrls: 'Özel ağ adreslerine izin ver' },
browser: {
allowPrivateUrls: 'Tarayıcıda özel ağ erişimi',
autoLocalForPrivateUrls: 'Özel ağ adreslerinde yerel tarayıcı',
useRealProfile: 'Gerçek tarayıcı profilimi kullan'
},
checkpoints: { enabled: 'Dosya geri yükleme noktaları', maxSnapshots: 'Geri yükleme noktası sınırı' },
voice: {
recordKey: 'Ses kaydı kısayolu',
maxRecordingSeconds: 'En uzun kayıt süresi',
autoTts: 'Yanıtları sesli oku'
},
stt: {
enabled: 'Konuşmayı yazıya çevir',
echoTranscripts: 'Ses dökümlerini sohbete ekle',
provider: 'Konuşmayı yazıya çevirme sağlayıcısı',
local: { model: 'Yerel ses dökümü modeli', language: 'Ses dökümü dili' },
openai: { model: 'OpenAI ses dökümü modeli' },
groq: { model: 'Groq ses dökümü modeli' },
mistral: { model: 'Mistral ses dökümü modeli' },
elevenlabs: {
modelId: 'ElevenLabs ses dökümü modeli',
languageCode: 'ElevenLabs dili',
tagAudioEvents: 'Ses olaylarını etiketle',
diarize: 'Konuşmacıları ayırt et'
}
},
tts: {
provider: 'Metni seslendirme sağlayıcısı',
edge: { voice: 'Edge sesi' },
openai: { model: 'OpenAI seslendirme modeli', voice: 'OpenAI sesi' },
elevenlabs: { voiceId: 'ElevenLabs sesi', modelId: 'ElevenLabs modeli' },
xai: {
voiceId: 'xAI (Grok) sesi',
language: 'xAI dili',
speed: 'xAI konuşma hızı',
autoSpeechTags: 'xAI otomatik ses etiketleri',
optimizeStreamingLatency: 'xAI akış gecikmesi iyileştirmesi',
sampleRate: 'xAI örnekleme hızı',
bitRate: 'xAI bit hızı'
},
minimax: { model: 'MiniMax seslendirme modeli', voiceId: 'MiniMax sesi' },
mistral: { model: 'Mistral seslendirme modeli', voiceId: 'Mistral sesi' },
gemini: { model: 'Gemini seslendirme modeli', voice: 'Gemini sesi' },
neutts: { model: 'NeuTTS modeli', device: 'NeuTTS işlem aygıtı' },
kittentts: { model: 'KittenTTS modeli', voice: 'KittenTTS sesi' },
piper: { voice: 'Piper sesi' },
deepinfra: { model: 'DeepInfra seslendirme modeli', voice: 'DeepInfra sesi' }
},
memory: {
memoryEnabled: 'Kalıcı bellek',
userProfileEnabled: 'Kullanıcı profili',
memoryCharLimit: 'Bellek karakter sınırı',
userCharLimit: 'Profil karakter sınırı',
provider: 'Bellek sağlayıcısı'
},
context: { engine: 'Bağlam yönetimi' },
compression: {
enabled: 'Otomatik özetleme',
threshold: 'Özetleme eşiği',
targetRatio: 'Özetleme hedef oranı',
protectLastN: 'Korunacak son mesajlar'
},
delegation: {
model: 'Alt ajan modeli',
provider: 'Alt ajan sağlayıcısı',
maxIterations: 'Alt ajan adım sınırı',
maxConcurrentChildren: 'Eşzamanlı alt ajanlar',
childTimeoutSeconds: 'Alt ajan zaman aşımı',
reasoningEffort: 'Alt ajan düşünme düzeyi'
},
updates: { nonInteractiveLocalChanges: 'Güncellemede yerel değişiklikler' }
})
export const TR_FIELD_DESCRIPTIONS = defineFieldCopy({
model: 'Mesaj alanında başka bir model seçmediğiniz sürece yeni sohbetlerde kullanılır.',
modelContextLength: 'Seçilen modelin algılanan bağlam sınırını kullanmak için 0 bırakın.',
fallbackProviders: 'Varsayılan model başarısız olursa sırayla denenecek sağlayıcı ve model çiftleri.',
toolsets: 'Ajanın kullanabileceği araç gruplarını belirler.',
display: {
personality: 'Yeni oturumlarda kullanılacak varsayılan asistan üslubu.',
showReasoning: 'Sunucu sağladığında modelin düşünme bölümlerini gösterir.'
},
desktop: {
repoScanEnabled: 'Projeler bölümünde göstermek üzere yerel klasörlerde Git depoları arar.',
repoScanRoots: 'Aranacak klasörler. Boş bırakırsanız kullanıcı klasörünüz taranır.',
repoScanExcludePaths: 'Depo aranırken bu klasörler ve alt klasörleri atlanır.'
},
timezone: 'IANA saat dilimi kimliği; örneğin Europe/Istanbul. Boş bırakırsanız sistem saat dilimi kullanılır.',
browser: {
useRealProfile:
'Yerel taramada gerçek girişlerinizi kullanır. Varsayılan tarayıcınızın çerez, oturum ve tercihleri yönetilen bir kopyaya aktarılır; uygulamanın Chromium tarayıcısı bu kopyayı kullanır. Açık profiliniz doğrudan kullanılmaz ve kopya her çalıştırmada yenilenir. Bulut tarayıcısı seçiliyken de ajan yerel profil oturumu açabilir. Chrome, Edge, Brave ve Chromium desteklenir. Varsayılan olarak kapalıdır.',
allowPrivateUrls: 'Tarayıcının yerel ve özel ağ adreslerine erişip erişemeyeceğini belirler.',
autoLocalForPrivateUrls: 'Özel ağ adresleri için bu bilgisayardaki tarayıcıyı kullanır.'
},
agent: {
imageInputMode: 'Görsel eklerinin modele nasıl gönderileceğini belirler.',
maxTurns: 'Bir çalışma durdurulmadan önce yapılabilecek en fazla araç çağrısı adımı.',
apiMaxRetries: 'Geçici API hatalarında yapılabilecek yeniden deneme sayısı.',
serviceTier: 'Sağlayıcının desteklediği hizmet düzeyi. Kullanılabilirlik ve ücret sağlayıcıya bağlıdır.',
toolUseEnforcement: 'Modelin araç kullanım kurallarına nasıl uyması gerektiğini belirler.'
},
terminal: {
cwd: 'Araç ve terminal işlemleri için varsayılan proje klasörü.',
backend: 'Komutların çalıştırılacağı yerel veya yalıtılmış ortam.',
timeout: 'Bir terminal komutunun tamamlanması için beklenecek en uzun süre.',
persistentShell: 'Desteklenen ortamlarda komutlar arasında kabuk durumunu korur.',
envPassthrough: 'Araç çalıştırma ortamına aktarılacak ortam değişkenleri.',
dockerImage: 'Docker ortamında kullanılacak konteyner imajı.',
singularityImage: 'Singularity ortamında kullanılacak imaj.',
modalImage: 'Modal ortamında kullanılacak imaj.',
daytonaImage: 'Daytona ortamında kullanılacak imaj.'
},
codeExecution: { mode: 'Kod çalıştırmanın mevcut projeyle ne ölçüde sınırlandırılacağını belirler.' },
fileReadMaxChars: 'Tek dosya okuma isteğinde alınabilecek en fazla karakter sayısı.',
toolOutput: {
maxBytes: 'Terminal çıktısında alınabilecek en fazla bayt sayısı.',
maxLines: 'Bir dosya sayfasında alınabilecek en fazla satır sayısı.',
maxLineLength: 'Tek çıktı satırında izin verilen en fazla uzunluk.'
},
approvals: {
mode: 'Açık onay gerektiren komutların nasıl ele alınacağını belirler.',
timeout: 'Onay isteminin zaman aşımına kadar bekleyeceği süre.',
mcpReloadConfirm: 'MCP sunucularını yeniden yüklemeden önce onay ister.'
},
commandAllowlist: 'Onay kuralları kapsamında izin verilecek komut kalıpları.',
security: {
redactSecrets: 'Algılanan gizli bilgileri mümkün olduğunda modelin görebildiği içerikten gizler.',
allowPrivateUrls: 'Araçların yerel ve özel ağ URL adreslerine erişimini belirler.'
},
checkpoints: {
enabled: 'Dosya düzenlemelerinden önce geri alınabilir kopyalar oluşturur.',
maxSnapshots: 'Saklanacak en fazla geri yükleme noktası sayısı.'
},
memory: {
memoryEnabled: 'Gelecekteki oturumlara yardımcı olabilecek kalıcı bilgileri saklar.',
userProfileEnabled: 'Kullanıcı tercihlerinin kısa bir profilini tutar.',
memoryCharLimit: 'Kalıcı belleğe ayrılan en fazla karakter sayısı.',
userCharLimit: 'Kullanıcı profiline ayrılan en fazla karakter sayısı.',
provider: 'Kalıcı bilgilerin yönetileceği bellek hizmeti. Yerleşik belleği de kullanabilirsiniz.'
},
context: { engine: 'Bağlam sınırına yaklaşan uzun sohbetlerin nasıl yönetileceğini belirler.' },
compression: {
enabled: 'Sohbet uzadığında eski bağlamı özetler.',
threshold: 'Bağlam kullanımı bu eşiğe geldiğinde özetleme başlar.',
targetRatio: 'Özetlemeden sonra korunması hedeflenen bağlam oranı.',
protectLastN: 'Özetlenmeden korunacak son mesaj sayısı.'
},
voice: {
autoTts: 'Asistan yanıtlarını otomatik olarak seslendirir.',
recordKey: 'Ses kaydını başlatmak için kullanılacak kısayol.',
maxRecordingSeconds: 'Bir ses kaydının saniye cinsinden en uzun süresi.'
},
tts: {
provider: 'Yazılı yanıtları sese dönüştürecek hizmet veya yerel model.',
xai: {
voiceId: 'xAI ses kimliği (örneğin eve) veya özel ses kimliği.',
language: 'Konuşma dili kodu (örneğin tr veya en); otomatik algılama için auto.',
speed: 'Konuşma hızı: 0.7 yavaş, 1.0 normal, 1.5 hızlı.',
autoSpeechTags: 'Seslendirmeden önce metne [laughing] veya [sighs] gibi ifade etiketleri ekletir.',
optimizeStreamingLatency: 'Kalite ve gecikme dengesi: 0 en yüksek kalite, 2 en düşük gecikme.',
sampleRate: 'Hertz cinsinden örnekleme hızı. Daha yüksek değer, daha yüksek kalite ve daha büyük dosya demektir.',
bitRate: 'Saniye başına bit cinsinden MP3 bit hızı. Yalnızca MP3 biçiminde geçerlidir.'
},
neutts: { device: 'NeuTTS modelinin çalıştırılacağı yerel işlem aygıtı.' }
},
stt: {
enabled: 'Yerel model veya sağlayıcı üzerinden konuşmayı yazıya çevirmeyi açar.',
echoTranscripts: 'Sesli mesajların ham 🎙️ dökümünü sohbete de gönderir.',
provider: 'Ses kayıtlarını yazıya çevirecek hizmet veya yerel model.',
local: { language: 'Ses dökümünde kullanılacak dil.', model: 'Bu bilgisayarda çalışacak ses dökümü modeli.' },
elevenlabs: {
languageCode: 'İsteğe bağlı ISO-639-3 dil kodu. Türkçe için tur; boş bırakırsanız dil otomatik algılanır.',
tagAudioEvents: 'Konuşma dışındaki ses olaylarını döküme etiket olarak ekler.',
diarize: 'Ses kaydındaki farklı konuşmacıları ayırt eder.'
}
},
delegation: {
model: 'Alt ajanların varsayılan modeli.',
provider: 'Alt ajanların model isteklerini işleyecek sağlayıcı.',
maxIterations: 'Her alt ajanın yapabileceği en fazla adım.',
maxConcurrentChildren: 'Aynı anda çalışabilecek en fazla alt ajan sayısı.',
childTimeoutSeconds: 'Alt ajan çalışması için saniye cinsinden en uzun süre.',
reasoningEffort: 'Alt ajan modelinin düşünmeye ayıracağı çaba. Destek modele bağlıdır.'
},
updates: {
nonInteractiveLocalChanges:
'Uygulama içinden güncellerken yerel kaynak değişiklikleri saklanır (stash) veya silinir (discard). Terminalden güncelleme her zaman sorar.'
}
})
// Only display labels change; model IDs and serialized option values stay intact.
export const TR_FIELD_OPTIONS: Record<string, Record<string, string>> = {
'approvals.mode': { manual: 'Elle onayla', smart: 'Akıllı onay', off: 'Kapalı' },
'agent.image_input_mode': { auto: 'Otomatik', native: 'Doğrudan modele gönder', text: 'Metin olarak işle' },
'agent.service_tier': { auto: 'Otomatik', default: 'Varsayılan', flex: 'Esnek', priority: 'Öncelikli' },
'terminal.backend': {
local: 'Yerel bilgisayar',
docker: 'Docker',
singularity: 'Singularity',
modal: 'Modal',
daytona: 'Daytona',
ssh: 'SSH'
},
'code_execution.mode': { project: 'Proje kapsamında', strict: 'Sıkı yalıtım' },
'context.engine': { compressor: 'Özetleyici', default: 'Varsayılan', custom: 'Özel' },
'stt.provider': { local: 'Yerel model' },
'tts.neutts.device': { cpu: 'İşlemci (CPU)', cuda: 'NVIDIA ekran kartı (CUDA)', mps: 'Apple grafik işlemcisi (MPS)' },
'updates.non_interactive_local_changes': { stash: 'Değişiklikleri sakla', discard: 'Değişiklikleri sil' },
'delegation.reasoning_effort': {
none: 'Yok',
minimal: 'En az',
low: 'Düşük',
medium: 'Orta',
high: 'Yüksek',
xhigh: 'Çok yüksek',
max: 'En yüksek'
}
}
+90
View File
@@ -0,0 +1,90 @@
import type { Translations } from './types'
export const TR_KEYBINDS: Translations['keybinds'] = {
title: 'Klavye kısayolları',
subtitle: open => `Değiştirmek için kısayola tıklayın. Bu paneli yeniden açmak için ${open}.`,
search: 'Kısayol ara…',
rebind: 'Değiştir',
reset: 'Varsayılana dön',
resetAll: 'Tümünü sıfırla',
pressKey: 'Bir tuşa basın…',
set: 'ayarla',
conflictWith: label => `${label}” için de kullanılıyor`,
categories: {
composer: 'Mesaj yazma',
profiles: 'Profiller',
session: 'Oturum',
navigation: 'Gezinme',
view: 'Görünüm'
},
actions: {
'keybinds.openPanel': 'Klavye kısayollarını aç',
'nav.commandPalette': 'Komut listesini aç',
'nav.commandCenter': 'Komut merkezini aç',
'nav.settings': 'Ayarları aç',
'nav.profiles': 'Profilleri aç',
'nav.skills': 'Yetenekleri aç',
'nav.messaging': 'Mesajlaşmayı aç',
'nav.artifacts': 'Çıktıları aç',
'nav.cron': 'Zamanlanmış işleri aç',
'nav.agents': 'Ajanları aç',
'session.new': 'Yeni oturum',
'session.newTab': 'Yeni oturum sekmesi',
'session.newWindow': 'Yeni pencere',
'session.next': 'Sonraki oturum',
'session.prev': 'Önceki oturum',
...Object.fromEntries(
Array.from({ length: 9 }, (_, index) => [`session.slot.${index + 1}`, `${index + 1}. son oturuma geç`])
),
'session.focusSearch': 'Oturumlarda ara',
'session.togglePin': 'Geçerli oturumu sabitle veya sabitlemeyi kaldır',
'session.archive': 'Geçerli oturumu arşivle',
'workspace.newWorktree': 'Yeni Git çalışma ağacı',
'workspace.openFolder': 'Klasörü proje olarak aç',
'composer.focus': 'Mesaj alanına odaklan',
'composer.modelPicker': 'Model seçiciyi aç',
'composer.voice': 'Sesli görüşmeyi başlat veya durdur',
'view.toggleSidebar': 'Oturum kenar çubuğunu göster veya gizle',
'view.toggleRightSidebar': 'Dosya gezginini göster veya gizle',
'view.toggleReview': 'İnceleme panelini göster veya gizle',
'view.toggleStatusbar': 'Durum çubuğunu göster veya gizle',
'view.toggleTabStrip': 'Sekmeleri göster veya gizle',
'view.showFiles': 'Dosya gezginini göster',
'view.showBrowser': 'Tarayıcıyı aç',
'view.toggleHud': 'Yüzen görünümü aç veya kapat',
'hud.snapToPointer': 'Yüzen görünümü fare işaretçisine taşı; açıkken tüm uygulamalarda geçerlidir',
'view.showTerminal': 'Terminali göster veya gizle',
'view.newTerminal': 'Yeni terminal',
'view.nextTerminal': 'Sonraki terminal',
'view.prevTerminal': 'Önceki terminal',
'view.closeTerminal': 'Terminali kapat',
'view.selectionToComposer': 'Seçimi mesaj alanına gönder',
'view.terminalCopy': 'Terminaldeki seçimi kopyala',
'view.terminalPaste': 'Terminale yapıştır',
'view.closeTab': 'Sekmeyi kapat',
'view.reopenTab': 'Kapatılan sekmeyi yeniden aç',
'view.flipPanes': 'Kenar çubuklarının yerini değiştir',
'view.findInPage': 'Sayfada bul',
'view.findNext': 'Sonraki eşleşmeyi bul',
'view.findPrevious': 'Önceki eşleşmeyi bul',
'appearance.toggleMode': 'Açık veya koyu görünüme geç',
'profile.default': 'Varsayılan profile geç',
...Object.fromEntries(
Array.from({ length: 18 }, (_, index) => [`profile.switch.${index + 1}`, `${index + 1}. profile geç`])
),
'profile.next': 'Sonraki profil',
'profile.prev': 'Önceki profil',
'profile.toggleAll': 'Tüm profiller görünümünü aç veya kapat',
'profile.create': 'Profil oluştur',
'composer.send': 'Mesajı gönder',
'composer.newline': 'Yeni satır ekle',
'composer.steer': 'Devam eden işi yönlendir',
'composer.queue': 'Mesajı kuyruğa ekle',
'composer.sendQueued': 'Sıradaki mesajı gönder',
'composer.mention': 'Dosya, klasör veya URL belirt',
'composer.slash': 'Eğik çizgi komut listesi',
'composer.help': 'Hızlı yardım',
'composer.history': 'Açılır liste veya geçmişte gezin',
'composer.cancel': 'Açılır listeyi kapat veya çalışmayı durdur'
}
}
+118
View File
@@ -0,0 +1,118 @@
import type { Translations } from './types'
export const TR_LOCAL_MODELS: Translations['settings']['localModels'] = {
title: 'Yerel modeller',
runtimeTitle: 'Yerel çalışma ortamı',
runtimeReady: backend => `Hazır · ${backend}`,
serverRunning: 'Çalışıyor',
runtimeInstalled: 'llama.cpp çalışma ortamı yüklü',
runtimeInstalledDetail: (tag, backend) =>
`${tag} derlemesi, ${backend} ortamı. Sunucuyu uygulama başlatır ve yönetir.`,
installTitle: 'Yerel çalışma ortamını yükle',
installDetail:
'llama.cpp çıkarım motorunu indirir (birkaç yüz MB). İndirdiğiniz modeller tamamen bu bilgisayarda çalışır; hesap gerekmez ve veriler bilgisayarınızdan çıkmaz.',
installAction: 'Çalışma ortamını yükle',
installing: 'Çalışma ortamı yükleniyor…',
installFailed: 'Çalışma ortamı yüklenemedi',
hardwareTitle: 'Bu bilgisayar',
hardwareLoading: 'Donanım denetleniyor…',
vram: label => `${label} ekran kartı belleği`,
ram: label => `${label} RAM`,
unifiedMemory: 'Birleşik bellek',
modelsTitle: 'Modeller',
recommended: 'Önerilen',
recommendedReason: {
'best-quality-resident':
'Tamamen ekran kartı belleğinde tam hızda çalışan en yüksek kaliteli model. Seçimde bu donanımdaki tahmini hız ve kalite birlikte değerlendirilir.',
'speed-gated-quality':
'Daha yüksek kaliteli bir model sığıyor ancak bellek bant genişliği nedeniyle çok yavaş yanıt verirdi. Bu model, hızlı kalabilen en iyi seçenektir.',
'fastest-resident':
'Bu donanımda hiçbir model tam hıza ulaşmıyor. Tamamen ekran kartı belleğinde çalışanlar arasında en yakını bu model.',
'least-painful-spilled':
'Hiçbir model tamamen ekran kartı belleğine sığmıyor. Sistem belleğinden en iyi çalışan seçenek bu model.'
},
downloaded: 'İndirildi',
downloadAction: size => `İndir · ${size}`,
downloadProgress: (done, total) => `İndiriliyor: ${done} / ${total}`,
downloadDoneToast: model => `${model} hazır.`,
installDoneToast: 'Yerel çalışma ortamı yüklendi ve hazır.',
quickstartTitle: 'Bu bilgisayarda bir model çalıştır',
quickstartDetail: (model, size) =>
`Tek tıklamayla yerel motoru ve ${model} modelini kurar (${size} indirme), yeni sohbetlerde varsayılan yapar. Veriler bu bilgisayarda kalır.`,
quickstartDetailReady: model =>
`${model}, yeni sohbetlerde varsayılan model yapılır. Her şey bu bilgisayarda çalışır.`,
quickstartAction: 'Benim için kur',
quickstartConfigure: 'Yapılandır…',
quickstartDoneToast: model => `${model} kuruldu. Yeni sohbetler bu bilgisayarda çalışacak.`,
quickstartFailed: 'Yerel model kurulamadı',
quickstartStageEngine: 'Motor',
quickstartStageModel: 'Model',
quickstartStageFinish: 'Tamamla',
useAction: 'Kullan',
activePill: 'Varsayılan',
updateTitle: 'Motor güncellemesi var',
updateDetail: (next, current) =>
`Yeni llama.cpp derlemesi ${next} yüklenebilir. Mevcut sürümünüz ${current}. İndirme sırasında modeller çalışmaya devam eder.`,
updateAction: 'Motoru güncelle',
updating: 'Motor güncelleniyor…',
upToDateTitle: 'Motor güncel',
upToDateDetail: (tag, backend) => `llama.cpp ${tag} (${backend}) çalışıyor; uygulamanın sunduğu güncel derleme.`,
updateToast: next => `Yeni yerel motor derlemesi ${next} hazır. Ayarlar → Yerel modeller bölümünden güncelleyin.`,
activeDetail: 'Yeni sohbetler bu modeli kullanır. İlk mesajı gönderdiğinizde belleğe yüklenir.',
activeNotLoaded: 'İlk mesajınızda belleğe yüklenir',
loadedPill: 'Bellekte',
placementResident: 'tamamı ekran kartında',
placementSpilled: 'bir kısmı RAMde',
placementResidentTip: 'Bu bağlam boyutunda tamamen ekran kartı belleğinde, tam hızda çalışır.',
placementSpilledTip:
'Modelin bir kısmı sistem belleğinden çalışıyor. Daha küçük bir derleme veya bağlam boyutu, modelin tamamen ekran kartına sığmasını sağlayabilir.',
loadingPill: 'Yükleniyor…',
ejectTip: 'Ekran kartı belleğini boşalt; sonraki mesajda yeniden yüklenir',
ejected: 'Model bellekten çıkarıldı; ekran kartı belleği boşaltıldı.',
ejectFailed: 'Model bellekten çıkarılamadı',
stopServer: 'Kapat',
startServer: 'Aç',
runtimeRunningDetail:
'Yerel sunucu çalışıyor. Kapatırsanız ekran kartı belleği boşalır; tekrar açana kadar yeni sohbetler yerel modelleri kullanamaz.',
serverStopped: 'Yerel sunucu durdu; ekran kartı belleği boşaltıldı.',
serverStarted: 'Yerel sunucu çalışıyor.',
serverStopFailed: 'Yerel sunucu durdurulamadı',
serverStartFailed: 'Yerel sunucu başlatılamadı',
activating: 'Başlatılıyor…',
activateFailed: model => `${model} modeline geçilemedi`,
activateDoneToast: model => `Yeni sohbetler ${model} modelini kullanacak.`,
downloadFailed: model => `${model} indirilemedi`,
pillFitsGpu: 'Ekran kartına sığıyor',
pillUsesRam: 'Sistem belleğini kullanır',
pillTooBig: 'Bu bilgisayar için çok büyük',
browseTitle: 'Başka modeller bul',
browseHint:
'Hugging Face genelinde arayın. Buradan indirilen modeller bilgisayarınızın kapasitesine göre seçilir; tarafımızca test edilmemiş olabilir.',
browsePlaceholder: 'Model adı veya geliştirici ara…',
browseSearching: 'Hugging Face aranıyor',
browseListing: 'Model dosyaları okunuyor',
browseShowFiles: 'Dosyaları göster',
browseRefresh: 'Yenile',
browseDownloads: 'indirme',
browseLikes: 'beğeni',
browseGated: 'Hugging Face girişi gerekiyor',
browseNoGguf: 'Uyumlu model dosyası bulunamadı.',
browseFitUnknown: 'Donanım uyumu bilinmiyor',
browseAlreadyDownloaded: 'Zaten indirildi.',
addedByYou: 'Sizin eklediğiniz',
browseDownloadStarted: '{name} indiriliyor',
browseDownloadAria: '{name} modelini indir',
sideloadButton: 'Model dosyası ekle',
sideloadTitle: 'GGUF model dosyası seçin',
sideloadDone: '{name} eklendi.',
sideloadAlreadyPresent: 'Zaten kitaplığınızda.',
pillFullContext: max => `Tam ${max} bağlam`,
pillFullContextTip: 'Başlangıçtan itibaren modelin tam bağlam penceresiyle çalışır',
pillUpTo: max => `${max} değerine kadar bağlam`,
pillGrowsTip: 'Sohbetiniz daha fazla alana ihtiyaç duydukça otomatik büyür',
pillVision: 'Görselleri anlayabilir',
deleteAction: 'Modeli sil',
deleteConfirm: model => `${model} diskten silinsin mi?`,
deleted: model => `${model} silindi.`,
deleteFailed: 'Silinemedi'
}
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest'
import type { MemoryProviderField } from '@/types/hermes'
import { localizeMemoryField } from './tr-memory-fields'
describe('memory provider presentation', () => {
const field: MemoryProviderField = {
key: 'sessionStrategy',
label: 'Session strategy',
kind: 'select',
description: 'How sessions map.',
group: 'Session',
info: 'Choose a strategy.',
inline: true,
is_set: true,
value: 'per-directory',
placeholder: '',
options: [
{ value: 'per-directory', label: 'Per directory', description: '' },
{ value: 'future', label: 'Custom option', description: 'Plugin supplied' }
]
}
it('translates guidance while preserving current, unknown and future values', () => {
const translated = localizeMemoryField('honcho', field, 'tr')
expect(translated.label).toBe('Oturum stratejisi')
expect(translated.info).toContain('Klasör başına')
expect(translated.group).toBe('Oturum')
expect(translated.options[0].label).toBe('Klasör başına')
expect(translated.options.map(option => option.value)).toEqual(field.options.map(option => option.value))
expect(translated.options[1]).toBe(field.options[1])
expect(translated.value).toBe(field.value)
expect(translated.key).toBe(field.key)
expect(field.label).toBe('Session strategy')
})
it('leaves other languages and third-party provider declarations unchanged', () => {
expect(localizeMemoryField('honcho', field, 'en')).toBe(field)
expect(localizeMemoryField('custom-provider', field, 'tr')).toBe(field)
const future = { ...field, key: 'unknown-option' }
expect(localizeMemoryField('honcho', future, 'tr')).toBe(future)
})
})
+196
View File
@@ -0,0 +1,196 @@
import type { MemoryProviderField } from '@/types/hermes'
type FieldCopy = Pick<MemoryProviderField, 'label'> &
Partial<Pick<MemoryProviderField, 'description' | 'info' | 'placeholder'>> & {
options?: Record<string, string | { label: string; description: string }>
}
const reasoning = { minimal: 'En az', low: 'Düşük', medium: 'Orta', high: 'Yüksek', max: 'En yüksek' }
/** Only presentation is translated; provider keys, credentials and enum values remain authoritative. */
export const TR_MEMORY_FIELDS: Record<string, Record<string, FieldCopy>> = {
honcho: {
apiKey: {
label: 'API anahtarı',
description: 'Honcho Cloud kimlik doğrulaması. Kendi sunucunuzdaki temel URL için gerekli değildir.',
placeholder: 'Honcho API anahtarını girin'
},
baseUrl: {
label: 'Temel URL',
description: 'Kendi sunucunuzdaki Honcho adresi. Belirtildiğinde ortam değişkenindeki adresin yerine kullanılır.',
placeholder: 'https://… (kendi sunucunuz)'
},
environment: {
label: 'Ortam',
description: 'Honcho ortamı. Temel URL belirtildiğinde kullanılmaz.',
options: { production: 'Bulut', local: 'Yerel' }
},
workspace: {
label: 'Çalışma alanı',
description: 'Honcho çalışma alanı kimliği. Varsayılan olarak profilin ana bilgisayarını kullanır.'
},
peerName: {
label: 'Kullanıcı kimliği',
description:
'Sabit kullanıcı kimliğiniz. Tek kullanıcılı kurulumlarda farklı platformların belleğini birleştirir.',
placeholder: 'ör. eri'
},
aiPeer: {
label: 'Yapay zekâ kimliği',
description: 'Yapay zekâ tarafının kimlik adı. Varsayılan olarak profilin ana bilgisayarını kullanır.'
},
sessionStrategy: {
label: 'Oturum stratejisi',
description: 'Konuşmaların Honcho oturumlarıyla nasıl eşleştirileceği.',
info: 'Oturum başına: her konuşma ayrı bir Honcho oturumu kullanır. Klasör başına: aynı çalışma klasöründeki konuşmalar ortak oturum kullanır. Depo başına: aynı Git deposundaki konuşmalar ortak oturum kullanır. Genel: tüm konuşmalar tek bir oturumu paylaşır.',
options: {
'per-session': 'Oturum başına',
'per-directory': 'Klasör başına',
'per-repo': 'Depo başına',
global: 'Genel'
}
},
timeout: {
label: 'İstek zaman aşımı',
description:
'Honcho HTTP istekleri için saniye cinsinden zaman aşımı. Boş bırakılırsa varsayılan süre kullanılır.'
},
pinUserPeer: {
label: 'Kullanıcı kimliğini sabitle',
description:
'Ağ geçidinin çalışma anındaki kimliği yerine belirtilen kullanıcı adını kullanır. Tek kullanıcılı kurulumlarda belleği birleştirir.'
},
runtimePeerPrefix: {
label: 'Çalışma anındaki kimlik öneki',
description: 'Ağ geçidinden gelen bilinmeyen kullanıcı kimliklerine eklenecek önek.',
placeholder: 'ör. telegram_'
},
userPeerAliases: {
label: 'Kullanıcı kimliği eşleştirmeleri',
description: 'Ağ geçidinin kullanıcı kimliklerini sabit Honcho kimlikleriyle eşleştirir.'
},
sessionPeerPrefix: {
label: 'Oturum kimliği öneki',
description: 'Oturum kimliği adlarının başına ana bilgisayar adını ekler.'
},
sessions: {
label: 'Özel oturum eşleştirmeleri',
description: 'Çözümleyici anahtarına göre kullanılacak oturum kimlikleri.'
},
saveMessages: { label: 'Mesajları kaydet', description: 'Konuşma mesajlarını Honcho üzerinde saklar.' },
writeFrequency: {
label: 'Yazma sıklığı',
description: 'Mesajların yazılacağı zaman: async, turn, session veya her N turda bir.',
info: 'async: mesajları geldikçe arka planda yazar. turn: her turun sonunda yazar. session: oturum sona erdiğinde yazar. N sayısı: her N turda bir yazar.'
},
dialecticReasoningLevel: {
label: 'Akıl yürütme düzeyi',
description: 'Diyalektik (peer.chat) çağrıları için akıl yürütme çabası.',
options: reasoning
},
dialecticDynamic: {
label: 'Dinamik akıl yürütme',
description: 'Modelin her çağrı için akıl yürütme düzeyini değiştirmesine izin verir.'
},
dialecticMaxChars: {
label: 'En fazla sonuç karakteri',
description: 'Sistem istemine eklenecek diyalektik sonucunun karakter sınırı.'
},
dialecticDepth: { label: 'Derinlik', description: 'Her döngüdeki diyalektik geçiş sayısı (13).' },
dialecticDepthLevels: {
label: 'Geçiş başına düzeyler',
description: 'Her geçişin akıl yürütme düzeyi; dizinin uzunluğu derinlik değeriyle eşleşmelidir.'
},
dialecticMaxInputChars: {
label: 'En fazla girdi karakteri',
description: 'peer.chat() çağrısına gönderilen sorgunun karakter sınırı.'
},
reasoningHeuristic: {
label: 'Uyarlanabilir akıl yürütme',
description: 'Uzun sorgularda akıl yürütme düzeyini yükseltir.'
},
reasoningLevelCap: {
label: 'Akıl yürütme üst sınırı',
description: 'Uyarlanabilir seçimde kullanılabilecek en yüksek akıl yürütme düzeyi.',
options: reasoning
},
recallMode: {
label: 'Bellekten getirme yöntemi',
description: 'Bellek bilgisinin getirilme yöntemi: karma, yalnızca bağlam veya yalnızca araçlar.',
info: 'Karma: otomatik eklenen bağlam ve gerektiğinde bellek araçları. Yalnızca bağlam: araçlar olmadan bağlama ekleme. Yalnızca araçlar: model belleği açıkça sorgular; bağlama otomatik ekleme yapılmaz.',
options: { hybrid: 'Karma', context: 'Yalnızca bağlam', tools: 'Yalnızca araçlar' }
},
contextTokens: {
label: 'Bağlam token sınırı',
description: 'Otomatik eklenen bağlam için token sınırı. Boş bırakılırsa sınır uygulanmaz.',
placeholder: '(sınırsız)'
},
initOnSessionStart: {
label: 'Oturum başında hazırla',
description: 'Araçlar modunda oturumu ilk araç çağrısını beklemeden başlangıçta hazırlar.'
},
messageMaxChars: {
label: 'Mesaj karakter sınırı',
description: 'Honchoya gönderilen her mesaj için en fazla karakter sayısı.'
},
observationMode: {
label: 'Gözlem yöntemi',
description:
'Kimlik başına gözlem ön ayarı. Yönlü gözlem tüm yönleri izler; birleşik gözlem ortak bir görünüm kullanır.',
options: { directional: 'Yönlü', unified: 'Birleşik' }
}
},
hindsight: {
mode: {
label: 'Bağlantı yöntemi',
description: 'AITURK’ün Hindsight ile bağlantı kurma yöntemi.',
options: {
cloud: { label: 'Bulut', description: 'Hindsight Cloud API; yalnızca API anahtarı gerektirir.' },
local_external: { label: 'Mevcut yerel sunucu', description: 'Çalışan bir Hindsight sunucusuna bağlanır.' }
}
},
api_key: {
label: 'API anahtarı',
description: 'Hindsight API kimlik doğrulaması için kullanılır.',
placeholder: 'Hindsight API anahtarını girin'
},
api_url: { label: 'API adresi' },
bank_id: { label: 'Bellek bankası kimliği' },
recall_budget: { label: 'Bellekten getirme bütçesi', options: { low: 'Düşük', mid: 'Orta', high: 'Yüksek' } }
}
}
const GROUPS: Record<string, string> = {
Connection: 'Bağlantı',
Identity: 'Kimlik',
Session: 'Oturum',
'Message writing': 'Mesajların yazılması',
Dialectic: 'Diyalektik',
Reasoning: 'Akıl yürütme',
Recall: 'Bellekten getirme',
Limits: 'Sınırlar',
Observation: 'Gözlem'
}
export function localizeMemoryField(provider: string, field: MemoryProviderField, locale: string): MemoryProviderField {
const copy = locale === 'tr' ? TR_MEMORY_FIELDS[provider]?.[field.key] : undefined
if (!copy) {
return field
}
const { options, ...text } = copy
return {
...field,
...text,
group: GROUPS[field.group] ?? field.group,
options: field.options.map(option => {
const translated = options?.[option.value]
return translated
? { ...option, ...(typeof translated === 'string' ? { label: translated } : translated) }
: option
})
}
}
+233
View File
@@ -0,0 +1,233 @@
import type { Translations } from './types'
export const TR_MESSAGING: Translations['messaging'] = {
search: 'Mesajlaşma platformlarında ara…',
loading: 'Mesajlaşma platformları yükleniyor…',
loadFailed: 'Mesajlaşma platformları yüklenemedi',
states: {
connected: 'Bağlı',
connecting: 'Bağlanıyor',
disabled: 'Devre dışı',
fatal: 'Hata',
gateway_stopped: 'Mesajlaşma ağ geçidi durdu',
not_configured: 'Kurulum gerekiyor',
pending_restart: 'Yeniden başlatma gerekiyor',
retrying: 'Yeniden deneniyor',
startup_failed: 'Başlatılamadı'
},
unknown: 'Bilinmiyor',
hintPendingRestart: 'Değişikliği uygulamak için durum çubuğundan ağ geçidini yeniden başlatın.',
hintGatewayStopped: 'Bağlanmak için durum çubuğundan ağ geçidini başlatın.',
credentialsSet: 'Kimlik bilgileri kaydedildi',
needsSetup: 'Kurulum gerekiyor',
gatewayStopped: 'Mesajlaşma ağ geçidi durdu',
getCredentials: 'Kimlik bilgilerinizi alın',
openSetupGuide: 'Kurulum kılavuzunu aç',
required: 'Gerekli',
recommended: 'Önerilen',
advanced: count => `Gelişmiş (${count})`,
noTokenNeeded:
'Bu platform için burada erişim anahtarı gerekmez. Yukarıdaki kurulum kılavuzunu izleyip aşağıdan etkinleştirin.',
enabled: 'Etkin',
disabled: 'Devre dışı',
unsavedChanges: 'Kaydedilmemiş değişiklikler',
saving: 'Kaydediliyor…',
saveChanges: 'Değişiklikleri kaydet',
saved: 'Kaydedildi',
replaceValue: 'Geçerli değeri değiştir',
openDocs: 'Belgeleri aç',
clearField: key => `${key} alanını temizle`,
enableAria: name => `${name} etkinleştir`,
disableAria: name => `${name} devre dışı bırak`,
platformEnabled: name => `${name} etkinleştirildi`,
platformDisabled: name => `${name} devre dışı bırakıldı`,
restartToApply: 'Değişiklik ağ geçidi yeniden başlatıldıktan sonra geçerli olur.',
setupSaved: name => `${name} ayarları kaydedildi`,
restartToReconnect: 'Yeni kimlik bilgileri ağ geçidi yeniden başlatıldıktan sonra geçerli olur.',
keyCleared: key => `${key} temizlendi`,
setupUpdated: name => `${name} ayarları güncellendi.`,
failedUpdate: name => `${name} güncellenemedi`,
failedSave: name => `${name} kaydedilemedi`,
failedClear: key => `${key} temizlenemedi`,
pendingRequests: count => `Bekleyen istekler (${count})`,
pendingAria: count => `${count} bekleyen eşleştirme isteği`,
approvedUsers: count => `Onaylanan kullanıcılar (${count})`,
approve: 'Onayla',
approving: 'Onaylanıyor…',
revoke: 'Erişimi kaldır',
revoking: 'Erişim kaldırılıyor…',
revokeAria: name => `${name} erişimini kaldır`,
revokeTitle: 'Erişimi kaldır',
revokeDesc: name => `${name} erişimini kaybeder ve sonraki mesajında tanınmaz.`,
approvedUser: name => `${name} onaylandı`,
approvedHint: 'Sonraki mesajında otomatik olarak tanınır.',
revokedUser: name => `${name} erişimi kaldırıldı`,
failedApprove: name => `${name} onaylanamadı`,
failedRevoke: name => `${name} erişimi kaldırılamadı`,
pairingLockedOut: 'Çok fazla başarısız onay denemesi nedeniyle platform kilitlendi. Daha sonra yeniden deneyin.',
waitingSince: minutes => (minutes < 1 ? 'az önce' : `${minutes} dk önce`),
fieldCopy: {
TELEGRAM_BOT_TOKEN: {
label: 'Bot erişim anahtarı',
help: '@BotFather ile bir bot oluşturup verilen anahtarı yapıştırın.',
placeholder: 'Telegram bot anahtarını yapıştırın'
},
TELEGRAM_ALLOWED_USERS: {
label: 'İzin verilen Telegram kullanıcı kimlikleri',
help: 'Önerilir. @userinfobot üzerinden alınan sayısal kimlikleri virgülle ayırın. Boş bırakırsanız herkes botunuza özel mesaj gönderebilir.'
},
TELEGRAM_PROXY: {
label: 'Vekil sunucu adresi',
help: 'Yalnızca Telegram erişiminin engellendiği ağlarda gerekir.'
},
DISCORD_BOT_TOKEN: {
label: 'Bot erişim anahtarı',
help: 'Discord Developer Portal üzerinden bir uygulama oluşturun, bot ekleyin ve anahtarını yapıştırın.'
},
DISCORD_ALLOWED_USERS: {
label: 'İzin verilen Discord kullanıcı kimlikleri',
help: 'Önerilir. Discord kullanıcı kimliklerini virgülle ayırın.'
},
DISCORD_REPLY_TO_MODE: {
label: 'Yanıtlama biçimi',
help: 'first: ilk mesaja yanıt, all: tüm mesajlara yanıt, off: kapalı.'
},
DISCORD_ALLOW_ALL_USERS: {
label: 'Tüm Discord kullanıcılarına izin ver',
help: 'Yalnızca geliştirme içindir. true olduğunda izin listesi olmadan herkes bota özel mesaj gönderebilir.'
},
DISCORD_HOME_CHANNEL: {
label: 'Ana kanal kimliği',
help: 'Botun zamanlanmış görev çıktılarını ve hatırlatmaları gönderdiği kanal.'
},
DISCORD_HOME_CHANNEL_NAME: {
label: 'Ana kanal adı',
help: 'Ana kanalın günlüklerde ve durum çıktısında görünen adı.'
},
BLUEBUBBLES_ALLOW_ALL_USERS: {
label: 'Tüm iMessage kullanıcılarına izin ver',
help: 'true olduğunda BlueBubbles izin listesi denetimi atlanır.'
},
MATTERMOST_ALLOW_ALL_USERS: { label: 'Tüm Mattermost kullanıcılarına izin ver' },
MATTERMOST_HOME_CHANNEL: { label: 'Ana kanal' },
QQ_ALLOW_ALL_USERS: { label: 'Tüm QQ kullanıcılarına izin ver' },
QQBOT_HOME_CHANNEL: {
label: 'QQ ana kanalı',
help: 'Zamanlanmış görev çıktıları için varsayılan kanal veya grup.'
},
QQBOT_HOME_CHANNEL_NAME: { label: 'QQ ana kanal adı' },
SLACK_BOT_TOKEN: {
label: 'Slack bot erişim anahtarı',
help: 'Slack uygulamanızı kurduktan sonra OAuth & Permissions bölümündeki bot anahtarını kullanın.',
placeholder: 'Slack bot anahtarını yapıştırın'
},
SLACK_APP_TOKEN: {
label: 'Slack uygulama erişim anahtarı',
help: 'Socket Mode için gereken uygulama düzeyindeki anahtarı kullanın.',
placeholder: 'Slack uygulama anahtarını yapıştırın'
},
SLACK_ALLOWED_USERS: {
label: 'İzin verilen Slack kullanıcı kimlikleri',
help: 'Önerilir. Slack kullanıcı kimliklerini virgülle ayırın.'
},
MATTERMOST_URL: { label: 'Sunucu adresi', placeholder: 'https://mattermost.example.com' },
MATTERMOST_TOKEN: { label: 'Bot erişim anahtarı' },
MATTERMOST_ALLOWED_USERS: {
label: 'İzin verilen kullanıcı kimlikleri',
help: 'Önerilir. Mattermost kullanıcı kimliklerini virgülle ayırın.'
},
MATRIX_HOMESERVER: { label: 'Ana sunucu adresi', placeholder: 'https://matrix.org' },
MATRIX_ACCESS_TOKEN: { label: 'Erişim anahtarı' },
MATRIX_USER_ID: { label: 'Bot kullanıcı kimliği', placeholder: '@aiturk:example.org' },
MATRIX_ALLOWED_USERS: {
label: 'İzin verilen Matrix kullanıcı kimlikleri',
help: 'Önerilir. @kullanici:sunucu biçimindeki kimlikleri virgülle ayırın.'
},
SIGNAL_HTTP_URL: {
label: 'Signal köprü adresi',
placeholder: 'http://127.0.0.1:8080',
help: 'Çalışan signal-cli REST köprüsünün adresi.'
},
SIGNAL_ACCOUNT: { label: 'Telefon numarası', help: 'signal-cli köprünüze kayıtlı numara.' },
SIGNAL_ALLOWED_USERS: {
label: 'İzin verilen Signal kullanıcıları',
help: 'Önerilir. Signal kimliklerini virgülle ayırın.'
},
WHATSAPP_ENABLED: {
label: 'WhatsApp köprüsünü etkinleştir',
help: 'Aşağıdaki anahtarla otomatik ayarlanır. Özel bir gereksiniminiz yoksa değiştirmeyin.'
},
WHATSAPP_MODE: { label: 'Köprü modu' },
WHATSAPP_ALLOWED_USERS: {
label: 'İzin verilen WhatsApp kullanıcıları',
help: 'Önerilir. Telefon numaralarını veya WhatsApp kimliklerini virgülle ayırın.'
}
},
platformIntro: {}
}
export const TR_WEBHOOKS: Translations['webhooks'] = {
search: 'Webhook aboneliklerinde ara…',
loading: 'Webhook abonelikleri yükleniyor…',
loadFailed: 'Webhook abonelikleri yüklenemedi',
subscriptions: count => `Abonelikler (${count})`,
hint: 'Alıcı çalışırken abonelik değişiklikleri anında uygulanır. Devre dışı abonelikler gelen olayları reddeder.',
empty: 'Henüz webhook aboneliği yok.',
disabledTitle: 'Webhook alıcısı devre dışı',
disabledBody:
'Webhook ayrı bir ağ geçidi platformudur. Gelen HTTP olaylarını kabul etmek için burada etkinleştirin. Telegram, Discord, Slack veya başka bir kanala çıktı gönderen abonelikler için ilgili sohbet kanalı da gerekir.',
enable: 'Webhook alıcısını etkinleştir',
enabling: 'Etkinleştiriliyor…',
enabled: name => `Etkinleştirildi: “${name}`,
disabled: name => `Devre dışı bırakıldı: “${name}`,
enableRow: 'Etkinleştir',
disableRow: 'Devre dışı bırak',
delete: 'Sil',
deleting: 'Siliniyor…',
deleted: 'Webhook silindi',
deleteTitle: 'Webhook sil',
deleteDescPrefix: 'Şu abonelik kalıcı olarak silinecek: ',
deleteDescSuffix: '. Bu işlem geri alınamaz.',
deleteFailed: name => `${name}” silinemedi`,
toggleFailed: (name, enabled) => `${name}${enabled ? 'etkinleştirilemedi' : 'devre dışı bırakılamadı'}`,
newSubscription: 'Yeni abonelik',
restarting: 'Ağ geçidi yeniden başlatılıyor…',
restartNeeded: 'Webhook etkin, ancak alıcının çalışması için ağ geçidi yeniden başlatılmalı.',
restartGateway: 'Ağ geçidini yeniden başlat',
restartingGateway: 'Yeniden başlatılıyor…',
restartFailed: detail => `Ağ geçidi yeniden başlatılamadı${detail}`,
enabledRestarting: 'Webhook etkinleştirildi; ağ geçidi yeniden başlatılıyor…',
all: '(tümü)',
deliverOnly: 'yalnızca ilet',
createdTitle: 'Abonelik oluşturuldu',
createdSecretHint: 'Gizli anahtarı şimdi kopyalayın; yalnızca bir kez gösterilir.',
webhookUrl: 'Webhook adresi',
secretOnce: 'Gizli anahtar (bir kez gösterilir)',
done: 'Tamam',
fieldName: 'Ad',
fieldNamePlaceholder: 'ör. github-push',
fieldDescription: 'Açıklama',
fieldDescriptionPlaceholder: 'Bu webhook ne yapar? (isteğe bağlı)',
fieldEvents: 'Olaylar',
fieldEventsPlaceholder: 'Virgülle ayırın; tümü için boş bırakın',
fieldSkills: 'Beceriler',
fieldSkillsPlaceholder: 'Virgülle ayrılmış beceri adları (isteğe bağlı)',
fieldDeliver: 'Gönderim hedefi',
fieldDeliverOnly: 'Yalnızca olay verisini ilet',
fieldPrompt: 'İstem',
fieldPromptPlaceholder: 'Webhook tetiklendiğinde ajanın izleyeceği talimatlar (isteğe bağlı)',
nameRequired: 'Ad gerekli',
create: 'Oluştur',
creating: 'Oluşturuluyor…',
created: 'Oluşturuldu',
createFailed: detail => `Oluşturulamadı: ${detail}`,
copy: 'Kopyala',
deliverOptions: {
log: 'Günlük',
telegram: 'Telegram',
discord: 'Discord',
slack: 'Slack',
email: 'E-posta',
github_comment: 'GitHub yorumu'
}
}
+59
View File
@@ -0,0 +1,59 @@
import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, expect, it } from 'vitest'
import { BOTS_LOCALES } from '@/plugins/hermes-bots/i18n'
import { KANBAN_LOCALES } from '@/plugins/kanban/i18n'
import { I18nProvider, useI18n } from './context'
import { registerPluginLocales, translatePlugin, usePluginI18n } from './plugin-i18n'
afterEach(cleanup)
function Probe() {
const { setLocale } = useI18n()
const t = usePluginI18n('kanban-tr-test')
return (
<>
<span>{t('newTask')}</span>
<button onClick={() => void setLocale('tr')} type="button">
Türkçe
</button>
</>
)
}
it('switches registered Kanban messages to Turkish and preserves interpolated task data', async () => {
const dispose = registerPluginLocales('kanban-tr-test', KANBAN_LOCALES)
try {
render(
<I18nProvider configClient={null} initialLocale="en">
<Probe />
</I18nProvider>
)
expect(screen.getByText('New task')).toBeTruthy()
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Türkçe' }))
})
expect(screen.getByText('Yeni görev')).toBeTruthy()
expect(translatePlugin('kanban-tr-test', 'tr', 'boardSettingsFor', ['Müşteri A'])).toBe('Pano ayarları — Müşteri A')
} finally {
dispose()
}
})
it('provides Turkish leaves for both built-in plugin catalogs', () => {
function leaves(value: unknown, prefix = ''): string[] {
if (typeof value === 'string' || typeof value === 'function') {
return [prefix]
}
return Object.entries(value as Record<string, unknown>).flatMap(([key, child]) => leaves(child, prefix + '.' + key))
}
for (const catalog of [BOTS_LOCALES, KANBAN_LOCALES]) {
expect(catalog.tr).toBeDefined()
expect(leaves(catalog.tr).sort()).toEqual(leaves(catalog.en).sort())
}
})
+269
View File
@@ -0,0 +1,269 @@
import type { Translations } from './types'
export const TR_PROFILES: Translations['profiles'] = {
close: 'Profilleri kapat',
nameHint: 'Küçük Latin harfleri, rakamlar, kısa çizgi ve alt çizgi kullanın. Ad bir harf veya rakamla başlamalıdır.',
title: 'Profiller',
count: count => `${count} profil`,
search: 'Profillerde ara…',
loading: 'Profiller yükleniyor…',
newProfile: 'Yeni profil',
importProfile: 'Profil içe aktar…',
exportProfile: 'Profili dışa aktar…',
imported: 'Profil içe aktarıldı',
exported: 'Profil dışa aktarıldı',
failedImport: 'Profil içe aktarılamadı',
failedExport: 'Profil dışa aktarılamadı',
allProfiles: 'Tüm profiller',
showAllProfiles: 'Tüm profilleri göster',
switchToProfile: name => `${name} profiline geç`,
switchToConnection: name => `${name} bağlantısına geç`,
switchConnectionFailed: name => `${name} bağlantısı kurulamadı`,
manageProfiles: 'Profilleri yönet…',
connectGateway: 'Ağ geçitlerini yönet…',
fleet: {
allOnGateway: 'Bu ağ geçidindeki tüm profiller',
gateway: gateway => `${gateway} üzerindeki profiller`,
gatewayUnreachable: gateway => `${gateway} · erişilemiyor`,
onGateway: (name, gateway) => `${name} · ${gateway}`,
switchTo: (name, gateway) => `${gateway} üzerindeki ${name} profiline geç`,
deleteOn: gateway => ` · ağ geçidi: ${gateway}`
},
remoteOverride: {
menuItem: 'Uzak bilgisayara bağlan…',
badge: host => `${host} üzerinde çalışır`,
title: profile => `${profile} profilini uzak bilgisayara bağla`,
description: 'Bu profildeki oturumlar, bu bilgisayar yerine belirttiğiniz uzak AITURK/Hermes sunucusunda çalışır.',
urlLabel: 'Uzak sunucu adresi',
urlPlaceholder: 'https://aiturk.example.com',
urlInvalid: 'http:// veya https:// ile başlayan tam bir adres girin',
tokenLabel: 'Erişim anahtarı',
tokenPlaceholder: 'Uzak oturumun erişim anahtarını yapıştırın',
tokenSavedHint: 'Bir anahtar zaten kayıtlı. Korumak için boş bırakın.',
plainTextOptIn:
'Bu bilgisayarda güvenli anahtar deposu yok; anahtar diske şifrelenmeden kaydedilecek. Yine de kaydet.',
collisionWarning: label =>
`Ayarlarda “${label}” adlı bir ağ geçidi zaten var. Bu profil bağlantısı ayrıdır ve mevcut ağ geçidini değiştirmez.`,
confirmTitle: 'Bu profil uzak bilgisayara bağlansın mı?',
confirmNote: (profile, host) =>
`${profile} profilindeki yeni sohbetler ${host} üzerinde çalışacak. Komutlar o bilgisayarda çalıştırılacak ve oradaki dosyalar okunacak. Yalnızca güvendiğiniz bir bilgisayara bağlanın.`,
confirmBack: 'Geri',
connect: 'Bağlan',
connecting: 'Bağlanıyor…',
disconnect: 'Uzak bağlantıyı kaldır',
savedTitle: 'Profil bağlandı',
savedMessage: (profile, host) => `${profile} artık ${host} üzerinde çalışıyor`,
removedTitle: 'Uzak bağlantı kaldırıldı',
removedMessage: profile => `${profile} artık bu bilgisayarda çalışıyor`,
removeFailed: 'Uzak bağlantı kaldırılamadı',
authFailedTitle: 'Uzak sunucu kayıtlı anahtarı reddetti',
authFailedMessage: (profile, host) =>
`${host}, ${profile} için kayıtlı anahtarı reddetti. Anahtar uzak sunucuda değiştirilmiş olabilir.`,
updateToken: 'Yeni anahtar gir…'
},
actions: 'İşlemler',
color: 'Renk…',
colorFor: 'Renk',
setColor: color => `${color} rengini seç`,
autoColor: 'Otomatik',
noProfiles: 'Henüz profil yok.',
selectPrompt: 'Ayrıntılarını görmek için bir profil seçin.',
refresh: 'Profilleri yenile',
refreshing: 'Profiller yenileniyor',
default: 'varsayılan',
skills: count => `${count} beceri`,
env: 'ortam',
defaultBadge: 'Varsayılan',
rename: 'Yeniden adlandır',
renameMenu: 'Yeniden adlandır…',
exportMenu: 'Dışa aktar…',
editSoul: 'SOUL.md dosyasını düzenle…',
copySetup: 'Kurulum komutunu kopyala',
copying: 'Kopyalanıyor…',
modelLabel: 'Model',
skillsLabel: 'Beceriler',
notSet: 'Ayarlanmadı',
soulDesc: 'Bu profilin sistem istemi ve kişilik talimatları.',
soulOptional: 'isteğe bağlı',
soulPlaceholder: mode => `Bu profilin sistem istemi / kişiliği.\n${mode} varsayılanını korumak için boş bırakın.`,
soulPlaceholderCloned: 'kopyalanan',
soulPlaceholderEmpty: 'boş',
unsavedChanges: 'Kaydedilmemiş değişiklikler',
loadingSoul: 'SOUL.md yükleniyor…',
emptySoul: 'SOUL.md boş; kişilik talimatlarını yazmaya başlayın…',
saving: 'Kaydediliyor…',
saveSoul: 'SOUL.md dosyasını kaydet',
deleteTitle: 'Profil silinsin mi?',
deleteDescPrefix: 'Silinecek profil: ',
deleteDescMid: '. Kaldırılacak dizin: ',
deleteDescSuffix: '. Bu işlem geri alınamaz.',
deleting: 'Siliniyor…',
createDesc: 'Profiller, ayarları, becerileri ve SOUL.md dosyaları ayrı olan bağımsız AITURK ortamlarıdır.',
nameLabel: 'Ad',
cloneFrom: 'Kopyalanacak profil',
cloneFromNone: 'Yok (boş)',
cloneFromDesc: 'Seçilen kaynak profilin ayarlarını, becerilerini ve SOUL.md dosyasını kopyalar.',
cloneFromDefault: 'Varsayılan profilden kopyala',
cloneFromDefaultDesc: 'Varsayılan profilinizin ayarlarını, becerilerini ve SOUL.md dosyasını kopyalar.',
invalidName: hint => `Geçersiz ad. ${hint}`,
nameRequired: 'Ad gerekli.',
creating: 'Oluşturuluyor…',
createAction: 'Profil oluştur',
renameTitle: 'Profili yeniden adlandır',
renameDescPrefix: 'Yeniden adlandırma profil dizinini ve şu konumdaki başlatma betiklerini günceller: ',
renameDescSuffix: '.',
displayNameTitle: 'Bu ajana ad verin',
displayNameDesc: 'Uygulama genelinde görünen adı belirler. Dahili profil kimliği “default” olarak kalır.',
displayNameLabel: 'Görünen ad',
newNameLabel: 'Yeni ad',
renaming: 'Yeniden adlandırılıyor…',
created: 'Profil oluşturuldu',
renamed: 'Profil yeniden adlandırıldı',
deleted: 'Profil silindi',
setupCopied: 'Kurulum komutu kopyalandı',
soulSaved: 'SOUL.md kaydedildi',
failedLoad: 'Profiller yüklenemedi',
failedDelete: 'Profil silinemedi',
failedCopy: 'Kurulum komutu kopyalanamadı',
failedLoadSoul: 'SOUL.md yüklenemedi',
failedSaveSoul: 'SOUL.md kaydedilemedi',
failedCreate: 'Profil oluşturulamadı',
failedRename: 'Profil yeniden adlandırılamadı'
}
export const TR_CRON: Translations['cron'] = {
close: 'Zamanlanmış görevleri kapat',
title: 'Zamanlanmış görevler',
count: count => `${count} görev`,
modelImpact: {
title: 'Zamanlanmış görevler inceleme bekliyor',
message: count => `Model ayarlarını inceleyene kadar ${count} zamanlanmış görev atlanacak.`,
detailMore: (names, remaining) => `${names} ve ${remaining} görev daha`,
review: 'Zamanlanmış görevleri incele',
saveFailed: 'AITURK model değişikliğini kaydetmedi.',
confirmTitle: 'Model seçimi uyarısı',
confirmDetail: 'Yalnızca bu koşulu kabul ediyorsanız onaylayın.',
confirmAction: 'Onayla',
declined: 'Verilerin eğitimde kullanılmasına ilişkin uyarıyı reddettiğiniz için model değişikliği iptal edildi.'
},
search: 'Zamanlanmış görevlerde ara…',
loading: 'Zamanlanmış görevler yükleniyor…',
states: {
enabled: 'etkin',
scheduled: 'zamanlandı',
running: 'çalışıyor',
paused: 'duraklatıldı',
disabled: 'devre dışı',
error: 'hata',
completed: 'tamamlandı'
},
deliveryLabels: { local: 'Bu masaüstü', telegram: 'Telegram', discord: 'Discord', slack: 'Slack', email: 'E-posta' },
scheduleLabels: {
daily: 'Her gün',
weekdays: 'Hafta içi',
weekly: 'Her hafta',
monthly: 'Her ay',
hourly: 'Her saat',
'every-15-minutes': '15 dakikada bir',
custom: 'Özel'
},
scheduleHints: {
daily: 'Her gün saat 09.00',
weekdays: 'Pazartesiden cumaya saat 09.00',
weekly: 'Her pazartesi saat 09.00',
monthly: 'Her ayın ilk günü saat 09.00',
hourly: 'Her saat başı',
'every-15-minutes': '15 dakikada bir',
custom: 'Cron ifadesi veya doğal dil'
},
days: {
'0': 'Pazar',
'1': 'Pazartesi',
'2': 'Salı',
'3': 'Çarşamba',
'4': 'Perşembe',
'5': 'Cuma',
'6': 'Cumartesi',
'7': 'Pazar'
},
dayFallback: value => `${value}. gün`,
everyDayAt: time => `Her gün ${time}`,
weekdaysAt: time => `Hafta içi ${time}`,
everyDayOfWeekAt: (day, time) => `Her ${day} ${time}`,
monthlyOnDayAt: (dayOfMonth, time) => `Her ayın ${dayOfMonth}. günü ${time}`,
topOfHour: 'Her saat başı',
everyHourAt: minute => `Her saatin ${minute}. dakikası`,
newCron: 'Yeni zamanlanmış görev',
emptyDescNew: 'Bir istemi cron ifadesiyle zamanlayın. AITURK görevi çalıştırıp sonuçları seçtiğiniz hedefe gönderir.',
emptyDescSearch: 'Daha genel bir arama deneyin.',
emptyTitleNew: 'Henüz zamanlanmış görev yok',
emptyTitleSearch: 'Eşleşme yok',
last: 'Son:',
next: 'Sonraki:',
noRuns: 'Henüz çalıştırılmadı',
manage: 'Yönet',
showRuns: 'Çalıştırmaları göster',
hideRuns: 'Çalıştırmaları gizle',
runHistory: 'Çalıştırma geçmişi',
actionsTitle: 'Zamanlanmış görev işlemleri',
resume: 'Görevi sürdür',
pause: 'Görevi duraklat',
resumeTitle: 'Sürdür',
pauseTitle: 'Duraklat',
triggerNow: 'Şimdi çalıştır',
edit: 'Görevi düzenle',
deleteTitle: 'Zamanlanmış görev silinsin mi?',
deleteDescPrefix: 'Kalıcı olarak silinecek görev: ',
deleteDescSuffix: '. Yeni çalıştırmalar hemen durdurulur.',
deleting: 'Siliniyor…',
resumed: 'Görev sürdürüldü',
paused: 'Görev duraklatıldı',
triggered: 'Görev tetiklendi',
deleted: 'Görev silindi',
created: 'Görev oluşturuldu',
updated: 'Görev güncellendi',
failedLoad: 'Zamanlanmış görevler yüklenemedi',
failedUpdate: 'Görev güncellenemedi',
failedTrigger: 'Görev tetiklenemedi',
failedDelete: 'Görev silinemedi',
failedSave: 'Görev kaydedilemedi',
editTitle: 'Zamanlanmış görevi düzenle',
createTitle: 'Yeni zamanlanmış görev',
editDesc: 'Zamanı, istemi veya gönderim hedefini güncelleyin. Değişiklikler sonraki çalıştırmada geçerli olur.',
createDesc:
'Bir istemi otomatik çalışacak şekilde zamanlayın. Cron ifadesi veya “every 15 minutes” gibi desteklenen bir zaman ifadesi kullanın.',
nameLabel: 'Ad',
namePlaceholder: 'Sabah özeti',
promptLabel: 'İstem',
promptPlaceholder: 'Okunmamış Slack konuşmalarımı özetle ve en önemli 5 tanesini e-postayla gönder…',
frequencyLabel: 'Sıklık',
deliverLabel: 'Gönderim hedefi',
deliverNeedsHomeChannel: 'önce bir ana kanal ayarlayın',
modelLabel: 'Model',
modelDefault: 'Varsayılan (genel model)',
customScheduleLabel: 'Özel zamanlama',
customPlaceholder: '0 9 * * * veya weekdays at 9am',
customHint: 'Cron ifadesi ya da “every hour” veya “weekdays at 9am” gibi desteklenen ifadeler.',
optional: 'İsteğe bağlı',
promptRequired: 'İstem gerekli.',
promptScheduleRequired: 'İstem ve zamanlama gerekli.',
scheduleRequired: 'Zamanlama gerekli.',
scriptOnlyEditHint: 'Yalnızca betik çalıştıran görev (AI istemi yok). Görev kimliği:',
saveChanges: 'Değişiklikleri kaydet',
createAction: 'Görevi zamanla',
tabs: { jobs: 'Görevler', blueprints: 'Şablonlar' },
blueprints: {
tab: 'Şablonlar',
startFrom: 'Başlangıç şablonu',
custom: 'Özel',
subtitle: 'Hazır otomasyonlar',
dialogDesc: 'Ayrıntıları doldurup zamanlayın.',
scheduleIt: 'Zamanla',
scheduling: 'Zamanlanıyor…',
scheduled: 'Şablon zamanlandı',
loading: 'Şablonlar yükleniyor…',
failedLoad: 'Şablonlar yüklenemedi',
emptyTitle: 'Kullanılabilir şablon yok',
emptyDesc: 'Bu sunucuda otomasyon şablonu bulunmuyor.'
}
}
@@ -0,0 +1,20 @@
import { describe, expect, it } from 'vitest'
import { PROVIDER_GROUPS } from '@/app/settings/constants'
import { providerDescription } from '@/app/settings/helpers'
describe('curated provider descriptions', () => {
it('translates every built-in description and preserves external descriptions', () => {
for (const group of PROVIDER_GROUPS) {
if (!group.description) {
continue
}
expect(providerDescription(group.name, group.description, 'tr'), group.name).not.toBe(group.description)
expect(providerDescription(group.name, group.description, 'en')).toBe(group.description)
expect(providerDescription(group.name, 'Custom provider description', 'tr')).toBe('Custom provider description')
}
expect(providerDescription('custom', 'Custom provider description', 'tr')).toBe('Custom provider description')
})
})
@@ -0,0 +1,28 @@
/** Display copy for the curated provider cards. Provider names remain identifiers. */
export const TR_PROVIDER_DESCRIPTIONS: Record<string, string> = {
'Nous Portal': 'Sunucuda çalışan Hermes ve Nous tarafından eğitilmiş modeller',
'Fireworks AI': 'OpenAI uyumlu doğrudan model APIsi',
OpenRouter: 'Yüzlerce gelişmiş modele tek noktadan erişim',
Anthropic: 'Claude API erişimi (Sonnet, Opus, Haiku)',
xAI: 'Grok modelleri; SuperGrok / Premium+ için OAuth kullanın',
Gemini: 'Google AI Studio üzerinden Gemini modelleri (1.5 / 2.0 / 2.5)',
DeepSeek: 'Doğrudan DeepSeek API erişimi (V3.x, R1)',
'DashScope (Qwen)': 'Alibaba Cloud DashScope üzerinden Qwen ve farklı sağlayıcıların modelleri',
'GLM / Z.AI': 'Zhipu GLM-4.6 ve Z.AI sunucu uç noktaları',
'Kimi / Moonshot': 'Moonshot Kimi K2 ve kodlama uç noktaları',
'Kimi (China)': 'Moonshot Çin uç noktası',
MiniMax: 'MiniMax-M2 ve Hailuo uluslararası uç noktaları',
'MiniMax (China)': 'MiniMax Çin ana karası uç noktası',
'Hugging Face': 'router.huggingface.co üzerinden 20den fazla açık modele erişim',
'OpenCode Zen': 'Seçilmiş kodlama modellerine kullandıkça öde yöntemiyle erişim',
'OpenCode Go': 'Açık kodlama modelleri için aylık $10 abonelik',
'NVIDIA NIM': 'build.nvidia.com veya kendi yerel NIM uç noktanız',
'Ollama Cloud': 'ollama.com üzerinde bulutta çalışan açık modeller',
'LM Studio': 'Yerel LM Studio sunucusu (OpenAI uyumlu)',
StepFun: 'StepFun Step Plan kodlama modelleri',
'Xiaomi MiMo': 'MiMo-V2.5 ve Xiaominin kendi modelleri',
'Arcee AI': 'Arcee sunucularında çalışan küçük ve orta boy modeller',
'GMI Cloud': 'GMI Cloud GPU ve model sunum hizmeti',
'Azure Foundry': 'Azure AI Foundry özel uç noktaları (OpenAI / Anthropic uyumlu)',
'AWS Bedrock': 'AWS profili ve bölgesiyle kimlik doğrulama'
}
@@ -0,0 +1,107 @@
import type { EN_RUNTIME_SETTINGS } from './en-runtime-settings'
export const TR_RUNTIME_SETTINGS: typeof EN_RUNTIME_SETTINGS = {
marketplaceThemes: 'VS Code Marketplace temaları',
noMatchingThemes: query => `${query}” ile eşleşen yüklü tema yok.`,
auxiliaryWarning: (count, tasks, provider) =>
`${count} yardımcı görev (${tasks}) hâlâ ${provider} üzerinden çalışıyor. Bu görevler ana modelinize geçirilmedi.`,
otherProviders: 'diğer sağlayıcılar',
pasteProviderKey: key => `${key} değerini yapıştırın`,
apiKey: 'API anahtarı',
activatingProvider: 'Etkinleştiriliyor…',
activateProvider: 'Etkinleştir',
setupProvider: provider => `${provider} kurulumu`,
provider: 'Sağlayıcı',
plugins: {
unavailable: 'Masaüstü eklentilerine ulaşılamıyor',
resolveFailed: 'Eklenti klasörünün konumu belirlenemedi',
openFailed: 'Eklenti klasörü açılamadı',
unknownError: 'Bilinmeyen hata',
noHome: 'Arka uç kendi ana klasörünü bildirmedi'
},
moa: {
title: 'Ajan topluluğu',
description:
'Mixture of Agents sağlayıcısı altında model olarak görünen adlandırılmış ön ayarları yapılandırın. Birleştirici model yanıtı oluşturur.',
preset: 'Ön ayar',
enabled: 'Etkin',
setDefault: 'Varsayılan yap',
newPreset: 'yeni ön ayar',
addPreset: 'Ön ayar ekle',
default: 'Varsayılan:',
reference: index => `Referans ${index}`,
toggleReference: (index, enabled) => `${index}. referansı ${enabled ? 'etkinleştir' : 'devre dışı bırak'}`,
addReference: 'Referans modeli ekle',
aggregator: 'Birleştirici model'
},
computerUse: {
linux: 'Masaüstünü X11/XWayland erişilebilirlik altyapısıyla kontrol eder; izin penceresi gösterilmez.',
win32: 'İlk çalıştırmada cua-driver UIAccess işlemi için Windows SmartScreen penceresi açılabilir.',
granted: 'İzin verildi',
notGranted: 'İzin verilmedi',
unknown: 'Bilinmiyor',
statusFailed: 'Bilgisayar kullanımı durumu okunamadı',
permissionsFailed: 'İzin isteği başlatılamadı',
approveTitle: 'Sistem Ayarları’nda onaylayın',
approveBody: 'macOS, CuaDriver adına bir izin penceresi gösterecek. Onayladıktan sonra buraya dönün.',
checking: 'Bilgisayar kullanımı durumu denetleniyor…',
unsupported: platform => `Bu platformda bilgisayar kullanımı desteklenmiyor (${platform}).`,
install: 'Bu bilgisayarı kontrol etmek için aşağıdan cua-driver bileşenini kurun.',
installGrant: ' Ardından buradan Erişilebilirlik ve Ekran Kaydı izinlerini verin.',
identity:
'İzinler CuaDriver kimliğine (com.trycua.driver) aittir; izin penceresinde Macinizi kontrol eden işlemin adı görünür.',
recheck: 'Yeniden denetle',
accessibility: 'Erişilebilirlik',
accessibilityHint:
'cua-driver bileşeninin tıklama ve tuş girdisi göndermesine, erişilebilirlik ağacını okumasına izin verir.',
screenRecording: 'Ekran Kaydı',
screenRecordingHint: 'cua-driver bileşeninin uygulama pencerelerinin ekran görüntüsünü almasına izin verir.',
driverHealth: 'Sürücü sağlığı',
ready: 'Hazır',
notReady: 'Hazır değil',
readyHint: 'Bilgisayar kullanımı hazır. Ajandan bir uygulamayı görüntüleyip kontrol etmesini isteyebilirsiniz.',
waiting: 'Onay bekleniyor…',
grant: 'İzinleri ver'
},
pool: {
warm: 'Hazır tutulan bot süreçleri',
warmHint:
'Anında geçiş için çalışır durumda tutulan bot süreçlerinin sayısı. Yüksek değer geçişi hızlandırır ve daha fazla bellek kullanır (süreç başına yaklaşık 60 MB). Değişiklik hemen uygulanır.',
idle: 'Boşta bekleme süresi',
idleAria: 'Bot sürecinin boşta bekleme süresi (milisaniye)',
idleHint:
'Kullanılmayan bot sürecinin kapanmadan önce hazır tutulacağı süre. Birkaç dakikada bir döndüğünüz botların yeniden başlatılmasını önlemek için artırın.'
},
memory: {
saveChanges: 'Değişiklikleri kaydet',
startFailed: 'Bağlantı başlatılamadı.',
timeout: 'Zaman aşımı oluştu; yeniden deneyin.',
connectionFailed: 'Bağlantı kurulamadı.',
connectOauth: 'OAuth ile bağlan',
reconnect: 'Yeniden bağlan',
connect: 'Bağlan',
apiKeySet: 'API anahtarı kayıtlı',
oauthSet: 'OAuth bağlantısı kayıtlı',
waiting: 'Tarayıcı onayı bekleniyor…',
loadFailed: 'Bellek sağlayıcısı ayarları yüklenemedi',
loading: 'Bellek sağlayıcısı ayarları yükleniyor…',
saveFailed: label => `${label} kaydedilemedi`,
settings: label => `${label} ayarları`,
credentialStatus: (label, set) => `${label}: ${set ? 'kayıtlı' : 'kayıtlı değil'}`,
fullConfig: 'Tüm ayarlar…',
saved: label => `${label} kaydedildi`,
updated: 'Bellek sağlayıcısı ayarları güncellendi.',
fullTitle: label => `${label} — tüm ayarlar`,
fullDescription: (label, profile) =>
`${profile} profili için ${label} seçenekleri. Boş alanlarda sunucunun çözümlenen değeri veya yerleşik varsayılan kullanılır.`,
reference: label => `${label} yapılandırma kılavuzu`,
other: 'Diğer',
about: label => `${label} hakkında`,
keepSecret: 'Mevcut değeri korumak için boş bırakın',
set: 'kayıtlı'
},
themeSearch: 'Temalarınızda veya VS Code Marketplace içinde ara…',
showOptions: 'Seçenekleri göster',
search: 'Ara…',
noResults: 'Sonuç bulunamadı.'
}
@@ -0,0 +1,91 @@
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
import { ConfigField } from '@/app/settings/config-field'
import { FIELD_DESCRIPTIONS, FIELD_LABELS, SECTIONS } from '@/app/settings/constants'
import { I18nProvider } from './context'
import { en } from './en'
import { trOverrides } from './tr'
import { TR_FIELD_DESCRIPTIONS, TR_FIELD_LABELS } from './tr-fields'
afterEach(cleanup)
const scrollDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'scrollIntoView')
beforeAll(() => Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', { configurable: true, value: vi.fn() }))
afterAll(() => {
if (scrollDescriptor) {
Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', scrollDescriptor)
} else {
Reflect.deleteProperty(HTMLElement.prototype, 'scrollIntoView')
}
})
describe('Turkish settings contents', () => {
it('covers every registered settings section, including sections absent from the English dictionary', () => {
for (const section of SECTIONS) {
expect(trOverrides.settings?.sections?.[section.id], section.id).toBeTruthy()
}
})
it('supplies every desktop message explicitly without English fallback', () => {
function check(reference: Record<string, unknown>, actual: Record<string, unknown>, prefix: string) {
for (const [key, value] of Object.entries(reference)) {
expect(actual[key], prefix + '.' + key).toBeDefined()
if (value && typeof value === 'object' && !Array.isArray(value)) {
check(value as Record<string, unknown>, actual[key] as Record<string, unknown>, prefix + '.' + key)
}
}
}
check(en as unknown as Record<string, unknown>, trOverrides as Record<string, unknown>, 'tr')
})
it('covers every curated field label and description without English fallback', () => {
for (const [key, value] of Object.entries(FIELD_LABELS)) {
expect(TR_FIELD_LABELS[key], key).toBeTruthy()
expect(TR_FIELD_LABELS[key], key).not.toBe(value)
}
for (const [key, value] of Object.entries(FIELD_DESCRIPTIONS)) {
expect(TR_FIELD_DESCRIPTIONS[key], key).toBeTruthy()
expect(TR_FIELD_DESCRIPTIONS[key], key).not.toBe(value)
}
})
it('renders translated field contents and retains the stored boolean value', async () => {
const onChange = vi.fn()
render(
<I18nProvider>
<ConfigField
onChange={onChange}
schema={{ type: 'boolean', description: 'Hide secrets' }}
schemaKey="security.redact_secrets"
value={true}
/>
</I18nProvider>
)
expect(screen.getByText('Gizli bilgileri maskele')).toBeTruthy()
expect(screen.getByText(TR_FIELD_DESCRIPTIONS['security.redactSecrets'])).toBeTruthy()
expect(screen.queryByText('Hide secrets')).toBeNull()
fireEvent.click(screen.getByRole('switch'))
await waitFor(() => expect(onChange).toHaveBeenCalledWith(false))
})
it('translates option labels without changing the backend enum value', async () => {
const onChange = vi.fn()
render(
<I18nProvider>
<ConfigField
onChange={onChange}
schema={{ type: 'select', options: ['manual', 'smart', 'off'] }}
schemaKey="approvals.mode"
value="manual"
/>
</I18nProvider>
)
expect(screen.getByText('Onay modu')).toBeTruthy()
expect(screen.getByRole('combobox').textContent).toContain('Elle onayla')
fireEvent.keyDown(screen.getByRole('combobox'), { key: 'ArrowDown' })
fireEvent.click(await screen.findByRole('option', { name: 'Akıllı onay' }))
expect(onChange).toHaveBeenCalledWith('smart')
})
})
+215
View File
@@ -0,0 +1,215 @@
import type { TranslationOverrides } from './define-locale'
export const TR_SETTINGS = {
quickEntry: {
enabledTitle: 'Hızlı mesaj',
enabledDesc: 'Genel bir klavye kısayoluyla küçük mesaj penceresini açın ve ana pencereye geçmeden istem gönderin.',
shortcutTitle: 'Hızlı mesaj kısayolu',
shortcutDesc: 'En az bir değiştirici tuş içermelidir; örneğin CommandOrControl+Shift+Space.',
active: 'Kısayol etkin.',
takenBy: 'Bu kısayolu başka bir uygulama kullanıyor. Farklı bir kısayol seçin.',
invalidShortcut: 'Geçersiz kısayol. En az bir değiştirici tuş ekleyin.'
},
keys: {
loading: 'API anahtarları ve kimlik bilgileri yükleniyor…',
failedLoad: 'API anahtarları yüklenemedi',
empty: 'Bu kategoride henüz bir ayar yapılmadı.'
},
search: { placeholder: 'Tüm ayarlarda ara…', pill: 'Ara' },
profileScope: {
appliesTo: 'Uygulandığı profil',
editsProfile: profile => `Bu sayfadaki değişiklikler “${profile}” profiline uygulanır.`
},
model: {
loading: 'Model ayarları yükleniyor…',
appliesDesc:
'Yeni oturumlarda uygulanır. Açık sohbette modeli değiştirmek için mesaj alanındaki model seçiciyi kullanın.',
provider: 'Sağlayıcı',
model: 'Model',
applying: 'Uygulanıyor…',
defaultsLabel: 'Varsayılanlar',
reasoning: 'Düşünme',
reasoningOff: 'Kapalı',
defaultsFailed: 'Varsayılan model ayarları kaydedilemedi',
loadFailed: 'Modeller yüklenemedi',
restartRequired:
'Sunucu güncellemeden sonra hâlâ eski kodu çalıştırıyor. Yeni kodu yüklemek için yeniden başlatın.',
restartBackend: 'Sunucuyu yeniden başlat',
restartingBackend: 'Sunucu yeniden başlatılıyor…',
restartFailed: 'Sunucu yeniden başlatılamadı',
auxiliaryTitle: 'Yardımcı modeller',
resetAllToMain: 'Tümünü ana modele döndür',
auxiliaryDesc:
'Yardımcı işler varsayılan olarak ana modeli kullanır. İsterseniz her iş için ayrı model seçebilirsiniz.',
setToMain: 'Ana modeli kullan',
change: 'Değiştir',
autoUseMain: 'otomatik · ana modeli kullan',
providerDefault: '(sağlayıcı varsayılanı)',
fallbackAdd: 'Yedek model ekle',
fallbackEmpty: 'Yedek model yok. Bir hata oluşmadıkça varsayılan model kullanılır.',
notInCatalog: 'bu sağlayıcının model listesinde yok; istekler yedek modele yönlendirilebilir.',
tasks: {
vision: { label: 'Görsel anlama', hint: 'Görsel inceleme' },
compression: { label: 'Özetleme', hint: 'Bağlamı kısaltma' },
skills_hub: { label: 'Yetenek merkezi', hint: 'Yetenek arama' },
approval: { label: 'Onay', hint: 'Akıllı otomatik onay' },
mcp: { label: 'MCP', hint: 'MCP araç yönlendirmesi' },
title_generation: { label: 'Başlık oluşturma', hint: 'Oturum başlıkları' },
review: { label: 'İnceleme', hint: '/review inceleme alt ajanı' },
curator: { label: 'Yetenek değerlendirme', hint: 'Yetenek kullanımını inceleme' }
}
},
mcp: {
loading: 'MCP sunucuları yükleniyor…',
failedLoad: 'MCP ayarları yüklenemedi',
nameRequiredTitle: 'Ad gerekli',
nameRequiredMessage: 'MCP sunucusu için bir yapılandırma adı girin.',
objectRequired: 'Sunucu ayarı bir JSON nesnesi olmalıdır',
invalidJson: 'Geçersiz MCP JSON verisi',
saveFailed: 'Kaydedilemedi',
removeFailed: 'Kaldırılamadı',
gatewayUnavailableTitle: 'Ağ geçidine ulaşılamıyor',
gatewayUnavailableMessage: 'MCPyi yeniden yüklemeden önce ağ geçidine yeniden bağlanın.',
reloadedTitle: 'MCP araçları yeniden yüklendi',
reloadedMessage: 'Yeni araç tanımları sonraki işlemlerde uygulanır.',
reloadFailed: 'MCP yeniden yüklenemedi',
savedTitle: 'MCP sunucusu kaydedildi',
savedMessage: name => `${name}, MCP yeniden yüklendiğinde uygulanır.`,
newServer: 'Yeni sunucu',
reload: 'MCPyi yeniden yükle',
reloading: 'Yeniden yükleniyor…',
emptyTitle: 'MCP sunucusu yok',
emptyDesc: 'MCP araçlarını kullanmak için bir stdio veya HTTP sunucusu ekleyin.',
disabled: 'devre dışı',
editServer: 'Sunucuyu düzenle',
name: 'Ad',
serverJson: 'Sunucu JSON ayarları',
remove: 'Kaldır',
saveServer: 'Sunucuyu kaydet',
test: 'Bağlantıyı dene',
testing: 'Deneniyor…',
testOk: count => `Bağlandı · ${count} araç kullanılabilir`,
testFailed: 'Bağlantı başarısız',
enableServer: name => `${name} sunucusunu etkinleştir`,
disableServer: name => `${name} sunucusunu kapat`,
serverEnabled: name => `${name} etkinleştirildi. Yeni oturumlarda uygulanır.`,
serverDisabled: name => `${name} kapatıldı. Yeni oturumlarda uygulanır.`,
toggleFailed: (name, enabled) => `${name} ${enabled ? 'etkinleştirilemedi' : 'kapatılamadı'}`,
tabServers: 'Sunucular',
tabCatalog: 'Katalog',
catalogLoading: 'MCP kataloğu yükleniyor…',
catalogLoadFailed: 'MCP kataloğu yüklenemedi',
catalogEmpty: 'Katalogda kayıt yok.',
catalogInstalled: 'Yüklü',
catalogEnabled: 'Etkin',
catalogNeedsInstall: 'Derleme gerekiyor',
catalogInstall: 'Yükle',
catalogInstalling: 'Yükleniyor…',
catalogInstallStarted: name => `${name} yükleniyor. Tamamlandığında yeni oturumlarda kullanılabilir.`,
catalogInstallFailed: name => `${name} yüklenemedi`,
catalogEnvPrompt: name => `${name} için kimlik bilgileri gerekiyor`,
catalogEnvRequired: 'Yüklemeden önce gerekli değerleri doldurun.',
capabilitySummary: (tools, prompts, resources) =>
[`${tools} araç`, ...(prompts ? [`${prompts} istem`] : []), ...(resources ? [`${resources} kaynak`] : [])].join(
', '
) + ' etkin',
costTokens: tokens => `Çağrı başına yaklaşık ${tokens} belirteç`,
usage30d: uses => `30 günde ${uses} kullanım`,
unusedPill: 'kullanılmadı',
statusConnecting: 'Bağlanıyor…',
statusNeedsAuth: 'Kimlik doğrulama gerekiyor',
statusError: 'Hata',
statusOff: 'Kapalı',
allServers: 'Tüm sunucular',
authenticatedTitle: 'Kimlik doğrulandı',
authenticatedMessage: (server, count) => `${server}: ${count} araç`,
waitingForBrowser: 'Tarayıcı bekleniyor…',
authenticate: 'Kimliğini doğrula',
unsavedConnect: 'Kaydedilmedi. Bağlanmak için mcp.json dosyasını kaydedin.',
enableTool: tool => `${tool} aracını etkinleştir`,
disableTool: tool => `${tool} aracını kapat`,
noOutput: 'Henüz çıktı yok.',
deepLinkTitle: 'MCP sunucusu eklensin mi?',
deepLinkDescription:
'Bir bağlantı bu MCP sunucusunun eklenmesini istiyor. Aşağıdaki ayarları inceleyin; bu bilgiler bağlantıdan geliyor.',
deepLinkStdioWarning:
'Bu sunucu, aşağıdaki komutla bilgisayarınızda yerel bir işlem çalıştırır. Yalnızca kaynağına güveniyorsanız devam edin.',
deepLinkConfirm: 'Sunucuyu ekle',
deepLinkNameInvalid: 'Adlar 164 harf, rakam, nokta, tire veya alt çizgiden oluşmalıdır.',
deepLinkNameConflict: name => `${name} adında bir sunucu zaten var. Başka bir ad seçin veya vazgeçin.`,
deepLinkErrorTitle: 'MCP kurulum bağlantısı reddedildi',
deepLinkErrorName: 'Bağlantıdaki sunucu adı eksik veya geçersiz.',
deepLinkErrorConfig: 'Bağlantıdaki ayar geçerli base64 kodlu JSON değil.',
deepLinkErrorShape: 'Ayar, metin türünde url veya command alanı içeren bir JSON nesnesi olmalıdır.',
deepLinkErrorUrl: 'Yalnızca http:// ve https:// sunucu adreslerine izin verilir.',
deepLinkErrorTooLarge: 'Ayar verisi 32 KB sınırını aşıyor.',
importButton: 'İçe aktar',
importPlaceholder:
'mcp.json bölümü, npx/docker komutu, claude mcp add satırı, URL veya Cursor bağlantısı yapıştırın…',
importNoMatch: 'Yapıştırılan metinde sunucu ayarı bulunamadı.',
importConfirm: 'mcp.json dosyasına ekle',
importConfirmMany: count => `${count} sunucuyu mcp.json dosyasına ekle`
},
plugins: {
title: 'Masaüstü eklentileri',
blurb:
'Uygulamayla gelen veya desktop-plugins klasörüne eklenen eklentiler. Kapatılan eklenti hemen devreden çıkar.',
count: n => `${n} yüklü`,
openFolder: 'Eklenti klasörünü aç',
rescan: 'Yeniden tara',
reveal: 'Dosya yöneticisinde göster',
enable: 'Etkinleştir',
disable: 'Kapat',
failed: 'başarısız',
empty: 'Henüz masaüstü eklentisi yüklü değil.',
kinds: { bundled: 'yerleşik', disk: 'diskte', runtime: 'çalışma ortamı' },
agent: {
title: 'Ajan eklentileri',
blurb:
'Ajan ortamına yüklenen araçlar, yetenekler, MCP sunucuları, kancalar ve / komutları. Taşınabilir yetenek ve MCP paketleri başka ajanlarda da kullanılabilir. Değişiklikler yeni oturumlarda uygulanır.',
appliesTo: 'Uygulandığı profil:',
empty: 'Henüz ajan eklentisi yüklü değil.',
loadFailed: 'Ajan eklentileri yüklenemedi',
portable: 'taşınabilir',
search: 'Eklenti ara…',
noMatches: 'Aramanızla eşleşen eklenti yok.',
toggleFailed: name => `${name} eklentisinin durumu değiştirilemedi`,
updateBackendToManage: 'Bu eklentiyi masaüstünden yönetmek için ajan sunucusunu güncelleyin.',
sources: { bundled: 'yerleşik', user: 'kullanıcı', git: 'Git', project: 'proje', entrypoint: 'pip' }
},
installModal: {
title: 'Eklenti yükle',
description: 'Yüklemeden önce deponun içeriğini inceleyin.',
repoLabel: 'Depo',
includesHeading: 'Paket içeriği',
agentLabel: 'Ajan eklentisi',
desktopLabel: 'Masaüstü arayüzü',
agentTargetLocal: profile => `${profile} ajan ortamına yüklenir (~/.hermes/plugins/)`,
agentTargetRemote: profile => `Bağlı ${profile} ajan ortamına yüklenir`,
desktopTarget: 'Bu uygulamanın yerel desktop-plugins klasörüne yüklenir',
desktopOnlyNote: 'Yalnızca masaüstüne yönelik paketler ajan eklentisi yüklemez.',
insecureWarning:
'Bu URL güvensiz veya yerel bir adres biçimi kullanıyor. Yayın ortamında https:// veya git@ kullanın.',
securityHeading: 'Yüklemeden önce',
securityIntro:
'Yalnızca güvendiğiniz kaynaklardan yükleyin. Nelerin ekleneceğini görmek için aşağıdaki depoyu inceleyin.',
sourceHeading: 'Kaynak kod',
viewRepository: 'Depoyu aç',
viewPluginFiles: 'Eklenti dosyalarını göster',
gitCloneLabel: 'Git klonlama adresi',
enableAgent: 'Yükledikten sonra ajan eklentisini etkinleştir',
forceReinstall: 'Yeniden yükle; yüklüyse mevcut eklentiyi değiştir',
install: 'Yükle',
installing: 'Yükleniyor…',
probing: 'Depo inceleniyor…',
probeUnavailable: 'Bu ortamda eklenti incelemesi kullanılamıyor.',
desktopUnavailable: 'Bu ortamda masaüstü eklentisi yüklenemiyor.',
selectComponent: 'Yüklenecek en az bir bileşen seçin.',
agentSuccess: name => `${name} ajan eklentisi yüklendi`,
desktopSuccess: name => `${name} masaüstü eklentisi yüklendi`,
agentFailed: 'Ajan eklentisi yüklenemedi',
desktopFailed: 'Masaüstü eklentisi yüklenemedi',
missingEnv: vars => `Eksik ortam değişkenleri: ${vars}. Ayarlar → Anahtarlar bölümünden ekleyin.`
}
}
} satisfies NonNullable<TranslationOverrides['settings']>
+80
View File
@@ -0,0 +1,80 @@
import type { EN_SURFACES } from './en-surfaces'
export const TR_SURFACES: typeof EN_SURFACES = {
pet: {
message: 'Mesaj…',
openApp: 'AITURKte aç',
run: ['çalışıyorum…', 'ilgileniyorum…', 'işliyorum…', 'hazırlıyorum…'],
review: ['düşünüyorum…', 'okuyorum…', 'inceliyorum…', 'kontrol ediyorum…'],
failed: ['bir sorun çıktı', 'bir hata oluştu'],
waiting: ['sıra sizde', 'yanıtınızı bekliyorum']
},
filters: {
updated: 'Güncellenme',
project: 'Proje',
status: 'Durum',
profile: 'Profil',
created: 'Oluşturulma',
tokens: 'Token sayısı',
cost: 'Maliyet',
manual: 'Elle sıralama',
preview: 'Önizleme',
pr: 'PR',
open: 'Açık',
draft: 'Taslak',
merged: 'Birleştirildi',
closed: 'Kapalı',
noPr: 'PR yok',
needsInput: 'Yanıt bekliyor',
working: 'Çalışıyor',
unread: 'Okunmadı',
idle: 'Boşta',
filters: 'Filtreler',
grouping: 'Gruplama',
ordering: 'Sıralama',
show: 'Göster',
pullRequest: 'Birleştirme isteği',
inbox: 'Gelen kutusu görünümü',
archived: 'Arşivlenenler',
reset: 'Varsayılanlara dön',
expand: 'Tümünü genişlet',
collapse: 'Tümünü daralt',
markRead: 'Tümünü okundu işaretle'
},
quickEntry: {
title: 'Hızlı giriş',
ask: 'AITURKe sor…',
disconnected: 'Bağlantı yok. Yeniden bağlanmak için AITURK’ü açın.',
sendTo: 'Gönderilecek yer',
target: 'Hedef oturum',
current: 'Açık sohbet',
newSession: 'Yeni oturum'
},
imageBackendTitle: 'Üretim için bir görsel sağlayıcısı ekleyin',
imageBackendDescription: 'Özel bir maskot oluşturmak için referans görselle çalışabilen bir sağlayıcı gerekir.',
setupImage: 'Görsel üretimini ayarla',
keyFrom: 'Anahtar alabileceğiniz sağlayıcılar:',
removeReference: 'Referansı kaldır',
addReference: 'Referans ekle',
sessionUnavailable: 'Bu oturum açılamadı',
noPage: (path: string) => `Bu adreste sayfa yok: ${path}`,
logUnavailable: (message: string) => `Günlük kullanılamıyor: ${message}`,
stop: 'Durdur',
moaPresets: 'MoA hazır ayarları',
learned: 'öğrenildi',
hub: 'katalog',
apiKey: 'API anahtarı',
skill: 'beceri',
memory: 'bellek',
mapAge: 'merkez = en eski · dış kısım = daha yeni',
editSkill: 'Beceriyi düzenle…',
editMemory: 'Belleği düzenle…',
archiveSkill: 'Beceriyi arşivle',
deleteMemory: 'Belleği sil',
editNode: (name: string) => `Düzenle: ${name}`,
deleteNode: (name: string) => `${name} silinsin mi?`,
permanentMemory: 'Bu bellek kalıcı olarak silinir.',
timeline: 'Zaman çizelgesinde gezin',
pause: 'Duraklat',
playTimeline: 'Zaman çizelgesini oynat'
}
+140
View File
@@ -0,0 +1,140 @@
import type { Translations } from './types'
export const TR_TOOLSETS: Translations['settings']['toolsets'] = {
loadingConfig: 'Ayarlar yükleniyor',
savedTitle: 'Kimlik bilgisi kaydedildi',
savedMessage: key => `${key} güncellendi.`,
removedTitle: 'Kimlik bilgisi kaldırıldı',
removedMessage: key => `${key} kaldırıldı.`,
failedSave: key => `${key} kaydedilemedi`,
failedRemove: key => `${key} kaldırılamadı`,
failedReveal: key => `${key} gösterilemedi`,
removeConfirm: key => `${key}, .env dosyasından kaldırılsın mı?`,
set: 'Ayarlı',
notSet: 'Ayarlanmadı',
selectedTitle: 'Sağlayıcı seçildi',
selectedMessage: provider => `${provider} artık etkin.`,
failedSelect: provider => `${provider} seçilemedi`,
failedLoad: 'Araç ayarları yüklenemedi',
noProviderOptions: 'Bu araç setinde sağlayıcı seçeneği yok. Etkinleştirdiğinizde mevcut kurulumunuzla çalışır.',
noProviders: 'Bu araç seti için şu anda kullanılabilir sağlayıcı yok.',
ready: 'Hazır',
needsSignIn: 'Giriş gerekiyor',
needsSetup: 'Kurulum gerekiyor',
activeBackend: 'Etkin',
activeBackendHint: 'Şu anda bu hizmet kullanılıyor',
useBackend: 'Bu hizmeti kullan',
nousIncluded: 'Nous aboneliğine dahildir. Etkinleştirmek için Nous Portala giriş yapın.',
nousAuthNeededTitle: 'Nous Portala giriş yapın',
nousAuthNeededMessage: provider => `${provider} kaydedildi; Nous Portala giriş yapana kadar etkinleşmez.`,
nousAuthSignIn: 'Giriş yap',
nousAuthDoneTitle: 'Nous Portala bağlandı',
nousAuthDoneMessage: 'Aboneliğinizin hizmetleri artık etkin.',
nousAuthFailed: 'Nous Portal girişi tamamlanmadı',
noApiKeyRequired: 'API anahtarı gerekmez.',
postSetupHint: step =>
`Bu hizmet için bir kez kurulum gerekir (${step}). İşlem bu bilgisayarda çalışır ve birkaç dakika sürebilir.`,
postSetupInstalledHint: 'Kurulu. Yalnızca bir sorun varsa kurulumu yeniden çalıştırın.',
postSetupRun: 'Kurulumu çalıştır',
postSetupRerun: 'Kurulumu yeniden çalıştır',
postSetupInstalled: 'Kurulu',
postSetupRunning: 'Yükleniyor…',
postSetupStarting: 'Başlatılıyor…',
postSetupCompleteTitle: 'Kurulum tamamlandı',
postSetupCompleteMessage: step => `${step} yüklendi.`,
postSetupErrorTitle: 'Kurulum hatalarla tamamlandı',
postSetupErrorMessage: step => `${step} günlüğünü kontrol edin.`,
postSetupFailed: step => `${step} kurulumu çalıştırılamadı`,
webSearchActive: backend => `Arama: ${backend}`,
webExtractActive: backend => `İçerik çıkarma: ${backend}`,
webCapabilityUnset: 'ayarlanmadı',
webUseForSearch: 'Aramada kullan',
webUseForExtract: 'İçerik çıkarmada kullan',
webUsedForSearch: 'Arama hizmeti',
webUsedForExtract: 'İçerik çıkarma hizmeti',
webCapabilitySelectedMessage: (provider, capability) =>
`${provider}, web ${capability === 'search' ? 'arama' : capability === 'extract' ? 'içerik çıkarma' : capability} işlemleri için seçildi.`,
failedSelectCapability: provider => `${provider} ayarlanamadı`,
loadingModels: 'Model kataloğu yükleniyor…',
modelSectionTitle: 'Model',
modelCount: count => `${count} model`,
modelInUse: 'Kullanımda',
modelDefault: 'varsayılan',
modelInactiveHint: 'Modeli değiştirmek için önce bu hizmeti seçin.',
modelSelectedTitle: 'Model seçildi',
modelSelectedMessage: model => `${model}, yeni oturumlarda kullanılacak.`,
failedSelectModel: model => `${model} seçilemedi`,
terminalBackend: {
sectionTitle: 'Komut çalıştırma ortamı',
loading: 'Çalıştırma ortamları denetleniyor…',
failedLoad: 'Terminal ortamları yüklenemedi',
ready: 'Hazır',
needsSetup: 'Kurulum gerekiyor',
unavailable: 'Kullanılamıyor',
inUse: 'Kullanımda',
selectedTitle: 'Çalıştırma ortamı seçildi',
selectedMessage: backend => `Yeni oturumlarda terminal komutları ${backend} üzerinden çalışacak.`,
failedSelect: backend => `${backend} seçilemedi`,
needsSetupHint: 'Bu ortamı şimdi seçebilirsiniz. Kurulum tamamlanana kadar komutlar çalışmayacaktır.'
},
browserRealProfile: {
label: 'Gerçek tarayıcı profilimi kullan',
description:
'Varsayılan tarayıcınızın giriş bilgileri ve çerezleri, ajanın kullanacağı yönetilen bir kopyaya aktarılır. Açık profiliniz doğrudan kullanılmaz. Yeni oturumlarda uygulanır.',
enabledTitle: 'Gerçek profille tarama açık',
enabledMessage: 'Yeni oturumlar varsayılan tarayıcı profilinizin kopyasını kullanacak.',
disabledTitle: 'Gerçek profille tarama kapalı',
disabledMessage: 'Profil kopyası silinecek. Yeni oturumlar temiz tarayıcı kullanacak.',
failedSave: 'Gerçek profil ayarı kaydedilemedi',
prompt: {
title: 'Sitelerinizde oturumunuz açık kalsın',
body: 'Ajan varsayılan tarayıcı profilinizin kopyasını kullansın; siteler oturumunuz açık olarak yüklensin.',
bulletSnapshot: 'Çerezler ve giriş bilgileri yönetilen bir kopyaya aktarılır.',
bulletLiveProfile: 'Açık tarayıcı profiliniz doğrudan kullanılmaz.',
bulletLocal: 'Profil kopyası bu bilgisayarda kalır.',
dontShowAgain: 'Bir daha gösterme',
notNow: 'Şimdi değil',
enable: 'Profilimi kullan'
}
}
}
export const TR_PET_SETTINGS: Translations['settings']['appearance']['pet'] = {
title: 'Maskot',
intro:
'Uygulamanın üzerinde dolaşan hareketli bir petdex maskotu seçin. Araçlar çalışırken hareket eder, başarıda sevinir ve hatalara tepki verir.',
restartHint:
'Maskotları kullanmak için uygulamayı kapatıp yeniden açın. Çalışan oturum bu özellik eklenmeden önce başlatılmış.',
on: 'Açık',
off: 'Kapalı',
scaleTitle: 'Boyut',
scaleDesc: 'Maskotun boyutunu değiştirir. Her yerde anında uygulanır.',
roamTitle: 'Dolaşma',
roamDesc: 'Boştayken maskotun pencere içinde dolaşmasına izin verir.',
chooseTitle: 'Maskot seçin',
chooseDesc: 'Seçtiğiniz maskot gerekirse indirilir ve etkinleştirilir.',
searchPlaceholder: 'Maskot ara…',
unreachable: 'petdex galerisine ulaşılamadı. Bağlantınızı kontrol edip bu sayfayı tekrar açın.',
noMatch: query => `${query}” ile eşleşen maskot yok.`,
installedTag: 'yüklü',
generatedTag: 'Oluşturuldu',
countCapped: (cap, total) => `${total} maskottan ${cap} tanesi gösteriliyor. Listeyi daraltmak için arayın.`,
count: n => `${n} maskot.`,
uninstall: name => `${name} maskotunu kaldır`,
delete: name => `${name} maskotunu sil`,
deleteTitle: name => `${name} silinsin mi?`,
deleteBody: 'Maskot kalıcı olarak silinir ve yeniden yüklenemez.',
deleteConfirm: 'Sil',
rename: name => `${name} adını değiştir`,
renameTitle: 'Maskotun adını değiştir',
renamePlaceholder: 'Maskotunuza ad verin',
renameSave: 'Kaydet',
exportPet: name => `${name} maskotunu dışa aktar`,
adoptFailed: slug => `${slug} maskotu eklenemedi`,
uninstallFailed: slug => `${slug} kaldırılamadı`,
renameFailed: slug => `${slug} yeniden adlandırılamadı`,
exportFailed: slug => `${slug} dışa aktarılamadı`,
noneAvailable: 'Şu anda etkinleştirilebilecek maskot yok.',
turnOnFailed: 'Maskot açılamadı.',
turnOffFailed: 'Maskot kapatılamadı.'
}
+1611 -415
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -7,6 +7,9 @@
import type { TipId } from '@/lib/tips/catalog'
import type { EN_RUNTIME_SETTINGS } from './en-runtime-settings'
import type { EN_SURFACES } from './en-surfaces'
export type Locale = 'tr' | 'en' | 'zh' | 'zh-hant' | 'ja' | 'ar' | 'ru'
export type ToolTitleKey =
@@ -51,6 +54,7 @@ interface AuxTaskCopy {
}
export interface Translations {
surfaces: typeof EN_SURFACES
common: {
apply: string
back: string
@@ -326,6 +330,7 @@ export interface Translations {
}
settings: {
runtime: typeof EN_RUNTIME_SETTINGS
closeSettings: string
exportConfig: string
importConfig: string
@@ -555,6 +560,7 @@ export interface Translations {
}
fieldLabels: Record<string, string>
fieldDescriptions: Record<string, string>
fieldOptions?: Record<string, Record<string, string>>
about: {
heading: string
version: (value: string) => string
+4
View File
@@ -1,8 +1,11 @@
import { defineFieldCopy } from '@/app/settings/field-copy'
import { EN_RUNTIME_SETTINGS } from './en-runtime-settings'
import { EN_SURFACES } from './en-surfaces'
import type { Translations } from './types'
export const zh: Translations = {
surfaces: EN_SURFACES,
common: {
apply: '应用',
back: '返回',
@@ -370,6 +373,7 @@ export const zh: Translations = {
},
settings: {
runtime: EN_RUNTIME_SETTINGS,
closeSettings: '关闭设置',
exportConfig: '导出配置',
importConfig: '导入配置',