feat(i18n): add bahasa indonesia translation

This commit is contained in:
Gilas Amalanda
2026-10-01 22:49:20 +08:00
committed by GitHub
parent cc87ab0cd1
commit 35a08e667b
16 changed files with 11967 additions and 9 deletions
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const source = readFileSync(new URL("../AiAssistant.vue", import.meta.url), "utf8");
const localePaths = ["az", "en", "es", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"];
const localePaths = ["az", "en", "es", "id", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"];
describe("AI assistant write confirmation replacement", () => {
it("renders a localized confirmation from the backend's semantic event", () => {
+2
View File
@@ -6,6 +6,7 @@ import { BackendErrorException, formatError, normalizeBackendError, sanitizeBack
import az from "@/i18n/locales/az";
import en from "@/i18n/locales/en";
import es from "@/i18n/locales/es";
import id from "@/i18n/locales/id";
import it from "@/i18n/locales/it";
import ja from "@/i18n/locales/ja";
import ko from "@/i18n/locales/ko";
@@ -20,6 +21,7 @@ const LOCALES = {
az,
en,
es,
id,
it,
ja,
ko,
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import it_ from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -15,6 +16,7 @@ const locales: Array<[string, Record<string, unknown>]> = [
["az", az],
["en", en],
["es", es],
["id", id],
["it", it_],
["ja", ja],
["ko", ko],
@@ -12,8 +12,8 @@ function localeSource(name: string): string {
return readFileSync(new URL(`../locales/${name}.ts`, import.meta.url), "utf8");
}
// Source of truth: `supportedLocales` in ../index.ts (11 entries, `ru` included).
const LOCALES = ["en", "zh-CN", "zh-TW", "ja", "ko", "es", "it", "pt-BR", "ru", "az", "tr"] as const;
// Source of truth: `supportedLocales` in ../index.ts (12 entries, `ru` included).
const LOCALES = ["en", "zh-CN", "zh-TW", "ja", "ko", "es", "it", "pt-BR", "ru", "az", "tr", "id"] as const;
function declaredString(source: string, key: string): string | undefined {
return source.match(new RegExp(String.raw`^\s*${key}:\s*"((?:[^"\\]|\\.)*)",\s*$`, "m"))?.[1];
+3 -2
View File
@@ -3,6 +3,7 @@ import { createI18n } from "vue-i18n";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import itLocale from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -20,9 +21,9 @@ import zhTW from "../locales/zh-TW";
vi.mock("../locales/fallback", () => ({ withEnglishFallback: (messages: Record<string, unknown>) => messages }));
type Messages = Record<string, unknown>;
type Locale = "az" | "en" | "es" | "it" | "ja" | "ko" | "pt-BR" | "ru" | "tr" | "zh-CN" | "zh-TW";
type Locale = "az" | "en" | "es" | "id" | "it" | "ja" | "ko" | "pt-BR" | "ru" | "tr" | "zh-CN" | "zh-TW";
const declared: Record<Locale, Messages> = { az, en, es, it: itLocale, ja, ko, "pt-BR": ptBR, ru, tr, "zh-CN": zhCN, "zh-TW": zhTW };
const declared: Record<Locale, Messages> = { az, en, es, id, it: itLocale, ja, ko, "pt-BR": ptBR, ru, tr, "zh-CN": zhCN, "zh-TW": zhTW };
const ALL_LOCALES = Object.keys(declared) as Locale[];
const EXCEPT_AZ_TR = ALL_LOCALES.filter((locale) => locale !== "az" && locale !== "tr");
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import it_ from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -15,6 +16,7 @@ const locales: Array<[string, Record<string, unknown>]> = [
["az", az],
["en", en],
["es", es],
["id", id],
["it", it_],
["ja", ja],
["ko", ko],
@@ -15,7 +15,7 @@ function historyKindsCluster(source: string): string | undefined {
return (source.match(/kinds: \{[^}]*\}/g) ?? []).find((cluster) => cluster.includes("redis_command:"));
}
const LOCALES = ["en", "zh-CN", "zh-TW", "ja", "ko", "es", "it", "pt-BR", "ru", "az", "tr"] as const;
const LOCALES = ["en", "zh-CN", "zh-TW", "ja", "ko", "es", "it", "pt-BR", "ru", "az", "tr", "id"] as const;
describe("history kinds mcp label parity", () => {
it.each(LOCALES)("%s: history.kinds declares mcp", (name) => {
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import itLocale from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -24,6 +25,7 @@ import zhTW from "../locales/zh-TW";
const locales: Array<[string, Record<string, unknown>]> = [
["az", az as Record<string, unknown>],
["es", es as Record<string, unknown>],
["id", id as Record<string, unknown>],
["it", itLocale as Record<string, unknown>],
["ja", ja as Record<string, unknown>],
["ko", ko as Record<string, unknown>],
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import it_ from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -19,6 +20,7 @@ const locales: Array<[string, Record<string, unknown>]> = [
["en", en as Record<string, unknown>],
["az", az as Record<string, unknown>],
["es", es],
["id", id],
["it", it_],
["ja", ja],
["ko", ko],
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import az from "../locales/az";
import en from "../locales/en";
import es from "../locales/es";
import id from "../locales/id";
import it_ from "../locales/it";
import ja from "../locales/ja";
import ko from "../locales/ko";
@@ -20,6 +21,7 @@ const locales: Array<[string, Record<string, unknown>]> = [
["en", en as Record<string, unknown>],
["az", az as Record<string, unknown>],
["es", es],
["id", id],
["it", it_],
["ja", ja],
["ko", ko],
+4 -2
View File
@@ -3,19 +3,20 @@ import en from "./locales/en";
import { safeLocalStorageGet } from "@/lib/backend/safeStorage";
import { persistAppLocale } from "@/lib/app/appAppearance";
export type Locale = "az" | "en" | "es" | "it" | "ja" | "ko" | "pt-BR" | "ru" | "tr" | "zh-CN" | "zh-TW";
export type Locale = "az" | "en" | "es" | "id" | "it" | "ja" | "ko" | "pt-BR" | "ru" | "tr" | "zh-CN" | "zh-TW";
type LocaleMessages = Record<string, unknown>;
type I18nGlobal = {
locale: { value: Locale };
setLocaleMessage: (locale: Locale, messages: LocaleMessages) => void;
};
const supportedLocales: Locale[] = ["az", "en", "es", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"];
const supportedLocales: Locale[] = ["az", "en", "es", "id", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"];
const defaultLocale: Locale = "en";
const loadedLocales = new Set<Locale>([defaultLocale]);
const localeLoaders: Record<Exclude<Locale, "en">, () => Promise<{ default: LocaleMessages }>> = {
az: () => import("./locales/az"),
es: () => import("./locales/es"),
id: () => import("./locales/id"),
it: () => import("./locales/it"),
ja: () => import("./locales/ja"),
ko: () => import("./locales/ko"),
@@ -45,6 +46,7 @@ export function localeFromLanguageTag(value: string | null | undefined): Locale
if (normalized === "az" || normalized.startsWith("az-")) return "az";
if (normalized === "en" || normalized.startsWith("en-")) return "en";
if (normalized === "es" || normalized.startsWith("es-")) return "es";
if (normalized === "id" || normalized.startsWith("id-")) return "id";
if (normalized === "it" || normalized.startsWith("it-")) return "it";
if (normalized === "ja" || normalized.startsWith("ja-")) return "ja";
if (normalized === "ko" || normalized.startsWith("ko-")) return "ko";
+472
View File
@@ -0,0 +1,472 @@
import type { ConsulMessages } from "./consulUi";
export const consulIdMessages = {
ui: {
unknown: "Tidak diketahui",
peeringPending: "Menunggu",
peeringEstablishing: "Sedang dibangun",
peeringActive: "Aktif",
peeringFailing: "Gagal",
peeringDeleting: "Sedang dihapus",
peeringTerminated: "Dihentikan",
refresh: "Segarkan",
cancel: "Batal",
create: "Buat",
update: "Perbarui",
save: "Simpan",
delete: "Hapus",
edit: "Edit",
apply: "Terapkan",
close: "Tutup",
hide: "Sembunyikan",
reveal: "Tampilkan",
copy: "Salin",
copied: "Disalin",
copyFailed: "Gagal menyalin",
copyOnce: "Salin sekali",
pause: "Jeda",
watchAction: "Pantau",
watchPrefix: "Pantau prefiks",
watchModePrefix: "Prefiks",
watchModeKey: "Kunci persis",
sessionProtected: "Dilindungi Sesi",
sessionProtectedHint: "Penyuntingan dan penghapusan dinonaktifkan untuk melindungi kunci terdistribusi ini.",
atomicTransaction: "Transaksi atomik",
nonAtomicBatches: "Tidak atomik antar {count} batch",
batchOperation: "Batch {batch} · OpIndex {op}",
operationTotals: "Berhasil {succeeded} · Konflik {conflicted} · Dilewati {skipped} · Gagal {failed}",
deleteOperationTotals: "Berhasil {succeeded} · Konflik {conflicted} · Gagal {failed}",
clientSideMigration: "DBX membaca dari sumber dan menulis ke target. Ini bukan replikasi antar-Datacenter native Consul.",
bundleFileType: "Paket KV Consul DBX",
sourceKeyMissingModifyIndex: "Kunci sumber tidak memiliki ModifyIndex",
transactionRejected: "Consul menolak transaksi",
overview: "Ringkasan klaster",
capabilities: "Kapabilitas",
probeLoading: "Memuat",
probeReady: "Siap",
probeForbidden: "Terlarang",
probeUnsupported: "Tidak didukung",
probeError: "Galat",
autopilotHealth: "Kesehatan Autopilot",
datacenter: "Datacenter",
agentNode: "Node Agent",
agentAddress: "Alamat Agent",
version: "Versi",
mode: "Mode",
server: "Server",
client: "Klien",
leader: "Leader",
raftPeers: "Peer Raft",
membersAlive: "Anggota hidup",
members: "Anggota",
node: "Node",
address: "Alamat",
status: "Status",
alive: "hidup",
leaving: "keluar",
failed: "gagal",
previousPage: "Halaman sebelumnya",
nextPage: "Halaman berikutnya",
pageStatus: "{page} / {pages} · total {total}",
searchAllServices: "Cari semua layanan",
searchAllNodes: "Cari semua node",
searchLocalServices: "Cari layanan Agent lokal",
query: "Kueri",
searchHealthChecks: "Cari nama, ID, node, layanan, output, atau catatan pemeriksaan",
allCheckTypes: "Semua jenis pemeriksaan",
clearFilters: "Bersihkan filter",
healthResultCount: "{filtered} dari {total} pemeriksaan",
services: "Layanan",
nodes: "Node",
service: "Layanan",
catalogServices: "Layanan katalog",
catalogNodes: "Node katalog",
noVisibleServices: "Tidak ada layanan yang terlihat",
noVisibleNodes: "Tidak ada node yang terlihat",
noMatchingServices: "Tidak ada layanan yang cocok",
noMatchingNodes: "Tidak ada node yang cocok",
agentTarget: "Target Agent: {target}",
agentTargetVerifying: "Memverifikasi target Agent",
unknownWritesDisabled: "tidak diketahui - penulisan dinonaktifkan",
targetAgent: "Agent target",
agentWriteReady: "Dapat ditulis",
agentReadOnly: "Baca saja",
agentWriteDisabledHint: "Tidak ada target Agent yang cocok dikonfigurasi, sehingga pemeliharaan dan pembatalan pendaftaran dinonaktifkan. Agent yang terdeteksi: {target}.",
agentWriteBlocked: {
connectionUnavailable: "Konfigurasi koneksi tidak tersedia. Sambungkan kembali sebelum menulis.",
readOnly: "Koneksi ini baca saja. Pembatalan pendaftaran layanan dinonaktifkan.",
transport: "Penulisan Agent tidak tersedia melalui Transport Layer. Sambungkan langsung ke Agent target.",
targetRequired: "Sunting koneksi dan konfigurasikan node serta alamat target Agent. Node harus cocok dengan Agent saat ini, dan alamat harus cocok dengan endpoint koneksi.",
identityUnavailable: "Tidak dapat membaca identitas Agent. Penulisan dinonaktifkan. Periksa koneksi dan izin baca Agent, lalu segarkan.",
nodeMismatch: "Node target yang dikonfigurasi tidak cocok dengan Agent saat ini. Periksa pengaturan koneksi.",
directAddressRequired: "Penulisan Agent memerlukan endpoint IP langsung atau localhost. Alamat DNS dan load-balanced tidak didukung.",
addressMismatch: "Alamat target Agent tidak cocok dengan endpoint koneksi. Periksa pengaturan koneksi.",
invalidAddress: "Alamat koneksi Consul tidak valid. Periksa pengaturan koneksi.",
},
register: "Daftarkan",
registrationHint: "Pendaftaran HTTP Agent dimiliki oleh runtime Agent target dan tidak mengubah berkas konfigurasi permanennya.",
name: "Nama",
id: "ID",
port: "Port",
tags: "Tag (dipisahkan koma)",
registerOn: "Daftarkan di {node}",
catalogInstances: "Instansi katalog",
nodeServices: "Layanan node",
serviceId: "ID layanan",
localAgentServices: "Layanan Agent lokal",
enableMaintenance: "Aktifkan mode pemeliharaan",
disableMaintenance: "Nonaktifkan mode pemeliharaan",
deregister: "Batalkan pendaftaran",
deregisterService: "Batalkan pendaftaran layanan lokal {id} dari {node}?",
deregistering: "Membatalkan pendaftaran",
deregisterServiceHint: "Ini menghapus pendaftaran layanan dan pemeriksaan terkait. Katalog akan disinkronkan setelahnya. Proses layanan tetap berjalan dan dapat mendaftarkan dirinya kembali.",
deregisterServiceSucceeded: "Pendaftaran layanan {id} dari {node} dibatalkan. Sinkronisasi katalog dapat memakan waktu; layanan dapat muncul kembali jika aplikasi mendaftarkannya lagi.",
deregisterRefreshFailed: "Layanan dibatalkan pendaftarannya, tetapi penyegaran gagal. Segarkan secara manual",
maintenanceReason: "Permintaan pengguna DBX",
serviceDetails: "Detail {service}",
kind: "Jenis",
serviceKind: "ServiceKind",
standard: "standar",
metadata: "Metadata",
nodeMeta: "Metadata node",
serviceMeta: "Metadata layanan",
nodeId: "ID node",
serviceWeights: "Baik / Peringatan",
taggedAddresses: "TaggedAddresses",
enableTagOverride: "EnableTagOverride",
agent: "Agent",
watch: "Pantau",
writeOperation: "Operasi tulis",
localServiceDetails: "Detail layanan lokal",
agentIdentityRequestTimedOut: "Pemuatan identitas Agent kehabisan waktu.",
localServicesRequestTimedOut: "Pemuatan layanan Agent lokal kehabisan waktu.",
localChecksRequestTimedOut: "Pemuatan pemeriksaan Agent lokal kehabisan waktu.",
healthChecks: "Pemeriksaan kesehatan",
state: "Status",
nodeName: "Nama node",
allStates: "Semua status",
passing: "Baik",
warning: "Peringatan",
critical: "Kritis",
watchPaused: "Pemantauan dijeda",
watchingIndex: "Memantau indeks {index}",
pauseWatch: "Jeda pemantauan",
startWatch: "Mulai pemantauan",
checkRegistrationHint: "Pemeriksaan Agent adalah pendaftaran runtime pada {node} dan tidak disimpan ke berkas konfigurasi Agent.",
type: "Jenis",
ttl: "TTL",
http: "HTTP",
tcp: "TCP",
grpc: "gRPC",
docker: "Docker",
script: "Script",
arguments: "Argumen",
containerId: "ID kontainer",
endpoint: "Endpoint",
interval: "Interval",
timeout: "Batas waktu",
commandArguments: "Argumen perintah",
clusterHealth: "Kesehatan klaster",
nodeHealth: "Kesehatan node: {node}",
serviceHealth: "Kesehatan layanan: {service}",
noMatchingHealthChecks: "Tidak ada pemeriksaan kesehatan yang cocok",
serviceInstances: "Instansi layanan",
localAgentChecks: "Pemeriksaan Agent lokal",
maintenance: "pemeliharaan",
ttlPass: "TTL lulus",
ttlWarn: "TTL peringatan",
ttlFail: "TTL gagal",
deregisterCheck: "Batalkan pendaftaran pemeriksaan {id} dari {node}?",
checkDetails: "Detail {check}",
checkId: "ID pemeriksaan",
notes: "Catatan",
output: "Output",
definition: "Definisi",
indexes: "CreateIndex / ModifyIndex",
sessionsAndLocks: "Sesi dan kunci",
sessions: "Sesi",
sessionDescription: "Sesi adalah kontrak mirip lease yang digunakan oleh kunci KV Consul. Sesi TTL memerlukan pembaruan berkala; Sesi tanpa TTL tetap ada hingga secara eksplisit dihancurkan atau divalidasi oleh pemeriksaannya.",
createSession: "Buat Sesi",
searchSessions: "Cari nama, ID, node, atau pemeriksaan Sesi",
sessionResultCount: "Menampilkan {filtered} dari {total} Sesi",
noMatchingSessions: "Tidak ada Sesi yang cocok",
allSessionTypes: "Semua jenis Sesi",
ttlSessions: "Sesi TTL",
persistentSessions: "Sesi tanpa TTL",
allBehaviors: "Semua perilaku",
aclFilteredSessions: "Daftar Sesi difilter oleh ACL",
sessionRequestTimedOut: "Pemuatan Sesi kehabisan waktu. Periksa koneksi Consul dan coba lagi.",
complete: "Lengkap",
lock: "Kunci",
lockManagement: "Pengelolaan kunci KV",
lockIndex: "LockIndex {index}",
lockDelay: "Penundaan kunci",
lockDelayHint: "0s–60s; menunda pengambilan ulang setelah invalidasi.",
nodeOptional: "Node (opsional)",
behavior: "Perilaku",
behaviorRelease: "release",
behaviorDelete: "delete",
behaviorHint: "release mempertahankan kunci yang dipegang; delete menghapusnya saat Sesi berakhir.",
releaseLocks: "Lepaskan kunci",
deleteKeys: "Hapus kunci",
deleteBehaviorWarning: "Perilaku=delete menghapus setiap kunci yang dipegang oleh Sesi ini saat Sesi divalidasi. Lanjutkan?",
checks: "Pemeriksaan",
nodeChecks: "Pemeriksaan node",
serviceChecks: "Pemeriksaan layanan",
nodeCheckShort: "Node",
serviceCheckShort: "Layanan",
serviceChecksPlaceholder: "service:api:health{'@'}namespace-a",
serviceChecksHint: "ID pemeriksaan dipisahkan koma; gunakan ID{'@'}namespace untuk pemeriksaan tercakup.",
lockHint: "Periksa kunci, pilih Sesi, lalu ambil atau lepaskan kunci advisori.",
key: "Kunci",
inspectKey: "Periksa kunci",
keyExists: "Kunci ada",
keyNotFound: "Kunci tidak ada",
keyUnlocked: "Kunci saat ini tidak dipegang",
keyHeldBy: "Dipegang oleh Sesi {session}",
sessionValue: "Sesi {id}",
modifyIndexValue: "ModifyIndex {index}",
createIndex: "CreateIndex",
modifyIndexLabel: "ModifyIndex",
selectSession: "Pilih Sesi",
sessionId: "ID Sesi",
expectedModifyIndex: "ModifyIndex yang diharapkan (0 untuk kunci baru)",
value: "Nilai",
releaseMatchingSession: "Lepaskan",
acquire: "Ambil",
unnamedSession: "Sesi tanpa nama",
heldKeys: "Kunci yang dipegang",
heldKeysIncomplete: "Hasil tidak lengkap atau terfilter ACL",
stop: "Hentikan",
renewNow: "Perbarui sekarang",
autoRenew: "Perbarui otomatis",
autoRenewPageHint: "Pembaruan otomatis hanya berjalan selama koneksi dan halaman ini tetap aktif.",
noRenewRequired: "Tidak perlu pembaruan",
noTtl: "Tanpa TTL",
ttlOptional: "TTL (opsional)",
ttlRangeHint: "Biarkan kosong untuk Sesi persisten, atau gunakan 10s–24h.",
invalidSessionTtl: "TTL harus kosong atau durasi valid dari 10s hingga 24h.",
invalidLockDelay: "Penundaan kunci harus berupa durasi valid dari 0s hingga 60s.",
destroy: "Hancurkan",
noHeldKeys: "Tidak ada kunci yang dipegang",
noVisibleSessions: "Tidak ada Sesi yang terlihat",
destroySession: "Hancurkan Sesi {id}? Kunci yang menggunakan Sesi ini dapat dilepaskan atau dihapus oleh Perilakunya.",
destroySessionImpact: "Hancurkan Sesi {id}? Perilaku: {behavior}. Kunci yang dipegang ({count}): {keys}",
sessionImpactIncomplete: "Dampak Sesi tidak lengkap atau terfilter ACL. Penghancuran diblokir.",
sessionDetails: "TTL {ttl} · {behavior} · pemeriksaan {checks}",
tokens: "Token",
policies: "Kebijakan",
roles: "Peran",
authMethods: "Metode autentikasi",
bindingRules: "Aturan pengikatan",
templatedPolicies: "Kebijakan templat",
capability: "Kapabilitas: {status}",
capabilitySupported: "Didukung",
capabilityUnsupported: "Tidak didukung",
capabilityDisabled: "Dinonaktifkan",
capabilityForbidden: "Tidak ada izin",
capabilityUnknown: "Tidak diketahui",
loading: "Memuat...",
viewOrEdit: "Lihat atau edit",
cloneToken: "Klon token",
deleteAndInspectReferences: "Hapus dan periksa referensi",
noResources: "Tidak ada sumber daya",
editResource: "Edit {kind}",
createResource: "Buat {kind}",
knownImpact: "Dampak yang diketahui: {tokens} token, {roles} peran, {bindingRules} aturan pengikatan",
incomplete: "(tidak lengkap)",
reviewAclChanges: "Tinjau perubahan ACL",
deleteResource: "Hapus {label}",
tokenReferences: "Referensi token: {tokens} · Referensi peran: {roles} · Referensi aturan pengikatan: {bindingRules}",
impactBlocked: "Dampak tidak lengkap atau terfilter ACL. Penghapusan diblokir.",
cloneTokenDescription: "Deskripsi untuk token klon",
scope: "Cakupan Consul",
adminPartition: "Admin Partition",
namespace: "Namespace",
default: "default",
applyScope: "Terapkan cakupan",
enterpriseCapability: "Kapabilitas Enterprise: {status}. Tindakan siklus hidup tidak tersedia.",
namespaces: "Namespace",
lifecycleImpact: "Dampak sumber daya tercakup",
inspectImpactAndDelete: "Periksa dampak dan hapus",
impactAclFiltered: "Consul melaporkan hasil yang terfilter ACL; penghapusan diblokir.",
impactUnavailable: "Tidak dapat menghitung: {resources}",
impactResource: {
services: "Layanan",
nodes: "Node",
kvKeys: "Kunci KV",
healthChecks: "Pemeriksaan kesehatan",
sessions: "Sesi",
configEntries: "Entri konfigurasi",
intentions: "Intention",
peerings: "Peering",
namespaces: "Namespace",
aclTokens: "Token ACL",
aclPolicies: "Kebijakan ACL",
aclRoles: "Peran ACL",
aclAuthMethods: "Metode autentikasi ACL",
aclBindingRules: "Aturan pengikatan ACL",
},
configEntries: "Entri Konfigurasi",
intentions: "Intention",
discoveryChain: "Discovery Chain",
peering: "Peering",
exportedServices: "Layanan yang diekspor",
configEntryKind: "Jenis entri konfigurasi",
loadKind: "Muat jenis",
newJson: "JSON baru",
modifyIndex: "ModifyIndex {index}",
rawJson: "JSON mentah",
newIntention: "Intention baru",
sourceService: "Layanan sumber",
destinationService: "Layanan tujuan",
check: "Periksa",
matchSource: "Cocokkan sumber",
matchDestination: "Cocokkan tujuan",
allowed: "Diizinkan",
denied: "Ditolak",
matchedIntentions: "Mencocokkan {count} intention",
details: "Detail",
serviceName: "Nama layanan",
compile: "Kompilasi",
defaultProtocol: "protokol default",
configuredDatacenter: "datacenter yang dikonfigurasi",
start: "Mulai",
next: "Berikutnya: {nodes}",
terminalTarget: "Terminal / target",
upstreamTargets: "Target upstream ({count})",
peerName: "Nama peer",
peeringToken: "Token peering untuk membangun peering",
generateToken: "Buat token",
establish: "Bangun",
editExportedServices: "Edit entri exported-services",
serviceMeshConfigEntry: "Entri konfigurasi Service Mesh",
applyWithCas: "Terapkan dengan CAS",
reviewMeshChanges: "Tinjau perubahan Service Mesh",
deleteConfig: "Hapus {kind}/{name}?",
deleteIntention: "Hapus intention {id}?",
deleteIntentionExact: "Hapus intention {source} -> {destination}?",
deletePeering: "Hapus peering {name}?",
permissions: "{count} izin",
actionRule: "aturan aksi",
tools: "Alat Consul",
preparedQueries: "Prepared query",
events: "Event",
coordinates: "Koordinat jaringan",
queryName: "Nama kueri",
targetService: "Layanan target",
targetServiceValue: "Layanan target: {service}",
cancelEdit: "Batalkan edit",
execute: "Jalankan",
explain: "Jelaskan",
eventName: "Nama event",
payload: "Payload",
fire: "Picu",
deletePreparedQuery: "Hapus prepared query {id}?",
nodesDatacenter: "{count} node · {datacenter}",
coordinateError: "{segment} · galat {error}",
preparedQueriesDescription:
"Kueri service-discovery yang dapat digunakan ulang dan tersimpan di Consul. Eksekusi me-resolve instansi layanan sehat yang cocok; Jelaskan menampilkan kueri efektif. Editor sederhana hanya mengubah nama dan layanan target, dengan mempertahankan field lanjutan yang sudah tersimpan oleh Consul.",
eventsDescription: "Pesan ringan best-effort yang didistribusikan melalui gossip Consul. Event adalah diagnostik atau notifikasi sementara, bukan antrean pesan permanen.",
coordinatesDescription: "Koordinat jaringan baca saja yang diestimasi Consul untuk membandingkan kedekatan jaringan. Ini bukan lokasi geografis.",
noPreparedQueries: "Tidak ada prepared query",
noEvents: "Tidak ada event terbaru",
noCoordinates: "Tidak ada koordinat jaringan",
queryExecutionResult: "Hasil eksekusi · {count} instansi · {datacenter}",
noQueryNodes: "Tidak ada instansi layanan yang cocok dengan kueri ini",
queryExplanation: "Kueri efektif",
eventNodeFilter: "Regex node (opsional)",
eventServiceFilter: "Regex layanan (opsional)",
eventTagFilter: "Regex tag (opsional)",
eventPayloadBytes: "Payload {count} / 100 byte",
segment: "Segmen",
error: "Galat",
adjustment: "Penyesuaian",
height: "Tinggi",
operatorReadOnly: "Operator (baca saja)",
snapshot: "Snapshot",
snapshotRestore: "Pemulihan snapshot",
targetDatacenter: "Datacenter target",
restoreSnapshot: "Pulihkan snapshot",
restoreSnapshotConfirmation: "RESTORE SNAPSHOT {datacenter}",
autopilotUpdate: "Pembaruan Autopilot",
cleanupDeadServers: "Bersihkan server mati",
updateAutopilot: "Perbarui Autopilot",
updateAutopilotConfirmation: "UPDATE AUTOPILOT",
raftOperations: "Operasi Raft",
serverId: "ID server",
peerAddress: "Alamat peer (hanya penghapusan)",
reenterIdAddress: "Masukkan ulang ID atau alamat",
transferLeader: "Transfer leader",
removePeer: "Hapus peer",
gossipKeyring: "Keyring gossip",
operation: "Operasi",
install: "Pasang",
use: "Gunakan",
remove: "Hapus",
gossipKey: "Kunci gossip",
changeKeyring: "Ubah keyring",
changeKeyringConfirmation: "CHANGE KEYRING",
licenseUpdate: "Pembaruan lisensi",
license: "Lisensi",
updateLicense: "Perbarui lisensi",
updateLicenseConfirmation: "UPDATE LICENSE",
},
tools: {
search: "Cari",
searchTitle: "Cari KV Consul",
searchQuery: "Teks yang dicari",
prefixOptional: "Prefiks (opsional)",
searchAll: "Kunci dan nilai",
searchKeys: "Hanya kunci",
searchValues: "Hanya nilai",
caseSensitive: "Peka huruf besar/kecil",
scanned: "Memindai {count} kunci",
searchLimited: "Hasil dibatasi untuk melindungi koneksi.",
noSearchResults: "Tidak ada kunci yang cocok",
searchSummary: "{matched} kecocokan dari {scanned} kunci yang dipindai",
exportSearchResults: "Ekspor hasil",
searchResultsFileType: "Hasil pencarian KV Consul",
searchResultsExported: "{count} hasil pencarian diekspor",
exportPrefix: "Ekspor prefiks",
prefix: "Prefiks",
emptyPrefixAll: "Biarkan kosong untuk semua kunci yang dapat diakses",
exportLimitHint: "Ekspor mencakup cakupan saat ini dan mempertahankan metadata kunci yang diperlukan untuk impor yang aman.",
exported: "{count} kunci diekspor",
import: "Impor",
importTitle: "Impor paket KV Consul",
invalidBundle: "Berkas ini bukan paket KV Consul DBX yang valid",
importApplied: "{count} kunci diimpor",
migrate: "Migrasikan",
migrateTitle: "Migrasikan KV Consul",
sourcePrefix: "Prefiks sumber",
targetConnection: "Koneksi target",
selectTarget: "Pilih koneksi target",
targetReadOnly: "Koneksi target bersifat baca saja.",
conflictPolicy: "Kebijakan konflik",
policyAbort: "Batalkan saat konflik",
policySkip: "Lewati konflik",
policyCas: "Gunakan CAS",
bundleSummary: "{count} kunci · Datacenter {dc} · Namespace {ns} · Partition {partition}",
creates: "Buat {count}",
updates: "Perbarui {count}",
unchanged: "Tidak berubah {count}",
skipped: "Dilewati {count}",
conflicts: "Konflik {count}",
loadPreview: "Muat pratinjau",
loadingPreview: "Memuat pratinjau...",
apply: "Terapkan",
preview: "Pratinjau",
deletePrefix: "Hapus prefiks",
deletePrefixTitle: "Hapus prefiks KV Consul",
deletePrefixPlaceholder: "Prefiks yang akan dihapus",
deletePrefixWarning: "Operasi ini menghapus setiap kunci yang terlihat di bawah prefiks. Tinjau pratinjau sebelum mengonfirmasi.",
candidates: "Kandidat {count}",
lockedCount: "Terkunci {count}",
filtered: "terfilter",
complete: "lengkap",
confirmDeletePrefix: "Hapus kunci yang dikonfirmasi",
prefixDeleted: "{count} kunci dihapus",
operation: { create: "Buat", update: "Perbarui", unchanged: "Tidak berubah", skipped: "Dilewati", conflict: "Konflik", locked: "Terkunci", succeeded: "Berhasil", conflicted: "Konflik", failed: "Gagal" },
},
} satisfies ConsulMessages;
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,7 @@ export const LOCALE_OPTIONS: { value: Locale; flag: string; label: string }[] =
{ value: "en", flag: "🇺🇸", label: "English" },
{ value: "az", flag: "🇦🇿", label: "Azərbaycan" },
{ value: "es", flag: "🇪🇸", label: "Español" },
{ value: "id", flag: "🇮🇩", label: "Bahasa Indonesia" },
{ value: "it", flag: "🇮🇹", label: "Italiano" },
{ value: "ja", flag: "🇯🇵", label: "日本語" },
{ value: "ko", flag: "🇰🇷", label: "한국어" },
+1 -1
View File
@@ -6,7 +6,7 @@ const runtimeHost = readFileSync("apps/desktop/src/components/sidebar/SidebarTre
const connectionMutationRuntime = readFileSync("apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts", "utf8");
const databaseSpecificMutationRuntime = readFileSync("apps/desktop/src/composables/useSidebarDatabaseSpecificMutationRuntime.ts", "utf8");
const tableMutationRuntime = readFileSync("apps/desktop/src/composables/useSidebarTableMutationRuntime.ts", "utf8");
const localeSources = Object.fromEntries(["az", "en", "es", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"].map((locale) => [locale, readFileSync(`apps/desktop/src/i18n/locales/${locale}.ts`, "utf8")]));
const localeSources = Object.fromEntries(["az", "en", "es", "id", "it", "ja", "ko", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"].map((locale) => [locale, readFileSync(`apps/desktop/src/i18n/locales/${locale}.ts`, "utf8")]));
function functionBody(name: string): string {
const source = [runtimeHost, connectionMutationRuntime, databaseSpecificMutationRuntime, tableMutationRuntime].find((candidate) => candidate.includes(`function ${name}(`));
+10
View File
@@ -730,6 +730,7 @@ enum LocaleFamily {
Japanese,
Korean,
Spanish,
Indonesian,
Italian,
Portuguese,
Russian,
@@ -759,6 +760,8 @@ fn locale_family(locale: &str) -> LocaleFamily {
LocaleFamily::Azerbaijani
} else if is_language("es") {
LocaleFamily::Spanish
} else if is_language("id") {
LocaleFamily::Indonesian
} else if is_language("tr") {
LocaleFamily::Turkish
} else if is_language("it") {
@@ -780,6 +783,7 @@ fn tray_menu_labels_for_locale(locale: &str) -> (&'static str, &'static str) {
LocaleFamily::Korean => ("DBX 표시", "DBX 종료"),
LocaleFamily::Azerbaijani => ("DBX-i göstər", "DBX-dən çıx"),
LocaleFamily::Spanish => ("Mostrar DBX", "Salir de DBX"),
LocaleFamily::Indonesian => ("Tampilkan DBX", "Keluar dari DBX"),
LocaleFamily::Italian => ("Mostra DBX", "Esci da DBX"),
LocaleFamily::Turkish => ("DBX'i Göster", "DBX'ten Çık"),
LocaleFamily::Portuguese => ("Mostrar DBX", "Sair do DBX"),
@@ -798,6 +802,7 @@ fn app_menu_copy_support_info_label(locale: &str) -> &'static str {
LocaleFamily::Korean => "지원 정보 복사",
LocaleFamily::Azerbaijani => "Dəstək məlumatlarını kopyala",
LocaleFamily::Spanish => "Copiar información",
LocaleFamily::Indonesian => "Salin Info Dukungan",
LocaleFamily::Italian => "Copia informazioni",
LocaleFamily::Turkish => "Destek bilgilerini kopyala",
LocaleFamily::Portuguese => "Copiar informações",
@@ -815,6 +820,7 @@ fn app_menu_close_tab_label(locale: &str) -> &'static str {
LocaleFamily::Korean => "탭 닫기",
LocaleFamily::Azerbaijani => "Vərəqi bağla",
LocaleFamily::Spanish => "Cerrar pestaña",
LocaleFamily::Indonesian => "Tutup Tab",
LocaleFamily::Italian => "Chiudi scheda",
LocaleFamily::Turkish => "Sekmeyi kapat",
LocaleFamily::Portuguese => "Fechar aba",
@@ -831,6 +837,7 @@ fn app_menu_quit_label(locale: &str, app_name: &str) -> String {
LocaleFamily::Korean => format!("{app_name} 종료"),
LocaleFamily::Azerbaijani => format!("{app_name}-dən çıx"),
LocaleFamily::Spanish => format!("Salir de {app_name}"),
LocaleFamily::Indonesian => format!("Keluar dari {app_name}"),
LocaleFamily::Italian => format!("Esci da {app_name}"),
LocaleFamily::Turkish => format!("{app_name} Uygulamasından Çık"),
LocaleFamily::Portuguese => format!("Sair do {app_name}"),
@@ -1044,6 +1051,7 @@ mod tests {
assert_eq!(tray_menu_labels_for_locale("ko-KR"), ("DBX 표시", "DBX 종료"));
assert_eq!(tray_menu_labels_for_locale("az-AZ"), ("DBX-i göstər", "DBX-dən çıx"));
assert_eq!(tray_menu_labels_for_locale("es-ES"), ("Mostrar DBX", "Salir de DBX"));
assert_eq!(tray_menu_labels_for_locale("id-ID"), ("Tampilkan DBX", "Keluar dari DBX"));
assert_eq!(tray_menu_labels_for_locale("it-IT"), ("Mostra DBX", "Esci da DBX"));
assert_eq!(tray_menu_labels_for_locale("pt-BR"), ("Mostrar DBX", "Sair do DBX"));
assert_eq!(tray_menu_labels_for_locale("tr-TR"), ("DBX'i Göster", "DBX'ten Çık"));
@@ -1063,6 +1071,7 @@ mod tests {
assert_eq!(app_menu_quit_label("tr-TR", "DBX"), "DBX Uygulamasından Çık");
assert_eq!(app_menu_quit_label("ru-RU", "DBX"), "Выйти из DBX");
assert_eq!(app_menu_quit_label("az-AZ", "DBX"), "DBX-dən çıx");
assert_eq!(app_menu_quit_label("id-ID", "DBX"), "Keluar dari DBX");
assert_eq!(app_menu_quit_label("en-US", "DBX"), "Quit DBX");
assert_eq!(app_menu_quit_label("", "DBX"), "Quit DBX");
assert_eq!(app_menu_copy_support_info_label("zh-CN"), "复制支持信息");
@@ -1071,6 +1080,7 @@ mod tests {
assert_eq!(app_menu_copy_support_info_label("tr-TR"), "Destek bilgilerini kopyala");
assert_eq!(app_menu_copy_support_info_label("ru-RU"), "Копировать сведения о поддержке");
assert_eq!(app_menu_copy_support_info_label("az-AZ"), "Dəstək məlumatlarını kopyala");
assert_eq!(app_menu_copy_support_info_label("id-ID"), "Salin Info Dukungan");
assert_eq!(app_menu_copy_support_info_label("en-US"), "Copy Support Info");
assert_eq!(app_menu_close_tab_label("zh-CN"), "关闭标签页");
assert_eq!(app_menu_close_tab_label("zh-TW"), "關閉分頁");