feat: add i18n framework with Indonesian translation support (#124)
* feat: add i18n support with separate translation files - Extract translations from store.js to separate files for easier management - Add translation files for English (en.js), Indonesian (id.js), Turkish (tr.js), and Chinese (zh.js) - Load translations via window.translations object before Alpine store initialization - Add Bahasa Indonesia option to language selector * feat: translate remaining hardcoded UI strings - Update index.html to use t() for Menu and GitHub labels - Update views to translate Tier, Quota, Live, tier badges, and close button - Update components to use translated error messages and confirmation dialogs - Update utils to use translated validation and error messages - Update app-init.js to use translated OAuth success/error messages
This commit is contained in:
committed by
GitHub
parent
9ffb83ab74
commit
e2d03f9b25
@@ -139,7 +139,7 @@
|
|||||||
<div class="w-64 flex flex-col h-full pt-6 pb-4 flex-shrink-0">
|
<div class="w-64 flex flex-col h-full pt-6 pb-4 flex-shrink-0">
|
||||||
<!-- Mobile Menu Header -->
|
<!-- Mobile Menu Header -->
|
||||||
<div class="flex items-center justify-between px-4 mb-6 lg:hidden">
|
<div class="flex items-center justify-between px-4 mb-6 lg:hidden">
|
||||||
<span class="text-sm font-bold text-white">Menu</span>
|
<span class="text-sm font-bold text-white" x-text="$store.global.t('menu')">Menu</span>
|
||||||
<button @click="sidebarOpen = false" class="text-gray-400 hover:text-white">
|
<button @click="sidebarOpen = false" class="text-gray-400 hover:text-white">
|
||||||
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span x-text="'V ' + $store.global.version">V 1.0.0</span>
|
<span x-text="'V ' + $store.global.version">V 1.0.0</span>
|
||||||
<a href="https://github.com/badri-s2001/antigravity-claude-proxy" target="_blank" rel="noopener noreferrer"
|
<a href="https://github.com/badri-s2001/antigravity-claude-proxy" target="_blank" rel="noopener noreferrer"
|
||||||
class="hover:text-neon-purple transition-colors">GitHub</a>
|
class="hover:text-neon-purple transition-colors" x-text="$store.global.t('github')">GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -353,6 +353,11 @@
|
|||||||
<script src="js/utils/account-actions.js"></script>
|
<script src="js/utils/account-actions.js"></script>
|
||||||
<script src="js/utils/validators.js"></script>
|
<script src="js/utils/validators.js"></script>
|
||||||
<script src="js/utils/model-config.js"></script>
|
<script src="js/utils/model-config.js"></script>
|
||||||
|
<!-- Translation files (must load before store.js) -->
|
||||||
|
<script src="js/translations/en.js"></script>
|
||||||
|
<script src="js/translations/zh.js"></script>
|
||||||
|
<script src="js/translations/tr.js"></script>
|
||||||
|
<script src="js/translations/id.js"></script>
|
||||||
<!-- 2. Alpine Stores (register alpine:init listeners) -->
|
<!-- 2. Alpine Stores (register alpine:init listeners) -->
|
||||||
<script src="js/store.js"></script>
|
<script src="js/store.js"></script>
|
||||||
<script src="js/data-store.js"></script>
|
<script src="js/data-store.js"></script>
|
||||||
|
|||||||
@@ -115,8 +115,11 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
const messageHandler = (event) => {
|
const messageHandler = (event) => {
|
||||||
if (event.data?.type === 'oauth-success') {
|
if (event.data?.type === 'oauth-success') {
|
||||||
const action = reAuthEmail ? 're-authenticated' : 'added';
|
const store = Alpine.store('global');
|
||||||
Alpine.store('global').showToast(`Account ${event.data.email} ${action} successfully`, 'success');
|
const successMsg = reAuthEmail
|
||||||
|
? store.t('accountReauthSuccess')
|
||||||
|
: store.t('accountAddedSuccess');
|
||||||
|
store.showToast(successMsg, 'success');
|
||||||
Alpine.store('data').fetchData();
|
Alpine.store('data').fetchData();
|
||||||
|
|
||||||
const modal = document.getElementById('add_account_modal');
|
const modal = document.getElementById('add_account_modal');
|
||||||
@@ -127,10 +130,10 @@ document.addEventListener('alpine:init', () => {
|
|||||||
window.addEventListener('message', messageHandler);
|
window.addEventListener('message', messageHandler);
|
||||||
setTimeout(() => window.removeEventListener('message', messageHandler), 300000);
|
setTimeout(() => window.removeEventListener('message', messageHandler), 300000);
|
||||||
} else {
|
} else {
|
||||||
Alpine.store('global').showToast(data.error || 'Failed to get auth URL', 'error');
|
Alpine.store('global').showToast(data.error || Alpine.store('global').t('failedToGetAuthUrl'), 'error');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Alpine.store('global').showToast('Failed to start OAuth flow: ' + e.message, 'error');
|
Alpine.store('global').showToast(Alpine.store('global').t('failedToStartOAuth') + ': ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ window.Components.claudeConfig = () => ({
|
|||||||
*/
|
*/
|
||||||
async executeSavePreset(name) {
|
async executeSavePreset(name) {
|
||||||
if (!name || !name.trim()) {
|
if (!name || !name.trim()) {
|
||||||
Alpine.store('global').showToast('Preset name is required', 'error');
|
Alpine.store('global').showToast(Alpine.store('global').t('presetNameRequired'), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,10 +363,10 @@ window.Components.claudeConfig = () => ({
|
|||||||
);
|
);
|
||||||
document.getElementById('save_preset_modal').close();
|
document.getElementById('save_preset_modal').close();
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.error || 'Save failed');
|
throw new Error(data.error || Alpine.store('global').t('saveFailed'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Alpine.store('global').showToast('Failed to save preset: ' + e.message, 'error');
|
Alpine.store('global').showToast(Alpine.store('global').t('failedToSavePreset') + ': ' + e.message, 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.savingPreset = false;
|
this.savingPreset = false;
|
||||||
}
|
}
|
||||||
@@ -377,12 +377,13 @@ window.Components.claudeConfig = () => ({
|
|||||||
*/
|
*/
|
||||||
async deleteSelectedPreset() {
|
async deleteSelectedPreset() {
|
||||||
if (!this.selectedPresetName) {
|
if (!this.selectedPresetName) {
|
||||||
Alpine.store('global').showToast('No preset selected', 'warning');
|
Alpine.store('global').showToast(Alpine.store('global').t('noPresetSelected'), 'warning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm deletion
|
// Confirm deletion
|
||||||
if (!confirm(`Delete preset "${this.selectedPresetName}"?`)) {
|
const confirmMsg = Alpine.store('global').t('deletePresetConfirm', { name: this.selectedPresetName });
|
||||||
|
if (!confirm(confirmMsg)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +409,10 @@ window.Components.claudeConfig = () => ({
|
|||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.error || 'Delete failed');
|
throw new Error(data.error || Alpine.store('global').t('deleteFailed'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Alpine.store('global').showToast('Failed to delete preset: ' + e.message, 'error');
|
Alpine.store('global').showToast(Alpine.store('global').t('failedToDeletePreset') + ': ' + e.message, 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.deletingPreset = false;
|
this.deletingPreset = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,15 +88,15 @@ window.Components.serverConfig = () => ({
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
throw new Error(data.error || 'Failed to change password');
|
throw new Error(data.error || store.t('failedToChangePassword'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update stored password
|
// Update stored password
|
||||||
store.webuiPassword = newPassword;
|
store.webuiPassword = newPassword;
|
||||||
store.showToast('Password changed successfully', 'success');
|
store.showToast(store.t('passwordChangedSuccess'), 'success');
|
||||||
this.hidePasswordDialog();
|
this.hidePasswordDialog();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
store.showToast('Failed to change password: ' + e.message, 'error');
|
store.showToast(store.t('failedToChangePassword') + ': ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -119,16 +119,16 @@ window.Components.serverConfig = () => ({
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status === 'ok') {
|
if (data.status === 'ok') {
|
||||||
const status = enabled ? 'enabled' : 'disabled';
|
const status = enabled ? store.t('enabledStatus') : store.t('disabledStatus');
|
||||||
store.showToast(`Debug mode ${status}`, 'success');
|
store.showToast(store.t('debugModeToggled', { status }), 'success');
|
||||||
await this.fetchServerConfig(); // Confirm server state
|
await this.fetchServerConfig(); // Confirm server state
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.error || 'Failed to update debug mode');
|
throw new Error(data.error || store.t('failedToUpdateDebugMode'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Rollback on error
|
// Rollback on error
|
||||||
this.serverConfig.debug = previousValue;
|
this.serverConfig.debug = previousValue;
|
||||||
store.showToast('Failed to update debug mode: ' + e.message, 'error');
|
store.showToast(store.t('failedToUpdateDebugMode') + ': ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -151,16 +151,16 @@ window.Components.serverConfig = () => ({
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status === 'ok') {
|
if (data.status === 'ok') {
|
||||||
const status = enabled ? 'enabled' : 'disabled';
|
const status = enabled ? store.t('enabledStatus') : store.t('disabledStatus');
|
||||||
store.showToast(`Token cache ${status}`, 'success');
|
store.showToast(store.t('tokenCacheToggled', { status }), 'success');
|
||||||
await this.fetchServerConfig(); // Confirm server state
|
await this.fetchServerConfig(); // Confirm server state
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.error || 'Failed to update token cache');
|
throw new Error(data.error || store.t('failedToUpdateTokenCache'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Rollback on error
|
// Rollback on error
|
||||||
this.serverConfig.persistTokenCache = previousValue;
|
this.serverConfig.persistTokenCache = previousValue;
|
||||||
store.showToast('Failed to update token cache: ' + e.message, 'error');
|
store.showToast(store.t('failedToUpdateTokenCache') + ': ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -206,15 +206,15 @@ window.Components.serverConfig = () => ({
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status === 'ok') {
|
if (data.status === 'ok') {
|
||||||
store.showToast(`${displayName} updated to ${value}`, 'success');
|
store.showToast(store.t('fieldUpdated', { displayName, value }), 'success');
|
||||||
await this.fetchServerConfig(); // Confirm server state
|
await this.fetchServerConfig(); // Confirm server state
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.error || `Failed to update ${displayName}`);
|
throw new Error(data.error || store.t('failedToUpdateField', { displayName }));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Rollback on error
|
// Rollback on error
|
||||||
this.serverConfig[fieldName] = previousValue;
|
this.serverConfig[fieldName] = previousValue;
|
||||||
store.showToast(`Failed to update ${displayName}: ` + e.message, 'error');
|
store.showToast(store.t('failedToUpdateField', { displayName }) + ': ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
}, window.AppConstants.INTERVALS.CONFIG_DEBOUNCE);
|
}, window.AppConstants.INTERVALS.CONFIG_DEBOUNCE);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,843 +39,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
// i18n
|
// i18n
|
||||||
lang: localStorage.getItem('app_lang') || 'en',
|
lang: localStorage.getItem('app_lang') || 'en',
|
||||||
translations: {
|
translations: window.translations || {},
|
||||||
en: {
|
|
||||||
dashboard: "Dashboard",
|
|
||||||
models: "Models",
|
|
||||||
accounts: "Accounts",
|
|
||||||
logs: "Logs",
|
|
||||||
settings: "Settings",
|
|
||||||
online: "ONLINE",
|
|
||||||
offline: "OFFLINE",
|
|
||||||
totalAccounts: "TOTAL ACCOUNTS",
|
|
||||||
active: "ACTIVE",
|
|
||||||
operational: "Operational",
|
|
||||||
rateLimited: "RATE LIMITED",
|
|
||||||
quotasDepleted: "{count}/{total} Quotas Depleted",
|
|
||||||
quotasDepletedTitle: "QUOTAS DEPLETED",
|
|
||||||
outOfTracked: "Out of {total} Tracked",
|
|
||||||
cooldown: "Cooldown",
|
|
||||||
searchPlaceholder: "Search models...",
|
|
||||||
allAccounts: "All Accounts",
|
|
||||||
stat: "STAT",
|
|
||||||
modelIdentity: "MODEL IDENTITY",
|
|
||||||
globalQuota: "GLOBAL QUOTA",
|
|
||||||
nextReset: "NEXT RESET",
|
|
||||||
distribution: "ACCOUNT DISTRIBUTION",
|
|
||||||
systemConfig: "System Configuration",
|
|
||||||
language: "Language",
|
|
||||||
pollingInterval: "Polling Interval",
|
|
||||||
maxDisplayLogs: "Max Displayed Logs",
|
|
||||||
showExhausted: "Show Exhausted Models",
|
|
||||||
showExhaustedDesc: "Display models even if they have 0% remaining quota.",
|
|
||||||
compactMode: "Compact Mode",
|
|
||||||
compactModeDesc: "Reduce padding in tables for higher information density.",
|
|
||||||
saveChanges: "Save Changes",
|
|
||||||
autoScroll: "Auto-scroll",
|
|
||||||
clearLogs: "Clear Logs",
|
|
||||||
accountManagement: "Account Management",
|
|
||||||
manageTokens: "Manage Google Account tokens and authorization states",
|
|
||||||
addAccount: "Add Account",
|
|
||||||
status: "STATUS",
|
|
||||||
enabled: "ENABLED",
|
|
||||||
health: "STATUS",
|
|
||||||
accountEmail: "ACCOUNT (EMAIL)",
|
|
||||||
source: "SOURCE",
|
|
||||||
projectId: "PROJECT ID",
|
|
||||||
sessionState: "SESSION STATE",
|
|
||||||
operations: "OPERATIONS",
|
|
||||||
delete: "Delete",
|
|
||||||
confirmDelete: "Are you sure you want to remove this account?",
|
|
||||||
cannotDeleteDatabase: "Cannot delete: This account is from Antigravity database (read-only)",
|
|
||||||
connectGoogle: "Connect Google Account",
|
|
||||||
reauthenticated: "re-authenticated",
|
|
||||||
added: "added",
|
|
||||||
successfully: "successfully",
|
|
||||||
accountAddedSuccess: "Account added successfully",
|
|
||||||
accountReauthSuccess: "Account re-authenticated successfully",
|
|
||||||
failedToGetAuthUrl: "Failed to get auth URL",
|
|
||||||
failedToStartOAuth: "Failed to start OAuth flow",
|
|
||||||
oauthInProgress: "OAuth in progress. Please complete authentication in the popup window...",
|
|
||||||
family: "Family",
|
|
||||||
model: "Model",
|
|
||||||
activeSuffix: "Active",
|
|
||||||
// Tabs
|
|
||||||
tabInterface: "Interface",
|
|
||||||
tabClaude: "Claude CLI",
|
|
||||||
tabModels: "Models",
|
|
||||||
tabServer: "Server Settings",
|
|
||||||
// Dashboard
|
|
||||||
linkedAccounts: "Linked Accounts",
|
|
||||||
noSignal: "NO SIGNAL DETECTED",
|
|
||||||
establishingUplink: "ESTABLISHING UPLINK...",
|
|
||||||
goToAccounts: "Go to Accounts",
|
|
||||||
// Settings - Models
|
|
||||||
modelsDesc: "Configure model visibility, pinning, and request routing.",
|
|
||||||
modelsPageDesc: "Real-time quota and status for all available models.",
|
|
||||||
showHidden: "Show Hidden Models",
|
|
||||||
hideHidden: "Hide Hidden Models",
|
|
||||||
hiddenOn: "Hidden: ON",
|
|
||||||
hiddenOff: "Hidden: OFF",
|
|
||||||
modelId: "Model ID",
|
|
||||||
actions: "Actions",
|
|
||||||
pinToTop: "Pin to top",
|
|
||||||
toggleVisibility: "Toggle Visibility",
|
|
||||||
noModels: "NO MODELS DETECTED",
|
|
||||||
modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.",
|
|
||||||
modelMapping: "Mapping (Target Model ID)",
|
|
||||||
// Settings - Claude
|
|
||||||
proxyConnection: "Proxy Connection",
|
|
||||||
modelSelection: "Model Selection",
|
|
||||||
defaultModelAliases: "DEFAULT MODEL ALIASES",
|
|
||||||
opusAlias: "Opus Alias",
|
|
||||||
sonnetAlias: "Sonnet Alias",
|
|
||||||
haikuAlias: "Haiku Alias",
|
|
||||||
claudeSettingsAlertPrefix: "Settings below directly modify",
|
|
||||||
claudeSettingsAlertSuffix: "Restart Claude CLI to apply.",
|
|
||||||
applyToClaude: "Apply to Claude CLI",
|
|
||||||
// Presets
|
|
||||||
configPresets: "Configuration Presets",
|
|
||||||
saveAsPreset: "Save as Preset",
|
|
||||||
deletePreset: "Delete Preset",
|
|
||||||
loadPreset: "Load preset into form",
|
|
||||||
load: "Load",
|
|
||||||
presetHint: "Select a preset to load it. Click \"Apply to Claude CLI\" to save changes.",
|
|
||||||
presetLoaded: "Preset loaded. Click \"Apply to Claude CLI\" to save.",
|
|
||||||
presetSaved: "Preset saved",
|
|
||||||
presetDeleted: "Preset deleted",
|
|
||||||
unsavedChangesTitle: "Unsaved Changes",
|
|
||||||
unsavedChangesMessage: "Your current configuration doesn't match any saved preset. If you switch, your current unsaved settings will be lost.",
|
|
||||||
loadAnyway: "Load Anyway",
|
|
||||||
savePresetTitle: "Save Preset",
|
|
||||||
savePresetDesc: "Save the current configuration as a reusable preset.",
|
|
||||||
presetName: "Preset Name",
|
|
||||||
presetNamePlaceholder: "e.g., My Work Setup",
|
|
||||||
savePreset: "Save Preset",
|
|
||||||
// Settings - Server
|
|
||||||
port: "Port",
|
|
||||||
uiVersion: "UI Version",
|
|
||||||
debugMode: "Debug Mode",
|
|
||||||
environment: "Environment",
|
|
||||||
serverReadOnly: "Settings managed via config.json. Restart server to apply changes.",
|
|
||||||
advancedSettings: "Advanced Settings",
|
|
||||||
reloadConfigTitle: "Reload Account Config",
|
|
||||||
reloadConfigDesc: "Force reload accounts.json from disk",
|
|
||||||
reload: "Reload",
|
|
||||||
// Config Specific
|
|
||||||
primaryModel: "Primary Model",
|
|
||||||
subAgentModel: "Sub-agent Model",
|
|
||||||
advancedOverrides: "Default Model Overrides",
|
|
||||||
opusModel: "Opus Model",
|
|
||||||
sonnetModel: "Sonnet Model",
|
|
||||||
haikuModel: "Haiku Model",
|
|
||||||
authToken: "Auth Token",
|
|
||||||
saveConfig: "Save to Claude CLI settings",
|
|
||||||
envVar: "Env",
|
|
||||||
// New Keys
|
|
||||||
systemName: "ANTIGRAVITY",
|
|
||||||
systemDesc: "CLAUDE PROXY SYSTEM",
|
|
||||||
connectGoogleDesc: "Connect a Google Workspace account to increase your API quota limit. The account will be used to proxy Claude requests via Antigravity.",
|
|
||||||
useCliCommand: "Use CLI Command",
|
|
||||||
close: "Close",
|
|
||||||
requestVolume: "Request Volume",
|
|
||||||
filter: "Filter",
|
|
||||||
all: "All",
|
|
||||||
none: "None",
|
|
||||||
noDataTracked: "No data tracked yet",
|
|
||||||
selectFamilies: "Select families to display",
|
|
||||||
selectModels: "Select models to display",
|
|
||||||
noLogsMatch: "No logs match filter",
|
|
||||||
connecting: "CONNECTING",
|
|
||||||
main: "Main",
|
|
||||||
system: "System",
|
|
||||||
refreshData: "Refresh Data",
|
|
||||||
connectionLost: "Connection Lost",
|
|
||||||
lastUpdated: "Last Updated",
|
|
||||||
grepLogs: "grep logs...",
|
|
||||||
noMatchingModels: "No matching models",
|
|
||||||
typeToSearch: "Type to search or select...",
|
|
||||||
or: "OR",
|
|
||||||
refreshingAccount: "Refreshing {email}...",
|
|
||||||
refreshedAccount: "Refreshed {email}",
|
|
||||||
refreshFailed: "Refresh failed",
|
|
||||||
accountToggled: "Account {email} {status}",
|
|
||||||
toggleFailed: "Toggle failed",
|
|
||||||
reauthenticating: "Re-authenticating {email}...",
|
|
||||||
authUrlFailed: "Failed to get auth URL",
|
|
||||||
deletedAccount: "Deleted {email}",
|
|
||||||
deleteFailed: "Delete failed",
|
|
||||||
accountsReloaded: "Accounts reloaded",
|
|
||||||
reloadFailed: "Reload failed",
|
|
||||||
claudeConfigSaved: "Claude configuration saved",
|
|
||||||
claudeConfigRestored: "Claude CLI restored to defaults",
|
|
||||||
saveConfigFailed: "Failed to save configuration",
|
|
||||||
restoreConfigFailed: "Failed to restore configuration",
|
|
||||||
restoreDefault: "Restore Default",
|
|
||||||
confirmRestoreTitle: "Confirm Restore",
|
|
||||||
confirmRestoreMessage: "Are you sure you want to restore Claude CLI to default settings? This will remove proxy configuration.",
|
|
||||||
confirmRestore: "Confirm Restore",
|
|
||||||
claudeActive: "Claude Active",
|
|
||||||
claudeEmpty: "Claude Empty",
|
|
||||||
geminiActive: "Gemini Active",
|
|
||||||
geminiEmpty: "Gemini Empty",
|
|
||||||
synced: "SYNCED",
|
|
||||||
syncing: "SYNCING...",
|
|
||||||
// Time range labels
|
|
||||||
last1Hour: "Last 1H",
|
|
||||||
last6Hours: "Last 6H",
|
|
||||||
last24Hours: "Last 24H",
|
|
||||||
last7Days: "Last 7D",
|
|
||||||
allTime: "All Time",
|
|
||||||
groupBy: "Group By",
|
|
||||||
// Additional
|
|
||||||
reloading: "Reloading...",
|
|
||||||
reloaded: "Reloaded",
|
|
||||||
lines: "lines",
|
|
||||||
enabledSeeLogs: "Enabled (See Logs)",
|
|
||||||
production: "Production",
|
|
||||||
configSaved: "Configuration Saved",
|
|
||||||
enterPassword: "Enter Web UI Password:",
|
|
||||||
ready: "READY",
|
|
||||||
depleted: "Depleted",
|
|
||||||
timeH: "H",
|
|
||||||
timeM: "M",
|
|
||||||
familyClaude: "Claude",
|
|
||||||
familyGemini: "Gemini",
|
|
||||||
familyOther: "Other",
|
|
||||||
enabledStatus: "enabled",
|
|
||||||
disabledStatus: "disabled",
|
|
||||||
logLevelInfo: "INFO",
|
|
||||||
logLevelSuccess: "SUCCESS",
|
|
||||||
logLevelWarn: "WARN",
|
|
||||||
logLevelError: "ERR",
|
|
||||||
totalColon: "Total:",
|
|
||||||
todayColon: "Today:",
|
|
||||||
hour1Colon: "1H:",
|
|
||||||
frequentModels: "Frequent",
|
|
||||||
smartTitle: "Auto-select top 5 most used models (24h)",
|
|
||||||
activeCount: "{count} Active",
|
|
||||||
allCaps: "ALL",
|
|
||||||
claudeCaps: "CLAUDE",
|
|
||||||
geminiCaps: "GEMINI",
|
|
||||||
modelMapping: "Mapping (Target Model ID)",
|
|
||||||
systemInfo: "System Information",
|
|
||||||
refresh: "Refresh",
|
|
||||||
runtimeConfig: "Runtime Configuration",
|
|
||||||
debugDesc: "Enable detailed logging (See Logs tab)",
|
|
||||||
networkRetry: "Network Retry Settings",
|
|
||||||
maxRetries: "Max Retries",
|
|
||||||
retryBaseDelay: "Retry Base Delay (ms)",
|
|
||||||
retryMaxDelay: "Retry Max Delay (ms)",
|
|
||||||
persistentSessions: "Persistent Sessions",
|
|
||||||
persistTokenDesc: "Save OAuth sessions to disk for faster restarts",
|
|
||||||
rateLimiting: "Account Rate Limiting & Timeouts",
|
|
||||||
defaultCooldown: "Default Cooldown",
|
|
||||||
defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.",
|
|
||||||
maxWaitThreshold: "Max Wait Before Error",
|
|
||||||
maxWaitDesc: "If all accounts are rate-limited longer than this, error immediately instead of waiting.",
|
|
||||||
saveConfigServer: "Save Configuration",
|
|
||||||
serverRestartAlert: "Changes saved to {path}. Restart server to apply some settings.",
|
|
||||||
changePassword: "Change WebUI Password",
|
|
||||||
changePasswordDesc: "Update the password for accessing this dashboard",
|
|
||||||
currentPassword: "Current Password",
|
|
||||||
newPassword: "New Password",
|
|
||||||
confirmNewPassword: "Confirm New Password",
|
|
||||||
passwordEmptyDesc: "Leave empty if no password set",
|
|
||||||
passwordLengthDesc: "At least 6 characters",
|
|
||||||
passwordConfirmDesc: "Re-enter new password",
|
|
||||||
cancel: "Cancel",
|
|
||||||
passwordsNotMatch: "Passwords do not match",
|
|
||||||
passwordTooShort: "Password must be at least 6 characters",
|
|
||||||
// Dashboard drill-down
|
|
||||||
clickToViewAllAccounts: "Click to view all accounts",
|
|
||||||
clickToViewModels: "Click to view Models page",
|
|
||||||
clickToViewLimitedAccounts: "Click to view rate-limited accounts",
|
|
||||||
clickToFilterClaude: "Click to filter Claude models",
|
|
||||||
clickToFilterGemini: "Click to filter Gemini models",
|
|
||||||
// Accounts page
|
|
||||||
searchAccounts: "Search accounts...",
|
|
||||||
noAccountsYet: "No Accounts Yet",
|
|
||||||
noAccountsDesc: "Get started by adding a Google account via OAuth, or use the CLI command to import credentials.",
|
|
||||||
addFirstAccount: "Add Your First Account",
|
|
||||||
noSearchResults: "No accounts match your search",
|
|
||||||
clearSearch: "Clear Search",
|
|
||||||
disabledAccountsNote: "<strong>Disabled accounts</strong> will not be used for request routing but remain in the configuration. Dashboard statistics only include enabled accounts.",
|
|
||||||
dangerousOperation: "⚠️ Dangerous Operation",
|
|
||||||
confirmDeletePrompt: "Are you sure you want to delete account",
|
|
||||||
deleteWarning: "⚠️ This action cannot be undone. All configuration and historical records will be permanently deleted.",
|
|
||||||
// OAuth progress
|
|
||||||
oauthWaiting: "Waiting for OAuth authorization...",
|
|
||||||
oauthWaitingDesc: "Please complete the authentication in the popup window. This may take up to 2 minutes.",
|
|
||||||
oauthCancelled: "OAuth authorization cancelled",
|
|
||||||
oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.",
|
|
||||||
oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.",
|
|
||||||
cancelOAuth: "Cancel",
|
|
||||||
// MCP CLI & Gemini 1M
|
|
||||||
mcpCliExperimental: "Experimental MCP CLI",
|
|
||||||
mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.",
|
|
||||||
gemini1mMode: "Gemini 1M Context Mode",
|
|
||||||
gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.",
|
|
||||||
gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.",
|
|
||||||
clickToSet: "Click to configure...",
|
|
||||||
none: "None",
|
|
||||||
// Quota Distribution
|
|
||||||
quotaDistribution: "Quota Distribution",
|
|
||||||
resetsIn: "Resets in {time}",
|
|
||||||
noQuotaData: "No quota data available for this account yet.",
|
|
||||||
},
|
|
||||||
zh: {
|
|
||||||
dashboard: "仪表盘",
|
|
||||||
models: "模型列表",
|
|
||||||
accounts: "账号管理",
|
|
||||||
logs: "运行日志",
|
|
||||||
settings: "系统设置",
|
|
||||||
online: "在线",
|
|
||||||
offline: "离线",
|
|
||||||
totalAccounts: "账号总数",
|
|
||||||
active: "活跃状态",
|
|
||||||
operational: "运行中",
|
|
||||||
rateLimited: "受限状态",
|
|
||||||
quotasDepleted: "{count}/{total} 配额耗尽",
|
|
||||||
quotasDepletedTitle: "配额耗尽数",
|
|
||||||
outOfTracked: "共追踪 {total} 个",
|
|
||||||
cooldown: "冷却中",
|
|
||||||
searchPlaceholder: "搜索模型...",
|
|
||||||
allAccounts: "所有账号",
|
|
||||||
stat: "状态",
|
|
||||||
modelIdentity: "模型标识",
|
|
||||||
globalQuota: "全局配额",
|
|
||||||
nextReset: "重置时间",
|
|
||||||
distribution: "账号分布",
|
|
||||||
systemConfig: "系统配置",
|
|
||||||
language: "语言设置",
|
|
||||||
pollingInterval: "数据轮询间隔",
|
|
||||||
maxDisplayLogs: "最大日志显示行数",
|
|
||||||
showExhausted: "显示耗尽模型",
|
|
||||||
showExhaustedDesc: "即使配额为 0% 也显示模型。",
|
|
||||||
compactMode: "紧凑模式",
|
|
||||||
compactModeDesc: "减少表格间距以显示更多信息。",
|
|
||||||
saveChanges: "保存更改",
|
|
||||||
autoScroll: "自动滚动",
|
|
||||||
clearLogs: "清除日志",
|
|
||||||
accountManagement: "账号管理",
|
|
||||||
manageTokens: "管理已授权的 Google 账号及其状态",
|
|
||||||
addAccount: "添加账号",
|
|
||||||
status: "状态",
|
|
||||||
enabled: "启用",
|
|
||||||
health: "状态",
|
|
||||||
accountEmail: "账号 (邮箱)",
|
|
||||||
source: "来源",
|
|
||||||
projectId: "项目 ID",
|
|
||||||
sessionState: "会话状态",
|
|
||||||
operations: "操作",
|
|
||||||
delete: "删除",
|
|
||||||
confirmDelete: "确定要移除此账号吗?",
|
|
||||||
cannotDeleteDatabase: "无法删除:此账号来自 Antigravity 数据库(只读)",
|
|
||||||
connectGoogle: "连接 Google 账号",
|
|
||||||
reauthenticated: "已重新认证",
|
|
||||||
added: "已添加",
|
|
||||||
successfully: "成功",
|
|
||||||
accountAddedSuccess: "账号添加成功",
|
|
||||||
accountReauthSuccess: "账号重新认证成功",
|
|
||||||
failedToGetAuthUrl: "获取认证链接失败",
|
|
||||||
failedToStartOAuth: "启动 OAuth 流程失败",
|
|
||||||
oauthInProgress: "OAuth 授权进行中,请在弹出窗口中完成认证...",
|
|
||||||
family: "系列",
|
|
||||||
model: "模型",
|
|
||||||
activeSuffix: "活跃",
|
|
||||||
manualReload: "重新加载配置",
|
|
||||||
// Tabs
|
|
||||||
tabInterface: "界面设置",
|
|
||||||
tabClaude: "Claude CLI",
|
|
||||||
tabModels: "模型管理",
|
|
||||||
tabServer: "服务器设置",
|
|
||||||
// Dashboard
|
|
||||||
linkedAccounts: "已关联账号",
|
|
||||||
noSignal: "无信号连接",
|
|
||||||
establishingUplink: "正在建立上行链路...",
|
|
||||||
goToAccounts: "前往账号管理",
|
|
||||||
// Settings - Models
|
|
||||||
modelsDesc: "配置模型的可见性、置顶和请求路由。",
|
|
||||||
modelsPageDesc: "所有可用模型的实时配额和状态。",
|
|
||||||
showHidden: "显示隐藏模型",
|
|
||||||
hideHidden: "隐藏被屏蔽模型",
|
|
||||||
hiddenOn: "隐藏模型: 显示",
|
|
||||||
hiddenOff: "隐藏模型: 隐藏",
|
|
||||||
modelId: "模型 ID",
|
|
||||||
actions: "操作",
|
|
||||||
pinToTop: "置顶",
|
|
||||||
toggleVisibility: "切换可见性",
|
|
||||||
noModels: "未检测到模型",
|
|
||||||
modelMappingHint: "服务端模型路由功能。Claude Code 用户请使用 'Claude CLI' 标签页以便捷配置。",
|
|
||||||
modelMapping: "映射 (目标模型 ID)",
|
|
||||||
// Settings - Claude
|
|
||||||
proxyConnection: "代理连接",
|
|
||||||
modelSelection: "模型选择",
|
|
||||||
defaultModelAliases: "默认模型映射 (别名)",
|
|
||||||
opusAlias: "Opus 别名",
|
|
||||||
sonnetAlias: "Sonnet 别名",
|
|
||||||
haikuAlias: "Haiku 别名",
|
|
||||||
claudeSettingsAlertPrefix: "以下设置直接修改",
|
|
||||||
claudeSettingsAlertSuffix: "重启 Claude CLI 生效。",
|
|
||||||
applyToClaude: "应用到 Claude CLI",
|
|
||||||
// Presets
|
|
||||||
configPresets: "配置预设",
|
|
||||||
saveAsPreset: "另存为预设",
|
|
||||||
deletePreset: "删除预设",
|
|
||||||
loadPreset: "加载预设到表单",
|
|
||||||
load: "加载",
|
|
||||||
presetHint: "选择预设以加载。点击“应用到 Claude CLI”以保存更改。",
|
|
||||||
presetLoaded: "预设已加载。点击“应用到 Claude CLI”以保存。",
|
|
||||||
presetSaved: "预设已保存",
|
|
||||||
presetDeleted: "预设已删除",
|
|
||||||
unsavedChangesTitle: "未保存的更改",
|
|
||||||
unsavedChangesMessage: "当前配置与任何已保存的预设都不匹配。如果切换预设,当前未保存的设置将会丢失。",
|
|
||||||
loadAnyway: "仍然加载",
|
|
||||||
savePresetTitle: "保存预设",
|
|
||||||
savePresetDesc: "将当前配置保存为可重复使用的预设。",
|
|
||||||
presetName: "预设名称",
|
|
||||||
presetNamePlaceholder: "例如:工作配置",
|
|
||||||
savePreset: "保存预设",
|
|
||||||
// Settings - Server
|
|
||||||
port: "端口",
|
|
||||||
uiVersion: "UI 版本",
|
|
||||||
debugMode: "调试模式",
|
|
||||||
environment: "运行环境",
|
|
||||||
serverReadOnly: "配置由 config.json 管理。重启服务器以应用更改。",
|
|
||||||
advancedSettings: "高级设置",
|
|
||||||
reloadConfigTitle: "重载账号配置",
|
|
||||||
reloadConfigDesc: "强制从磁盘重新读取 accounts.json",
|
|
||||||
reload: "重载",
|
|
||||||
// Config Specific
|
|
||||||
primaryModel: "主模型",
|
|
||||||
subAgentModel: "子代理模型",
|
|
||||||
advancedOverrides: "默认模型覆盖 (高级)",
|
|
||||||
opusModel: "Opus 模型",
|
|
||||||
sonnetModel: "Sonnet 模型",
|
|
||||||
haikuModel: "Haiku 模型",
|
|
||||||
authToken: "认证令牌",
|
|
||||||
saveConfig: "保存到 Claude CLI 设置",
|
|
||||||
envVar: "环境变量",
|
|
||||||
// New Keys
|
|
||||||
systemName: "ANTIGRAVITY",
|
|
||||||
systemDesc: "CLAUDE 代理系统",
|
|
||||||
connectGoogleDesc: "连接 Google Workspace 账号以增加 API 配额。该账号将用于通过 Antigravity 代理 Claude 请求。",
|
|
||||||
useCliCommand: "使用命令行",
|
|
||||||
close: "关闭",
|
|
||||||
requestVolume: "请求量",
|
|
||||||
filter: "筛选",
|
|
||||||
all: "全选",
|
|
||||||
none: "清空",
|
|
||||||
noDataTracked: "暂无追踪数据",
|
|
||||||
selectFamilies: "选择要显示的系列",
|
|
||||||
selectModels: "选择要显示的模型",
|
|
||||||
noLogsMatch: "没有符合过滤条件的日志",
|
|
||||||
connecting: "正在连接",
|
|
||||||
main: "主菜单",
|
|
||||||
system: "系统",
|
|
||||||
refreshData: "刷新数据",
|
|
||||||
connectionLost: "连接已断开",
|
|
||||||
lastUpdated: "最后更新",
|
|
||||||
grepLogs: "过滤日志...",
|
|
||||||
noMatchingModels: "没有匹配的模型",
|
|
||||||
typeToSearch: "输入以搜索或选择...",
|
|
||||||
or: "或",
|
|
||||||
refreshingAccount: "正在刷新 {email}...",
|
|
||||||
refreshedAccount: "已完成刷新 {email}",
|
|
||||||
refreshFailed: "刷新失败",
|
|
||||||
accountToggled: "账号 {email} 已{status}",
|
|
||||||
toggleFailed: "切换失败",
|
|
||||||
reauthenticating: "正在重新认证 {email}...",
|
|
||||||
authUrlFailed: "获取认证链接失败",
|
|
||||||
deletedAccount: "已删除 {email}",
|
|
||||||
deleteFailed: "删除失败",
|
|
||||||
accountsReloaded: "账号配置已重载",
|
|
||||||
reloadFailed: "重载失败",
|
|
||||||
claudeConfigSaved: "Claude 配置已保存",
|
|
||||||
claudeConfigRestored: "Claude CLI 已恢复默认设置",
|
|
||||||
saveConfigFailed: "保存配置失败",
|
|
||||||
restoreConfigFailed: "恢复配置失败",
|
|
||||||
restoreDefault: "恢复默认",
|
|
||||||
confirmRestoreTitle: "确认恢复",
|
|
||||||
confirmRestoreMessage: "确定要将 Claude CLI 恢复为默认设置吗?这将移除代理配置。",
|
|
||||||
confirmRestore: "确认恢复",
|
|
||||||
claudeActive: "Claude 活跃",
|
|
||||||
claudeEmpty: "Claude 耗尽",
|
|
||||||
geminiActive: "Gemini 活跃",
|
|
||||||
geminiEmpty: "Gemini 耗尽",
|
|
||||||
synced: "已同步",
|
|
||||||
syncing: "正在同步...",
|
|
||||||
// 时间范围标签
|
|
||||||
last1Hour: "最近 1 小时",
|
|
||||||
last6Hours: "最近 6 小时",
|
|
||||||
last24Hours: "最近 24 小时",
|
|
||||||
last7Days: "最近 7 天",
|
|
||||||
allTime: "最后全部",
|
|
||||||
groupBy: "分组方式",
|
|
||||||
// Additional
|
|
||||||
reloading: "正在重载...",
|
|
||||||
reloaded: "已重载",
|
|
||||||
lines: "行",
|
|
||||||
enabledSeeLogs: "已启用 (见日志)",
|
|
||||||
production: "生产环境",
|
|
||||||
configSaved: "配置已保存",
|
|
||||||
enterPassword: "请输入 Web UI 密码:",
|
|
||||||
ready: "就绪",
|
|
||||||
depleted: "已耗尽",
|
|
||||||
timeH: "时",
|
|
||||||
timeM: "分",
|
|
||||||
familyClaude: "Claude 系列",
|
|
||||||
familyGemini: "Gemini 系列",
|
|
||||||
familyOther: "其他系列",
|
|
||||||
enabledStatus: "已启用",
|
|
||||||
disabledStatus: "已禁用",
|
|
||||||
logLevelInfo: "信息",
|
|
||||||
logLevelSuccess: "成功",
|
|
||||||
logLevelWarn: "警告",
|
|
||||||
logLevelError: "错误",
|
|
||||||
totalColon: "总计:",
|
|
||||||
todayColon: "今日:",
|
|
||||||
hour1Colon: "1小时:",
|
|
||||||
frequentModels: "常用推荐",
|
|
||||||
smartTitle: "自动选出过去 24 小时最常用的 5 个模型",
|
|
||||||
activeCount: "{count} 活跃",
|
|
||||||
allCaps: "全部",
|
|
||||||
claudeCaps: "CLAUDE",
|
|
||||||
geminiCaps: "GEMINI",
|
|
||||||
modelMapping: "映射 (目标模型 ID)",
|
|
||||||
systemInfo: "系统信息",
|
|
||||||
refresh: "刷新",
|
|
||||||
runtimeConfig: "运行时配置",
|
|
||||||
debugDesc: "启用详细日志记录 (见运行日志)",
|
|
||||||
networkRetry: "网络重试设置",
|
|
||||||
maxRetries: "最大重试次数",
|
|
||||||
retryBaseDelay: "重试基础延迟 (毫秒)",
|
|
||||||
retryMaxDelay: "重试最大延迟 (毫秒)",
|
|
||||||
persistentSessions: "持久化登录会话",
|
|
||||||
persistTokenDesc: "将登录会话保存到磁盘以实现快速重启",
|
|
||||||
rateLimiting: "账号限流与超时",
|
|
||||||
defaultCooldown: "默认冷却时间",
|
|
||||||
defaultCooldownDesc: "当 API 未提供重置时间时的备用冷却时间。",
|
|
||||||
maxWaitThreshold: "最大等待阈值",
|
|
||||||
maxWaitDesc: "如果所有账号的限流时间超过此阈值,立即返回错误而非等待。",
|
|
||||||
saveConfigServer: "保存配置",
|
|
||||||
serverRestartAlert: "配置已保存至 {path}。部分更改可能需要重启服务器。",
|
|
||||||
changePassword: "修改 WebUI 密码",
|
|
||||||
changePasswordDesc: "更新访问此仪表盘的密码",
|
|
||||||
currentPassword: "当前密码",
|
|
||||||
newPassword: "新密码",
|
|
||||||
confirmNewPassword: "确认新密码",
|
|
||||||
passwordEmptyDesc: "如果未设置密码请留空",
|
|
||||||
passwordLengthDesc: "至少 6 个字符",
|
|
||||||
passwordConfirmDesc: "请再次输入新密码",
|
|
||||||
cancel: "取消",
|
|
||||||
passwordsNotMatch: "密码不匹配",
|
|
||||||
passwordTooShort: "密码至少需要 6 个字符",
|
|
||||||
// Dashboard drill-down
|
|
||||||
clickToViewAllAccounts: "点击查看所有账号",
|
|
||||||
clickToViewModels: "点击查看模型页面",
|
|
||||||
clickToViewLimitedAccounts: "点击查看受限账号",
|
|
||||||
clickToFilterClaude: "点击筛选 Claude 模型",
|
|
||||||
clickToFilterGemini: "点击筛选 Gemini 模型",
|
|
||||||
// 账号页面
|
|
||||||
searchAccounts: "搜索账号...",
|
|
||||||
noAccountsYet: "还没有添加任何账号",
|
|
||||||
noAccountsDesc: "点击上方的 \"添加账号\" 按钮通过 OAuth 添加 Google 账号,或者使用 CLI 命令导入凭证。",
|
|
||||||
addFirstAccount: "添加第一个账号",
|
|
||||||
noSearchResults: "没有找到匹配的账号",
|
|
||||||
clearSearch: "清除搜索",
|
|
||||||
disabledAccountsNote: "<strong>已禁用的账号</strong>不会用于请求路由,但仍保留在配置中。仪表盘统计数据仅包含已启用的账号。",
|
|
||||||
dangerousOperation: "⚠️ 危险操作",
|
|
||||||
confirmDeletePrompt: "确定要删除账号",
|
|
||||||
deleteWarning: "⚠️ 此操作不可撤销,账号的所有配置和历史记录将永久删除。",
|
|
||||||
// OAuth 进度
|
|
||||||
oauthWaiting: "等待 OAuth 授权中...",
|
|
||||||
oauthWaitingDesc: "请在弹出窗口中完成认证。此过程最长可能需要 2 分钟。",
|
|
||||||
oauthCancelled: "已取消 OAuth 授权",
|
|
||||||
oauthTimeout: "⏱️ OAuth 授权超时,请重试。",
|
|
||||||
oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。",
|
|
||||||
cancelOAuth: "取消",
|
|
||||||
// MCP CLI & Gemini 1M
|
|
||||||
mcpCliExperimental: "实验性 MCP CLI",
|
|
||||||
mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。",
|
|
||||||
gemini1mMode: "Gemini 1M 上下文模式",
|
|
||||||
gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。",
|
|
||||||
gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。",
|
|
||||||
clickToSet: "点击进行配置...",
|
|
||||||
none: "无",
|
|
||||||
// Quota Distribution
|
|
||||||
quotaDistribution: "配额分布",
|
|
||||||
resetsIn: "{time} 后重置",
|
|
||||||
noQuotaData: "暂无此账号的配额数据。",
|
|
||||||
},
|
|
||||||
tr: {
|
|
||||||
dashboard: "Panel",
|
|
||||||
models: "Modeller",
|
|
||||||
accounts: "Hesaplar",
|
|
||||||
logs: "Günlükler",
|
|
||||||
settings: "Ayarlar",
|
|
||||||
online: "ÇEVRİMİÇİ",
|
|
||||||
offline: "ÇEVRİMDIŞI",
|
|
||||||
totalAccounts: "TOPLAM HESAP",
|
|
||||||
active: "AKTİF",
|
|
||||||
operational: "Çalışıyor",
|
|
||||||
rateLimited: "HIZ SINIRLANDI",
|
|
||||||
quotasDepleted: "{count}/{total} Kota Tükendi",
|
|
||||||
quotasDepletedTitle: "KOTA TÜKENDİ",
|
|
||||||
outOfTracked: "{total} Takip Edilen İçinden",
|
|
||||||
cooldown: "Soğuma",
|
|
||||||
searchPlaceholder: "Modelleri ara...",
|
|
||||||
allAccounts: "Tüm Hesaplar",
|
|
||||||
stat: "DURUM",
|
|
||||||
modelIdentity: "MODEL KİMLİĞİ",
|
|
||||||
globalQuota: "GENEL KOTA",
|
|
||||||
nextReset: "SONRAKİ SIFIRLAMA",
|
|
||||||
distribution: "HESAP DAĞILIMI",
|
|
||||||
systemConfig: "Sistem Yapılandırması",
|
|
||||||
language: "Dil",
|
|
||||||
pollingInterval: "Veri Güncelleme Aralığı",
|
|
||||||
maxDisplayLogs: "Maksimum Görüntülenen Günlük",
|
|
||||||
showExhausted: "Tükenmiş Modelleri Göster",
|
|
||||||
showExhaustedDesc: "%0 kotası kalan modelleri de göster.",
|
|
||||||
compactMode: "Kompakt Mod",
|
|
||||||
compactModeDesc: "Daha fazla bilgi göstermek için tablo boşluklarını azalt.",
|
|
||||||
saveChanges: "Değişiklikleri Kaydet",
|
|
||||||
autoScroll: "Otomatik Kaydır",
|
|
||||||
clearLogs: "Günlükleri Temizle",
|
|
||||||
accountManagement: "Hesap Yönetimi",
|
|
||||||
manageTokens: "Google Hesap jetonlarını ve yetkilendirme durumlarını yönet",
|
|
||||||
addAccount: "Hesap Ekle",
|
|
||||||
status: "DURUM",
|
|
||||||
enabled: "ETKİN",
|
|
||||||
health: "SAĞLIK",
|
|
||||||
accountEmail: "HESAP (E-POSTA)",
|
|
||||||
source: "KAYNAK",
|
|
||||||
projectId: "PROJE ID",
|
|
||||||
sessionState: "OTURUM DURUMU",
|
|
||||||
operations: "İŞLEMLER",
|
|
||||||
delete: "Sil",
|
|
||||||
confirmDelete: "Bu hesabı kaldırmak istediğinizden emin misiniz?",
|
|
||||||
cannotDeleteDatabase: "Silinemez: Bu hesap Antigravity veritabanından (salt okunur)",
|
|
||||||
connectGoogle: "Google Hesabı Bağla",
|
|
||||||
reauthenticated: "yeniden doğrulandı",
|
|
||||||
added: "eklendi",
|
|
||||||
successfully: "başarıyla",
|
|
||||||
accountAddedSuccess: "Hesap başarıyla eklendi",
|
|
||||||
accountReauthSuccess: "Hesap başarıyla yeniden doğrulandı",
|
|
||||||
failedToGetAuthUrl: "Yetkilendirme URL'si alınamadı",
|
|
||||||
failedToStartOAuth: "OAuth akışı başlatılamadı",
|
|
||||||
oauthInProgress: "OAuth devam ediyor. Lütfen açılır pencerede kimlik doğrulamayı tamamlayın...",
|
|
||||||
family: "Aile",
|
|
||||||
model: "Model",
|
|
||||||
activeSuffix: "Aktif",
|
|
||||||
manualReload: "Yapılandırmayı Yeniden Yükle",
|
|
||||||
// Tabs
|
|
||||||
tabInterface: "Arayüz",
|
|
||||||
tabClaude: "Claude CLI",
|
|
||||||
tabModels: "Modeller",
|
|
||||||
tabServer: "Sunucu Ayarları",
|
|
||||||
// Dashboard
|
|
||||||
linkedAccounts: "Bağlı Hesaplar",
|
|
||||||
noSignal: "SİNYAL YOK",
|
|
||||||
establishingUplink: "BAĞLANTI KURULUYOR...",
|
|
||||||
goToAccounts: "Hesaplara Git",
|
|
||||||
// Settings - Models
|
|
||||||
modelsDesc: "Model görünürlüğünü, sabitlemeyi ve istek yönlendirmeyi yapılandırın.",
|
|
||||||
modelsPageDesc: "Tüm mevcut modeller için gerçek zamanlı kota ve durum.",
|
|
||||||
showHidden: "Gizli Modelleri Göster",
|
|
||||||
hideHidden: "Gizli Modelleri Gizle",
|
|
||||||
hiddenOn: "Gizli: AÇIK",
|
|
||||||
hiddenOff: "Gizli: KAPALI",
|
|
||||||
modelId: "Model ID",
|
|
||||||
actions: "İşlemler",
|
|
||||||
pinToTop: "En Üste Sabitle",
|
|
||||||
toggleVisibility: "Görünürlüğü Değiştir",
|
|
||||||
noModels: "MODEL ALGILANMADI",
|
|
||||||
modelMappingHint: "Sunucu tarafı model yönlendirme. Claude Code kullanıcıları: istemci tarafı kurulumu için 'Claude CLI' sekmesine bakın.",
|
|
||||||
modelMapping: "Eşleştirme (Hedef Model ID)",
|
|
||||||
// Settings - Claude
|
|
||||||
proxyConnection: "Proxy Bağlantısı",
|
|
||||||
modelSelection: "Model Seçimi",
|
|
||||||
defaultModelAliases: "VARSAYILAN MODEL TAKMA ADLARI",
|
|
||||||
opusAlias: "Opus Takma Adı",
|
|
||||||
sonnetAlias: "Sonnet Takma Adı",
|
|
||||||
haikuAlias: "Haiku Takma Adı",
|
|
||||||
claudeSettingsAlertPrefix: "Aşağıdaki ayarlar doğrudan değiştirir",
|
|
||||||
claudeSettingsAlertSuffix: "Uygulamak için Claude CLI'yı yeniden başlatın.",
|
|
||||||
applyToClaude: "Claude CLI'ya Uygula",
|
|
||||||
// Settings - Server
|
|
||||||
port: "Port",
|
|
||||||
uiVersion: "Arayüz Sürümü",
|
|
||||||
debugMode: "Hata Ayıklama Modu",
|
|
||||||
environment: "Ortam",
|
|
||||||
serverReadOnly: "Ayarlar config.json üzerinden yönetilir. Değişiklikleri uygulamak için sunucuyu yeniden başlatın.",
|
|
||||||
advancedSettings: "Gelişmiş Ayarlar",
|
|
||||||
reloadConfigTitle: "Hesap Yapılandırmasını Yeniden Yükle",
|
|
||||||
reloadConfigDesc: "accounts.json dosyasını diskten yeniden yüklemeye zorla",
|
|
||||||
reload: "Yeniden Yükle",
|
|
||||||
// Config Specific
|
|
||||||
primaryModel: "Birincil Model",
|
|
||||||
subAgentModel: "Alt Ajan Modeli",
|
|
||||||
advancedOverrides: "Varsayılan Model Geçersiz Kılmaları",
|
|
||||||
opusModel: "Opus Modeli",
|
|
||||||
sonnetModel: "Sonnet Modeli",
|
|
||||||
haikuModel: "Haiku Modeli",
|
|
||||||
authToken: "Yetkilendirme Jetonu",
|
|
||||||
saveConfig: "Claude CLI ayarlarına kaydet",
|
|
||||||
envVar: "Ortam Değişkeni",
|
|
||||||
// New Keys
|
|
||||||
systemName: "ANTIGRAVITY",
|
|
||||||
systemDesc: "CLAUDE PROXY SİSTEMİ",
|
|
||||||
connectGoogleDesc: "API kota limitinizi artırmak için bir Google Workspace hesabı bağlayın. Bu hesap, Claude isteklerini Antigravity üzerinden vekil sunucu olarak kullanmak için kullanılacaktır.",
|
|
||||||
useCliCommand: "CLI Komutunu Kullan",
|
|
||||||
close: "Kapat",
|
|
||||||
requestVolume: "İstek Hacmi",
|
|
||||||
filter: "Filtrele",
|
|
||||||
all: "Tümü",
|
|
||||||
none: "Hiçbiri",
|
|
||||||
noDataTracked: "Henüz veri izlenmedi",
|
|
||||||
selectFamilies: "Görüntülenecek aileleri seçin",
|
|
||||||
selectModels: "Görüntülenecek modelleri seçin",
|
|
||||||
noLogsMatch: "Filtreyle eşleşen günlük yok",
|
|
||||||
connecting: "BAĞLANILIYOR",
|
|
||||||
main: "Ana",
|
|
||||||
system: "Sistem",
|
|
||||||
refreshData: "Verileri Yenile",
|
|
||||||
connectionLost: "Bağlantı Kaybedildi",
|
|
||||||
lastUpdated: "Son Güncelleme",
|
|
||||||
grepLogs: "günlükleri ara...",
|
|
||||||
noMatchingModels: "Eşleşen model yok",
|
|
||||||
typeToSearch: "Aramak veya seçmek için yazın...",
|
|
||||||
or: "VEYA",
|
|
||||||
refreshingAccount: "{email} yenileniyor...",
|
|
||||||
refreshedAccount: "{email} yenilendi",
|
|
||||||
refreshFailed: "Yenileme başarısız",
|
|
||||||
accountToggled: "Hesap {email} {status}",
|
|
||||||
toggleFailed: "Değiştirme başarısız",
|
|
||||||
reauthenticating: "{email} yeniden doğrulanıyor...",
|
|
||||||
authUrlFailed: "Yetkilendirme URL'si alınamadı",
|
|
||||||
deletedAccount: "{email} silindi",
|
|
||||||
deleteFailed: "Silme başarısız",
|
|
||||||
accountsReloaded: "Hesaplar yeniden yüklendi",
|
|
||||||
reloadFailed: "Yeniden yükleme başarısız",
|
|
||||||
claudeConfigSaved: "Claude yapılandırması kaydedildi",
|
|
||||||
claudeConfigRestored: "Claude CLI varsayılanlara geri yüklendi",
|
|
||||||
saveConfigFailed: "Yapılandırma kaydedilemedi",
|
|
||||||
restoreConfigFailed: "Yapılandırma geri yüklenemedi",
|
|
||||||
restoreDefault: "Varsayılana Dön",
|
|
||||||
confirmRestoreTitle: "Geri Yüklemeyi Onayla",
|
|
||||||
confirmRestoreMessage: "Claude CLI'yı varsayılan ayarlara geri yüklemek istediğinizden emin misiniz? Bu işlem proxy yapılandırmasını kaldıracaktır.",
|
|
||||||
confirmRestore: "Geri Yüklemeyi Onayla",
|
|
||||||
claudeActive: "Claude Aktif",
|
|
||||||
claudeEmpty: "Claude Boş",
|
|
||||||
geminiActive: "Gemini Aktif",
|
|
||||||
geminiEmpty: "Gemini Boş",
|
|
||||||
synced: "EŞİTLENDİ",
|
|
||||||
syncing: "EŞİTLENİYOR...",
|
|
||||||
// Time range labels
|
|
||||||
last1Hour: "Son 1S",
|
|
||||||
last6Hours: "Son 6S",
|
|
||||||
last24Hours: "Son 24S",
|
|
||||||
last7Days: "Son 7G",
|
|
||||||
allTime: "Tüm Zamanlar",
|
|
||||||
groupBy: "Gruplama Ölçütü",
|
|
||||||
// Additional
|
|
||||||
reloading: "Yeniden yükleniyor...",
|
|
||||||
reloaded: "Yeniden yüklendi",
|
|
||||||
lines: "satır",
|
|
||||||
enabledSeeLogs: "Etkin (Günlüklere Bak)",
|
|
||||||
production: "Üretim",
|
|
||||||
configSaved: "Yapılandırma Kaydedildi",
|
|
||||||
enterPassword: "Web UI Parolasını Girin:",
|
|
||||||
ready: "HAZIR",
|
|
||||||
depleted: "Tükendi",
|
|
||||||
timeH: "S",
|
|
||||||
timeM: "D",
|
|
||||||
familyClaude: "Claude",
|
|
||||||
familyGemini: "Gemini",
|
|
||||||
familyOther: "Diğer",
|
|
||||||
enabledStatus: "etkin",
|
|
||||||
disabledStatus: "devre dışı",
|
|
||||||
logLevelInfo: "BİLGİ",
|
|
||||||
logLevelSuccess: "BAŞARILI",
|
|
||||||
logLevelWarn: "UYARI",
|
|
||||||
logLevelError: "HATA",
|
|
||||||
totalColon: "Toplam:",
|
|
||||||
todayColon: "Bugün:",
|
|
||||||
hour1Colon: "1S:",
|
|
||||||
frequentModels: "Sık Kullanılan",
|
|
||||||
smartTitle: "En çok kullanılan 5 modeli otomatik seç (24s)",
|
|
||||||
activeCount: "{count} Aktif",
|
|
||||||
allCaps: "TÜMÜ",
|
|
||||||
claudeCaps: "CLAUDE",
|
|
||||||
geminiCaps: "GEMINI",
|
|
||||||
modelMapping: "Eşleştirme (Hedef Model ID)",
|
|
||||||
systemInfo: "Sistem Bilgisi",
|
|
||||||
refresh: "Yenile",
|
|
||||||
runtimeConfig: "Çalışma Zamanı Yapılandırması",
|
|
||||||
debugDesc: "Ayrıntılı günlük kaydını etkinleştir (Günlükler sekmesine bakın)",
|
|
||||||
networkRetry: "Ağ Yeniden Deneme Ayarları",
|
|
||||||
maxRetries: "Maksimum Deneme",
|
|
||||||
retryBaseDelay: "Yeniden Deneme Temel Gecikmesi (ms)",
|
|
||||||
retryMaxDelay: "Yeniden Deneme Maksimum Gecikmesi (ms)",
|
|
||||||
persistentSessions: "Kalıcı Oturumlar",
|
|
||||||
persistTokenDesc: "Daha hızlı yeniden başlatmalar için OAuth oturumlarını diske kaydet",
|
|
||||||
rateLimiting: "Hesap Hız Sınırlama ve Zaman Aşımları",
|
|
||||||
defaultCooldown: "Varsayılan Soğuma Süresi",
|
|
||||||
maxWaitThreshold: "Maksimum Bekleme Eşiği (Yapışkan)",
|
|
||||||
maxWaitDesc: "Yapışkan bir hesabın değiştirmeden önce sıfırlanması için beklenecek maksimum süre.",
|
|
||||||
saveConfigServer: "Yapılandırmayı Kaydet",
|
|
||||||
serverRestartAlert: "Değişiklikler {path} konumuna kaydedildi. Bazı ayarları uygulamak için sunucuyu yeniden başlatın.",
|
|
||||||
changePassword: "WebUI Parolasını Değiştir",
|
|
||||||
changePasswordDesc: "Bu panoya erişim parolasını güncelle",
|
|
||||||
currentPassword: "Mevcut Parola",
|
|
||||||
newPassword: "Yeni Parola",
|
|
||||||
confirmNewPassword: "Yeni Parolayı Onayla",
|
|
||||||
passwordEmptyDesc: "Parola ayarlanmamışsa boş bırakın",
|
|
||||||
passwordLengthDesc: "En az 6 karakter",
|
|
||||||
passwordConfirmDesc: "Yeni parolayı tekrar girin",
|
|
||||||
cancel: "İptal",
|
|
||||||
passwordsNotMatch: "Parolalar eşleşmiyor",
|
|
||||||
passwordTooShort: "Parola en az 6 karakter olmalıdır",
|
|
||||||
// Dashboard drill-down
|
|
||||||
clickToViewAllAccounts: "Tüm hesapları görüntülemek için tıklayın",
|
|
||||||
clickToViewModels: "Modeller sayfasını görüntülemek için tıklayın",
|
|
||||||
clickToViewLimitedAccounts: "Hız sınırı olan hesapları görüntülemek için tıklayın",
|
|
||||||
clickToFilterClaude: "Claude modellerini filtrelemek için tıklayın",
|
|
||||||
clickToFilterGemini: "Gemini modellerini filtrelemek için tıklayın",
|
|
||||||
// Accounts page
|
|
||||||
searchAccounts: "Hesap ara...",
|
|
||||||
noAccountsYet: "Henüz Hesap Yok",
|
|
||||||
noAccountsDesc: "OAuth üzerinden bir Google hesabı ekleyerek veya kimlik bilgilerini içe aktarmak için CLI komutunu kullanarak başlayın.",
|
|
||||||
addFirstAccount: "İlk Hesabınızı Ekleyin",
|
|
||||||
noSearchResults: "Aramanızla eşleşen hesap yok",
|
|
||||||
clearSearch: "Aramayı Temizle",
|
|
||||||
disabledAccountsNote: "<strong>Devre dışı bırakılan hesaplar</strong> istek yönlendirmesi için kullanılmayacak ancak yapılandırmada kalacaktır. Pano istatistikleri yalnızca etkin hesapları içerir.",
|
|
||||||
dangerousOperation: "⚠️ Tehlikeli İşlem",
|
|
||||||
confirmDeletePrompt: "Hesabı silmek istediğinizden emin misiniz",
|
|
||||||
deleteWarning: "⚠️ Bu işlem geri alınamaz. Tüm yapılandırma ve geçmiş kayıtları kalıcı olarak silinecektir.",
|
|
||||||
// OAuth progress
|
|
||||||
oauthWaiting: "OAuth yetkilendirmesi bekleniyor...",
|
|
||||||
oauthWaitingDesc: "Lütfen açılır pencerede kimlik doğrulamasını tamamlayın. Bu işlem 2 dakikaya kadar sürebilir.",
|
|
||||||
oauthCancelled: "OAuth yetkilendirmesi iptal edildi",
|
|
||||||
oauthTimeout: "⏱️ OAuth yetkilendirmesi zaman aşımına uğradı. Lütfen tekrar deneyin.",
|
|
||||||
oauthWindowClosed: "OAuth penceresi kapatıldı. Yetkilendirme tamamlanmamış olabilir.",
|
|
||||||
cancelOAuth: "İptal",
|
|
||||||
// MCP CLI & Gemini 1M
|
|
||||||
mcpCliExperimental: "Deneysel MCP CLI",
|
|
||||||
mcpCliDesc: "Daha az bağlam tüketimi ile güvenilir araç kullanımı için deneysel MCP entegrasyonunu etkinleştirir.",
|
|
||||||
gemini1mMode: "Gemini 1M Bağlam Modu",
|
|
||||||
gemini1mDesc: "1M bağlam penceresi desteği için Gemini modellerine [1m] son eki ekler.",
|
|
||||||
gemini1mWarning: "⚠ Büyük bağlam, Gemini-3-Pro performansını düşürebilir.",
|
|
||||||
clickToSet: "Yapılandırmak için tıklayın...",
|
|
||||||
none: "Hiçbiri",
|
|
||||||
// Quota Distribution
|
|
||||||
quotaDistribution: "Kota Dağılımı",
|
|
||||||
resetsIn: "{time} içinde sıfırlanır",
|
|
||||||
noQuotaData: "Bu hesap için henüz kota verisi yok.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Toast Messages
|
// Toast Messages
|
||||||
toast: null,
|
toast: null,
|
||||||
|
|||||||
327
public/js/translations/en.js
Normal file
327
public/js/translations/en.js
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
/**
|
||||||
|
* English Translations
|
||||||
|
*/
|
||||||
|
window.translations = window.translations || {};
|
||||||
|
window.translations.en = {
|
||||||
|
dashboard: "Dashboard",
|
||||||
|
models: "Models",
|
||||||
|
accounts: "Accounts",
|
||||||
|
logs: "Logs",
|
||||||
|
settings: "Settings",
|
||||||
|
online: "ONLINE",
|
||||||
|
offline: "OFFLINE",
|
||||||
|
totalAccounts: "TOTAL ACCOUNTS",
|
||||||
|
active: "ACTIVE",
|
||||||
|
operational: "Operational",
|
||||||
|
rateLimited: "RATE LIMITED",
|
||||||
|
quotasDepleted: "{count}/{total} Quotas Depleted",
|
||||||
|
quotasDepletedTitle: "QUOTAS DEPLETED",
|
||||||
|
outOfTracked: "Out of {total} Tracked",
|
||||||
|
cooldown: "Cooldown",
|
||||||
|
searchPlaceholder: "Search models...",
|
||||||
|
allAccounts: "All Accounts",
|
||||||
|
stat: "STAT",
|
||||||
|
modelIdentity: "MODEL IDENTITY",
|
||||||
|
globalQuota: "GLOBAL QUOTA",
|
||||||
|
nextReset: "NEXT RESET",
|
||||||
|
distribution: "ACCOUNT DISTRIBUTION",
|
||||||
|
systemConfig: "System Configuration",
|
||||||
|
language: "Language",
|
||||||
|
pollingInterval: "Polling Interval",
|
||||||
|
maxDisplayLogs: "Max Displayed Logs",
|
||||||
|
showExhausted: "Show Exhausted Models",
|
||||||
|
showExhaustedDesc: "Display models even if they have 0% remaining quota.",
|
||||||
|
compactMode: "Compact Mode",
|
||||||
|
compactModeDesc: "Reduce padding in tables for higher information density.",
|
||||||
|
saveChanges: "Save Changes",
|
||||||
|
autoScroll: "Auto-scroll",
|
||||||
|
clearLogs: "Clear Logs",
|
||||||
|
accountManagement: "Account Management",
|
||||||
|
manageTokens: "Manage Google Account tokens and authorization states",
|
||||||
|
addAccount: "Add Account",
|
||||||
|
status: "STATUS",
|
||||||
|
enabled: "ENABLED",
|
||||||
|
health: "STATUS",
|
||||||
|
accountEmail: "ACCOUNT (EMAIL)",
|
||||||
|
source: "SOURCE",
|
||||||
|
projectId: "PROJECT ID",
|
||||||
|
sessionState: "SESSION STATE",
|
||||||
|
operations: "OPERATIONS",
|
||||||
|
delete: "Delete",
|
||||||
|
fix: "Fix",
|
||||||
|
confirmDelete: "Are you sure you want to remove this account?",
|
||||||
|
cannotDeleteDatabase: "Cannot delete: This account is from Antigravity database (read-only)",
|
||||||
|
connectGoogle: "Connect Google Account",
|
||||||
|
reauthenticated: "re-authenticated",
|
||||||
|
added: "added",
|
||||||
|
successfully: "successfully",
|
||||||
|
accountAddedSuccess: "Account added successfully",
|
||||||
|
accountReauthSuccess: "Account re-authenticated successfully",
|
||||||
|
failedToGetAuthUrl: "Failed to get auth URL",
|
||||||
|
failedToStartOAuth: "Failed to start OAuth flow",
|
||||||
|
oauthInProgress: "OAuth in progress. Please complete authentication in the popup window...",
|
||||||
|
family: "Family",
|
||||||
|
model: "Model",
|
||||||
|
activeSuffix: "Active",
|
||||||
|
// Tabs
|
||||||
|
tabInterface: "Interface",
|
||||||
|
tabClaude: "Claude CLI",
|
||||||
|
tabModels: "Models",
|
||||||
|
tabServer: "Server Settings",
|
||||||
|
// Dashboard
|
||||||
|
linkedAccounts: "Linked Accounts",
|
||||||
|
noSignal: "NO SIGNAL DETECTED",
|
||||||
|
establishingUplink: "ESTABLISHING UPLINK...",
|
||||||
|
goToAccounts: "Go to Accounts",
|
||||||
|
// Settings - Models
|
||||||
|
modelsDesc: "Configure model visibility, pinning, and request routing.",
|
||||||
|
modelsPageDesc: "Real-time quota and status for all available models.",
|
||||||
|
showHidden: "Show Hidden Models",
|
||||||
|
hideHidden: "Hide Hidden Models",
|
||||||
|
hiddenOn: "Hidden: ON",
|
||||||
|
hiddenOff: "Hidden: OFF",
|
||||||
|
modelId: "Model ID",
|
||||||
|
actions: "Actions",
|
||||||
|
pinToTop: "Pin to top",
|
||||||
|
toggleVisibility: "Toggle Visibility",
|
||||||
|
noModels: "NO MODELS DETECTED",
|
||||||
|
modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.",
|
||||||
|
modelMapping: "Mapping (Target Model ID)",
|
||||||
|
// Settings - Claude
|
||||||
|
proxyConnection: "Proxy Connection",
|
||||||
|
modelSelection: "Model Selection",
|
||||||
|
defaultModelAliases: "DEFAULT MODEL ALIASES",
|
||||||
|
opusAlias: "Opus Alias",
|
||||||
|
sonnetAlias: "Sonnet Alias",
|
||||||
|
haikuAlias: "Haiku Alias",
|
||||||
|
claudeSettingsAlertPrefix: "Settings below directly modify",
|
||||||
|
claudeSettingsAlertSuffix: "Restart Claude CLI to apply.",
|
||||||
|
applyToClaude: "Apply to Claude CLI",
|
||||||
|
// Presets
|
||||||
|
configPresets: "Configuration Presets",
|
||||||
|
saveAsPreset: "Save as Preset",
|
||||||
|
deletePreset: "Delete Preset",
|
||||||
|
loadPreset: "Load preset into form",
|
||||||
|
load: "Load",
|
||||||
|
presetHint: "Select a preset to load it. Click \"Apply to Claude CLI\" to save changes.",
|
||||||
|
presetLoaded: "Preset loaded. Click \"Apply to Claude CLI\" to save.",
|
||||||
|
presetSaved: "Preset saved",
|
||||||
|
presetDeleted: "Preset deleted",
|
||||||
|
unsavedChangesTitle: "Unsaved Changes",
|
||||||
|
unsavedChangesMessage: "Your current configuration doesn't match any saved preset. If you switch, your current unsaved settings will be lost.",
|
||||||
|
loadAnyway: "Load Anyway",
|
||||||
|
savePresetTitle: "Save Preset",
|
||||||
|
savePresetDesc: "Save the current configuration as a reusable preset.",
|
||||||
|
presetName: "Preset Name",
|
||||||
|
presetNamePlaceholder: "e.g., My Work Setup",
|
||||||
|
savePreset: "Save Preset",
|
||||||
|
// Settings - Server
|
||||||
|
port: "Port",
|
||||||
|
uiVersion: "UI Version",
|
||||||
|
debugMode: "Debug Mode",
|
||||||
|
environment: "Environment",
|
||||||
|
serverReadOnly: "Settings managed via config.json. Restart server to apply changes.",
|
||||||
|
advancedSettings: "Advanced Settings",
|
||||||
|
reloadConfigTitle: "Reload Account Config",
|
||||||
|
reloadConfigDesc: "Force reload accounts.json from disk",
|
||||||
|
reload: "Reload",
|
||||||
|
// Config Specific
|
||||||
|
primaryModel: "Primary Model",
|
||||||
|
subAgentModel: "Sub-agent Model",
|
||||||
|
advancedOverrides: "Default Model Overrides",
|
||||||
|
opusModel: "Opus Model",
|
||||||
|
sonnetModel: "Sonnet Model",
|
||||||
|
haikuModel: "Haiku Model",
|
||||||
|
authToken: "Auth Token",
|
||||||
|
saveConfig: "Save to Claude CLI settings",
|
||||||
|
envVar: "Env",
|
||||||
|
// New Keys
|
||||||
|
systemName: "ANTIGRAVITY",
|
||||||
|
systemDesc: "CLAUDE PROXY SYSTEM",
|
||||||
|
connectGoogleDesc: "Connect a Google Workspace account to increase your API quota limit. The account will be used to proxy Claude requests via Antigravity.",
|
||||||
|
useCliCommand: "Use CLI Command",
|
||||||
|
close: "Close",
|
||||||
|
requestVolume: "Request Volume",
|
||||||
|
filter: "Filter",
|
||||||
|
all: "All",
|
||||||
|
none: "None",
|
||||||
|
noDataTracked: "No data tracked yet",
|
||||||
|
selectFamilies: "Select families to display",
|
||||||
|
selectModels: "Select models to display",
|
||||||
|
noLogsMatch: "No logs match filter",
|
||||||
|
connecting: "CONNECTING",
|
||||||
|
main: "Main",
|
||||||
|
system: "System",
|
||||||
|
refreshData: "Refresh Data",
|
||||||
|
connectionLost: "Connection Lost",
|
||||||
|
lastUpdated: "Last Updated",
|
||||||
|
grepLogs: "grep logs...",
|
||||||
|
noMatchingModels: "No matching models",
|
||||||
|
typeToSearch: "Type to search or select...",
|
||||||
|
or: "OR",
|
||||||
|
refreshingAccount: "Refreshing {email}...",
|
||||||
|
refreshedAccount: "Refreshed {email}",
|
||||||
|
refreshFailed: "Refresh failed",
|
||||||
|
accountToggled: "Account {email} {status}",
|
||||||
|
toggleFailed: "Toggle failed",
|
||||||
|
reauthenticating: "Re-authenticating {email}...",
|
||||||
|
authUrlFailed: "Failed to get auth URL",
|
||||||
|
deletedAccount: "Deleted {email}",
|
||||||
|
deleteFailed: "Delete failed",
|
||||||
|
accountsReloaded: "Accounts reloaded",
|
||||||
|
reloadFailed: "Reload failed",
|
||||||
|
claudeConfigSaved: "Claude configuration saved",
|
||||||
|
claudeConfigRestored: "Claude CLI restored to defaults",
|
||||||
|
saveConfigFailed: "Failed to save configuration",
|
||||||
|
restoreConfigFailed: "Failed to restore configuration",
|
||||||
|
restoreDefault: "Restore Default",
|
||||||
|
confirmRestoreTitle: "Confirm Restore",
|
||||||
|
confirmRestoreMessage: "Are you sure you want to restore Claude CLI to default settings? This will remove proxy configuration.",
|
||||||
|
confirmRestore: "Confirm Restore",
|
||||||
|
claudeActive: "Claude Active",
|
||||||
|
claudeEmpty: "Claude Empty",
|
||||||
|
geminiActive: "Gemini Active",
|
||||||
|
geminiEmpty: "Gemini Empty",
|
||||||
|
synced: "SYNCED",
|
||||||
|
syncing: "SYNCING...",
|
||||||
|
// Time range labels
|
||||||
|
last1Hour: "Last 1H",
|
||||||
|
last6Hours: "Last 6H",
|
||||||
|
last24Hours: "Last 24H",
|
||||||
|
last7Days: "Last 7D",
|
||||||
|
allTime: "All Time",
|
||||||
|
groupBy: "Group By",
|
||||||
|
// Additional
|
||||||
|
reloading: "Reloading...",
|
||||||
|
reloaded: "Reloaded",
|
||||||
|
lines: "lines",
|
||||||
|
enabledSeeLogs: "Enabled (See Logs)",
|
||||||
|
production: "Production",
|
||||||
|
configSaved: "Configuration Saved",
|
||||||
|
enterPassword: "Enter Web UI Password:",
|
||||||
|
ready: "READY",
|
||||||
|
depleted: "Depleted",
|
||||||
|
timeH: "H",
|
||||||
|
timeM: "M",
|
||||||
|
familyClaude: "Claude",
|
||||||
|
familyGemini: "Gemini",
|
||||||
|
familyOther: "Other",
|
||||||
|
enabledStatus: "enabled",
|
||||||
|
disabledStatus: "disabled",
|
||||||
|
logLevelInfo: "INFO",
|
||||||
|
logLevelSuccess: "SUCCESS",
|
||||||
|
logLevelWarn: "WARN",
|
||||||
|
logLevelError: "ERR",
|
||||||
|
totalColon: "Total:",
|
||||||
|
todayColon: "Today:",
|
||||||
|
hour1Colon: "1H:",
|
||||||
|
frequentModels: "Frequent",
|
||||||
|
smartTitle: "Auto-select top 5 most used models (24h)",
|
||||||
|
activeCount: "{count} Active",
|
||||||
|
allCaps: "ALL",
|
||||||
|
claudeCaps: "CLAUDE",
|
||||||
|
geminiCaps: "GEMINI",
|
||||||
|
modelMapping: "Mapping (Target Model ID)",
|
||||||
|
systemInfo: "System Information",
|
||||||
|
refresh: "Refresh",
|
||||||
|
runtimeConfig: "Runtime Configuration",
|
||||||
|
debugDesc: "Enable detailed logging (See Logs tab)",
|
||||||
|
networkRetry: "Network Retry Settings",
|
||||||
|
maxRetries: "Max Retries",
|
||||||
|
retryBaseDelay: "Retry Base Delay (ms)",
|
||||||
|
retryMaxDelay: "Retry Max Delay (ms)",
|
||||||
|
persistentSessions: "Persistent Sessions",
|
||||||
|
persistTokenDesc: "Save OAuth sessions to disk for faster restarts",
|
||||||
|
rateLimiting: "Account Rate Limiting & Timeouts",
|
||||||
|
defaultCooldown: "Default Cooldown",
|
||||||
|
defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.",
|
||||||
|
maxWaitThreshold: "Max Wait Before Error",
|
||||||
|
maxWaitDesc: "If all accounts are rate-limited longer than this, error immediately instead of waiting.",
|
||||||
|
saveConfigServer: "Save Configuration",
|
||||||
|
serverRestartAlert: "Changes saved to {path}. Restart server to apply some settings.",
|
||||||
|
changePassword: "Change WebUI Password",
|
||||||
|
changePasswordDesc: "Update the password for accessing this dashboard",
|
||||||
|
currentPassword: "Current Password",
|
||||||
|
newPassword: "New Password",
|
||||||
|
confirmNewPassword: "Confirm New Password",
|
||||||
|
passwordEmptyDesc: "Leave empty if no password set",
|
||||||
|
passwordLengthDesc: "At least 6 characters",
|
||||||
|
passwordConfirmDesc: "Re-enter new password",
|
||||||
|
cancel: "Cancel",
|
||||||
|
passwordsNotMatch: "Passwords do not match",
|
||||||
|
passwordTooShort: "Password must be at least 6 characters",
|
||||||
|
// Dashboard drill-down
|
||||||
|
clickToViewAllAccounts: "Click to view all accounts",
|
||||||
|
clickToViewModels: "Click to view Models page",
|
||||||
|
clickToViewLimitedAccounts: "Click to view rate-limited accounts",
|
||||||
|
clickToFilterClaude: "Click to filter Claude models",
|
||||||
|
clickToFilterGemini: "Click to filter Gemini models",
|
||||||
|
// Accounts page
|
||||||
|
searchAccounts: "Search accounts...",
|
||||||
|
noAccountsYet: "No Accounts Yet",
|
||||||
|
noAccountsDesc: "Get started by adding a Google account via OAuth, or use the CLI command to import credentials.",
|
||||||
|
addFirstAccount: "Add Your First Account",
|
||||||
|
noSearchResults: "No accounts match your search",
|
||||||
|
clearSearch: "Clear Search",
|
||||||
|
disabledAccountsNote: "<strong>Disabled accounts</strong> will not be used for request routing but remain in the configuration. Dashboard statistics only include enabled accounts.",
|
||||||
|
dangerousOperation: "⚠️ Dangerous Operation",
|
||||||
|
confirmDeletePrompt: "Are you sure you want to delete account",
|
||||||
|
deleteWarning: "⚠️ This action cannot be undone. All configuration and historical records will be permanently deleted.",
|
||||||
|
// OAuth progress
|
||||||
|
oauthWaiting: "Waiting for OAuth authorization...",
|
||||||
|
oauthWaitingDesc: "Please complete the authentication in the popup window. This may take up to 2 minutes.",
|
||||||
|
oauthCancelled: "OAuth authorization cancelled",
|
||||||
|
oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.",
|
||||||
|
oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.",
|
||||||
|
cancelOAuth: "Cancel",
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "Experimental MCP CLI",
|
||||||
|
mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.",
|
||||||
|
gemini1mMode: "Gemini 1M Context Mode",
|
||||||
|
gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.",
|
||||||
|
gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.",
|
||||||
|
clickToSet: "Click to configure...",
|
||||||
|
none: "None",
|
||||||
|
// Quota Distribution
|
||||||
|
quotaDistribution: "Quota Distribution",
|
||||||
|
resetsIn: "Resets in {time}",
|
||||||
|
noQuotaData: "No quota data available for this account yet.",
|
||||||
|
// UI Elements
|
||||||
|
pageTitle: "Antigravity Console",
|
||||||
|
live: "Live",
|
||||||
|
tier: "Tier",
|
||||||
|
quota: "Quota",
|
||||||
|
tierUltra: "Ultra",
|
||||||
|
tierPro: "Pro",
|
||||||
|
tierFree: "Free",
|
||||||
|
menu: "Menu",
|
||||||
|
github: "GitHub",
|
||||||
|
noData: "No data",
|
||||||
|
// Error Messages
|
||||||
|
operationFailed: "Operation failed",
|
||||||
|
unknownError: "Unknown error",
|
||||||
|
presetNameRequired: "Preset name is required",
|
||||||
|
saveFailed: "Save failed",
|
||||||
|
failedToSavePreset: "Failed to save preset",
|
||||||
|
noPresetSelected: "No preset selected",
|
||||||
|
deletePresetConfirm: "Delete preset \"{name}\"?",
|
||||||
|
failedToDeletePreset: "Failed to delete preset",
|
||||||
|
failedToChangePassword: "Failed to change password",
|
||||||
|
passwordChangedSuccess: "Password changed successfully",
|
||||||
|
debugModeToggled: "Debug mode {status}",
|
||||||
|
tokenCacheToggled: "Token cache {status}",
|
||||||
|
failedToUpdateTokenCache: "Failed to update token cache",
|
||||||
|
failedToUpdateDebugMode: "Failed to update debug mode",
|
||||||
|
failedToRefreshAccount: "Failed to refresh account",
|
||||||
|
failedToDeleteAccount: "Failed to delete account",
|
||||||
|
failedToReloadAccounts: "Failed to reload accounts",
|
||||||
|
failedToUpdateModelConfig: "Failed to update model config",
|
||||||
|
fieldUpdated: "{displayName} updated to {value}",
|
||||||
|
failedToUpdateField: "Failed to update {displayName}",
|
||||||
|
// Validation Messages
|
||||||
|
mustBeValidNumber: "{fieldName} must be a valid number",
|
||||||
|
mustBeAtLeast: "{fieldName} must be at least {min}",
|
||||||
|
mustBeAtMost: "{fieldName} must be at most {max}",
|
||||||
|
cannotBeEmpty: "{fieldName} cannot be empty",
|
||||||
|
mustBeTrueOrFalse: "Value must be true or false",
|
||||||
|
};
|
||||||
371
public/js/translations/id.js
Normal file
371
public/js/translations/id.js
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
/**
|
||||||
|
* Indonesian (Bahasa Indonesia) Translations
|
||||||
|
*
|
||||||
|
* Panduan Terminologi IT:
|
||||||
|
* - Istilah teknis umum tetap dalam bahasa Inggris (OAuth, API, token, proxy, debug, cache, dll.)
|
||||||
|
* - Istilah UI umum diterjemahkan (Simpan, Hapus, Batal, dll.)
|
||||||
|
* - Pesan error dan status menggunakan campuran yang konsisten
|
||||||
|
*/
|
||||||
|
window.translations = window.translations || {};
|
||||||
|
window.translations.id = {
|
||||||
|
// Navigation
|
||||||
|
dashboard: "Dashboard",
|
||||||
|
models: "Model",
|
||||||
|
accounts: "Akun",
|
||||||
|
logs: "Log",
|
||||||
|
settings: "Pengaturan",
|
||||||
|
|
||||||
|
// Status
|
||||||
|
online: "ONLINE",
|
||||||
|
offline: "OFFLINE",
|
||||||
|
totalAccounts: "TOTAL AKUN",
|
||||||
|
active: "AKTIF",
|
||||||
|
operational: "Berjalan Normal",
|
||||||
|
rateLimited: "DIBATASI",
|
||||||
|
quotasDepleted: "{count}/{total} Kuota Habis",
|
||||||
|
quotasDepletedTitle: "KUOTA HABIS",
|
||||||
|
outOfTracked: "Dari {total} Terpantau",
|
||||||
|
cooldown: "Cooldown",
|
||||||
|
|
||||||
|
// Search & Filters
|
||||||
|
searchPlaceholder: "Cari model...",
|
||||||
|
allAccounts: "Semua Akun",
|
||||||
|
stat: "STATUS",
|
||||||
|
modelIdentity: "IDENTITAS MODEL",
|
||||||
|
globalQuota: "KUOTA GLOBAL",
|
||||||
|
nextReset: "RESET BERIKUTNYA",
|
||||||
|
distribution: "DISTRIBUSI AKUN",
|
||||||
|
|
||||||
|
// System Configuration
|
||||||
|
systemConfig: "Konfigurasi Sistem",
|
||||||
|
language: "Bahasa",
|
||||||
|
pollingInterval: "Interval Polling",
|
||||||
|
maxDisplayLogs: "Maks. Log Ditampilkan",
|
||||||
|
showExhausted: "Tampilkan Model Habis",
|
||||||
|
showExhaustedDesc: "Tampilkan model meskipun kuotanya sudah 0%.",
|
||||||
|
compactMode: "Mode Ringkas",
|
||||||
|
compactModeDesc: "Tampilan tabel lebih padat untuk informasi lebih banyak.",
|
||||||
|
saveChanges: "Simpan Perubahan",
|
||||||
|
|
||||||
|
// Logs
|
||||||
|
autoScroll: "Auto-scroll",
|
||||||
|
clearLogs: "Hapus Log",
|
||||||
|
|
||||||
|
// Account Management
|
||||||
|
accountManagement: "Kelola Akun",
|
||||||
|
manageTokens: "Kelola token akun Google dan status otorisasi",
|
||||||
|
addAccount: "Tambah Akun",
|
||||||
|
status: "STATUS",
|
||||||
|
enabled: "AKTIF",
|
||||||
|
health: "STATUS",
|
||||||
|
accountEmail: "AKUN (EMAIL)",
|
||||||
|
source: "SUMBER",
|
||||||
|
projectId: "PROJECT ID",
|
||||||
|
sessionState: "STATUS SESI",
|
||||||
|
operations: "AKSI",
|
||||||
|
delete: "Hapus",
|
||||||
|
confirmDelete: "Yakin ingin menghapus akun ini?",
|
||||||
|
cannotDeleteDatabase: "Tidak bisa dihapus: Akun ini dari database Antigravity (read-only)",
|
||||||
|
connectGoogle: "Hubungkan Akun Google",
|
||||||
|
reauthenticated: "diautentikasi ulang",
|
||||||
|
added: "ditambahkan",
|
||||||
|
successfully: "berhasil",
|
||||||
|
accountAddedSuccess: "Akun berhasil ditambahkan",
|
||||||
|
accountReauthSuccess: "Akun berhasil diautentikasi ulang",
|
||||||
|
failedToGetAuthUrl: "Gagal mendapatkan URL autentikasi",
|
||||||
|
failedToStartOAuth: "Gagal memulai proses OAuth",
|
||||||
|
oauthInProgress: "Proses OAuth sedang berjalan. Silakan selesaikan autentikasi di jendela popup...",
|
||||||
|
family: "Jenis",
|
||||||
|
model: "Model",
|
||||||
|
activeSuffix: "Aktif",
|
||||||
|
manualReload: "Muat Ulang Konfigurasi",
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
tabInterface: "Tampilan",
|
||||||
|
tabClaude: "Claude CLI",
|
||||||
|
tabModels: "Model",
|
||||||
|
tabServer: "Server",
|
||||||
|
|
||||||
|
// Dashboard
|
||||||
|
linkedAccounts: "Akun Terhubung",
|
||||||
|
noSignal: "TIDAK ADA SINYAL",
|
||||||
|
establishingUplink: "MENGHUBUNGKAN...",
|
||||||
|
goToAccounts: "Lihat Akun",
|
||||||
|
|
||||||
|
// Settings - Models
|
||||||
|
modelsDesc: "Atur visibilitas model, pin, dan routing request.",
|
||||||
|
modelsPageDesc: "Kuota dan status real-time untuk semua model yang tersedia.",
|
||||||
|
showHidden: "Tampilkan Model Tersembunyi",
|
||||||
|
hideHidden: "Sembunyikan Model Tersembunyi",
|
||||||
|
hiddenOn: "Tersembunyi: YA",
|
||||||
|
hiddenOff: "Tersembunyi: TIDAK",
|
||||||
|
modelId: "ID Model",
|
||||||
|
actions: "Aksi",
|
||||||
|
pinToTop: "Pin ke atas",
|
||||||
|
toggleVisibility: "Tampilkan/Sembunyikan",
|
||||||
|
noModels: "MODEL TIDAK DITEMUKAN",
|
||||||
|
modelMappingHint: "Routing model di sisi server. Pengguna Claude Code: lihat tab 'Claude CLI' untuk pengaturan di sisi klien.",
|
||||||
|
modelMapping: "Mapping (Target Model ID)",
|
||||||
|
|
||||||
|
// Settings - Claude
|
||||||
|
proxyConnection: "Koneksi Proxy",
|
||||||
|
modelSelection: "Pilihan Model",
|
||||||
|
defaultModelAliases: "ALIAS MODEL DEFAULT",
|
||||||
|
opusAlias: "Alias Opus",
|
||||||
|
sonnetAlias: "Alias Sonnet",
|
||||||
|
haikuAlias: "Alias Haiku",
|
||||||
|
claudeSettingsAlertPrefix: "Pengaturan di bawah langsung mengubah",
|
||||||
|
claudeSettingsAlertSuffix: "Restart Claude CLI untuk menerapkan.",
|
||||||
|
applyToClaude: "Simpan ke Claude CLI",
|
||||||
|
|
||||||
|
// Presets
|
||||||
|
configPresets: "Preset Konfigurasi",
|
||||||
|
saveAsPreset: "Simpan sebagai Preset",
|
||||||
|
deletePreset: "Hapus Preset",
|
||||||
|
loadPreset: "Muat preset",
|
||||||
|
load: "Muat",
|
||||||
|
presetHint: "Pilih preset untuk dimuat. Klik \"Simpan ke Claude CLI\" untuk menyimpan.",
|
||||||
|
presetLoaded: "Preset dimuat. Klik \"Simpan ke Claude CLI\" untuk menyimpan.",
|
||||||
|
presetSaved: "Preset tersimpan",
|
||||||
|
presetDeleted: "Preset terhapus",
|
||||||
|
unsavedChangesTitle: "Ada Perubahan Belum Disimpan",
|
||||||
|
unsavedChangesMessage: "Konfigurasi saat ini tidak cocok dengan preset tersimpan. Jika beralih, perubahan akan hilang.",
|
||||||
|
loadAnyway: "Tetap Muat",
|
||||||
|
savePresetTitle: "Simpan Preset",
|
||||||
|
savePresetDesc: "Simpan konfigurasi saat ini sebagai preset.",
|
||||||
|
presetName: "Nama Preset",
|
||||||
|
presetNamePlaceholder: "contoh: Setup Kantor",
|
||||||
|
savePreset: "Simpan Preset",
|
||||||
|
|
||||||
|
// Settings - Server
|
||||||
|
port: "Port",
|
||||||
|
uiVersion: "Versi UI",
|
||||||
|
debugMode: "Mode Debug",
|
||||||
|
environment: "Environment",
|
||||||
|
serverReadOnly: "Pengaturan dikelola melalui config.json. Restart server untuk menerapkan.",
|
||||||
|
advancedSettings: "Pengaturan Lanjutan",
|
||||||
|
reloadConfigTitle: "Muat Ulang Konfigurasi Akun",
|
||||||
|
reloadConfigDesc: "Paksa muat ulang accounts.json dari disk",
|
||||||
|
reload: "Muat Ulang",
|
||||||
|
|
||||||
|
// Config Specific
|
||||||
|
primaryModel: "Model Utama",
|
||||||
|
subAgentModel: "Model Sub-agent",
|
||||||
|
advancedOverrides: "Timpa Model Default",
|
||||||
|
opusModel: "Model Opus",
|
||||||
|
sonnetModel: "Model Sonnet",
|
||||||
|
haikuModel: "Model Haiku",
|
||||||
|
authToken: "Token Auth",
|
||||||
|
saveConfig: "Simpan ke Claude CLI",
|
||||||
|
envVar: "Env",
|
||||||
|
|
||||||
|
// System
|
||||||
|
systemName: "ANTIGRAVITY",
|
||||||
|
systemDesc: "CLAUDE PROXY SYSTEM",
|
||||||
|
connectGoogleDesc: "Hubungkan akun Google Workspace untuk meningkatkan kuota API. Akun akan digunakan untuk meneruskan request Claude via Antigravity.",
|
||||||
|
useCliCommand: "Gunakan Perintah CLI",
|
||||||
|
close: "Tutup",
|
||||||
|
requestVolume: "Volume Request",
|
||||||
|
filter: "Filter",
|
||||||
|
all: "Semua",
|
||||||
|
none: "Tidak Ada",
|
||||||
|
noDataTracked: "Belum ada data tercatat",
|
||||||
|
selectFamilies: "Pilih jenis model untuk ditampilkan",
|
||||||
|
selectModels: "Pilih model untuk ditampilkan",
|
||||||
|
noLogsMatch: "Tidak ada log yang sesuai filter",
|
||||||
|
connecting: "MENGHUBUNGKAN",
|
||||||
|
main: "Utama",
|
||||||
|
system: "Sistem",
|
||||||
|
refreshData: "Refresh Data",
|
||||||
|
connectionLost: "Koneksi Terputus",
|
||||||
|
lastUpdated: "Terakhir Diperbarui",
|
||||||
|
grepLogs: "cari log...",
|
||||||
|
noMatchingModels: "Tidak ada model yang cocok",
|
||||||
|
typeToSearch: "Ketik untuk mencari...",
|
||||||
|
or: "ATAU",
|
||||||
|
|
||||||
|
// Account Operations
|
||||||
|
refreshingAccount: "Memperbarui {email}...",
|
||||||
|
refreshedAccount: "{email} berhasil diperbarui",
|
||||||
|
refreshFailed: "Gagal memperbarui",
|
||||||
|
accountToggled: "Akun {email} {status}",
|
||||||
|
toggleFailed: "Gagal mengubah status",
|
||||||
|
reauthenticating: "Autentikasi ulang {email}...",
|
||||||
|
authUrlFailed: "Gagal mendapatkan URL autentikasi",
|
||||||
|
deletedAccount: "{email} berhasil dihapus",
|
||||||
|
deleteFailed: "Gagal menghapus",
|
||||||
|
accountsReloaded: "Akun berhasil dimuat ulang",
|
||||||
|
reloadFailed: "Gagal memuat ulang",
|
||||||
|
|
||||||
|
// Claude Config
|
||||||
|
claudeConfigSaved: "Konfigurasi Claude tersimpan",
|
||||||
|
claudeConfigRestored: "Claude CLI dikembalikan ke default",
|
||||||
|
saveConfigFailed: "Gagal menyimpan konfigurasi",
|
||||||
|
restoreConfigFailed: "Gagal mengembalikan konfigurasi",
|
||||||
|
restoreDefault: "Reset ke Default",
|
||||||
|
confirmRestoreTitle: "Konfirmasi Reset",
|
||||||
|
confirmRestoreMessage: "Yakin ingin mengembalikan Claude CLI ke pengaturan default? Konfigurasi proxy akan dihapus.",
|
||||||
|
confirmRestore: "Ya, Reset",
|
||||||
|
|
||||||
|
// Status Labels
|
||||||
|
claudeActive: "Claude Aktif",
|
||||||
|
claudeEmpty: "Claude Kosong",
|
||||||
|
geminiActive: "Gemini Aktif",
|
||||||
|
geminiEmpty: "Gemini Kosong",
|
||||||
|
synced: "SINKRON",
|
||||||
|
syncing: "SINKRONISASI...",
|
||||||
|
|
||||||
|
// Time range labels
|
||||||
|
last1Hour: "1 Jam Terakhir",
|
||||||
|
last6Hours: "6 Jam Terakhir",
|
||||||
|
last24Hours: "24 Jam Terakhir",
|
||||||
|
last7Days: "7 Hari Terakhir",
|
||||||
|
allTime: "Semua Waktu",
|
||||||
|
groupBy: "Kelompokkan",
|
||||||
|
|
||||||
|
// Additional
|
||||||
|
reloading: "Memuat ulang...",
|
||||||
|
reloaded: "Dimuat ulang",
|
||||||
|
lines: "baris",
|
||||||
|
enabledSeeLogs: "Aktif (Lihat Log)",
|
||||||
|
production: "Produksi",
|
||||||
|
configSaved: "Konfigurasi Tersimpan",
|
||||||
|
enterPassword: "Masukkan Password Web UI:",
|
||||||
|
ready: "SIAP",
|
||||||
|
depleted: "Habis",
|
||||||
|
timeH: "j",
|
||||||
|
timeM: "m",
|
||||||
|
familyClaude: "Claude",
|
||||||
|
familyGemini: "Gemini",
|
||||||
|
familyOther: "Lainnya",
|
||||||
|
enabledStatus: "diaktifkan",
|
||||||
|
disabledStatus: "dinonaktifkan",
|
||||||
|
logLevelInfo: "INFO",
|
||||||
|
logLevelSuccess: "OK",
|
||||||
|
logLevelWarn: "WARN",
|
||||||
|
logLevelError: "ERROR",
|
||||||
|
totalColon: "Total:",
|
||||||
|
todayColon: "Hari Ini:",
|
||||||
|
hour1Colon: "1j:",
|
||||||
|
frequentModels: "Sering Dipakai",
|
||||||
|
smartTitle: "Otomatis pilih 5 model paling sering dipakai (24 jam)",
|
||||||
|
activeCount: "{count} Aktif",
|
||||||
|
allCaps: "SEMUA",
|
||||||
|
claudeCaps: "CLAUDE",
|
||||||
|
geminiCaps: "GEMINI",
|
||||||
|
|
||||||
|
// System Info
|
||||||
|
systemInfo: "Informasi Sistem",
|
||||||
|
refresh: "Refresh",
|
||||||
|
runtimeConfig: "Konfigurasi Runtime",
|
||||||
|
debugDesc: "Aktifkan log detail (Lihat tab Log)",
|
||||||
|
networkRetry: "Pengaturan Retry Jaringan",
|
||||||
|
maxRetries: "Maks. Retry",
|
||||||
|
retryBaseDelay: "Jeda Awal Retry (ms)",
|
||||||
|
retryMaxDelay: "Jeda Maks. Retry (ms)",
|
||||||
|
persistentSessions: "Sesi Persisten",
|
||||||
|
persistTokenDesc: "Simpan sesi OAuth ke disk agar startup lebih cepat",
|
||||||
|
rateLimiting: "Rate Limiting & Timeout Akun",
|
||||||
|
defaultCooldown: "Cooldown Default",
|
||||||
|
defaultCooldownDesc: "Cooldown bawaan jika API tidak memberikan waktu reset.",
|
||||||
|
maxWaitThreshold: "Batas Tunggu Maksimal",
|
||||||
|
maxWaitDesc: "Jika semua akun terkena rate limit lebih lama dari ini, langsung gagal.",
|
||||||
|
saveConfigServer: "Simpan Konfigurasi",
|
||||||
|
serverRestartAlert: "Tersimpan ke {path}. Restart server untuk menerapkan.",
|
||||||
|
|
||||||
|
// Password
|
||||||
|
changePassword: "Ubah Password WebUI",
|
||||||
|
changePasswordDesc: "Ubah password untuk akses dashboard ini",
|
||||||
|
currentPassword: "Password Saat Ini",
|
||||||
|
newPassword: "Password Baru",
|
||||||
|
confirmNewPassword: "Konfirmasi Password Baru",
|
||||||
|
passwordEmptyDesc: "Kosongkan jika belum ada password",
|
||||||
|
passwordLengthDesc: "Minimal 6 karakter",
|
||||||
|
passwordConfirmDesc: "Masukkan ulang password baru",
|
||||||
|
cancel: "Batal",
|
||||||
|
passwordsNotMatch: "Password tidak cocok",
|
||||||
|
passwordTooShort: "Password minimal 6 karakter",
|
||||||
|
|
||||||
|
// Dashboard drill-down
|
||||||
|
clickToViewAllAccounts: "Klik untuk lihat semua akun",
|
||||||
|
clickToViewModels: "Klik untuk lihat halaman Model",
|
||||||
|
clickToViewLimitedAccounts: "Klik untuk lihat akun yang dibatasi",
|
||||||
|
clickToFilterClaude: "Klik untuk filter model Claude",
|
||||||
|
clickToFilterGemini: "Klik untuk filter model Gemini",
|
||||||
|
|
||||||
|
// Accounts page
|
||||||
|
searchAccounts: "Cari akun...",
|
||||||
|
noAccountsYet: "Belum Ada Akun",
|
||||||
|
noAccountsDesc: "Mulai dengan menambahkan akun Google via OAuth, atau gunakan perintah CLI untuk import kredensial.",
|
||||||
|
addFirstAccount: "Tambah Akun Pertama",
|
||||||
|
noSearchResults: "Tidak ada akun yang cocok",
|
||||||
|
clearSearch: "Reset Pencarian",
|
||||||
|
disabledAccountsNote: "<strong>Akun nonaktif</strong> tidak akan digunakan untuk routing tapi tetap tersimpan di konfigurasi. Statistik dashboard hanya mencakup akun aktif.",
|
||||||
|
dangerousOperation: "⚠️ Operasi Berbahaya",
|
||||||
|
confirmDeletePrompt: "Yakin ingin menghapus akun",
|
||||||
|
deleteWarning: "⚠️ Tindakan ini tidak bisa dibatalkan. Semua pengaturan dan riwayat akan dihapus permanen.",
|
||||||
|
|
||||||
|
// OAuth progress
|
||||||
|
oauthWaiting: "Menunggu otorisasi OAuth...",
|
||||||
|
oauthWaitingDesc: "Silakan selesaikan autentikasi di jendela popup. Proses ini bisa memakan waktu hingga 2 menit.",
|
||||||
|
oauthCancelled: "Otorisasi OAuth dibatalkan",
|
||||||
|
oauthTimeout: "⏱️ Waktu otorisasi OAuth habis. Silakan coba lagi.",
|
||||||
|
oauthWindowClosed: "Jendela OAuth ditutup. Otorisasi mungkin tidak lengkap.",
|
||||||
|
cancelOAuth: "Batal",
|
||||||
|
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "MCP CLI (Eksperimental)",
|
||||||
|
mcpCliDesc: "Aktifkan integrasi MCP eksperimental untuk penggunaan tool yang lebih stabil dengan konsumsi konteks lebih rendah.",
|
||||||
|
gemini1mMode: "Mode Konteks Gemini 1M",
|
||||||
|
gemini1mDesc: "Tambahkan suffix [1m] ke model Gemini untuk context window 1M.",
|
||||||
|
gemini1mWarning: "⚠ Konteks besar dapat menurunkan performa Gemini-3-Pro.",
|
||||||
|
clickToSet: "Klik untuk atur...",
|
||||||
|
|
||||||
|
// Quota Distribution
|
||||||
|
quotaDistribution: "Distribusi Kuota",
|
||||||
|
resetsIn: "Reset dalam {time}",
|
||||||
|
noQuotaData: "Data kuota belum tersedia untuk akun ini.",
|
||||||
|
|
||||||
|
// Completed TODOs
|
||||||
|
pageTitle: "Antigravity Console",
|
||||||
|
live: "Live",
|
||||||
|
tier: "Tier",
|
||||||
|
quota: "Kuota",
|
||||||
|
tierUltra: "Ultra",
|
||||||
|
tierPro: "Pro",
|
||||||
|
tierFree: "Gratis",
|
||||||
|
menu: "Menu",
|
||||||
|
github: "GitHub",
|
||||||
|
noData: "Tidak ada data",
|
||||||
|
fix: "Perbaiki",
|
||||||
|
|
||||||
|
// Error Messages
|
||||||
|
operationFailed: "Operasi gagal",
|
||||||
|
unknownError: "Error tidak diketahui",
|
||||||
|
presetNameRequired: "Nama preset wajib diisi",
|
||||||
|
saveFailed: "Gagal menyimpan",
|
||||||
|
failedToSavePreset: "Gagal menyimpan preset",
|
||||||
|
noPresetSelected: "Tidak ada preset dipilih",
|
||||||
|
deletePresetConfirm: "Hapus preset \"{name}\"?",
|
||||||
|
deleteFailed: "Gagal menghapus",
|
||||||
|
failedToDeletePreset: "Gagal menghapus preset",
|
||||||
|
failedToChangePassword: "Gagal mengubah password",
|
||||||
|
passwordChangedSuccess: "Password berhasil diubah",
|
||||||
|
debugModeToggled: "Mode debug {status}",
|
||||||
|
tokenCacheToggled: "Cache token {status}",
|
||||||
|
failedToUpdateTokenCache: "Gagal memperbarui cache token",
|
||||||
|
failedToUpdateDebugMode: "Gagal memperbarui mode debug",
|
||||||
|
failedToRefreshAccount: "Gagal memperbarui akun",
|
||||||
|
failedToDeleteAccount: "Gagal menghapus akun",
|
||||||
|
failedToReloadAccounts: "Gagal memuat ulang akun",
|
||||||
|
failedToUpdateModelConfig: "Gagal memperbarui konfigurasi model",
|
||||||
|
fieldUpdated: "{displayName} diubah menjadi {value}",
|
||||||
|
failedToUpdateField: "Gagal memperbarui {displayName}",
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
mustBeValidNumber: "{fieldName} harus berupa angka valid",
|
||||||
|
mustBeAtLeast: "{fieldName} minimal {min}",
|
||||||
|
mustBeAtMost: "{fieldName} maksimal {max}",
|
||||||
|
cannotBeEmpty: "{fieldName} tidak boleh kosong",
|
||||||
|
mustBeTrueOrFalse: "Nilai harus true atau false",
|
||||||
|
};
|
||||||
316
public/js/translations/tr.js
Normal file
316
public/js/translations/tr.js
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/**
|
||||||
|
* Turkish (Türkçe) Translations
|
||||||
|
*/
|
||||||
|
window.translations = window.translations || {};
|
||||||
|
window.translations.tr = {
|
||||||
|
dashboard: "Panel",
|
||||||
|
models: "Modeller",
|
||||||
|
accounts: "Hesaplar",
|
||||||
|
logs: "Günlükler",
|
||||||
|
settings: "Ayarlar",
|
||||||
|
online: "ÇEVRİMİÇİ",
|
||||||
|
offline: "ÇEVRİMDIŞI",
|
||||||
|
totalAccounts: "TOPLAM HESAP",
|
||||||
|
active: "AKTİF",
|
||||||
|
operational: "Çalışıyor",
|
||||||
|
rateLimited: "HIZ SINIRLANDI",
|
||||||
|
quotasDepleted: "{count}/{total} Kota Tükendi",
|
||||||
|
quotasDepletedTitle: "KOTA TÜKENDİ",
|
||||||
|
outOfTracked: "{total} Takip Edilen İçinden",
|
||||||
|
cooldown: "Soğuma",
|
||||||
|
searchPlaceholder: "Modelleri ara...",
|
||||||
|
allAccounts: "Tüm Hesaplar",
|
||||||
|
stat: "DURUM",
|
||||||
|
modelIdentity: "MODEL KİMLİĞİ",
|
||||||
|
globalQuota: "GENEL KOTA",
|
||||||
|
nextReset: "SONRAKİ SIFIRLAMA",
|
||||||
|
distribution: "HESAP DAĞILIMI",
|
||||||
|
systemConfig: "Sistem Yapılandırması",
|
||||||
|
language: "Dil",
|
||||||
|
pollingInterval: "Veri Güncelleme Aralığı",
|
||||||
|
maxDisplayLogs: "Maksimum Görüntülenen Günlük",
|
||||||
|
showExhausted: "Tükenmiş Modelleri Göster",
|
||||||
|
showExhaustedDesc: "%0 kotası kalan modelleri de göster.",
|
||||||
|
compactMode: "Kompakt Mod",
|
||||||
|
compactModeDesc: "Daha fazla bilgi göstermek için tablo boşluklarını azalt.",
|
||||||
|
saveChanges: "Değişiklikleri Kaydet",
|
||||||
|
autoScroll: "Otomatik Kaydır",
|
||||||
|
clearLogs: "Günlükleri Temizle",
|
||||||
|
accountManagement: "Hesap Yönetimi",
|
||||||
|
manageTokens: "Google Hesap jetonlarını ve yetkilendirme durumlarını yönet",
|
||||||
|
addAccount: "Hesap Ekle",
|
||||||
|
status: "DURUM",
|
||||||
|
enabled: "ETKİN",
|
||||||
|
health: "SAĞLIK",
|
||||||
|
accountEmail: "HESAP (E-POSTA)",
|
||||||
|
source: "KAYNAK",
|
||||||
|
projectId: "PROJE ID",
|
||||||
|
sessionState: "OTURUM DURUMU",
|
||||||
|
operations: "İŞLEMLER",
|
||||||
|
delete: "Sil",
|
||||||
|
confirmDelete: "Bu hesabı kaldırmak istediğinizden emin misiniz?",
|
||||||
|
cannotDeleteDatabase: "Silinemez: Bu hesap Antigravity veritabanından (salt okunur)",
|
||||||
|
connectGoogle: "Google Hesabı Bağla",
|
||||||
|
reauthenticated: "yeniden doğrulandı",
|
||||||
|
added: "eklendi",
|
||||||
|
successfully: "başarıyla",
|
||||||
|
accountAddedSuccess: "Hesap başarıyla eklendi",
|
||||||
|
accountReauthSuccess: "Hesap başarıyla yeniden doğrulandı",
|
||||||
|
failedToGetAuthUrl: "Yetkilendirme URL'si alınamadı",
|
||||||
|
failedToStartOAuth: "OAuth akışı başlatılamadı",
|
||||||
|
oauthInProgress: "OAuth devam ediyor. Lütfen açılır pencerede kimlik doğrulamayı tamamlayın...",
|
||||||
|
family: "Aile",
|
||||||
|
model: "Model",
|
||||||
|
activeSuffix: "Aktif",
|
||||||
|
manualReload: "Yapılandırmayı Yeniden Yükle",
|
||||||
|
// Tabs
|
||||||
|
tabInterface: "Arayüz",
|
||||||
|
tabClaude: "Claude CLI",
|
||||||
|
tabModels: "Modeller",
|
||||||
|
tabServer: "Sunucu Ayarları",
|
||||||
|
// Dashboard
|
||||||
|
linkedAccounts: "Bağlı Hesaplar",
|
||||||
|
noSignal: "SİNYAL YOK",
|
||||||
|
establishingUplink: "BAĞLANTI KURULUYOR...",
|
||||||
|
goToAccounts: "Hesaplara Git",
|
||||||
|
// Settings - Models
|
||||||
|
modelsDesc: "Model görünürlüğünü, sabitlemeyi ve istek yönlendirmeyi yapılandırın.",
|
||||||
|
modelsPageDesc: "Tüm mevcut modeller için gerçek zamanlı kota ve durum.",
|
||||||
|
showHidden: "Gizli Modelleri Göster",
|
||||||
|
hideHidden: "Gizli Modelleri Gizle",
|
||||||
|
hiddenOn: "Gizli: AÇIK",
|
||||||
|
hiddenOff: "Gizli: KAPALI",
|
||||||
|
modelId: "Model ID",
|
||||||
|
actions: "İşlemler",
|
||||||
|
pinToTop: "En Üste Sabitle",
|
||||||
|
toggleVisibility: "Görünürlüğü Değiştir",
|
||||||
|
noModels: "MODEL ALGILANMADI",
|
||||||
|
modelMappingHint: "Sunucu tarafı model yönlendirme. Claude Code kullanıcıları: istemci tarafı kurulumu için 'Claude CLI' sekmesine bakın.",
|
||||||
|
modelMapping: "Eşleştirme (Hedef Model ID)",
|
||||||
|
// Settings - Claude
|
||||||
|
proxyConnection: "Proxy Bağlantısı",
|
||||||
|
modelSelection: "Model Seçimi",
|
||||||
|
defaultModelAliases: "VARSAYILAN MODEL TAKMA ADLARI",
|
||||||
|
opusAlias: "Opus Takma Adı",
|
||||||
|
sonnetAlias: "Sonnet Takma Adı",
|
||||||
|
haikuAlias: "Haiku Takma Adı",
|
||||||
|
claudeSettingsAlertPrefix: "Aşağıdaki ayarlar doğrudan değiştirir",
|
||||||
|
claudeSettingsAlertSuffix: "Uygulamak için Claude CLI'yı yeniden başlatın.",
|
||||||
|
applyToClaude: "Claude CLI'ya Uygula",
|
||||||
|
// Settings - Server
|
||||||
|
port: "Port",
|
||||||
|
uiVersion: "Arayüz Sürümü",
|
||||||
|
debugMode: "Hata Ayıklama Modu",
|
||||||
|
environment: "Ortam",
|
||||||
|
serverReadOnly: "Ayarlar config.json üzerinden yönetilir. Değişiklikleri uygulamak için sunucuyu yeniden başlatın.",
|
||||||
|
advancedSettings: "Gelişmiş Ayarlar",
|
||||||
|
reloadConfigTitle: "Hesap Yapılandırmasını Yeniden Yükle",
|
||||||
|
reloadConfigDesc: "accounts.json dosyasını diskten yeniden yüklemeye zorla",
|
||||||
|
reload: "Yeniden Yükle",
|
||||||
|
// Config Specific
|
||||||
|
primaryModel: "Birincil Model",
|
||||||
|
subAgentModel: "Alt Ajan Modeli",
|
||||||
|
advancedOverrides: "Varsayılan Model Geçersiz Kılmaları",
|
||||||
|
opusModel: "Opus Modeli",
|
||||||
|
sonnetModel: "Sonnet Modeli",
|
||||||
|
haikuModel: "Haiku Modeli",
|
||||||
|
authToken: "Yetkilendirme Jetonu",
|
||||||
|
saveConfig: "Claude CLI ayarlarına kaydet",
|
||||||
|
envVar: "Ortam Değişkeni",
|
||||||
|
// New Keys
|
||||||
|
systemName: "ANTIGRAVITY",
|
||||||
|
systemDesc: "CLAUDE PROXY SİSTEMİ",
|
||||||
|
connectGoogleDesc: "API kota limitinizi artırmak için bir Google Workspace hesabı bağlayın. Bu hesap, Claude isteklerini Antigravity üzerinden vekil sunucu olarak kullanmak için kullanılacaktır.",
|
||||||
|
useCliCommand: "CLI Komutunu Kullan",
|
||||||
|
close: "Kapat",
|
||||||
|
requestVolume: "İstek Hacmi",
|
||||||
|
filter: "Filtrele",
|
||||||
|
all: "Tümü",
|
||||||
|
none: "Hiçbiri",
|
||||||
|
noDataTracked: "Henüz veri izlenmedi",
|
||||||
|
selectFamilies: "Görüntülenecek aileleri seçin",
|
||||||
|
selectModels: "Görüntülenecek modelleri seçin",
|
||||||
|
noLogsMatch: "Filtreyle eşleşen günlük yok",
|
||||||
|
connecting: "BAĞLANILIYOR",
|
||||||
|
main: "Ana",
|
||||||
|
system: "Sistem",
|
||||||
|
refreshData: "Verileri Yenile",
|
||||||
|
connectionLost: "Bağlantı Kaybedildi",
|
||||||
|
lastUpdated: "Son Güncelleme",
|
||||||
|
grepLogs: "günlükleri ara...",
|
||||||
|
noMatchingModels: "Eşleşen model yok",
|
||||||
|
typeToSearch: "Aramak veya seçmek için yazın...",
|
||||||
|
or: "VEYA",
|
||||||
|
refreshingAccount: "{email} yenileniyor...",
|
||||||
|
refreshedAccount: "{email} yenilendi",
|
||||||
|
refreshFailed: "Yenileme başarısız",
|
||||||
|
accountToggled: "Hesap {email} {status}",
|
||||||
|
toggleFailed: "Değiştirme başarısız",
|
||||||
|
reauthenticating: "{email} yeniden doğrulanıyor...",
|
||||||
|
authUrlFailed: "Yetkilendirme URL'si alınamadı",
|
||||||
|
deletedAccount: "{email} silindi",
|
||||||
|
deleteFailed: "Silme başarısız",
|
||||||
|
accountsReloaded: "Hesaplar yeniden yüklendi",
|
||||||
|
reloadFailed: "Yeniden yükleme başarısız",
|
||||||
|
claudeConfigSaved: "Claude yapılandırması kaydedildi",
|
||||||
|
claudeConfigRestored: "Claude CLI varsayılanlara geri yüklendi",
|
||||||
|
saveConfigFailed: "Yapılandırma kaydedilemedi",
|
||||||
|
restoreConfigFailed: "Yapılandırma geri yüklenemedi",
|
||||||
|
restoreDefault: "Varsayılana Dön",
|
||||||
|
confirmRestoreTitle: "Geri Yüklemeyi Onayla",
|
||||||
|
confirmRestoreMessage: "Claude CLI'yı varsayılan ayarlara geri yüklemek istediğinizden emin misiniz? Bu işlem proxy yapılandırmasını kaldıracaktır.",
|
||||||
|
confirmRestore: "Geri Yüklemeyi Onayla",
|
||||||
|
claudeActive: "Claude Aktif",
|
||||||
|
claudeEmpty: "Claude Boş",
|
||||||
|
geminiActive: "Gemini Aktif",
|
||||||
|
geminiEmpty: "Gemini Boş",
|
||||||
|
synced: "EŞİTLENDİ",
|
||||||
|
syncing: "EŞİTLENİYOR...",
|
||||||
|
// Time range labels
|
||||||
|
last1Hour: "Son 1S",
|
||||||
|
last6Hours: "Son 6S",
|
||||||
|
last24Hours: "Son 24S",
|
||||||
|
last7Days: "Son 7G",
|
||||||
|
allTime: "Tüm Zamanlar",
|
||||||
|
groupBy: "Gruplama Ölçütü",
|
||||||
|
// Additional
|
||||||
|
reloading: "Yeniden yükleniyor...",
|
||||||
|
reloaded: "Yeniden yüklendi",
|
||||||
|
lines: "satır",
|
||||||
|
enabledSeeLogs: "Etkin (Günlüklere Bak)",
|
||||||
|
production: "Üretim",
|
||||||
|
configSaved: "Yapılandırma Kaydedildi",
|
||||||
|
enterPassword: "Web UI Parolasını Girin:",
|
||||||
|
ready: "HAZIR",
|
||||||
|
depleted: "Tükendi",
|
||||||
|
timeH: "S",
|
||||||
|
timeM: "D",
|
||||||
|
familyClaude: "Claude",
|
||||||
|
familyGemini: "Gemini",
|
||||||
|
familyOther: "Diğer",
|
||||||
|
enabledStatus: "etkin",
|
||||||
|
disabledStatus: "devre dışı",
|
||||||
|
logLevelInfo: "BİLGİ",
|
||||||
|
logLevelSuccess: "BAŞARILI",
|
||||||
|
logLevelWarn: "UYARI",
|
||||||
|
logLevelError: "HATA",
|
||||||
|
totalColon: "Toplam:",
|
||||||
|
todayColon: "Bugün:",
|
||||||
|
hour1Colon: "1S:",
|
||||||
|
frequentModels: "Sık Kullanılan",
|
||||||
|
smartTitle: "En çok kullanılan 5 modeli otomatik seç (24s)",
|
||||||
|
activeCount: "{count} Aktif",
|
||||||
|
allCaps: "TÜMÜ",
|
||||||
|
claudeCaps: "CLAUDE",
|
||||||
|
geminiCaps: "GEMINI",
|
||||||
|
modelMapping: "Eşleştirme (Hedef Model ID)",
|
||||||
|
systemInfo: "Sistem Bilgisi",
|
||||||
|
refresh: "Yenile",
|
||||||
|
runtimeConfig: "Çalışma Zamanı Yapılandırması",
|
||||||
|
debugDesc: "Ayrıntılı günlük kaydını etkinleştir (Günlükler sekmesine bakın)",
|
||||||
|
networkRetry: "Ağ Yeniden Deneme Ayarları",
|
||||||
|
maxRetries: "Maksimum Deneme",
|
||||||
|
retryBaseDelay: "Yeniden Deneme Temel Gecikmesi (ms)",
|
||||||
|
retryMaxDelay: "Yeniden Deneme Maksimum Gecikmesi (ms)",
|
||||||
|
persistentSessions: "Kalıcı Oturumlar",
|
||||||
|
persistTokenDesc: "Daha hızlı yeniden başlatmalar için OAuth oturumlarını diske kaydet",
|
||||||
|
rateLimiting: "Hesap Hız Sınırlama ve Zaman Aşımları",
|
||||||
|
defaultCooldown: "Varsayılan Soğuma Süresi",
|
||||||
|
maxWaitThreshold: "Maksimum Bekleme Eşiği (Yapışkan)",
|
||||||
|
maxWaitDesc: "Yapışkan bir hesabın değiştirmeden önce sıfırlanması için beklenecek maksimum süre.",
|
||||||
|
saveConfigServer: "Yapılandırmayı Kaydet",
|
||||||
|
serverRestartAlert: "Değişiklikler {path} konumuna kaydedildi. Bazı ayarları uygulamak için sunucuyu yeniden başlatın.",
|
||||||
|
changePassword: "WebUI Parolasını Değiştir",
|
||||||
|
changePasswordDesc: "Bu panoya erişim parolasını güncelle",
|
||||||
|
currentPassword: "Mevcut Parola",
|
||||||
|
newPassword: "Yeni Parola",
|
||||||
|
confirmNewPassword: "Yeni Parolayı Onayla",
|
||||||
|
passwordEmptyDesc: "Parola ayarlanmamışsa boş bırakın",
|
||||||
|
passwordLengthDesc: "En az 6 karakter",
|
||||||
|
passwordConfirmDesc: "Yeni parolayı tekrar girin",
|
||||||
|
cancel: "İptal",
|
||||||
|
passwordsNotMatch: "Parolalar eşleşmiyor",
|
||||||
|
passwordTooShort: "Parola en az 6 karakter olmalıdır",
|
||||||
|
// Dashboard drill-down
|
||||||
|
clickToViewAllAccounts: "Tüm hesapları görüntülemek için tıklayın",
|
||||||
|
clickToViewModels: "Modeller sayfasını görüntülemek için tıklayın",
|
||||||
|
clickToViewLimitedAccounts: "Hız sınırı olan hesapları görüntülemek için tıklayın",
|
||||||
|
clickToFilterClaude: "Claude modellerini filtrelemek için tıklayın",
|
||||||
|
clickToFilterGemini: "Gemini modellerini filtrelemek için tıklayın",
|
||||||
|
// Accounts page
|
||||||
|
searchAccounts: "Hesap ara...",
|
||||||
|
noAccountsYet: "Henüz Hesap Yok",
|
||||||
|
noAccountsDesc: "OAuth üzerinden bir Google hesabı ekleyerek veya kimlik bilgilerini içe aktarmak için CLI komutunu kullanarak başlayın.",
|
||||||
|
addFirstAccount: "İlk Hesabınızı Ekleyin",
|
||||||
|
noSearchResults: "Aramanızla eşleşen hesap yok",
|
||||||
|
clearSearch: "Aramayı Temizle",
|
||||||
|
disabledAccountsNote: "<strong>Devre dışı bırakılan hesaplar</strong> istek yönlendirmesi için kullanılmayacak ancak yapılandırmada kalacaktır. Pano istatistikleri yalnızca etkin hesapları içerir.",
|
||||||
|
dangerousOperation: "⚠️ Tehlikeli İşlem",
|
||||||
|
confirmDeletePrompt: "Hesabı silmek istediğinizden emin misiniz",
|
||||||
|
deleteWarning: "⚠️ Bu işlem geri alınamaz. Tüm yapılandırma ve geçmiş kayıtları kalıcı olarak silinecektir.",
|
||||||
|
// OAuth progress
|
||||||
|
oauthWaiting: "OAuth yetkilendirmesi bekleniyor...",
|
||||||
|
oauthWaitingDesc: "Lütfen açılır pencerede kimlik doğrulamasını tamamlayın. Bu işlem 2 dakikaya kadar sürebilir.",
|
||||||
|
oauthCancelled: "OAuth yetkilendirmesi iptal edildi",
|
||||||
|
oauthTimeout: "⏱️ OAuth yetkilendirmesi zaman aşımına uğradı. Lütfen tekrar deneyin.",
|
||||||
|
oauthWindowClosed: "OAuth penceresi kapatıldı. Yetkilendirme tamamlanmamış olabilir.",
|
||||||
|
cancelOAuth: "İptal",
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "Deneysel MCP CLI",
|
||||||
|
mcpCliDesc: "Daha az bağlam tüketimi ile güvenilir araç kullanımı için deneysel MCP entegrasyonunu etkinleştirir.",
|
||||||
|
gemini1mMode: "Gemini 1M Bağlam Modu",
|
||||||
|
gemini1mDesc: "1M bağlam penceresi desteği için Gemini modellerine [1m] son eki ekler.",
|
||||||
|
gemini1mWarning: "⚠ Büyük bağlam, Gemini-3-Pro performansını düşürebilir.",
|
||||||
|
clickToSet: "Yapılandırmak için tıklayın...",
|
||||||
|
none: "Hiçbiri",
|
||||||
|
// Quota Distribution
|
||||||
|
quotaDistribution: "Kota Dağılımı",
|
||||||
|
resetsIn: "{time} içinde sıfırlanır",
|
||||||
|
noQuotaData: "Bu hesap için henüz kota verisi yok.",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Hardcoded strings from HTML
|
||||||
|
// pageTitle: "Antigravity Console",
|
||||||
|
// live: "Live",
|
||||||
|
// tier: "Tier",
|
||||||
|
// quota: "Quota",
|
||||||
|
// tierUltra: "Ultra",
|
||||||
|
// tierPro: "Pro",
|
||||||
|
// tierFree: "Free",
|
||||||
|
// menu: "Menu",
|
||||||
|
// github: "GitHub",
|
||||||
|
// noData: "No data",
|
||||||
|
// fix: "Fix",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Hardcoded strings from JS (Error Messages)
|
||||||
|
// operationFailed: "Operation failed",
|
||||||
|
// unknownError: "Unknown error",
|
||||||
|
// presetNameRequired: "Preset name is required",
|
||||||
|
// saveFailed: "Save failed",
|
||||||
|
// failedToSavePreset: "Failed to save preset",
|
||||||
|
// noPresetSelected: "No preset selected",
|
||||||
|
// deletePresetConfirm: "Delete preset \"{name}\"?",
|
||||||
|
// deleteFailed: "Delete failed",
|
||||||
|
// failedToDeletePreset: "Failed to delete preset",
|
||||||
|
// failedToChangePassword: "Failed to change password",
|
||||||
|
// passwordChangedSuccess: "Password changed successfully",
|
||||||
|
// debugModeToggled: "Debug mode {status}",
|
||||||
|
// tokenCacheToggled: "Token cache {status}",
|
||||||
|
// failedToUpdateTokenCache: "Failed to update token cache",
|
||||||
|
// failedToUpdateDebugMode: "Failed to update debug mode",
|
||||||
|
// failedToRefreshAccount: "Failed to refresh account",
|
||||||
|
// failedToDeleteAccount: "Failed to delete account",
|
||||||
|
// failedToReloadAccounts: "Failed to reload accounts",
|
||||||
|
// failedToUpdateModelConfig: "Failed to update model config",
|
||||||
|
// fieldUpdated: "{displayName} updated to {value}",
|
||||||
|
// failedToUpdateField: "Failed to update {displayName}",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Validation messages from validators.js
|
||||||
|
// mustBeValidNumber: "{fieldName} must be a valid number",
|
||||||
|
// mustBeAtLeast: "{fieldName} must be at least {min}",
|
||||||
|
// mustBeAtMost: "{fieldName} must be at most {max}",
|
||||||
|
// cannotBeEmpty: "{fieldName} cannot be empty",
|
||||||
|
// mustBeTrueOrFalse: "Value must be true or false",
|
||||||
|
|
||||||
|
// TODO: Missing translation - Server config (exists in EN but missing here)
|
||||||
|
// defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.",
|
||||||
|
};
|
||||||
332
public/js/translations/zh.js
Normal file
332
public/js/translations/zh.js
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
/**
|
||||||
|
* Chinese (中文) Translations
|
||||||
|
*/
|
||||||
|
window.translations = window.translations || {};
|
||||||
|
window.translations.zh = {
|
||||||
|
dashboard: "仪表盘",
|
||||||
|
models: "模型列表",
|
||||||
|
accounts: "账号管理",
|
||||||
|
logs: "运行日志",
|
||||||
|
settings: "系统设置",
|
||||||
|
online: "在线",
|
||||||
|
offline: "离线",
|
||||||
|
totalAccounts: "账号总数",
|
||||||
|
active: "活跃状态",
|
||||||
|
operational: "运行中",
|
||||||
|
rateLimited: "受限状态",
|
||||||
|
quotasDepleted: "{count}/{total} 配额耗尽",
|
||||||
|
quotasDepletedTitle: "配额耗尽数",
|
||||||
|
outOfTracked: "共追踪 {total} 个",
|
||||||
|
cooldown: "冷却中",
|
||||||
|
searchPlaceholder: "搜索模型...",
|
||||||
|
allAccounts: "所有账号",
|
||||||
|
stat: "状态",
|
||||||
|
modelIdentity: "模型标识",
|
||||||
|
globalQuota: "全局配额",
|
||||||
|
nextReset: "重置时间",
|
||||||
|
distribution: "账号分布",
|
||||||
|
systemConfig: "系统配置",
|
||||||
|
language: "语言设置",
|
||||||
|
pollingInterval: "数据轮询间隔",
|
||||||
|
maxDisplayLogs: "最大日志显示行数",
|
||||||
|
showExhausted: "显示耗尽模型",
|
||||||
|
showExhaustedDesc: "即使配额为 0% 也显示模型。",
|
||||||
|
compactMode: "紧凑模式",
|
||||||
|
compactModeDesc: "减少表格间距以显示更多信息。",
|
||||||
|
saveChanges: "保存更改",
|
||||||
|
autoScroll: "自动滚动",
|
||||||
|
clearLogs: "清除日志",
|
||||||
|
accountManagement: "账号管理",
|
||||||
|
manageTokens: "管理已授权的 Google 账号及其状态",
|
||||||
|
addAccount: "添加账号",
|
||||||
|
status: "状态",
|
||||||
|
enabled: "启用",
|
||||||
|
health: "状态",
|
||||||
|
accountEmail: "账号 (邮箱)",
|
||||||
|
source: "来源",
|
||||||
|
projectId: "项目 ID",
|
||||||
|
sessionState: "会话状态",
|
||||||
|
operations: "操作",
|
||||||
|
delete: "删除",
|
||||||
|
confirmDelete: "确定要移除此账号吗?",
|
||||||
|
cannotDeleteDatabase: "无法删除:此账号来自 Antigravity 数据库(只读)",
|
||||||
|
connectGoogle: "连接 Google 账号",
|
||||||
|
reauthenticated: "已重新认证",
|
||||||
|
added: "已添加",
|
||||||
|
successfully: "成功",
|
||||||
|
accountAddedSuccess: "账号添加成功",
|
||||||
|
accountReauthSuccess: "账号重新认证成功",
|
||||||
|
failedToGetAuthUrl: "获取认证链接失败",
|
||||||
|
failedToStartOAuth: "启动 OAuth 流程失败",
|
||||||
|
oauthInProgress: "OAuth 授权进行中,请在弹出窗口中完成认证...",
|
||||||
|
family: "系列",
|
||||||
|
model: "模型",
|
||||||
|
activeSuffix: "活跃",
|
||||||
|
manualReload: "重新加载配置",
|
||||||
|
// Tabs
|
||||||
|
tabInterface: "界面设置",
|
||||||
|
tabClaude: "Claude CLI",
|
||||||
|
tabModels: "模型管理",
|
||||||
|
tabServer: "服务器设置",
|
||||||
|
// Dashboard
|
||||||
|
linkedAccounts: "已关联账号",
|
||||||
|
noSignal: "无信号连接",
|
||||||
|
establishingUplink: "正在建立上行链路...",
|
||||||
|
goToAccounts: "前往账号管理",
|
||||||
|
// Settings - Models
|
||||||
|
modelsDesc: "配置模型的可见性、置顶和请求路由。",
|
||||||
|
modelsPageDesc: "所有可用模型的实时配额和状态。",
|
||||||
|
showHidden: "显示隐藏模型",
|
||||||
|
hideHidden: "隐藏被屏蔽模型",
|
||||||
|
hiddenOn: "隐藏模型: 显示",
|
||||||
|
hiddenOff: "隐藏模型: 隐藏",
|
||||||
|
modelId: "模型 ID",
|
||||||
|
actions: "操作",
|
||||||
|
pinToTop: "置顶",
|
||||||
|
toggleVisibility: "切换可见性",
|
||||||
|
noModels: "未检测到模型",
|
||||||
|
modelMappingHint: "服务端模型路由功能。Claude Code 用户请使用 'Claude CLI' 标签页以便捷配置。",
|
||||||
|
modelMapping: "映射 (目标模型 ID)",
|
||||||
|
// Settings - Claude
|
||||||
|
proxyConnection: "代理连接",
|
||||||
|
modelSelection: "模型选择",
|
||||||
|
defaultModelAliases: "默认模型映射 (别名)",
|
||||||
|
opusAlias: "Opus 别名",
|
||||||
|
sonnetAlias: "Sonnet 别名",
|
||||||
|
haikuAlias: "Haiku 别名",
|
||||||
|
claudeSettingsAlertPrefix: "以下设置直接修改",
|
||||||
|
claudeSettingsAlertSuffix: "重启 Claude CLI 生效。",
|
||||||
|
applyToClaude: "应用到 Claude CLI",
|
||||||
|
// Presets
|
||||||
|
configPresets: "配置预设",
|
||||||
|
saveAsPreset: "另存为预设",
|
||||||
|
deletePreset: "删除预设",
|
||||||
|
loadPreset: "加载预设到表单",
|
||||||
|
load: "加载",
|
||||||
|
presetHint: "选择预设以加载。点击“应用到 Claude CLI”以保存更改。",
|
||||||
|
presetLoaded: "预设已加载。点击“应用到 Claude CLI”以保存。",
|
||||||
|
presetSaved: "预设已保存",
|
||||||
|
presetDeleted: "预设已删除",
|
||||||
|
unsavedChangesTitle: "未保存的更改",
|
||||||
|
unsavedChangesMessage: "当前配置与任何已保存的预设都不匹配。如果切换预设,当前未保存的设置将会丢失。",
|
||||||
|
loadAnyway: "仍然加载",
|
||||||
|
savePresetTitle: "保存预设",
|
||||||
|
savePresetDesc: "将当前配置保存为可重复使用的预设。",
|
||||||
|
presetName: "预设名称",
|
||||||
|
presetNamePlaceholder: "例如:工作配置",
|
||||||
|
savePreset: "保存预设",
|
||||||
|
// Settings - Server
|
||||||
|
port: "端口",
|
||||||
|
uiVersion: "UI 版本",
|
||||||
|
debugMode: "调试模式",
|
||||||
|
environment: "运行环境",
|
||||||
|
serverReadOnly: "配置由 config.json 管理。重启服务器以应用更改。",
|
||||||
|
advancedSettings: "高级设置",
|
||||||
|
reloadConfigTitle: "重载账号配置",
|
||||||
|
reloadConfigDesc: "强制从磁盘重新读取 accounts.json",
|
||||||
|
reload: "重载",
|
||||||
|
// Config Specific
|
||||||
|
primaryModel: "主模型",
|
||||||
|
subAgentModel: "子代理模型",
|
||||||
|
advancedOverrides: "默认模型覆盖 (高级)",
|
||||||
|
opusModel: "Opus 模型",
|
||||||
|
sonnetModel: "Sonnet 模型",
|
||||||
|
haikuModel: "Haiku 模型",
|
||||||
|
authToken: "认证令牌",
|
||||||
|
saveConfig: "保存到 Claude CLI 设置",
|
||||||
|
envVar: "环境变量",
|
||||||
|
// New Keys
|
||||||
|
systemName: "ANTIGRAVITY",
|
||||||
|
systemDesc: "CLAUDE 代理系统",
|
||||||
|
connectGoogleDesc: "连接 Google Workspace 账号以增加 API 配额。该账号将用于通过 Antigravity 代理 Claude 请求。",
|
||||||
|
useCliCommand: "使用命令行",
|
||||||
|
close: "关闭",
|
||||||
|
requestVolume: "请求量",
|
||||||
|
filter: "筛选",
|
||||||
|
all: "全选",
|
||||||
|
none: "清空",
|
||||||
|
noDataTracked: "暂无追踪数据",
|
||||||
|
selectFamilies: "选择要显示的系列",
|
||||||
|
selectModels: "选择要显示的模型",
|
||||||
|
noLogsMatch: "没有符合过滤条件的日志",
|
||||||
|
connecting: "正在连接",
|
||||||
|
main: "主菜单",
|
||||||
|
system: "系统",
|
||||||
|
refreshData: "刷新数据",
|
||||||
|
connectionLost: "连接已断开",
|
||||||
|
lastUpdated: "最后更新",
|
||||||
|
grepLogs: "过滤日志...",
|
||||||
|
noMatchingModels: "没有匹配的模型",
|
||||||
|
typeToSearch: "输入以搜索或选择...",
|
||||||
|
or: "或",
|
||||||
|
refreshingAccount: "正在刷新 {email}...",
|
||||||
|
refreshedAccount: "已完成刷新 {email}",
|
||||||
|
refreshFailed: "刷新失败",
|
||||||
|
accountToggled: "账号 {email} 已{status}",
|
||||||
|
toggleFailed: "切换失败",
|
||||||
|
reauthenticating: "正在重新认证 {email}...",
|
||||||
|
authUrlFailed: "获取认证链接失败",
|
||||||
|
deletedAccount: "已删除 {email}",
|
||||||
|
deleteFailed: "删除失败",
|
||||||
|
accountsReloaded: "账号配置已重载",
|
||||||
|
reloadFailed: "重载失败",
|
||||||
|
claudeConfigSaved: "Claude 配置已保存",
|
||||||
|
claudeConfigRestored: "Claude CLI 已恢复默认设置",
|
||||||
|
saveConfigFailed: "保存配置失败",
|
||||||
|
restoreConfigFailed: "恢复配置失败",
|
||||||
|
restoreDefault: "恢复默认",
|
||||||
|
confirmRestoreTitle: "确认恢复",
|
||||||
|
confirmRestoreMessage: "确定要将 Claude CLI 恢复为默认设置吗?这将移除代理配置。",
|
||||||
|
confirmRestore: "确认恢复",
|
||||||
|
claudeActive: "Claude 活跃",
|
||||||
|
claudeEmpty: "Claude 耗尽",
|
||||||
|
geminiActive: "Gemini 活跃",
|
||||||
|
geminiEmpty: "Gemini 耗尽",
|
||||||
|
synced: "已同步",
|
||||||
|
syncing: "正在同步...",
|
||||||
|
// 时间范围标签
|
||||||
|
last1Hour: "最近 1 小时",
|
||||||
|
last6Hours: "最近 6 小时",
|
||||||
|
last24Hours: "最近 24 小时",
|
||||||
|
last7Days: "最近 7 天",
|
||||||
|
allTime: "最后全部",
|
||||||
|
groupBy: "分组方式",
|
||||||
|
// Additional
|
||||||
|
reloading: "正在重载...",
|
||||||
|
reloaded: "已重载",
|
||||||
|
lines: "行",
|
||||||
|
enabledSeeLogs: "已启用 (见日志)",
|
||||||
|
production: "生产环境",
|
||||||
|
configSaved: "配置已保存",
|
||||||
|
enterPassword: "请输入 Web UI 密码:",
|
||||||
|
ready: "就绪",
|
||||||
|
depleted: "已耗尽",
|
||||||
|
timeH: "时",
|
||||||
|
timeM: "分",
|
||||||
|
familyClaude: "Claude 系列",
|
||||||
|
familyGemini: "Gemini 系列",
|
||||||
|
familyOther: "其他系列",
|
||||||
|
enabledStatus: "已启用",
|
||||||
|
disabledStatus: "已禁用",
|
||||||
|
logLevelInfo: "信息",
|
||||||
|
logLevelSuccess: "成功",
|
||||||
|
logLevelWarn: "警告",
|
||||||
|
logLevelError: "错误",
|
||||||
|
totalColon: "总计:",
|
||||||
|
todayColon: "今日:",
|
||||||
|
hour1Colon: "1小时:",
|
||||||
|
frequentModels: "常用推荐",
|
||||||
|
smartTitle: "自动选出过去 24 小时最常用的 5 个模型",
|
||||||
|
activeCount: "{count} 活跃",
|
||||||
|
allCaps: "全部",
|
||||||
|
claudeCaps: "CLAUDE",
|
||||||
|
geminiCaps: "GEMINI",
|
||||||
|
modelMapping: "映射 (目标模型 ID)",
|
||||||
|
systemInfo: "系统信息",
|
||||||
|
refresh: "刷新",
|
||||||
|
runtimeConfig: "运行时配置",
|
||||||
|
debugDesc: "启用详细日志记录 (见运行日志)",
|
||||||
|
networkRetry: "网络重试设置",
|
||||||
|
maxRetries: "最大重试次数",
|
||||||
|
retryBaseDelay: "重试基础延迟 (毫秒)",
|
||||||
|
retryMaxDelay: "重试最大延迟 (毫秒)",
|
||||||
|
persistentSessions: "持久化登录会话",
|
||||||
|
persistTokenDesc: "将登录会话保存到磁盘以实现快速重启",
|
||||||
|
rateLimiting: "账号限流与超时",
|
||||||
|
defaultCooldown: "默认冷却时间",
|
||||||
|
defaultCooldownDesc: "当 API 未提供重置时间时的备用冷却时间。",
|
||||||
|
maxWaitThreshold: "最大等待阈值",
|
||||||
|
maxWaitDesc: "如果所有账号的限流时间超过此阈值,立即返回错误而非等待。",
|
||||||
|
saveConfigServer: "保存配置",
|
||||||
|
serverRestartAlert: "配置已保存至 {path}。部分更改可能需要重启服务器。",
|
||||||
|
changePassword: "修改 WebUI 密码",
|
||||||
|
changePasswordDesc: "更新访问此仪表盘的密码",
|
||||||
|
currentPassword: "当前密码",
|
||||||
|
newPassword: "新密码",
|
||||||
|
confirmNewPassword: "确认新密码",
|
||||||
|
passwordEmptyDesc: "如果未设置密码请留空",
|
||||||
|
passwordLengthDesc: "至少 6 个字符",
|
||||||
|
passwordConfirmDesc: "请再次输入新密码",
|
||||||
|
cancel: "取消",
|
||||||
|
passwordsNotMatch: "密码不匹配",
|
||||||
|
passwordTooShort: "密码至少需要 6 个字符",
|
||||||
|
// Dashboard drill-down
|
||||||
|
clickToViewAllAccounts: "点击查看所有账号",
|
||||||
|
clickToViewModels: "点击查看模型页面",
|
||||||
|
clickToViewLimitedAccounts: "点击查看受限账号",
|
||||||
|
clickToFilterClaude: "点击筛选 Claude 模型",
|
||||||
|
clickToFilterGemini: "点击筛选 Gemini 模型",
|
||||||
|
// 账号页面
|
||||||
|
searchAccounts: "搜索账号...",
|
||||||
|
noAccountsYet: "还没有添加任何账号",
|
||||||
|
noAccountsDesc: "点击上方的 \"添加账号\" 按钮通过 OAuth 添加 Google 账号,或者使用 CLI 命令导入凭证。",
|
||||||
|
addFirstAccount: "添加第一个账号",
|
||||||
|
noSearchResults: "没有找到匹配的账号",
|
||||||
|
clearSearch: "清除搜索",
|
||||||
|
disabledAccountsNote: "<strong>已禁用的账号</strong>不会用于请求路由,但仍保留在配置中。仪表盘统计数据仅包含已启用的账号。",
|
||||||
|
dangerousOperation: "⚠️ 危险操作",
|
||||||
|
confirmDeletePrompt: "确定要删除账号",
|
||||||
|
deleteWarning: "⚠️ 此操作不可撤销,账号的所有配置和历史记录将永久删除。",
|
||||||
|
// OAuth 进度
|
||||||
|
oauthWaiting: "等待 OAuth 授权中...",
|
||||||
|
oauthWaitingDesc: "请在弹出窗口中完成认证。此过程最长可能需要 2 分钟。",
|
||||||
|
oauthCancelled: "已取消 OAuth 授权",
|
||||||
|
oauthTimeout: "⏱️ OAuth 授权超时,请重试。",
|
||||||
|
oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。",
|
||||||
|
cancelOAuth: "取消",
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "实验性 MCP CLI",
|
||||||
|
mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。",
|
||||||
|
gemini1mMode: "Gemini 1M 上下文模式",
|
||||||
|
gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。",
|
||||||
|
gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。",
|
||||||
|
clickToSet: "点击进行配置...",
|
||||||
|
none: "无",
|
||||||
|
// Quota Distribution
|
||||||
|
quotaDistribution: "配额分布",
|
||||||
|
resetsIn: "{time} 后重置",
|
||||||
|
noQuotaData: "暂无此账号的配额数据。",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Hardcoded strings from HTML
|
||||||
|
// pageTitle: "Antigravity Console",
|
||||||
|
// live: "Live",
|
||||||
|
// tier: "Tier",
|
||||||
|
// quota: "Quota",
|
||||||
|
// tierUltra: "Ultra",
|
||||||
|
// tierPro: "Pro",
|
||||||
|
// tierFree: "Free",
|
||||||
|
// menu: "Menu",
|
||||||
|
// github: "GitHub",
|
||||||
|
// noData: "No data",
|
||||||
|
// fix: "Fix",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Hardcoded strings from JS (Error Messages)
|
||||||
|
// operationFailed: "Operation failed",
|
||||||
|
// unknownError: "Unknown error",
|
||||||
|
// presetNameRequired: "Preset name is required",
|
||||||
|
// saveFailed: "Save failed",
|
||||||
|
// failedToSavePreset: "Failed to save preset",
|
||||||
|
// noPresetSelected: "No preset selected",
|
||||||
|
// deletePresetConfirm: "Delete preset \"{name}\"?",
|
||||||
|
// deleteFailed: "Delete failed",
|
||||||
|
// failedToDeletePreset: "Failed to delete preset",
|
||||||
|
// failedToChangePassword: "Failed to change password",
|
||||||
|
// passwordChangedSuccess: "Password changed successfully",
|
||||||
|
// debugModeToggled: "Debug mode {status}",
|
||||||
|
// tokenCacheToggled: "Token cache {status}",
|
||||||
|
// failedToUpdateTokenCache: "Failed to update token cache",
|
||||||
|
// failedToUpdateDebugMode: "Failed to update debug mode",
|
||||||
|
// failedToRefreshAccount: "Failed to refresh account",
|
||||||
|
// failedToDeleteAccount: "Failed to delete account",
|
||||||
|
// failedToReloadAccounts: "Failed to reload accounts",
|
||||||
|
// failedToUpdateModelConfig: "Failed to update model config",
|
||||||
|
// fieldUpdated: "{displayName} updated to {value}",
|
||||||
|
// failedToUpdateField: "Failed to update {displayName}",
|
||||||
|
|
||||||
|
// TODO: Missing translations - Validation messages from validators.js
|
||||||
|
// mustBeValidNumber: "{fieldName} must be a valid number",
|
||||||
|
// mustBeAtLeast: "{fieldName} must be at least {min}",
|
||||||
|
// mustBeAtMost: "{fieldName} must be at most {max}",
|
||||||
|
// cannotBeEmpty: "{fieldName} cannot be empty",
|
||||||
|
// mustBeTrueOrFalse: "Value must be true or false",
|
||||||
|
};
|
||||||
@@ -26,7 +26,7 @@ window.AccountActions.refreshAccount = async function(email) {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status !== 'ok') {
|
if (data.status !== 'ok') {
|
||||||
return { success: false, error: data.error || 'Refresh failed' };
|
return { success: false, error: data.error || Alpine.store('global').t('refreshFailed') };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发数据刷新
|
// 触发数据刷新
|
||||||
@@ -73,7 +73,7 @@ window.AccountActions.toggleAccount = async function(email, enabled) {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status !== 'ok') {
|
if (data.status !== 'ok') {
|
||||||
throw new Error(data.error || 'Toggle failed');
|
throw new Error(data.error || Alpine.store('global').t('toggleFailed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确认服务器状态
|
// 确认服务器状态
|
||||||
@@ -111,7 +111,7 @@ window.AccountActions.deleteAccount = async function(email) {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status !== 'ok') {
|
if (data.status !== 'ok') {
|
||||||
return { success: false, error: data.error || 'Delete failed' };
|
return { success: false, error: data.error || Alpine.store('global').t('deleteFailed') };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发数据刷新
|
// 触发数据刷新
|
||||||
@@ -146,7 +146,7 @@ window.AccountActions.getFixAccountUrl = async function(email) {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status !== 'ok') {
|
if (data.status !== 'ok') {
|
||||||
return { success: false, error: data.error || 'Failed to get auth URL' };
|
return { success: false, error: data.error || Alpine.store('global').t('authUrlFailed') };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true, url: data.url };
|
return { success: true, url: data.url };
|
||||||
@@ -176,7 +176,7 @@ window.AccountActions.reloadAccounts = async function() {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.status !== 'ok') {
|
if (data.status !== 'ok') {
|
||||||
return { success: false, error: data.error || 'Reload failed' };
|
return { success: false, error: data.error || Alpine.store('global').t('reloadFailed') };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发数据刷新
|
// 触发数据刷新
|
||||||
|
|||||||
@@ -13,18 +13,19 @@ window.ErrorHandler = window.ErrorHandler || {};
|
|||||||
* @param {Function} options.onError - Custom error handler callback
|
* @param {Function} options.onError - Custom error handler callback
|
||||||
* @returns {Promise<any>} Result of the function or undefined on error
|
* @returns {Promise<any>} Result of the function or undefined on error
|
||||||
*/
|
*/
|
||||||
window.ErrorHandler.safeAsync = async function(fn, errorMessage = 'Operation failed', options = {}) {
|
window.ErrorHandler.safeAsync = async function(fn, errorMessage = null, options = {}) {
|
||||||
const { rethrow = false, onError = null } = options;
|
const { rethrow = false, onError = null } = options;
|
||||||
const store = Alpine.store('global');
|
const store = Alpine.store('global');
|
||||||
|
const defaultErrorMessage = errorMessage || store.t('operationFailed');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Log error for debugging
|
// Log error for debugging
|
||||||
console.error(`[ErrorHandler] ${errorMessage}:`, error);
|
console.error(`[ErrorHandler] ${defaultErrorMessage}:`, error);
|
||||||
|
|
||||||
// Show toast notification
|
// Show toast notification
|
||||||
const fullMessage = `${errorMessage}: ${error.message || 'Unknown error'}`;
|
const fullMessage = `${defaultErrorMessage}: ${error.message || store.t('unknownError')}`;
|
||||||
store.showToast(fullMessage, 'error');
|
store.showToast(fullMessage, 'error');
|
||||||
|
|
||||||
// Call custom error handler if provided
|
// Call custom error handler if provided
|
||||||
@@ -51,11 +52,11 @@ window.ErrorHandler.safeAsync = async function(fn, errorMessage = 'Operation fai
|
|||||||
* @param {string} errorMessage - Error message prefix
|
* @param {string} errorMessage - Error message prefix
|
||||||
* @returns {Function} Wrapped method
|
* @returns {Function} Wrapped method
|
||||||
*/
|
*/
|
||||||
window.ErrorHandler.wrapMethod = function(method, errorMessage = 'Operation failed') {
|
window.ErrorHandler.wrapMethod = function(method, errorMessage = null) {
|
||||||
return async function(...args) {
|
return async function(...args) {
|
||||||
return window.ErrorHandler.safeAsync(
|
return window.ErrorHandler.safeAsync(
|
||||||
() => method.apply(this, args),
|
() => method.apply(this, args),
|
||||||
errorMessage
|
errorMessage || Alpine.store('global').t('operationFailed')
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ window.ModelConfigUtils.updateModelConfig = async function(modelId, configUpdate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to update model config');
|
throw new Error(store.t('failedToUpdateModelConfig'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimistic update of local state
|
// Optimistic update of local state
|
||||||
@@ -38,5 +38,5 @@ window.ModelConfigUtils.updateModelConfig = async function(modelId, configUpdate
|
|||||||
|
|
||||||
// Recompute quota rows to reflect changes
|
// Recompute quota rows to reflect changes
|
||||||
dataStore.computeQuotaRows();
|
dataStore.computeQuotaRows();
|
||||||
}, 'Failed to update model config');
|
}, Alpine.store('global').t('failedToUpdateModelConfig'));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ window.Validators = window.Validators || {};
|
|||||||
*/
|
*/
|
||||||
window.Validators.validateRange = function(value, min, max, fieldName = 'Value') {
|
window.Validators.validateRange = function(value, min, max, fieldName = 'Value') {
|
||||||
const numValue = Number(value);
|
const numValue = Number(value);
|
||||||
|
const t = Alpine.store('global').t;
|
||||||
|
|
||||||
if (isNaN(numValue)) {
|
if (isNaN(numValue)) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
value: min,
|
value: min,
|
||||||
error: `${fieldName} must be a valid number`
|
error: t('mustBeValidNumber', { fieldName })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value')
|
|||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
value: min,
|
value: min,
|
||||||
error: `${fieldName} must be at least ${min}`
|
error: t('mustBeAtLeast', { fieldName, min })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value')
|
|||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
value: max,
|
value: max,
|
||||||
error: `${fieldName} must be at most ${max}`
|
error: t('mustBeAtMost', { fieldName, max })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +65,13 @@ window.Validators.validatePort = function(port) {
|
|||||||
*/
|
*/
|
||||||
window.Validators.validateNotEmpty = function(value, fieldName = 'Field') {
|
window.Validators.validateNotEmpty = function(value, fieldName = 'Field') {
|
||||||
const trimmedValue = String(value || '').trim();
|
const trimmedValue = String(value || '').trim();
|
||||||
|
const t = Alpine.store('global').t;
|
||||||
|
|
||||||
if (trimmedValue.length === 0) {
|
if (trimmedValue.length === 0) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
value: trimmedValue,
|
value: trimmedValue,
|
||||||
error: `${fieldName} cannot be empty`
|
error: t('cannotBeEmpty', { fieldName })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ window.Validators.validateBoolean = function(value) {
|
|||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
value: false,
|
value: false,
|
||||||
error: 'Value must be true or false'
|
error: Alpine.store('global').t('mustBeTrueOrFalse')
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,8 @@
|
|||||||
<th class="pl-6 py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-16" x-text="$store.global.t('enabled')">Enabled</th>
|
<th class="pl-6 py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-16" x-text="$store.global.t('enabled')">Enabled</th>
|
||||||
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider flex-1 min-w-[200px]" x-text="$store.global.t('accountEmail')">Account (Email)</th>
|
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider flex-1 min-w-[200px]" x-text="$store.global.t('accountEmail')">Account (Email)</th>
|
||||||
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-20" x-text="$store.global.t('source')">Source</th>
|
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-20" x-text="$store.global.t('source')">Source</th>
|
||||||
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-16">Tier</th>
|
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-16" x-text="$store.global.t('tier')">Tier</th>
|
||||||
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-32">Quota</th>
|
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-32" x-text="$store.global.t('quota')">Quota</th>
|
||||||
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-24" x-text="$store.global.t('health')">Health</th>
|
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-24" x-text="$store.global.t('health')">Health</th>
|
||||||
<th class="py-3 pr-6 text-right text-[10px] font-bold text-gray-500 uppercase tracking-wider w-32" x-text="$store.global.t('operations')">Operations</th>
|
<th class="py-3 pr-6 text-right text-[10px] font-bold text-gray-500 uppercase tracking-wider w-32" x-text="$store.global.t('operations')">Operations</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -265,7 +265,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form method="dialog" class="modal-backdrop">
|
<form method="dialog" class="modal-backdrop">
|
||||||
<button>close</button>
|
<button x-text="$store.global.t('close')">close</button>
|
||||||
</form>
|
</form>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form method="dialog" class="modal-backdrop">
|
<form method="dialog" class="modal-backdrop">
|
||||||
<button>close</button>
|
<button x-text="$store.global.t('close')">close</button>
|
||||||
</form>
|
</form>
|
||||||
</dialog>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<span class="absolute w-1.5 h-1.5 bg-neon-green rounded-full animate-ping opacity-75"></span>
|
<span class="absolute w-1.5 h-1.5 bg-neon-green rounded-full animate-ping opacity-75"></span>
|
||||||
<span class="relative w-1.5 h-1.5 bg-neon-green rounded-full"></span>
|
<span class="relative w-1.5 h-1.5 bg-neon-green rounded-full"></span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-[10px] font-mono text-gray-500 uppercase tracking-wider">Live</span>
|
<span class="text-[10px] font-mono text-gray-500 uppercase tracking-wider" x-text="$store.global.t('live')">Live</span>
|
||||||
<span class="text-gray-700">•</span>
|
<span class="text-gray-700">•</span>
|
||||||
<span class="text-[10px] font-mono text-gray-400 tabular-nums"
|
<span class="text-[10px] font-mono text-gray-400 tabular-nums"
|
||||||
x-text="new Date().toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', second: '2-digit'})">
|
x-text="new Date().toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', second: '2-digit'})">
|
||||||
@@ -78,17 +78,17 @@
|
|||||||
<div class="flex items-center gap-1 mt-2 text-[10px] font-mono flex-wrap" x-show="stats.subscription">
|
<div class="flex items-center gap-1 mt-2 text-[10px] font-mono flex-wrap" x-show="stats.subscription">
|
||||||
<template x-if="stats.subscription?.ultra > 0">
|
<template x-if="stats.subscription?.ultra > 0">
|
||||||
<span class="px-1.5 py-0.5 rounded bg-yellow-500/10 text-yellow-400 border border-yellow-500/30">
|
<span class="px-1.5 py-0.5 rounded bg-yellow-500/10 text-yellow-400 border border-yellow-500/30">
|
||||||
<span x-text="stats.subscription.ultra"></span> Ultra
|
<span x-text="stats.subscription.ultra"></span> <span x-text="$store.global.t('tierUltra')">Ultra</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-if="stats.subscription?.pro > 0">
|
<template x-if="stats.subscription?.pro > 0">
|
||||||
<span class="px-1.5 py-0.5 rounded bg-blue-500/10 text-blue-400 border border-blue-500/30">
|
<span class="px-1.5 py-0.5 rounded bg-blue-500/10 text-blue-400 border border-blue-500/30">
|
||||||
<span x-text="stats.subscription.pro"></span> Pro
|
<span x-text="stats.subscription.pro"></span> <span x-text="$store.global.t('tierPro')">Pro</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-if="stats.subscription?.free > 0">
|
<template x-if="stats.subscription?.free > 0">
|
||||||
<span class="px-1.5 py-0.5 rounded bg-gray-500/10 text-gray-400 border border-gray-500/30">
|
<span class="px-1.5 py-0.5 rounded bg-gray-500/10 text-gray-400 border border-gray-500/30">
|
||||||
<span x-text="stats.subscription.free"></span> Free
|
<span x-text="stats.subscription.free"></span> <span x-text="$store.global.t('tierFree')">Free</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -213,7 +213,7 @@
|
|||||||
<!-- Account Status Indicators -->
|
<!-- Account Status Indicators -->
|
||||||
<div class="flex flex-wrap gap-1 justify-start max-w-[200px]" x-data="{ maxVisible: 12 }">
|
<div class="flex flex-wrap gap-1 justify-start max-w-[200px]" x-data="{ maxVisible: 12 }">
|
||||||
<template x-if="!row.quotaInfo || row.quotaInfo.length === 0">
|
<template x-if="!row.quotaInfo || row.quotaInfo.length === 0">
|
||||||
<div class="text-[10px] text-gray-600 italic">No data</div>
|
<div class="text-[10px] text-gray-600 italic" x-text="$store.global.t('noData')">No data</div>
|
||||||
</template>
|
</template>
|
||||||
<template x-if="row.quotaInfo && row.quotaInfo.length > 0">
|
<template x-if="row.quotaInfo && row.quotaInfo.length > 0">
|
||||||
<div class="flex flex-wrap gap-1 justify-start">
|
<div class="flex flex-wrap gap-1 justify-start">
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
<option value="en">English</option>
|
<option value="en">English</option>
|
||||||
<option value="zh">中文</option>
|
<option value="zh">中文</option>
|
||||||
<option value="tr">Türkçe</option>
|
<option value="tr">Türkçe</option>
|
||||||
|
<option value="id">Bahasa Indonesia</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user