This is an automated email from the ASF dual-hosted git repository. wu-sheng pushed a commit to branch feat/infra-3d-config-i18n in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit 6dab9cd7278e6e217bd91dc39d7861e42d6c6136 Author: Wu Sheng <[email protected]> AuthorDate: Mon Jun 1 22:31:35 2026 +0800 feat(infra-3d): internationalize the 3D-map config admin page The /admin/3d-map config editor was the only admin page still rendering hardcoded English in every locale — it landed after the 0.6.0 i18n pass. Wire it through vue-i18n like the other admin pages and ship full eight-locale coverage. - Infra3dAdminView.vue: 58 t() keys plus 5 <i18n-t> blocks for the prose hints with inline <code>/<strong>; named-arg interpolation for the dynamic counts, the via tag, and the Push-button state. Layer keys, MQE ids, and the .* regex stay verbatim. - en.json: 55 new source keys. - de/es/fr/ja/ko/pt/zh-CN: the 55 keys translated, matching each catalog's existing terminology. --- CHANGELOG.md | 2 +- .../features/admin/infra-3d/Infra3dAdminView.vue | 158 +++++++++++---------- apps/ui/src/i18n/locales/de.json | 57 +++++++- apps/ui/src/i18n/locales/en.json | 57 +++++++- apps/ui/src/i18n/locales/es.json | 57 +++++++- apps/ui/src/i18n/locales/fr.json | 57 +++++++- apps/ui/src/i18n/locales/ja.json | 57 +++++++- apps/ui/src/i18n/locales/ko.json | 57 +++++++- apps/ui/src/i18n/locales/pt.json | 57 +++++++- apps/ui/src/i18n/locales/zh-CN.json | 57 +++++++- 10 files changed, 532 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e471c8..607bd9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ per device. - **UI chrome.** Every routed page and every shared sub-component renders through `vue-i18n`; non-English locales now cover every admin page (Roles, Users, Auth status, Alert page setup, Global - defaults), every operate page (Alerting rules, DSL catalog / editor / + defaults, 3D-map config), every operate page (Alerting rules, DSL catalog / editor / dump, OAL catalog, Live debugger + MAL / LAL / OAL, Capture history, Metrics inspect, OAP config, TTL), the alarms surface, and the shared modals. Long lede paragraphs that previously rendered as diff --git a/apps/ui/src/features/admin/infra-3d/Infra3dAdminView.vue b/apps/ui/src/features/admin/infra-3d/Infra3dAdminView.vue index 23a627b..4636d2c 100644 --- a/apps/ui/src/features/admin/infra-3d/Infra3dAdminView.vue +++ b/apps/ui/src/features/admin/infra-3d/Infra3dAdminView.vue @@ -42,6 +42,7 @@ --> <script setup lang="ts"> import { computed, onMounted, ref, watch } from 'vue'; +import { useI18n } from 'vue-i18n'; import { useLayers } from '@/shell/useLayers'; import { bff, @@ -68,6 +69,7 @@ import MonacoDiff from '@/features/operate/_shared/MonacoDiff.vue'; // and an out-of-tree layer (config exists, OAP no longer reports it) // also shows so the admin can remove it. const { availableLayers } = useLayers(); +const { t } = useI18n(); // ── Template-sync state ─────────────────────────────────────────────── // The 3D-map config is a singleton template kind — ONE row, @@ -415,8 +417,8 @@ const layersByTier = computed<Record<string, LayerRow[]>>(() => { // bucket (tagged "filtered out"), never under a tier even if pinned, so // the editor matches what the scene renders. if (resolvedLevels.value[r.key]?.via === 'filtered') continue; - const t = explicitTier.value[r.key]; - if (t && out[t]) out[t].push(r); + const tierId = explicitTier.value[r.key]; + if (tierId && out[tierId]) out[tierId].push(r); } return out; }); @@ -567,47 +569,47 @@ const stats = computed(() => { <div class="i3d-admin"> <header class="hd"> <div class="hd-text"> - <span class="kicker">Dashboard setup · 3D Infra Map</span> - <h1>3D Infrastructure Map</h1> + <span class="kicker">{{ t('Dashboard setup · 3D Infra Map') }}</span> + <h1>{{ t('3D Infrastructure Map') }}</h1> <p class="lede"> - Config for the <code>/3d/map</code> view, published to OAP. Levels - control the vertical stack; per-layer color + metrics drive each - cube. Edits save to a <strong>local draft in this browser</strong>; - <strong>Check diff & push</strong> publishes to OAP — the map - renders the remote, with bundled defaults as fallback. + <i18n-t keypath="Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback." tag="span" scope="global"> + <template #mapPath><code>/3d/map</code></template> + <template #localDraft><strong>{{ t('local draft in this browser') }}</strong></template> + <template #checkDiffPush><strong>{{ t('Check diff & push') }}</strong></template> + </i18n-t> </p> </div> <div class="hd-actions"> <span class="src-pill" :data-src="editorSource"> - editing: {{ editorSource }} + {{ t('editing: {source}', { source: editorSource }) }} <TemplateStatusBadge v-if="badge" :status="badge" /> </span> <div class="reset-wrap"> - <button class="btn" :disabled="pushing" @click="resetMenuOpen = !resetMenuOpen">Reset to ▾</button> + <button class="btn" :disabled="pushing" @click="resetMenuOpen = !resetMenuOpen">{{ t('Reset to') }} ▾</button> <div v-if="resetMenuOpen" class="reset-menu"> <button class="reset-item" :disabled="isSynced" - :title="isSynced ? 'Bundled equals OAP-live — nothing to reset to.' : 'Discard current edits and reload the bundled (shipped) default.'" + :title="isSynced ? t('Bundled equals OAP-live — nothing to reset to.') : t('Discard current edits and reload the bundled (shipped) default.')" @click="resetTo('bundled')" > - Bundled<span v-if="isSynced" class="reset-suffix"> (synced)</span> + {{ t('Bundled') }}<span v-if="isSynced" class="reset-suffix"> ({{ t('synced') }})</span> </button> <button class="reset-item" :disabled="!hasRemote" - :title="hasRemote ? 'Discard current edits and reload OAP\'s live version.' : 'OAP has no copy of this config yet.'" + :title="hasRemote ? t('Discard current edits and reload OAP\'s live version.') : t('OAP has no copy of this config yet.')" @click="resetTo('remote')" > - Remote + {{ t('Remote') }} </button> </div> </div> <button class="btn" :disabled="!dirty" @click="save"> - {{ hasLocalDraft && !dirty ? 'Saved local' : 'Save local' }} + {{ hasLocalDraft && !dirty ? t('Saved local') : t('Save local') }} </button> <button class="btn primary" :disabled="readOnly || (!dirty && !hasLocalDraft)" @click="openPushDiff"> - Check diff & push + {{ t('Check diff & push') }} </button> </div> </header> @@ -618,15 +620,19 @@ const stats = computed(() => { </ul> <div v-if="loadError" class="loading"> - Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry. + {{ t('Couldn\'t load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.') }} </div> - <div v-else-if="!ready" class="loading">Loading config…</div> + <div v-else-if="!ready" class="loading">{{ t('Loading config…') }}</div> <template v-else-if="draft"> <!-- ── Global filter ─────────────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Global layer filter</h2> - <span class="sec-hint">The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged "filtered out"). Default <code>.*</code> admits all.</span> + <h2>{{ t('Global layer filter') }}</h2> + <span class="sec-hint"> + <i18n-t keypath='The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged "filtered out"). Default {dotStar} admits all.' tag="span" scope="global"> + <template #dotStar><code>.*</code></template> + </i18n-t> + </span> </header> <div class="sect-body"> <label class="field"> @@ -639,14 +645,18 @@ const stats = computed(() => { <!-- ── Tiers & layers ─────────────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Tiers & layers (top → bottom)</h2> + <h2>{{ t('Tiers & layers (top → bottom)') }}</h2> <span class="sec-hint"> - Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking. - <strong>{{ stats.oap }}</strong> in OAP<template v-if="stats.unclassified > 0"> · - <strong class="warn-count">{{ stats.unclassified }}</strong> unpinned → fallback</template> + {{ t('Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.') }} + <i18n-t keypath="{count} in OAP" tag="span" scope="global"> + <template #count><strong>{{ stats.oap }}</strong></template> + </i18n-t><template v-if="stats.unclassified > 0"> · + <i18n-t keypath="{count} unpinned → fallback" tag="span" scope="global"> + <template #count><strong class="warn-count">{{ stats.unclassified }}</strong></template> + </i18n-t></template> </span> - <input class="inp search" v-model="layerSearch" placeholder="filter layers…" /> - <button type="button" class="btn small" @click="addLevel">+ add tier</button> + <input class="inp search" v-model="layerSearch" :placeholder="t('filter layers…')" /> + <button type="button" class="btn small" @click="addLevel">{{ t('+ add tier') }}</button> </header> <div class="sect-body"> <article v-for="(lvl, idx) in levelsSorted" :key="lvl.id" class="tier-card"> @@ -654,11 +664,11 @@ const stats = computed(() => { <span class="lvl-order">#{{ lvl.order }}</span> <input class="inp lvl-id mono" v-model="lvl.id" placeholder="apps" /> <input class="inp lvl-label" v-model="lvl.label" placeholder="Apps" /> - <span class="tier-count">{{ layersByTier[lvl.id]?.length ?? 0 }} layers</span> + <span class="tier-count">{{ t('{count} layers', { count: layersByTier[lvl.id]?.length ?? 0 }) }}</span> <div class="lvl-spacer" /> <button type="button" class="btn tiny" :disabled="idx === 0" @click="moveLevel(idx, -1)">↑</button> <button type="button" class="btn tiny" :disabled="idx === levelsSorted.length - 1" @click="moveLevel(idx, 1)">↓</button> - <button type="button" class="btn tiny danger" @click="removeLevel(lvl.id)">remove</button> + <button type="button" class="btn tiny danger" @click="removeLevel(lvl.id)">{{ t('remove') }}</button> </header> <div class="tier-body"> <div class="layer-rows"> @@ -666,20 +676,20 @@ const stats = computed(() => { <input type="color" class="color-pick" :value="row.spec?.color ?? '#8a8a8a'" @input="(e) => (ensureLayerSpec(row.key).color = (e.target as HTMLInputElement).value)" /> <span class="layer-key">{{ row.key }}</span> <template v-if="row.spec?.metric"> - <input class="inp mono metric-mqe" v-model="row.spec.metric.mqe" placeholder="mqe e.g. service_cpm" /> - <input class="inp metric-lbl" v-model="row.spec.metric.label" placeholder="label" /> - <input class="inp metric-unit" v-model="row.spec.metric.unit" placeholder="unit" /> - <button class="btn tiny danger" type="button" title="remove metric" @click="clearMetric(row.key)">⊘</button> + <input class="inp mono metric-mqe" v-model="row.spec.metric.mqe" :placeholder="t('mqe e.g. service_cpm')" /> + <input class="inp metric-lbl" v-model="row.spec.metric.label" :placeholder="t('label')" /> + <input class="inp metric-unit" v-model="row.spec.metric.unit" :placeholder="t('unit')" /> + <button class="btn tiny danger" type="button" :title="t('remove metric')" @click="clearMetric(row.key)">⊘</button> </template> - <button v-else class="btn tiny ghost" type="button" @click="ensureMetric(row.key)">+ metric</button> + <button v-else class="btn tiny ghost" type="button" @click="ensureMetric(row.key)">{{ t('+ metric') }}</button> <div class="row-spacer" /> <select class="inp tier-select" :value="explicitTier[row.key] ?? ''" @change="(e) => onMoveTier(row.key, e)"> - <option value="">— unpinned —</option> - <option v-for="t in levelsSorted" :key="t.id" :value="t.id">{{ t.label }}</option> + <option value="">{{ t('— unpinned —') }}</option> + <option v-for="tier in levelsSorted" :key="tier.id" :value="tier.id">{{ tier.label }}</option> </select> - <button class="btn tiny ghost" type="button" title="Remove from this tier (moves to Unpinned)" @click="assignLayerToLevel(row.key, null)">×</button> + <button class="btn tiny ghost" type="button" :title="t('Remove from this tier (moves to Unpinned)')" @click="assignLayerToLevel(row.key, null)">×</button> </div> - <div v-if="(layersByTier[lvl.id]?.length ?? 0) === 0" class="tier-empty">No layers pinned — use a layer's tier dropdown to move one here.</div> + <div v-if="(layersByTier[lvl.id]?.length ?? 0) === 0" class="tier-empty">{{ t('No layers pinned — use a layer\'s tier dropdown to move one here.') }}</div> </div> </div> </article> @@ -689,10 +699,11 @@ const stats = computed(() => { <!-- ── Unpinned → failover ────────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Unpinned layers</h2> + <h2>{{ t('Unpinned layers') }}</h2> <span class="sec-hint"> - Pinned to no tier — they land on the failover tier - (<strong>{{ levelLabel(draft.unknownLayer.level) }}</strong>). Pick a tier to pin one. + <i18n-t keypath="Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one." tag="span" scope="global"> + <template #failoverTier><strong>{{ levelLabel(draft.unknownLayer.level) }}</strong></template> + </i18n-t> </span> </header> <div class="sect-body"> @@ -707,22 +718,22 @@ const stats = computed(() => { <span class="layer-key">{{ row.key }}</span> <template v-if="row.spec?.metric"> <input class="inp mono metric-mqe" v-model="row.spec.metric.mqe" placeholder="mqe" /> - <input class="inp metric-lbl" v-model="row.spec.metric.label" placeholder="label" /> - <input class="inp metric-unit" v-model="row.spec.metric.unit" placeholder="unit" /> - <button class="btn tiny danger" type="button" title="remove metric" @click="clearMetric(row.key)">⊘</button> + <input class="inp metric-lbl" v-model="row.spec.metric.label" :placeholder="t('label')" /> + <input class="inp metric-unit" v-model="row.spec.metric.unit" :placeholder="t('unit')" /> + <button class="btn tiny danger" type="button" :title="t('remove metric')" @click="clearMetric(row.key)">⊘</button> </template> - <button v-else class="btn tiny ghost" type="button" @click="ensureMetric(row.key)">+ metric</button> + <button v-else class="btn tiny ghost" type="button" @click="ensureMetric(row.key)">{{ t('+ metric') }}</button> <div class="row-spacer" /> - <span class="via-tag" :data-via="resolvedLevels[row.key]?.via" :title="`falls to ${resolvedLevels[row.key]?.via}`"> - {{ resolvedLevels[row.key]?.via === 'filtered' ? 'filtered out' : '→ ' + levelLabel(resolvedLevels[row.key]?.levelId ?? null) }} + <span class="via-tag" :data-via="resolvedLevels[row.key]?.via" :title="t('falls to {via}', { via: resolvedLevels[row.key]?.via })"> + {{ resolvedLevels[row.key]?.via === 'filtered' ? t('filtered out') : '→ ' + levelLabel(resolvedLevels[row.key]?.levelId ?? null) }} </span> <select class="inp tier-select" :value="explicitTier[row.key] ?? ''" @change="(e) => onMoveTier(row.key, e)"> - <option value="">— pin to tier —</option> - <option v-for="t in levelsSorted" :key="t.id" :value="t.id">{{ t.label }}</option> + <option value="">{{ t('— pin to tier —') }}</option> + <option v-for="tier in levelsSorted" :key="tier.id" :value="tier.id">{{ tier.label }}</option> </select> - <button class="btn tiny danger" type="button" title="Delete this layer from the config entirely" @click="removeLayerFromConfig(row.key)">×</button> + <button class="btn tiny danger" type="button" :title="t('Delete this layer from the config entirely')" @click="removeLayerFromConfig(row.key)">×</button> </div> - <div v-if="unpinnedRows.length === 0" class="empty">No unpinned layers.</div> + <div v-if="unpinnedRows.length === 0" class="empty">{{ t('No unpinned layers.') }}</div> </div> </div> </section> @@ -730,9 +741,9 @@ const stats = computed(() => { <!-- ── Groups ────────────────────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Logic groups</h2> - <span class="sec-hint">Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.</span> - <button type="button" class="btn small" @click="addGroup">+ add group</button> + <h2>{{ t('Logic groups') }}</h2> + <span class="sec-hint">{{ t('Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.') }}</span> + <button type="button" class="btn small" @click="addGroup">{{ t('+ add group') }}</button> </header> <div class="sect-body"> <div class="groups-grid"> @@ -747,40 +758,40 @@ const stats = computed(() => { <input class="inp group-id mono" v-model="g.id" placeholder="self-observability" /> <input class="inp group-label" v-model="g.label" placeholder="Self-Observability" /> <div class="lvl-spacer" /> - <button type="button" class="btn tiny danger" @click="removeGroup(g.id)">remove</button> + <button type="button" class="btn tiny danger" @click="removeGroup(g.id)">{{ t('remove') }}</button> </header> <div class="group-body"> <div class="row-2"> <label class="field"> - <span class="lbl small">level</span> + <span class="lbl small">{{ t('level') }}</span> <select class="inp" v-model="g.level"> <option v-for="lvl in levelsSorted" :key="lvl.id" :value="lvl.id">{{ lvl.label }} ({{ lvl.id }})</option> </select> </label> <label class="field"> - <span class="lbl small">icon</span> + <span class="lbl small">{{ t('icon') }}</span> <select class="inp" v-model="g.icon"> <option v-for="ic in ICON_NAMES" :key="ic" :value="ic">{{ ic }}</option> </select> </label> </div> <div class="field"> - <span class="lbl small">member layers ({{ g.layers.length }})</span> + <span class="lbl small">{{ t('member layers ({count})', { count: g.layers.length }) }}</span> <div class="chips"> <span v-for="k in g.layers" :key="k" class="chip"> {{ k }} - <button class="x" type="button" title="remove from group" @click="removeLayerFromGroup(g, k)">×</button> + <button class="x" type="button" :title="t('remove from group')" @click="removeLayerFromGroup(g, k)">×</button> </span> <select class="add-layer" :value="''" @change="(e) => onAddLayerToGroup(g, e)"> - <option value="">+ add layer…</option> + <option value="">{{ t('+ add layer…') }}</option> <option v-for="k in groupCandidates(g)" :key="k" :value="k">{{ k }}</option> </select> </div> - <p v-if="g.layers.length === 0" class="hint-sm warn">A group needs at least one layer — pushing will be rejected until you add one.</p> + <p v-if="g.layers.length === 0" class="hint-sm warn">{{ t('A group needs at least one layer — pushing will be rejected until you add one.') }}</p> </div> </div> </article> - <div v-if="(draft.groups ?? []).length === 0" class="empty">No logic groups. Add one to cluster related layers into a single block.</div> + <div v-if="(draft.groups ?? []).length === 0" class="empty">{{ t('No logic groups. Add one to cluster related layers into a single block.') }}</div> </div> </div> </section> @@ -788,17 +799,15 @@ const stats = computed(() => { <!-- ── Service-map layers ─────────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Service-map layers</h2> + <h2>{{ t('Service-map layers') }}</h2> <span class="sec-hint"> - These layers' templates provide a service map, so their cubes render - as a call graph (and seed the cross-layer hierarchy). Read-only — - it's a layer-template property, not a 3D-map setting. + {{ t('These layers\' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it\'s a layer-template property, not a 3D-map setting.') }} </span> </header> <div class="sect-body"> <div class="chips"> <span v-for="k in serviceMapLayers" :key="k" class="chip">{{ k }}</span> - <span v-if="serviceMapLayers.length === 0" class="chips-empty">None reporting a service map.</span> + <span v-if="serviceMapLayers.length === 0" class="chips-empty">{{ t('None reporting a service map.') }}</span> </div> </div> </section> @@ -806,12 +815,12 @@ const stats = computed(() => { <!-- ── Unknown layer fallback ─────────────────────────────────── --> <section class="sect"> <header class="sect-head"> - <h2>Failover tier</h2> - <span class="sec-hint">The single catch-all: any layer no tier pins lands here.</span> + <h2>{{ t('Failover tier') }}</h2> + <span class="sec-hint">{{ t('The single catch-all: any layer no tier pins lands here.') }}</span> </header> <div class="sect-body"> <label class="field"> - <span class="lbl">level</span> + <span class="lbl">{{ t('level') }}</span> <select class="inp fallback-level" v-model="draft.unknownLayer.level"> <option v-for="lvl in levelsSorted" :key="lvl.id" :value="lvl.id">{{ lvl.label }} ({{ lvl.id }})</option> </select> @@ -822,11 +831,10 @@ const stats = computed(() => { </template> <!-- ── Check diff & push ──────────────────────────────────────────── --> - <Modal :open="pushDiffOpen" title="Push 3D-map config to OAP" width="min(1100px, 94vw)" @close="pushDiffOpen = false"> + <Modal :open="pushDiffOpen" :title="t('Push 3D-map config to OAP')" width="min(1100px, 94vw)" @close="pushDiffOpen = false"> <div class="push-modal"> <p class="push-lede"> - Left = live on OAP (remote). Right = your local draft. Pushing - replaces the OAP copy — the map renders it on the next visit. + {{ t('Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.') }} </p> <ul v-if="pushErr && pushErr.length" class="issues"> <li v-for="(it, i) in pushErr" :key="i"><code>{{ it }}</code></li> @@ -834,9 +842,9 @@ const stats = computed(() => { <MonacoDiff :original="pushRemotePretty" :modified="pushLocalPretty" language="json" /> </div> <template #footer> - <button class="btn" :disabled="pushing" @click="pushDiffOpen = false">Cancel</button> + <button class="btn" :disabled="pushing" @click="pushDiffOpen = false">{{ t('Cancel') }}</button> <button class="btn primary" :disabled="pushing || readOnly" @click="pushToOap"> - {{ pushing ? 'Pushing…' : 'Push to OAP' }} + {{ pushing ? t('Pushing…') : t('Push to OAP') }} </button> </template> </Modal> diff --git a/apps/ui/src/i18n/locales/de.json b/apps/ui/src/i18n/locales/de.json index 013daa3..0d800f8 100644 --- a/apps/ui/src/i18n/locales/de.json +++ b/apps/ui/src/i18n/locales/de.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— Wähle einen laufenden Pod oder prüfe, ob On-Demand-Pod-Logs in OAP aktiviert sind.", "Select a service to begin.": "Wähle einen Service, um zu beginnen.", "Select a pod to list its containers.": "Wähle einen Pod, um seine Container aufzulisten.", - "Select a container, then press Start to tail its logs.": "Wähle einen Container und drücke Start, um seine Logs live zu verfolgen." + "Select a container, then press Start to tail its logs.": "Wähle einen Container und drücke Start, um seine Logs live zu verfolgen.", + "Dashboard setup · 3D Infra Map": "Dashboard-Einrichtung · 3D Infra Map", + "3D Infrastructure Map": "3D-Infrastrukturkarte", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "Konfiguration für die Ansicht {mapPath}, auf OAP veröffentlicht. Ebenen steuern die vertikale Stapelung; Farbe und Metriken pro Ebene bestimmen jeden Würfel. Änderungen werden in einem {localDraft} gespeichert; {checkDiffPush} verö [...] + "local draft in this browser": "lokaler Entwurf in diesem Browser", + "editing: {source}": "Bearbeitung: {source}", + "Reset to": "Zurücksetzen auf", + "Bundled equals OAP-live — nothing to reset to.": "Mitgeliefert entspricht der OAP-Live-Version — nichts zum Zurücksetzen.", + "synced": "synchron", + "OAP has no copy of this config yet.": "OAP hat noch keine Kopie dieser Konfiguration.", + "Saved local": "Lokal gespeichert", + "Save local": "Lokal speichern", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "3D-map-Konfiguration konnte nicht geladen werden — der BFF ist möglicherweise nicht erreichbar. Seite neu laden, um es erneut zu versuchen.", + "Loading config…": "Konfiguration wird geladen…", + "Global layer filter": "Globaler Ebenen-Filter", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "Die einzige übergeordnete Schranke — eine Ebene, die diese JS-regex ausschließt, erscheint nicht auf der Karte (sie wird unten weiterhin unter „Nicht angeheftet“ mit der Markierung „filtered out“ angezeigt). Der Standard {dotStar} lässt alle zu.", + "Tiers & layers (top → bottom)": "Stufen & Ebenen (oben → unten)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "Jede Ebene gehört zu genau einer Stufe — lege sie über das Stufen-Dropdown fest; die Reihenfolge entspricht der vertikalen Stapelung.", + "{count} in OAP": "{count} in OAP", + "{count} unpinned → fallback": "{count} nicht angeheftet → Fallback", + "filter layers…": "Ebenen filtern…", + "+ add tier": "+ Stufe hinzufügen", + "{count} layers": "{count} Ebenen", + "mqe e.g. service_cpm": "mqe, z. B. service_cpm", + "label": "Bezeichnung", + "unit": "Einheit", + "remove metric": "Metrik entfernen", + "+ metric": "+ Metrik", + "— unpinned —": "— nicht angeheftet —", + "Remove from this tier (moves to Unpinned)": "Aus dieser Stufe entfernen (wandert zu „Nicht angeheftet“)", + "No layers pinned — use a layer's tier dropdown to move one here.": "Keine Ebenen angeheftet — verschiebe eine über das Stufen-Dropdown einer Ebene hierher.", + "Unpinned layers": "Nicht angeheftete Ebenen", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "An keine Stufe angeheftet — sie landen auf der Failover-Stufe ({failoverTier}). Wähle eine Stufe aus, um eine anzuheften.", + "falls to {via}": "fällt auf {via} zurück", + "filtered out": "filtered out", + "— pin to tier —": "— an Stufe anheften —", + "Delete this layer from the config entirely": "Diese Ebene vollständig aus der Konfiguration löschen", + "No unpinned layers.": "Keine nicht angehefteten Ebenen.", + "Logic groups": "Logikgruppen", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "Mehrere Ebenen, die als ein beschrifteter Block auf einer Stufe dargestellt werden (z. B. Self-Observability). Jedes Mitglied behält seine eigene Würfelfarbe.", + "+ add group": "+ Gruppe hinzufügen", + "level": "Ebene", + "icon": "Symbol", + "member layers ({count})": "Mitglieds-Ebenen ({count})", + "remove from group": "aus Gruppe entfernen", + "+ add layer…": "+ Ebene hinzufügen…", + "A group needs at least one layer — pushing will be rejected until you add one.": "Eine Gruppe braucht mindestens eine Ebene — die Veröffentlichung wird abgelehnt, bis du eine hinzufügst.", + "No logic groups. Add one to cluster related layers into a single block.": "Keine Logikgruppen. Füge eine hinzu, um zusammengehörige Ebenen zu einem einzigen Block zu bündeln.", + "Service-map layers": "Service-Map-Ebenen", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "Die Vorlagen dieser Ebenen liefern eine Service-Map, daher werden ihre Würfel als Aufrufgraph dargestellt (und legen den Grundstein für die ebenenübergreifende Hierarchie). Schreibgeschützt — es ist eine Eigenschaft der Ebenen-Vorlage, keine 3D-map-Einstellung.", + "None reporting a service map.": "Keine meldet eine Service-Map.", + "Failover tier": "Failover-Stufe", + "The single catch-all: any layer no tier pins lands here.": "Die einzige Auffangstufe: jede Ebene, die an keine Stufe angeheftet ist, landet hier.", + "Push 3D-map config to OAP": "3D-map-Konfiguration auf OAP veröffentlichen", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "Links = live auf OAP (Remote). Rechts = dein lokaler Entwurf. Die Veröffentlichung ersetzt die OAP-Kopie — die Karte zeigt sie beim nächsten Besuch.", + "Push to OAP": "Auf OAP veröffentlichen" } diff --git a/apps/ui/src/i18n/locales/en.json b/apps/ui/src/i18n/locales/en.json index 236a926..1780696 100644 --- a/apps/ui/src/i18n/locales/en.json +++ b/apps/ui/src/i18n/locales/en.json @@ -1225,5 +1225,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.", "Select a service to begin.": "Select a service to begin.", "Select a pod to list its containers.": "Select a pod to list its containers.", - "Select a container, then press Start to tail its logs.": "Select a container, then press Start to tail its logs." + "Select a container, then press Start to tail its logs.": "Select a container, then press Start to tail its logs.", + "Dashboard setup · 3D Infra Map": "Dashboard setup · 3D Infra Map", + "3D Infrastructure Map": "3D Infrastructure Map", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundle [...] + "local draft in this browser": "local draft in this browser", + "editing: {source}": "editing: {source}", + "Reset to": "Reset to", + "Bundled equals OAP-live — nothing to reset to.": "Bundled equals OAP-live — nothing to reset to.", + "synced": "synced", + "OAP has no copy of this config yet.": "OAP has no copy of this config yet.", + "Saved local": "Saved local", + "Save local": "Save local", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.", + "Loading config…": "Loading config…", + "Global layer filter": "Global layer filter", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.", + "Tiers & layers (top → bottom)": "Tiers & layers (top → bottom)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.", + "{count} in OAP": "{count} in OAP", + "{count} unpinned → fallback": "{count} unpinned → fallback", + "filter layers…": "filter layers…", + "+ add tier": "+ add tier", + "{count} layers": "{count} layers", + "mqe e.g. service_cpm": "mqe e.g. service_cpm", + "label": "label", + "unit": "unit", + "remove metric": "remove metric", + "+ metric": "+ metric", + "— unpinned —": "— unpinned —", + "Remove from this tier (moves to Unpinned)": "Remove from this tier (moves to Unpinned)", + "No layers pinned — use a layer's tier dropdown to move one here.": "No layers pinned — use a layer's tier dropdown to move one here.", + "Unpinned layers": "Unpinned layers", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.", + "falls to {via}": "falls to {via}", + "filtered out": "filtered out", + "— pin to tier —": "— pin to tier —", + "Delete this layer from the config entirely": "Delete this layer from the config entirely", + "No unpinned layers.": "No unpinned layers.", + "Logic groups": "Logic groups", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.", + "+ add group": "+ add group", + "level": "level", + "icon": "icon", + "member layers ({count})": "member layers ({count})", + "remove from group": "remove from group", + "+ add layer…": "+ add layer…", + "A group needs at least one layer — pushing will be rejected until you add one.": "A group needs at least one layer — pushing will be rejected until you add one.", + "No logic groups. Add one to cluster related layers into a single block.": "No logic groups. Add one to cluster related layers into a single block.", + "Service-map layers": "Service-map layers", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.", + "None reporting a service map.": "None reporting a service map.", + "Failover tier": "Failover tier", + "The single catch-all: any layer no tier pins lands here.": "The single catch-all: any layer no tier pins lands here.", + "Push 3D-map config to OAP": "Push 3D-map config to OAP", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.", + "Push to OAP": "Push to OAP" } diff --git a/apps/ui/src/i18n/locales/es.json b/apps/ui/src/i18n/locales/es.json index 304d877..4df1934 100644 --- a/apps/ui/src/i18n/locales/es.json +++ b/apps/ui/src/i18n/locales/es.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— elige un Pod en ejecución, o verifica que los logs de Pod bajo demanda estén habilitados en OAP.", "Select a service to begin.": "Selecciona un servicio para empezar.", "Select a pod to list its containers.": "Selecciona un Pod para listar sus contenedores.", - "Select a container, then press Start to tail its logs.": "Selecciona un contenedor y pulsa Inicio para seguir sus logs en vivo." + "Select a container, then press Start to tail its logs.": "Selecciona un contenedor y pulsa Inicio para seguir sus logs en vivo.", + "Dashboard setup · 3D Infra Map": "Configuración de paneles · 3D Infra Map", + "3D Infrastructure Map": "3D Infrastructure Map", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "Configuración de la vista {mapPath}, publicada en OAP. Los niveles controlan el apilado vertical; el color y las métricas de cada capa definen cada cubo. Las ediciones se guardan en un {localDraft}; {checkDiffPush} publica en OAP — [...] + "local draft in this browser": "borrador local en este navegador", + "editing: {source}": "editando: {source}", + "Reset to": "Restablecer a", + "Bundled equals OAP-live — nothing to reset to.": "Bundled coincide con OAP-live — no hay nada a lo que restablecer.", + "synced": "sincronizado", + "OAP has no copy of this config yet.": "OAP aún no tiene ninguna copia de esta configuración.", + "Saved local": "Guardado localmente", + "Save local": "Guardar localmente", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "No se pudo cargar la configuración del 3D-map — puede que el BFF no esté disponible. Recarga la página para reintentar.", + "Loading config…": "Cargando configuración…", + "Global layer filter": "Filtro global de capas", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "El único filtro de nivel superior — una capa que este regex de JS excluye queda fuera del mapa (aún aparece más abajo en No fijadas, marcada como \"filtered out\"). El valor predeterminado {dotStar} admite todas.", + "Tiers & layers (top → bottom)": "Niveles y capas (arriba → abajo)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "Cada capa pertenece a un nivel — asígnalo con el menú desplegable de nivel; el orden = apilado vertical.", + "{count} in OAP": "{count} en OAP", + "{count} unpinned → fallback": "{count} no fijadas → respaldo", + "filter layers…": "filtrar capas…", + "+ add tier": "+ agregar nivel", + "{count} layers": "{count} capas", + "mqe e.g. service_cpm": "mqe p. ej. service_cpm", + "label": "etiqueta", + "unit": "unidad", + "remove metric": "quitar métrica", + "+ metric": "+ métrica", + "— unpinned —": "— no fijadas —", + "Remove from this tier (moves to Unpinned)": "Quitar de este nivel (pasa a No fijadas)", + "No layers pinned — use a layer's tier dropdown to move one here.": "No hay capas fijadas — usa el menú desplegable de nivel de una capa para mover una aquí.", + "Unpinned layers": "Capas no fijadas", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "Sin nivel asignado — caen en el nivel de respaldo ({failoverTier}). Elige un nivel para fijar una.", + "falls to {via}": "cae a {via}", + "filtered out": "filtered out", + "— pin to tier —": "— fijar a un nivel —", + "Delete this layer from the config entirely": "Eliminar esta capa por completo de la configuración", + "No unpinned layers.": "No hay capas sin fijar.", + "Logic groups": "Grupos lógicos", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "Varias capas dibujadas como un único bloque con etiqueta en un nivel (p. ej. Self-Observability). Cada miembro conserva el color de su propio cubo.", + "+ add group": "+ agregar grupo", + "level": "nivel", + "icon": "icono", + "member layers ({count})": "capas miembro ({count})", + "remove from group": "quitar del grupo", + "+ add layer…": "+ agregar capa…", + "A group needs at least one layer — pushing will be rejected until you add one.": "Un grupo necesita al menos una capa — el push se rechazará hasta que agregues una.", + "No logic groups. Add one to cluster related layers into a single block.": "No hay grupos lógicos. Agrega uno para agrupar capas relacionadas en un solo bloque.", + "Service-map layers": "Capas con service map", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "Las plantillas de estas capas proporcionan un service map, por lo que sus cubos se muestran como un call graph (y siembran la jerarquía entre capas). Solo lectura — es una propiedad de la plantilla de la capa, no un ajuste del 3D-map.", + "None reporting a service map.": "Ninguna reporta un service map.", + "Failover tier": "Nivel de respaldo", + "The single catch-all: any layer no tier pins lands here.": "El único nivel comodín: cualquier capa que ningún nivel fije termina aquí.", + "Push 3D-map config to OAP": "Publicar la configuración del 3D-map en OAP", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "Izquierda = en vivo en OAP (remote). Derecha = tu borrador local. El push reemplaza la copia en OAP — el mapa la mostrará en la próxima visita.", + "Push to OAP": "Publicar en OAP" } diff --git a/apps/ui/src/i18n/locales/fr.json b/apps/ui/src/i18n/locales/fr.json index 9d97b22..d0fd337 100644 --- a/apps/ui/src/i18n/locales/fr.json +++ b/apps/ui/src/i18n/locales/fr.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— choisissez un Pod en cours d'exécution, ou vérifiez que les logs de Pod à la demande sont activés sur OAP.", "Select a service to begin.": "Sélectionnez un service pour commencer.", "Select a pod to list its containers.": "Sélectionnez un Pod pour lister ses conteneurs.", - "Select a container, then press Start to tail its logs.": "Sélectionnez un conteneur, puis appuyez sur Début pour suivre ses logs en direct." + "Select a container, then press Start to tail its logs.": "Sélectionnez un conteneur, puis appuyez sur Début pour suivre ses logs en direct.", + "Dashboard setup · 3D Infra Map": "Configuration du tableau de bord · 3D Infra Map", + "3D Infrastructure Map": "Carte d'infrastructure 3D", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "Configuration de la vue {mapPath}, publiée sur OAP. Les niveaux contrôlent l'empilement vertical ; la couleur et les métriques propres à chaque couche pilotent chaque cube. Les modifications sont enregistrées dans un {localDraft} ; [...] + "local draft in this browser": "brouillon local dans ce navigateur", + "editing: {source}": "édition : {source}", + "Reset to": "Réinitialiser à", + "Bundled equals OAP-live — nothing to reset to.": "Bundled est identique à la version OAP en ligne — rien à réinitialiser.", + "synced": "synchronisé", + "OAP has no copy of this config yet.": "OAP n'a pas encore de copie de cette configuration.", + "Saved local": "Enregistré en local", + "Save local": "Enregistrer en local", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "Impossible de charger la configuration de la 3D-map — le BFF est peut-être inaccessible. Actualisez la page pour réessayer.", + "Loading config…": "Chargement de la configuration…", + "Global layer filter": "Filtre global des couches", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "L'unique filtre de premier niveau — une couche que ce regex JS exclut disparaît de la carte (elle reste affichée plus bas dans les Non épinglées, marquée « filtré »). La valeur par défaut {dotStar} admet tout.", + "Tiers & layers (top → bottom)": "Paliers et couches (haut → bas)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "Chaque couche appartient à un seul palier — définissez-le via le menu déroulant du palier ; l'ordre correspond à l'empilement vertical.", + "{count} in OAP": "{count} dans OAP", + "{count} unpinned → fallback": "{count} non épinglées → repli", + "filter layers…": "filtrer les couches…", + "+ add tier": "+ ajouter un palier", + "{count} layers": "{count} couches", + "mqe e.g. service_cpm": "mqe, p. ex. service_cpm", + "label": "libellé", + "unit": "unité", + "remove metric": "supprimer la métrique", + "+ metric": "+ métrique", + "— unpinned —": "— non épinglées —", + "Remove from this tier (moves to Unpinned)": "Retirer de ce palier (déplace vers Non épinglées)", + "No layers pinned — use a layer's tier dropdown to move one here.": "Aucune couche épinglée — utilisez le menu déroulant de palier d'une couche pour en déplacer une ici.", + "Unpinned layers": "Couches non épinglées", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "Épinglées à aucun palier — elles atterrissent sur le palier de secours ({failoverTier}). Choisissez un palier pour en épingler une.", + "falls to {via}": "bascule vers {via}", + "filtered out": "filtré", + "— pin to tier —": "— épingler à un palier —", + "Delete this layer from the config entirely": "Supprimer entièrement cette couche de la configuration", + "No unpinned layers.": "Aucune couche non épinglée.", + "Logic groups": "Groupes logiques", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "Plusieurs couches dessinées comme un seul bloc étiqueté sur un palier (p. ex. Self-Observability). Chaque membre conserve la couleur de son propre cube.", + "+ add group": "+ ajouter un groupe", + "level": "niveau", + "icon": "icône", + "member layers ({count})": "couches membres ({count})", + "remove from group": "retirer du groupe", + "+ add layer…": "+ ajouter une couche…", + "A group needs at least one layer — pushing will be rejected until you add one.": "Un groupe nécessite au moins une couche — la publication sera refusée tant que vous n'en ajoutez pas une.", + "No logic groups. Add one to cluster related layers into a single block.": "Aucun groupe logique. Ajoutez-en un pour regrouper des couches apparentées en un seul bloc.", + "Service-map layers": "Couches à carte de services", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "Les modèles de ces couches fournissent une carte de services, leurs cubes s'affichent donc comme un graphe d'appels (et amorcent la hiérarchie inter-couches). Lecture seule — c'est une propriété du modèle de couche, pas un paramètre de la 3D-map.", + "None reporting a service map.": "Aucune ne signale de carte de services.", + "Failover tier": "Palier de secours", + "The single catch-all: any layer no tier pins lands here.": "Le palier fourre-tout unique : toute couche qu'aucun palier n'épingle atterrit ici.", + "Push 3D-map config to OAP": "Publier la configuration de la 3D-map sur OAP", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "À gauche = en ligne sur OAP (Remote). À droite = votre brouillon local. La publication remplace la copie OAP — la carte l'affiche à la prochaine visite.", + "Push to OAP": "Publier sur OAP" } diff --git a/apps/ui/src/i18n/locales/ja.json b/apps/ui/src/i18n/locales/ja.json index 54be75d..81511ff 100644 --- a/apps/ui/src/i18n/locales/ja.json +++ b/apps/ui/src/i18n/locales/ja.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— 実行中の Pod を選択するか、オンデマンド Pod ログが OAP で有効になっているか確認してください。", "Select a service to begin.": "サービスを選択して開始してください。", "Select a pod to list its containers.": "Pod を選択してコンテナを一覧表示します。", - "Select a container, then press Start to tail its logs.": "コンテナを選択し、「開始」を押してログをライブで追尾します。" + "Select a container, then press Start to tail its logs.": "コンテナを選択し、「開始」を押してログをライブで追尾します。", + "Dashboard setup · 3D Infra Map": "ダッシュボード設定 · 3D Infra Map", + "3D Infrastructure Map": "3D インフラマップ", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "{mapPath} ビューの設定で、OAP に公開されます。レベルは垂直方向の積み重ねを制御し、レイヤーごとの色とメトリックが各キューブを表現します。編集内容は {localDraft} に保存され、{checkDiffPush} で OAP に公開されます。マップはリモート版を表示し、バンドルのデフォルトがフォールバックとなります。", + "local draft in this browser": "このブラウザ内のローカル草稿", + "editing: {source}": "編集中: {source}", + "Reset to": "次にリセット", + "Bundled equals OAP-live — nothing to reset to.": "バンドル版が OAP の公開版と一致しています — リセット先はありません。", + "synced": "同期済み", + "OAP has no copy of this config yet.": "OAP にはこの設定のコピーがまだありません。", + "Saved local": "ローカルに保存しました", + "Save local": "ローカルに保存", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "3D-map の設定を読み込めませんでした — BFF に接続できない可能性があります。ページを再読み込みして再試行してください。", + "Loading config…": "設定を読み込んでいます…", + "Global layer filter": "グローバルレイヤーフィルター", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "唯一の最上位ゲートです — この JS regex が除外したレイヤーはマップから外れます(「filtered out」のタグ付きで下の未ピン留め欄には表示されます)。デフォルトの {dotStar} はすべてを許可します。", + "Tiers & layers (top → bottom)": "ティアとレイヤー(上 → 下)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "各レイヤーはいずれか 1 つのティアに属します — ティアのドロップダウンで設定します。順序は垂直方向の積み重ねを表します。", + "{count} in OAP": "OAP に {count} 件", + "{count} unpinned → fallback": "未ピン留め {count} 件 → フォールバック", + "filter layers…": "レイヤーを絞り込み…", + "+ add tier": "+ ティアを追加", + "{count} layers": "{count} レイヤー", + "mqe e.g. service_cpm": "mqe 例: service_cpm", + "label": "ラベル", + "unit": "単位", + "remove metric": "メトリックを削除", + "+ metric": "+ メトリック", + "— unpinned —": "— 未ピン留め —", + "Remove from this tier (moves to Unpinned)": "このティアから外す(未ピン留めに移動)", + "No layers pinned — use a layer's tier dropdown to move one here.": "ピン留めされたレイヤーがありません — レイヤーのティアドロップダウンを使ってここに移動してください。", + "Unpinned layers": "未ピン留めのレイヤー", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "どのティアにもピン留めされておらず、フェイルオーバーティア({failoverTier})に配置されます。ティアを選択してピン留めしてください。", + "falls to {via}": "{via} に落ちる", + "filtered out": "filtered out", + "— pin to tier —": "— ティアにピン留め —", + "Delete this layer from the config entirely": "このレイヤーを設定から完全に削除", + "No unpinned layers.": "未ピン留めのレイヤーはありません。", + "Logic groups": "ロジックグループ", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "複数のレイヤーを 1 つのラベル付きブロックとしてティア上に描画します(例: Self-Observability)。各メンバーはそれぞれのキューブの色を保持します。", + "+ add group": "+ グループを追加", + "level": "レベル", + "icon": "アイコン", + "member layers ({count})": "メンバーレイヤー({count})", + "remove from group": "グループから外す", + "+ add layer…": "+ レイヤーを追加…", + "A group needs at least one layer — pushing will be rejected until you add one.": "グループには少なくとも 1 つのレイヤーが必要です — 追加するまで公開は拒否されます。", + "No logic groups. Add one to cluster related layers into a single block.": "ロジックグループがありません。追加すると、関連するレイヤーを 1 つのブロックにまとめられます。", + "Service-map layers": "サービスマップのレイヤー", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "これらのレイヤーのテンプレートはサービスマップを提供するため、キューブはコールグラフとして描画されます(レイヤー横断の階層の起点にもなります)。読み取り専用です — これは 3D-map の設定ではなく、レイヤーテンプレートのプロパティです。", + "None reporting a service map.": "サービスマップを報告しているものはありません。", + "Failover tier": "フェイルオーバーティア", + "The single catch-all: any layer no tier pins lands here.": "唯一の受け皿です。どのティアにもピン留めされていないレイヤーはここに配置されます。", + "Push 3D-map config to OAP": "3D-map 設定を OAP に公開", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "左 = OAP 上の公開版(リモート)。右 = あなたのローカル草稿。公開すると OAP 上のコピーが置き換えられ、次回アクセス時にマップへ反映されます。", + "Push to OAP": "OAP に公開" } diff --git a/apps/ui/src/i18n/locales/ko.json b/apps/ui/src/i18n/locales/ko.json index d549051..4b1f50b 100644 --- a/apps/ui/src/i18n/locales/ko.json +++ b/apps/ui/src/i18n/locales/ko.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— 실행 중인 Pod를 선택하거나, OAP에서 온디맨드 Pod 로그가 활성화되어 있는지 확인하세요.", "Select a service to begin.": "시작하려면 서비스를 선택하세요.", "Select a pod to list its containers.": "컨테이너를 나열하려면 Pod를 선택하세요.", - "Select a container, then press Start to tail its logs.": "컨테이너를 선택한 다음 시작을 눌러 로그를 실시간으로 확인하세요." + "Select a container, then press Start to tail its logs.": "컨테이너를 선택한 다음 시작을 눌러 로그를 실시간으로 확인하세요.", + "Dashboard setup · 3D Infra Map": "대시보드 설정 · 3D Infra Map", + "3D Infrastructure Map": "3D 인프라 맵", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "OAP에 게시되는 {mapPath} 화면의 설정입니다. 레벨은 수직 적층 순서를 정하고, 각 큐브는 레이어별 색상과 메트릭으로 표현됩니다. 편집 내용은 {localDraft}에 저장되며, {checkDiffPush}로 OAP에 게시합니다 — 맵은 원격 버전을 렌더링하고 번들 기본값을 폴백으로 사용합니다.", + "local draft in this browser": "이 브라우저의 로컬 초안", + "editing: {source}": "편집 중: {source}", + "Reset to": "재설정 대상", + "Bundled equals OAP-live — nothing to reset to.": "번들과 OAP 라이브가 동일 — 재설정할 대상이 없습니다.", + "synced": "동기화됨", + "OAP has no copy of this config yet.": "OAP에 아직 이 설정의 복사본이 없습니다.", + "Saved local": "로컬에 저장됨", + "Save local": "로컬에 저장", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "3D-map 설정을 불러오지 못했습니다 — BFF에 연결할 수 없을 수 있습니다. 페이지를 새로 고쳐 다시 시도하세요.", + "Loading config…": "설정을 불러오는 중…", + "Global layer filter": "전역 레이어 필터", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "최상위 단일 관문입니다 — 이 JS regex가 제외하는 레이어는 맵에서 빠집니다(아래 미고정 목록에는 \"filtered out\"으로 표시되어 그대로 남습니다). 기본값 {dotStar}은 모두 허용합니다.", + "Tiers & layers (top → bottom)": "티어 및 레이어 (위 → 아래)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "모든 레이어는 하나의 티어에 속합니다 — 티어 드롭다운으로 지정하며, 순서가 곧 수직 적층 순서입니다.", + "{count} in OAP": "OAP에 {count}개", + "{count} unpinned → fallback": "미고정 {count}개 → 폴백", + "filter layers…": "레이어 필터…", + "+ add tier": "+ 티어 추가", + "{count} layers": "레이어 {count}개", + "mqe e.g. service_cpm": "mqe 예: service_cpm", + "label": "라벨", + "unit": "단위", + "remove metric": "메트릭 제거", + "+ metric": "+ 메트릭", + "— unpinned —": "— 미고정 —", + "Remove from this tier (moves to Unpinned)": "이 티어에서 제거 (미고정으로 이동)", + "No layers pinned — use a layer's tier dropdown to move one here.": "고정된 레이어가 없습니다 — 레이어의 티어 드롭다운으로 여기로 옮기세요.", + "Unpinned layers": "미고정 레이어", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "어느 티어에도 고정되지 않아 폴백 티어({failoverTier})에 배치됩니다. 고정하려면 티어를 선택하세요.", + "falls to {via}": "{via}(으)로 폴백", + "filtered out": "필터로 제외됨", + "— pin to tier —": "— 티어에 고정 —", + "Delete this layer from the config entirely": "이 레이어를 설정에서 완전히 삭제", + "No unpinned layers.": "미고정 레이어가 없습니다.", + "Logic groups": "로직 그룹", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "여러 레이어를 티어 위에 라벨이 붙은 하나의 블록으로 그립니다(예: Self-Observability). 각 멤버는 자신의 큐브 색상을 그대로 유지합니다.", + "+ add group": "+ 그룹 추가", + "level": "레벨", + "icon": "아이콘", + "member layers ({count})": "멤버 레이어 ({count}개)", + "remove from group": "그룹에서 제거", + "+ add layer…": "+ 레이어 추가…", + "A group needs at least one layer — pushing will be rejected until you add one.": "그룹에는 레이어가 최소 하나 필요합니다 — 하나를 추가하기 전까지 게시가 거부됩니다.", + "No logic groups. Add one to cluster related layers into a single block.": "로직 그룹이 없습니다. 관련 레이어를 하나의 블록으로 묶으려면 추가하세요.", + "Service-map layers": "서비스 맵 레이어", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "이 레이어들의 템플릿은 서비스 맵을 제공하므로, 해당 큐브는 호출 그래프로 렌더링되고 레이어 간 계층 구조의 기반이 됩니다. 읽기 전용입니다 — 이는 레이어 템플릿의 속성이며 3D-map 설정이 아닙니다.", + "None reporting a service map.": "서비스 맵을 보고하는 레이어가 없습니다.", + "Failover tier": "폴백 티어", + "The single catch-all: any layer no tier pins lands here.": "단일 포괄 티어입니다: 어느 티어에도 고정되지 않은 레이어가 모두 여기에 배치됩니다.", + "Push 3D-map config to OAP": "3D-map 설정을 OAP에 게시", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "왼쪽 = OAP 라이브(원격). 오른쪽 = 내 로컬 초안. 게시하면 OAP 복사본을 교체하며, 다음 방문 시 맵이 이를 렌더링합니다.", + "Push to OAP": "OAP에 게시" } diff --git a/apps/ui/src/i18n/locales/pt.json b/apps/ui/src/i18n/locales/pt.json index 007a655..7228384 100644 --- a/apps/ui/src/i18n/locales/pt.json +++ b/apps/ui/src/i18n/locales/pt.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— escolha um Pod em execução, ou verifique se os logs de Pod sob demanda estão habilitados no OAP.", "Select a service to begin.": "Selecione um serviço para começar.", "Select a pod to list its containers.": "Selecione um Pod para listar seus contêineres.", - "Select a container, then press Start to tail its logs.": "Selecione um contêiner e pressione Início para acompanhar seus logs ao vivo." + "Select a container, then press Start to tail its logs.": "Selecione um contêiner e pressione Início para acompanhar seus logs ao vivo.", + "Dashboard setup · 3D Infra Map": "Configuração de painéis · 3D Infra Map", + "3D Infrastructure Map": "3D Infrastructure Map", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "Configuração da visão {mapPath}, publicada no OAP. Os níveis controlam o empilhamento vertical; a cor e as métricas de cada camada definem cada cubo. As edições são salvas em um {localDraft}; {checkDiffPush} publica no OAP — o mapa [...] + "local draft in this browser": "rascunho local neste navegador", + "editing: {source}": "editando: {source}", + "Reset to": "Redefinir para", + "Bundled equals OAP-live — nothing to reset to.": "Bundled coincide com a versão em produção do OAP — nada para redefinir.", + "synced": "sincronizado", + "OAP has no copy of this config yet.": "O OAP ainda não tem uma cópia desta configuração.", + "Saved local": "Salvo localmente", + "Save local": "Salvar localmente", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "Não foi possível carregar a configuração do 3D-map — o BFF pode estar indisponível. Atualize a página para tentar de novo.", + "Loading config…": "Carregando a configuração…", + "Global layer filter": "Filtro global de camadas", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "O único filtro de nível superior — uma camada excluída por este regex JS fica fora do mapa (ainda aparece abaixo em Não fixadas, marcada como \"filtered out\"). O padrão {dotStar} admite todas.", + "Tiers & layers (top → bottom)": "Níveis e camadas (topo → base)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "Cada camada pertence a um nível — defina-o pela lista suspensa de nível; a ordem = empilhamento vertical.", + "{count} in OAP": "{count} no OAP", + "{count} unpinned → fallback": "{count} não fixadas → fallback", + "filter layers…": "filtrar camadas…", + "+ add tier": "+ adicionar nível", + "{count} layers": "{count} camadas", + "mqe e.g. service_cpm": "mqe ex.: service_cpm", + "label": "rótulo", + "unit": "unidade", + "remove metric": "remover métrica", + "+ metric": "+ métrica", + "— unpinned —": "— não fixadas —", + "Remove from this tier (moves to Unpinned)": "Remover deste nível (move para Não fixadas)", + "No layers pinned — use a layer's tier dropdown to move one here.": "Nenhuma camada fixada — use a lista de nível de uma camada para mover uma para cá.", + "Unpinned layers": "Camadas não fixadas", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "Sem nível fixado — caem no nível de failover ({failoverTier}). Escolha um nível para fixar uma delas.", + "falls to {via}": "cai para {via}", + "filtered out": "filtered out", + "— pin to tier —": "— fixar em nível —", + "Delete this layer from the config entirely": "Excluir esta camada completamente da configuração", + "No unpinned layers.": "Nenhuma camada não fixada.", + "Logic groups": "Grupos lógicos", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "Várias camadas desenhadas como um único bloco rotulado em um nível (p.ex. Self-Observability). Cada membro mantém a cor do próprio cubo.", + "+ add group": "+ adicionar grupo", + "level": "nível", + "icon": "ícone", + "member layers ({count})": "camadas membro ({count})", + "remove from group": "remover do grupo", + "+ add layer…": "+ adicionar camada…", + "A group needs at least one layer — pushing will be rejected until you add one.": "Um grupo precisa de pelo menos uma camada — a publicação será rejeitada até você adicionar uma.", + "No logic groups. Add one to cluster related layers into a single block.": "Nenhum grupo lógico. Adicione um para agrupar camadas relacionadas em um único bloco.", + "Service-map layers": "Camadas com mapa de serviços", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "Os templates destas camadas fornecem um mapa de serviços, então seus cubos são renderizados como um grafo de chamadas (e alimentam a hierarquia entre camadas). Somente leitura — é uma propriedade do template da camada, não uma configuração do 3D-map.", + "None reporting a service map.": "Nenhuma reportando um mapa de serviços.", + "Failover tier": "Nível de failover", + "The single catch-all: any layer no tier pins lands here.": "O único nível coringa: toda camada que nenhum nível fixa cai aqui.", + "Push 3D-map config to OAP": "Publicar a configuração do 3D-map no OAP", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "Esquerda = em produção no OAP (remote). Direita = seu rascunho local. Publicar substitui a cópia do OAP — o mapa passa a renderizá-la na próxima visita.", + "Push to OAP": "Publicar no OAP" } diff --git a/apps/ui/src/i18n/locales/zh-CN.json b/apps/ui/src/i18n/locales/zh-CN.json index 883551a..9ba66c1 100644 --- a/apps/ui/src/i18n/locales/zh-CN.json +++ b/apps/ui/src/i18n/locales/zh-CN.json @@ -1214,5 +1214,60 @@ "— pick a currently-running pod, or check that on-demand pod logs are enabled on OAP.": "— 请选择一个正在运行的 Pod,或确认 OAP 已启用按需 Pod 日志。", "Select a service to begin.": "请选择服务以开始。", "Select a pod to list its containers.": "选择一个 Pod 以列出其容器。", - "Select a container, then press Start to tail its logs.": "选择一个容器,然后点击“开始”以实时查看其日志。" + "Select a container, then press Start to tail its logs.": "选择一个容器,然后点击“开始”以实时查看其日志。", + "Dashboard setup · 3D Infra Map": "仪表板设置 · 3D Infra Map", + "3D Infrastructure Map": "3D 基础设施地图", + "Config for the {mapPath} view, published to OAP. Levels control the vertical stack; per-layer color + metrics drive each cube. Edits save to a {localDraft}; {checkDiffPush} publishes to OAP — the map renders the remote, with bundled defaults as fallback.": "{mapPath} 视图的配置,发布到 OAP。层级(level)控制垂直堆叠;每个 layer 的颜色与指标决定对应方块的呈现。修改会保存到{localDraft};{checkDiffPush}将其发布到 OAP —— 地图渲染的是远端版本,内置默认值作为兜底。", + "local draft in this browser": "当前浏览器中的本地草稿", + "editing: {source}": "正在编辑:{source}", + "Reset to": "重置为", + "Bundled equals OAP-live — nothing to reset to.": "内置版与 OAP 实时版本一致 —— 无需重置。", + "synced": "已同步", + "OAP has no copy of this config yet.": "OAP 还没有此配置的副本。", + "Saved local": "已保存到本地", + "Save local": "保存到本地", + "Couldn't load the 3D-map config — the BFF may be unreachable. Refresh the page to retry.": "无法加载 3D-map 配置 —— BFF 可能不可达。请刷新页面重试。", + "Loading config…": "正在加载配置…", + "Global layer filter": "全局 layer 过滤", + "The one top-level gate — a layer this JS regex excludes is off the map (it still shows below in Unpinned, tagged \"filtered out\"). Default {dotStar} admits all.": "唯一的顶级开关 —— 被这段 JS regex 排除的 layer 不会出现在地图上(它仍会显示在下方的“未固定”中,并标记为“filtered out”)。默认 {dotStar} 放行所有 layer。", + "Tiers & layers (top → bottom)": "层组与 layer(从上到下)", + "Every layer belongs to one tier — set it with the tier dropdown; order = vertical stacking.": "每个 layer 都归属于一个层组 —— 通过层组下拉框设置;顺序即垂直堆叠次序。", + "{count} in OAP": "OAP 中 {count} 个", + "{count} unpinned → fallback": "{count} 个未固定 → 兜底", + "filter layers…": "过滤 layer…", + "+ add tier": "+ 添加层组", + "{count} layers": "{count} 个 layer", + "mqe e.g. service_cpm": "mqe,例如 service_cpm", + "label": "标签", + "unit": "单位", + "remove metric": "移除指标", + "+ metric": "+ 指标", + "— unpinned —": "— 未固定 —", + "Remove from this tier (moves to Unpinned)": "从该层组移除(移至“未固定”)", + "No layers pinned — use a layer's tier dropdown to move one here.": "尚无固定的 layer —— 使用某个 layer 的层组下拉框将其移到这里。", + "Unpinned layers": "未固定的 layer", + "Pinned to no tier — they land on the failover tier ({failoverTier}). Pick a tier to pin one.": "未固定到任何层组 —— 它们会落到兜底层组({failoverTier})。选择一个层组即可固定。", + "falls to {via}": "落到 {via}", + "filtered out": "已过滤", + "— pin to tier —": "— 固定到层组 —", + "Delete this layer from the config entirely": "将该 layer 从配置中彻底删除", + "No unpinned layers.": "没有未固定的 layer。", + "Logic groups": "逻辑分组", + "Several layers drawn as one labelled block on a tier (e.g. Self-Observability). Each member keeps its own cube color.": "将多个 layer 在某个层组上绘制为一个带标签的整块(例如 Self-Observability)。每个成员仍保留各自方块的颜色。", + "+ add group": "+ 添加分组", + "level": "层级", + "icon": "图标", + "member layers ({count})": "成员 layer({count})", + "remove from group": "从分组移除", + "+ add layer…": "+ 添加 layer…", + "A group needs at least one layer — pushing will be rejected until you add one.": "分组至少需要一个 layer —— 添加之前推送会被拒绝。", + "No logic groups. Add one to cluster related layers into a single block.": "暂无逻辑分组。添加一个,即可将相关 layer 聚合为同一整块。", + "Service-map layers": "服务地图 layer", + "These layers' templates provide a service map, so their cubes render as a call graph (and seed the cross-layer hierarchy). Read-only — it's a layer-template property, not a 3D-map setting.": "这些 layer 的模板提供服务地图,因此其方块会渲染为调用关系图(并作为跨 layer 层级关系的起点)。只读 —— 这是 layer 模板的属性,而非 3D-map 的设置。", + "None reporting a service map.": "没有 layer 上报服务地图。", + "Failover tier": "兜底层组", + "The single catch-all: any layer no tier pins lands here.": "唯一的兜底层组:任何未被固定到具体层组的 layer 都会落到这里。", + "Push 3D-map config to OAP": "将 3D-map 配置推送至 OAP", + "Left = live on OAP (remote). Right = your local draft. Pushing replaces the OAP copy — the map renders it on the next visit.": "左侧 = OAP 上的线上版本(远端)。右侧 = 你的本地草稿。推送会替换 OAP 上的副本 —— 下次访问时地图便以其渲染。", + "Push to OAP": "推送至 OAP" }
