This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 2a1919eb5cf docs(blog): add Meet Horizon UI 15-17 (final three) (#883)
2a1919eb5cf is described below

commit 2a1919eb5cf58e5c2cf63841cae3ff82238c3cf0
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Jun 30 14:33:21 2026 +0800

    docs(blog): add Meet Horizon UI 15-17 (final three) (#883)
    
    * docs(blog): add Meet Horizon UI 15-17 (final three) — Customization, 
Localization, Getting Started
    
    Closes out the Meet Horizon UI series (Act 5 — make it yours & adopt):
    
    - 15/17 Customization: Config-Driven Layer Templates — the local-draft → 
preview → publish model, the widget canvas, add-a-layer, and export/import 
portability (4 figures).
    - 16/17 Localization in Eight Languages — server-side per-locale overlays, 
click-to-translate, the 8-language locale chip, and a localized dashboard (3 
figures).
    - 17/17 Getting Started & Migration — single env-driven container, the OAP 
10.x vs 11 compatibility matrix, and drop-in migration from an existing UI 
(code blocks + table, no figures).
    
    * docs(blog): add Chinese versions of Meet Horizon UI 15-17
    
    Chinese translations for the final three posts (Customization, 
Localization, Getting Started & Migration), under content/zh/ with the same 
slugs and figures as the English originals.
---
 .../index.md                                       |  49 ++++++++++++
 .../index.md                                       |  81 ++++++++++++++++++++
 .../index.md                                       |  42 +++++++++++
 .../index.md                                       |  51 +++++++++++++
 .../index.md                                       |  83 +++++++++++++++++++++
 .../index.md                                       |  44 +++++++++++
 .../p15-templates-01-layer-admin.webp              | Bin 0 -> 134742 bytes
 .../p15-templates-02-widget-editor.webp            | Bin 0 -> 153620 bytes
 .../horizon-0.7.0/p15-templates-03-diff-push.webp  | Bin 0 -> 131084 bytes
 .../horizon-0.7.0/p15-templates-04-overview.webp   | Bin 0 -> 148214 bytes
 .../horizon-0.7.0/p16-i18n-01-translations.webp    | Bin 0 -> 88782 bytes
 .../horizon-0.7.0/p16-i18n-02-locale-chip.webp     | Bin 0 -> 34406 bytes
 .../horizon-0.7.0/p16-i18n-03-localized.webp       | Bin 0 -> 149850 bytes
 13 files changed, 350 insertions(+)

diff --git 
a/content/blog/2026-06-30-horizon-ui-customization-and-templates/index.md 
b/content/blog/2026-06-30-horizon-ui-customization-and-templates/index.md
new file mode 100644
index 00000000000..55fb761736c
--- /dev/null
+++ b/content/blog/2026-06-30-horizon-ui-customization-and-templates/index.md
@@ -0,0 +1,49 @@
+---
+title: "Meet Horizon UI · 15/17: Customization — Config-Driven Layer Templates"
+date: 2026-06-30
+author: Sheng Wu
+description: "Part 15 of the Meet Horizon UI series: the whole console is 
driven by templates you can edit. Open any layer or overview as a template, 
change its widgets, components, and labels in a local draft, preview it, and 
publish it to OAP for the whole org — with diff-before-push and export/import."
+tags:
+  - Engineering
+  - Cloud Native
+---
+
+This is the fifteenth post in the [Meet Horizon 
UI](/blog/2026-06-21-skywalking-horizon-ui-introduction/) series, and it opens 
**Act 5 — make it yours & adopt**. Everything you've seen across this series — 
the per-layer dashboards, the overviews, the topology, the 3D map — is **not 
hard-coded**. It's all driven by **templates**, and Horizon ships the editor 
for them. This post is that editor: change any dashboard in a local draft, 
preview it, and publish it to OAP so the whole org sees it.
+
+## Everything is a template
+
+Open **Admin → Layer dashboards** and every layer the backend reports is there 
to configure. The editing model is the important part, and it's the same 
everywhere: **Save (local)** keeps your edits *in this browser only* — it never 
touches the server; the **live, shared version** lives on OAP; and the 
**bundled** JSON Horizon ships is just the seed and a read-only fallback. A 
status badge tells you where each layer stands — **synced**, **diverged** (the 
bundle differs from what's live on [...]
+
+A layer's setup is more than charts: you choose **which sub-views it exposes** 
(Service, Instances, Topology, Deployment, Traces, Logs, profiling…), its 
display **alias**, and even the **menu nouns** — the Istio mesh layer below 
renames "Instances" to *Sidecars*.
+
+![Figure 1: The Layer dashboards admin — the header with 
Save/Reset/Preview/Check-diff-and-push controls, and the layer setup showing 
component toggles, alias, and menu-label 
renaming.](/screenshots/horizon-0.7.0/p15-templates-01-layer-admin.webp)
+Figure 1: The Layer dashboards admin — every layer is a template. The header 
carries the whole model: **Save (local)** in your browser, **Reset to** / 
**Preview** the Bundled or Remote version, and **Check diff & push** to 
publish. Below, the layer chooses which sub-views it exposes, its alias, and 
renamed menu nouns (here *Sidecars* for instances).</br>
+
+## Edit the widgets
+
+Inside each scope, the dashboard is a **12-column grid** you edit directly — 
**drag a header to reorder**, **drag a corner to resize**, **+ Add widget** to 
add one. Click any widget and its editor drawer opens: the **MQE 
expression(s)** that feed it, the widget **type** (line / top / table / card…), 
**title**, **unit**, and a **Visible when** gate that hides the widget unless 
an expression has a value or an entity attribute matches.
+
+![Figure 2: The widget editor canvas — a 12-column grid of widgets with one 
selected, and the edit drawer showing id, title, tip, type, unit, MQE 
expressions, and a Visible-when 
gate.](/screenshots/horizon-0.7.0/p15-templates-02-widget-editor.webp)
+Figure 2: The widget canvas — a 12-column grid you drag to reorder and resize. 
Click a widget and its drawer opens: the **MQE expression(s)**, type, title, 
unit, and a **Visible when** gate.</br>
+
+## Publish, safely
+
+Nothing you do reaches other users until you publish — and publishing shows 
you exactly what will change first. **Check diff & push** opens a side-by-side 
diff (the live **remote** on the left, **your local** draft on the right); only 
then, on **Confirm push**, does the draft replace the live version for 
everyone. The button is enabled only when your local actually differs from 
remote.
+
+![Figure 3: The "Publish local to OAP?" diff modal — a side-by-side JSON diff 
with a widget title change highlighted (Traffic to "Traffic Name Changed"), and 
Cancel / Confirm push 
buttons.](/screenshots/horizon-0.7.0/p15-templates-03-diff-push.webp)
+Figure 3: Check diff & push — before a draft goes live for everyone, a 
side-by-side diff (remote left, your local right) shows exactly what changes. 
Here a widget title is renamed; nothing publishes until you **Confirm 
push**.</br>
+
+This is also how you **add a layer**. A layer the backend reports but Horizon 
ships no template for opens on a blank default — configure its components and 
widgets, **Save**, and that first push publishes the template to OAP. No 
per-layer JSON has to be shipped for a layer to be fully configurable.
+
+## Overviews, and portability
+
+The **Overview templates** editor is the same model on a 12-column canvas that 
mirrors the live grid (with mock data — the real page uses real data). **+ New 
dashboard** writes a local draft; **Delete** is a soft-disable (OAP has no hard 
delete). And every template admin page — layer dashboards, overviews, the 
3D-map config, translations — carries **Export** and **Import**: Export 
downloads the *in-use* version (what users actually render) as a JSON file for 
backup, sharing, or moving a  [...]
+
+![Figure 4: The Overview templates admin — the Services Dashboard on a 
12-column canvas with section headers, KPI tiles, a topology widget, and an 
active-alarms widget, plus the New-dashboard / export / import / draft 
controls.](/screenshots/horizon-0.7.0/p15-templates-04-overview.webp)
+Figure 4: Overview templates are the same model — a 12-column canvas with mock 
data, **+ New dashboard** as a local draft, and **Export / Import** to move a 
dashboard between OAP backends.</br>
+
+## Where it runs
+
+Editing and previewing are entirely **browser-local** — no OAP call happens 
until you publish. Publishing writes the template to OAP's **ui-template 
store** through the admin host, which arrives with OAP 11; the bundled JSON is 
a seed and read-only fallback, and the OAP-published version always wins at 
render time. Access is role-gated: publishing layer dashboards needs 
`dashboard:write`, overviews need `overview:write`. For the field reference — 
the template shapes, the widget types, an [...]
+
+Next up: **Localization** — how those same templates speak eight languages.
diff --git 
a/content/blog/2026-06-30-horizon-ui-getting-started-and-migration/index.md 
b/content/blog/2026-06-30-horizon-ui-getting-started-and-migration/index.md
new file mode 100644
index 00000000000..3842061bdfc
--- /dev/null
+++ b/content/blog/2026-06-30-horizon-ui-getting-started-and-migration/index.md
@@ -0,0 +1,81 @@
+---
+title: "Meet Horizon UI · 17/17: Getting Started & Migration"
+date: 2026-06-30
+author: Sheng Wu
+description: "The finale of the Meet Horizon UI series: install Horizon as a 
single env-driven container, point it at your OAP, and — if you're on the old 
UI — swap it in drop-in. Plus the OAP 10.x vs 11.x compatibility matrix: what 
works on the query port, and what needs OAP 11's admin host."
+tags:
+  - Release
+  - Community
+---
+
+This is the seventeenth and final post in the [Meet Horizon 
UI](/blog/2026-06-21-skywalking-horizon-ui-introduction/) series, closing **Act 
5 — make it yours & adopt**. Sixteen posts toured what Horizon shows, does, 
governs, and lets you customize. This one is the practical close: how to get it 
running, what it needs from your backend, and how to swap it in for an existing 
UI.
+
+## One image, one config
+
+Horizon ships as a **single container image** — the Vue UI and its Fastify BFF 
in one artifact — published to GHCR at `ghcr.io/apache/skywalking-horizon-ui`. 
There's one configuration file, `horizon.yaml`, and its defining trait is that 
**every field is an environment-variable token** (`${HORIZON_X:default}`) 
expanded *before* the YAML is parsed. So you can run the image with nothing 
mounted and set only the env vars you care about, or copy the file, edit it, 
and mount it.
+
+```yaml
+# horizon.yaml — every field is an env token: ${HORIZON_X:default},
+# expanded before YAML parsing. Run image-native with env vars, or mount this 
file.
+server:
+  host: "${HORIZON_SERVER_HOST:127.0.0.1}"   # the image sets 0.0.0.0
+  port: ${HORIZON_SERVER_PORT:8081}
+
+oap:
+  queryUrl:  "${HORIZON_OAP_QUERY_URL:http://127.0.0.1:12800}";          # 
GraphQL — required
+  adminUrl:  "${HORIZON_OAP_ADMIN_URL:http://127.0.0.1:17128}";          # 
admin REST — operate features
+  zipkinUrl: "${HORIZON_OAP_ZIPKIN_URL:http://127.0.0.1:9412/zipkin}";   # 
optional
+
+auth:
+  backend: "${HORIZON_AUTH_BACKEND:local}"     # local | ldap
+  local:
+    users: ${HORIZON_AUTH_LOCAL_USERS:[]}      # JSON; hash with: pnpm 
--filter bff cli:hash
+
+session:
+  ttlMinutes: ${HORIZON_SESSION_TTL_MINUTES:60}
+  cookieSecure: ${HORIZON_SESSION_COOKIE_SECURE:false}   # set true behind 
HTTPS
+```
+
+Pointing it at an existing OAP is three URLs. A container run is then just env 
vars over the image:
+
+```bash
+docker run -d --name horizon -p 8081:8081 \
+  -e HORIZON_SERVER_HOST=0.0.0.0 \
+  -e HORIZON_OAP_QUERY_URL=http://oap:12800 \
+  -e HORIZON_OAP_ADMIN_URL=http://oap:17128 \
+  -e 
HORIZON_AUTH_LOCAL_USERS='[{"username":"admin","passwordHash":"$argon2id$...","roles":["admin"]}]'
 \
+  ghcr.io/apache/skywalking-horizon-ui:<version>
+```
+
+Two things worth knowing on the first boot. There is **no default 
admin/admin** — with the `local` backend and no users (or `ldap` with no group 
mappings) the BFF starts but no one can sign in until you configure it; you 
generate password hashes with `pnpm --filter bff cli:hash`. And for 
reproducible deploys, **pin to a specific release tag or commit SHA** rather 
than a rolling tag.
+
+## What works on which OAP
+
+Horizon is built **natively against OAP 11.x**, and it **partially supports 
OAP 10.x**. The split is clean and maps to the two halves of this series: the 
**observe** data-plane runs against OAP's query port and works on both lines; 
the **operate** surfaces live on OAP's admin port, which only 11.x runs.
+
+| Surface | OAP 10.x | OAP 11.x | Port |
+|---|:---:|:---:|---|
+| Layer dashboards, overviews, topology | ✓ | ✓ | query `:12800` |
+| Traces (native + Zipkin), logs, alarms (read), profiling | ✓ | ✓ | query 
`:12800` (+ `:9412` for Zipkin) |
+| Inspect, DSL Management, Live Debugger, Alarm-rule editor | — | ✓ | admin 
`:17128` |
+| Cluster Status → Admin pane, template & translation publishing | — | ✓ | 
admin `:17128` |
+
+Crucially, Horizon **never reads the OAP version number** — it detects each 
capability by probing for the module and GraphQL fields it needs, hides the 
sidebar entries it can't back, and falls admin pages back to read-only when the 
admin port is dark. So if you only need triage (dashboards, alarms, traces, 
logs), a 10.x backend is enough; anything in the operate half needs 11.x with 
its admin modules (`admin-server`, `receiver-runtime-rule`, `dsl-debugging`, 
`inspect`) enabled.
+
+## Swapping in for an existing UI
+
+If you run the previous-generation UI today, the migration is **drop-in**. 
Horizon speaks the **same OAP GraphQL query protocol and the same MQE 
language**, so there are **no agent changes and no backend changes** — you 
point Horizon at the OAP you already run. The clean cutover is to run both side 
by side, let people use Horizon against live data, and retire the old UI when 
you're ready. Everything Horizon adds on top — its 
[governance](/blog/2026-06-30-horizon-ui-access-control-and-sec [...]
+
+## Verify and operate
+
+Confirm the connection from the [Cluster 
Status](/blog/2026-06-30-horizon-ui-platform-introspection/) page: the topbar 
carries the OAP build-version chip, and the Query pane shows version, timezone, 
and a health score; the Admin and Zipkin panes light up to match what your 
backend exposes. A few operational notes for production:
+
+- **Persist state.** Admin-edited templates land under 
`/app/bundled_templates` and the audit, setup, and alarm files under `/data`; 
mount durable volumes there or those edits are ephemeral and vanish with the 
container.
+- **Sessions are per-BFF.** They live in each node's memory with no shared 
store, so multiple replicas need sticky sessions (otherwise a failover means 
re-login).
+- **Probes and TLS.** `/api/health` is public with no OAP dependency — wire it 
to your container probes — and set `session.cookieSecure: true` behind HTTPS.
+
+For the full reference — the [container 
image](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/setup/container-image/),
 the 
[`horizon.yaml`](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/setup/horizon-yaml/)
 field-by-field, and the [OAP compatibility 
matrix](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/compatibility/oap-version/)
 — see the docs.
+
+## That's the series
+
+Seventeen posts, five acts: we **oriented** in the console, **observed** 
services across layers — metrics, traces, logs, topology, profiling — 
**operated** on the backend with runtime rules, live debugging, and inspection, 
**governed** it with access control, and finally made it **ours** with 
templates, eight languages, and a clean install. The best next step is to stop 
reading and start clicking: the public demo at 
[demo.skywalking.apache.org](https://demo.skywalking.apache.org) runs Ho [...]
diff --git a/content/blog/2026-06-30-horizon-ui-localization-i18n/index.md 
b/content/blog/2026-06-30-horizon-ui-localization-i18n/index.md
new file mode 100644
index 00000000000..26830d6f7fc
--- /dev/null
+++ b/content/blog/2026-06-30-horizon-ui-localization-i18n/index.md
@@ -0,0 +1,42 @@
+---
+title: "Meet Horizon UI · 16/17: Localization in Eight Languages"
+date: 2026-06-30
+author: Sheng Wu
+description: "Part 16 of the Meet Horizon UI series: Horizon speaks eight 
languages, not by re-translating on every render but as server-side overlays 
merged onto the same templates. Pick a language from the topbar, or click any 
widget on the Translations admin to translate it — while every value OAP 
supplies stays verbatim."
+tags:
+  - Engineering
+  - Community
+---
+
+This is the sixteenth post in the [Meet Horizon 
UI](/blog/2026-06-21-skywalking-horizon-ui-introduction/) series, still in 
**Act 5 — make it yours & adopt**. The [previous 
post](/blog/2026-06-30-horizon-ui-customization-and-templates/) showed that the 
whole console is driven by templates. Localization builds straight on that: 
Horizon speaks **eight languages**, and a translation is just an **overlay on 
the same template** — not a fork, and not a re-translation on every render.
+
+## Translations are overlays, resolved once on the server
+
+Each non-English locale is an **overlay catalog** layered onto the English 
**source template**. When the BFF serves a template, it reads your chosen 
locale (from a request header), **merges the overlay onto the source once**, 
and returns the localized template — translation is resolved a single time on 
the server, not per chart at mount. The merge is forgiving: it deep-merges onto 
the source, and any leaf the overlay doesn't translate **falls back to 
English**, so a half-translated catal [...]
+
+There's a deliberate line about *what* gets translated. The **chrome** does — 
widget titles, tips, labels, menu aliases. But **data OAP supplies never 
does**: service, instance, and endpoint names, tags, log lines, alarm-rule 
names, and span operations render exactly as the backend reports them. Product 
and protocol names (SkyWalking, Kubernetes, Envoy), MQE expressions, and codes 
like RPM / P95 / SLA stay verbatim too.
+
+## Click to translate
+
+You don't edit JSON to localize. **Admin → Translations** gives you a live 
preview in your target language: pick the template and the language, **click 
any widget**, and a panel opens showing each translatable field — the English 
source above, your translation below. A progress counter tracks how far along 
each language is, and the same draft model from the templates post applies: 
**Stage local** keeps it in your browser, **Check diff & push** publishes the 
overlay to OAP, and **Export / [...]
+
+![Figure 1: The Translations admin translating to French — a floating panel 
with EN source vs target for a widget's title and tip, while RPM / P95 / SLA 
labels stay verbatim, over a live French preview of the 
dashboard.](/screenshots/horizon-0.7.0/p16-i18n-01-translations.webp)
+Figure 1: The Translations admin — pick a language (here Français), click any 
widget in the live preview, and type the translation. The title and tip 
translate; codes like `RPM` / `P95` / `SLA` stay verbatim — and so does every 
value OAP supplies.</br>
+
+## Eight languages, picked per device
+
+The set is eight first-class locales: **English** (the source) plus **Deutsch, 
Español, Français, 日本語, 한국어, Português, 中文 (简体)**. You switch from the 
**language chip** in the topbar — on every page, including the pre-auth login — 
and the choice persists per device.
+
+![Figure 2: The topbar language menu open, listing English at the top, then 
Deutsch, Español, Français, Japanese, Korean, Português, and 
Chinese.](/screenshots/horizon-0.7.0/p16-i18n-02-locale-chip.webp)
+Figure 2: The topbar language chip — eight first-class languages (English plus 
Deutsch, Español, Français, 日本語, 한국어, Português, 中文), picked per device on 
every page including the login.</br>
+
+Switch the language and the whole console follows. Here is the General Service 
dashboard in Chinese — the sidebar, tabs, and widget titles are localized, 
while the API paths, service names, and metric values stay exactly as OAP 
reports them. Notice that a few widget titles are still in English: those 
leaves simply aren't translated yet, so they fall back to the source — exactly 
the graceful degradation the overlay model is built for.
+
+![Figure 3: The General Service dashboard rendered in Chinese — localized 
sidebar (概览, 服务仪表板, 告警, 通用服务), localized widget titles (流量, 错误率), with API 
paths and metric values 
unchanged.](/screenshots/horizon-0.7.0/p16-i18n-03-localized.webp)
+Figure 3: The same General Service dashboard in Chinese — sidebar, tabs, and 
widget titles localized, while service names, API paths, and metric values stay 
exactly as OAP reports them. Untranslated leaves fall back to English.</br>
+
+## Where it runs
+
+Locale resolution happens **BFF-side**, so it works on any OAP. Publishing a 
translation writes a sibling overlay to OAP's template store through the admin 
host (OAP 11), gated on `overview:write`; the eight UI-chrome message catalogs 
are bundled and switch synchronously with no network fetch. A CI gate 
(`i18n:validate`) keeps every source template paired with an overlay per locale 
so nothing drifts. For the field reference — the translatable-field rules and 
the add-a-language recipe — s [...]
+
+Next, the series closes with **Getting Started & Migration** — installing 
Horizon and swapping it in for an existing UI.
diff --git 
a/content/zh/2026-06-30-horizon-ui-customization-and-templates/index.md 
b/content/zh/2026-06-30-horizon-ui-customization-and-templates/index.md
new file mode 100644
index 00000000000..c7529967e81
--- /dev/null
+++ b/content/zh/2026-06-30-horizon-ui-customization-and-templates/index.md
@@ -0,0 +1,51 @@
+---
+title: "认识 Horizon UI · 15/17:用模板定制控制台"
+date: 2026-06-30
+author: 吴晟
+description: "Horizon UI 系列第十五篇:整个控制台都由可编辑模板驱动。你可以把任意 layer 或 overview 
打开成模板,在本地草稿里调整组件、widget 和文案,预览后发布到 OAP 给整个组织使用,并在发布前查看差异,也可以导出和导入。"
+tags:
+  - Engineering
+  - Cloud Native
+---
+
+*译自英文原文:[Meet Horizon UI · 15/17: Customization — Config-Driven Layer 
Templates](/blog/2026-06-30-horizon-ui-customization-and-templates/)。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第十五篇,也开启第五幕 **make it yours & adopt**。这个系列里你看到的 per-layer 
dashboard、overview、topology、3D map,都**不是写死在代码里**。它们由一套套 **template** 驱动,Horizon 
也把编辑这些 template 的工具做进了控制台。这篇讲的就是这个编辑器:在本地草稿里修改任意 dashboard,先预览,再发布到 
OAP,让整个组织都看到同一个版本。
+
+## 一切都是模板
+
+打开 **Admin → Layer dashboards**,后端上报的每个 layer 
都可以配置。这里最重要的是编辑模型,而且所有模板编辑器都遵循同一套模型:**Save (local)** 
只把修改保存在当前浏览器里,不会碰服务端;真正被所有人看到的**共享版本**保存在 OAP;Horizon 随版本发布的 **bundled** JSON 
只是种子模板和只读 fallback。状态 badge 会告诉你每个 layer 当前处在哪种状态:**synced** 
表示本地和远端一致;**diverged** 表示 bundled 和 OAP 上的 live 版本不同,渲染时以 OAP 为准;**local** 
表示当前浏览器里有未发布的编辑。**Reset to ▾** 可以把 Bundled 或 Remote 重新加载到编辑器;**Preview ▾** 则会用 
Local、Bundled 或 Remote 版本打开真实页面预览。
+
+一个 layer 的配置不只是图表。你还可以选择它暴露哪些 **sub-view**,比如 
Service、Instances、Topology、Deployment、Traces、Logs、profiling;可以设置展示用的 
**alias**,甚至可以改菜单里的名词。下面的 Istio mesh layer 就把 “Instances” 改成了 *Sidecars*。
+
+![图 1:Layer dashboards 管理页:顶部有 Save/Reset/Preview/Check-diff-and-push 控制,下面是 
layer 配置,包括组件开关、alias 
和菜单文案重命名。](/screenshots/horizon-0.7.0/p15-templates-01-layer-admin.webp)
+图 1:Layer dashboards 管理页:每个 layer 都是一个 template。顶部操作区体现了完整模型:**Save (local)** 
保存在浏览器里,**Reset to** / **Preview** Bundled 或 Remote 版本,最后用 **Check diff & 
push** 发布。下面可以选择这个 layer 暴露哪些 sub-view、设置 alias,并重命名菜单名词,比如把 instances 叫作 
*Sidecars*。</br>
+
+## 编辑 Widget
+
+每个 scope 里的 dashboard 都是一个可以直接编辑的 **12 列网格**:拖动 header 可以调整顺序,拖动角落可以改变大小,点 **+ 
Add widget** 可以新增 widget。点击任意 widget,会打开它的编辑抽屉:这里可以改驱动它的 **MQE 
expression**、widget **type**(line / top / table / card 
等)、**title**、**unit**,还可以设置 **Visible when** 条件,让某个表达式有值或者某个实体属性匹配时才显示这个 widget。
+
+![图 2:Widget 编辑画布:12 列 widget 网格,选中一个 widget 后右侧抽屉展示 
id、title、tip、type、unit、MQE expressions 和 Visible-when 
条件。](/screenshots/horizon-0.7.0/p15-templates-02-widget-editor.webp)
+图 2:Widget 画布:一个可以拖拽排序、调整大小的 12 列网格。点中 widget 后会打开抽屉,编辑 **MQE 
expression**、type、title、unit 和 **Visible when** 条件。</br>
+
+## 发布前先看差异
+
+在你发布之前,本地修改不会影响其他用户;而发布之前,Horizon 会先让你看清楚到底改了什么。点击 **Check diff & push** 
会打开左右对照的 diff:左侧是当前 live 的 **remote** 版本,右侧是**你的 local** 草稿。只有继续点 **Confirm 
push**,本地草稿才会替换 OAP 上的 live 版本,所有用户才会看到变化。只有 local 和 remote 真的不一样时,这个按钮才会启用。
+
+![图 3:“Publish local to OAP?” diff 弹窗:左右对照 JSON diff,高亮了 widget 标题从 Traffic 改为 
“Traffic Name Changed”,底部有 Cancel / Confirm 
push。](/screenshots/horizon-0.7.0/p15-templates-03-diff-push.webp)
+图 3:Check diff & push:草稿发布给所有人之前,先用左右对照 diff 展示变化(remote 在左,本地草稿在右)。这里改了一个 
widget title;只有点 **Confirm push** 才会真正发布。</br>
+
+新增 layer 也走这套流程。后端已经上报、但 Horizon 没有内置模板的 layer,会先打开一个空白默认模板;你配置它的 components 和 
widgets,**Save** 后第一次 push 就会把模板发布到 OAP。一个 layer 不需要先随版本带上 JSON 文件,才能变成完整可配置的页面。
+
+## Overview 与迁移复用
+
+**Overview templates** 编辑器也使用同样的模型:一个 12 列画布,布局和线上页面一致,只是编辑器里使用 mock 
data,真实页面会使用真实数据。**+ New dashboard** 会写出一个本地草稿;**Delete** 是软禁用,因为 OAP 目前没有 hard 
delete。所有模板管理页也都有 **Export** 和 **Import**,包括 layer dashboards、overviews、3D map 
config 和 translations:Export 会把当前实际使用的版本下载成 JSON 文件,便于备份、共享,或者把一个 dashboard 
搬到另一个 OAP;Import 读取 JSON 文件、校验,然后作为**本地草稿**加载进来,供你预览和发布。Import 不会直接写 OAP。
+
+![图 4:Overview templates 管理页:Services Dashboard 位于 12 列画布上,包含 section 
header、KPI tiles、topology widget 和 active-alarms widget,以及 New-dashboard / 
export / import / draft 
控制。](/screenshots/horizon-0.7.0/p15-templates-04-overview.webp)
+图 4:Overview templates 使用同一套模型:12 列画布、mock data、作为本地草稿创建的 **+ New 
dashboard**,以及用 **Export / Import** 在不同 OAP 后端之间迁移 dashboard。</br>
+
+## 它在哪里运行
+
+编辑和预览完全发生在**浏览器本地**;只有发布时才会调用 OAP。发布会通过 OAP 11 提供的 admin host,把 template 写入 
OAP 的 **ui-template store**。Bundled JSON 是种子模板和只读 fallback;只要 OAP 上发布过版本,渲染时就以 
OAP 版本为准。权限也按角色控制:发布 layer dashboards 需要 `dashboard:write`,发布 overviews 需要 
`overview:write`。字段参考,包括 template 结构、widget 类型和新增 layer 的流程,可以看 [Layer 
templates](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/customization/layer-templates/)、[Overview
 templates](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/cus 
[...]
+
+下一篇:[八种语言的本地化](/zh/2026-06-30-horizon-ui-localization-i18n/):同一套 template 
如何支持八种语言。
diff --git 
a/content/zh/2026-06-30-horizon-ui-getting-started-and-migration/index.md 
b/content/zh/2026-06-30-horizon-ui-getting-started-and-migration/index.md
new file mode 100644
index 00000000000..915f590dc9e
--- /dev/null
+++ b/content/zh/2026-06-30-horizon-ui-getting-started-and-migration/index.md
@@ -0,0 +1,83 @@
+---
+title: "认识 Horizon UI · 17/17:安装与迁移"
+date: 2026-06-30
+author: 吴晟
+description: "Meet Horizon UI 系列收官篇:用一个环境变量驱动的容器启动 Horizon,指向已有 OAP;如果你还在使用上一代 
UI,也可以把 Horizon 平滑替换进去。文中还说明 OAP 10.x 和 11.x 的兼容边界:哪些功能只需要 query port,哪些需要 OAP 
11 的 admin host。"
+tags:
+  - Release
+  - Community
+---
+
+*译自英文原文:[Meet Horizon UI · 17/17: Getting Started & 
Migration](/blog/2026-06-30-horizon-ui-getting-started-and-migration/)。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第十七篇,也是最后一篇,为第五幕 **make it yours & adopt** 收尾。前十六篇已经讲过 Horizon 
能展示什么、能操作什么、如何治理,以及如何定制。这篇回到最实际的问题:怎样把它跑起来,它对后端有什么要求,以及怎样替换掉现有 UI。
+
+## 一个镜像,一份配置
+
+Horizon 以**单个容器镜像**发布:Vue UI 和 Fastify BFF 打在同一个 artifact 里,镜像位于 
GHCR:`ghcr.io/apache/skywalking-horizon-ui`。配置文件只有一个:`horizon.yaml`。它最重要的特点是,**每个字段都是环境变量
 token**(`${HORIZON_X:default}`),并且会在 YAML 
解析之前展开。所以你可以不挂载任何文件,只用环境变量启动镜像;也可以复制这份文件,修改后挂载进去。
+
+```yaml
+# horizon.yaml — 每个字段都是 env token: ${HORIZON_X:default}
+# 会在 YAML 解析前展开。可以直接用环境变量启动镜像,也可以挂载这份文件。
+server:
+  host: "${HORIZON_SERVER_HOST:127.0.0.1}"   # 镜像内默认设置为 0.0.0.0
+  port: ${HORIZON_SERVER_PORT:8081}
+
+oap:
+  queryUrl:  "${HORIZON_OAP_QUERY_URL:http://127.0.0.1:12800}";          # 
GraphQL,必需
+  adminUrl:  "${HORIZON_OAP_ADMIN_URL:http://127.0.0.1:17128}";          # 
admin REST,operate 功能使用
+  zipkinUrl: "${HORIZON_OAP_ZIPKIN_URL:http://127.0.0.1:9412/zipkin}";   # 可选
+
+auth:
+  backend: "${HORIZON_AUTH_BACKEND:local}"     # local | ldap
+  local:
+    users: ${HORIZON_AUTH_LOCAL_USERS:[]}      # JSON;用 pnpm --filter bff 
cli:hash 生成 hash
+
+session:
+  ttlMinutes: ${HORIZON_SESSION_TTL_MINUTES:60}
+  cookieSecure: ${HORIZON_SESSION_COOKIE_SECURE:false}   # HTTPS 后面应设为 true
+```
+
+把 Horizon 指向已有 OAP,只需要三个 URL。容器启动命令就是给镜像加上环境变量:
+
+```bash
+docker run -d --name horizon -p 8081:8081 \
+  -e HORIZON_SERVER_HOST=0.0.0.0 \
+  -e HORIZON_OAP_QUERY_URL=http://oap:12800 \
+  -e HORIZON_OAP_ADMIN_URL=http://oap:17128 \
+  -e 
HORIZON_AUTH_LOCAL_USERS='[{"username":"admin","passwordHash":"$argon2id$...","roles":["admin"]}]'
 \
+  ghcr.io/apache/skywalking-horizon-ui:<version>
+```
+
+第一次启动时有两点需要注意。第一,Horizon **没有默认的 admin/admin**。使用 `local` 后端但没有配置用户,或者使用 
`ldap` 但没有配置 group mapping 时,BFF 会启动,但没人能登录;密码哈希可以用 `pnpm --filter bff 
cli:hash` 生成。第二,为了让部署可复现,生产环境应该固定到明确的 release tag 或 commit SHA,而不是使用滚动标签。
+
+## 哪些功能需要哪个 OAP
+
+Horizon **主要面向 OAP 11.x 构建**,同时**部分支持 OAP 10.x**。边界很清楚,也对应这个系列的两半:**observe** 
数据面走 OAP query port,两条版本线都能用;**operate** 页面依赖 OAP admin port,只有 11.x 提供。
+
+| 功能 | OAP 10.x | OAP 11.x | 端口 |
+|---|:---:|:---:|---|
+| Layer dashboards、overviews、topology | ✓ | ✓ | query `:12800` |
+| Traces(native + Zipkin)、logs、alarms(read)、profiling | ✓ | ✓ | query 
`:12800`(Zipkin 使用 `:9412`) |
+| Inspect、DSL Management、Live Debugger、Alarm-rule editor | — | ✓ | admin 
`:17128` |
+| Cluster Status → Admin pane、template 和 translation 发布 | — | ✓ | admin 
`:17128` |
+
+关键点是,Horizon **不会靠读取 OAP 版本号来判断能力**。它会探测所需 module 和 GraphQL 
field:能支撑的功能才显示侧边栏入口;admin port 不可用时,admin 页面会降级成只读或显示明确提示。所以如果你只需要 triage,也就是 
dashboard、alarm、trace、log,OAP 10.x 就够了;operate 这半边需要 OAP 11.x,并启用对应 admin 
modules(`admin-server`、`receiver-runtime-rule`、`dsl-debugging`、`inspect`)。
+
+## 替换现有 UI
+
+如果你现在运行的是上一代 UI,迁移到 Horizon 可以做成**平滑替换**。Horizon 使用**同一套 OAP GraphQL query 
protocol 和同一套 MQE 语言**,所以**不需要改 agent,也不需要改后端**;只要把 Horizon 指向正在运行的 OAP 
即可。更稳妥的切换方式是先让两个 UI 并行运行,让大家用 Horizon 访问 live data,等准备好了再下线旧 UI。Horizon 
额外提供的东西,比如 
[governance](/zh/2026-06-30-horizon-ui-access-control-and-security/)(RBAC、auth、audit、themes)和
 [config-driven 
templates](/zh/2026-06-30-horizon-ui-customization-and-templates/),都是 Horizon 
自己在 BFF 里叠加的能力,和 OAP 本身相互独立。
+
+## 验证与生产运行
+
+可以从 [Cluster Status](/zh/2026-06-30-horizon-ui-platform-introspection/) 
页面确认连接情况:topbar 会显示 OAP build-version chip,Query 面板会展示版本、时区和健康评分;Admin 和 Zipkin 
面板则会根据后端实际暴露的能力亮起。生产环境还要注意几件事:
+
+- **持久化状态。** 管理员编辑的 template 会落在 `/app/bundled_templates`,audit、setup 和 alarm 
文件会落在 `/data`;这两个路径应该挂载持久化 volume,否则容器重建后这些修改会丢失。
+- **Session 按 BFF 节点保存。** Session 保存在每个节点内存里,没有共享存储;多副本部署需要 sticky 
sessions,否则故障切换后用户要重新登录。
+- **探针和 TLS。** `/api/health` 是公开接口,不依赖 OAP,适合作为容器探针;如果部署在 HTTPS 后面,记得把 
`session.cookieSecure` 设为 `true`。
+
+完整参考可以看文档:[container 
image](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/setup/container-image/)、[`horizon.yaml`](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/setup/horizon-yaml/)
 字段说明,以及 [OAP compatibility 
matrix](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/compatibility/oap-version/)。
+
+## 系列到这里结束
+
+十七篇,五幕:我们先在控制台里**建立方向感**,然后跨 layer **观察**服务的 metrics、traces、logs、topology 和 
profiling;接着用 runtime rules、live debugging 和 inspect **操作**后端;再通过 access 
control **治理**控制台;最后用 templates、八种语言和清晰的安装路径,把它变成自己的工具。下一步最好不是继续读,而是直接点开试试:公开 
demo [demo.skywalking.apache.org](https://demo.skywalking.apache.org) 已经把 
Horizon 接到了一套 live SkyWalking 后端上。谢谢一路读到这里。
diff --git a/content/zh/2026-06-30-horizon-ui-localization-i18n/index.md 
b/content/zh/2026-06-30-horizon-ui-localization-i18n/index.md
new file mode 100644
index 00000000000..5305dad9f8e
--- /dev/null
+++ b/content/zh/2026-06-30-horizon-ui-localization-i18n/index.md
@@ -0,0 +1,44 @@
+---
+title: "认识 Horizon UI · 16/17:八种语言的本地化"
+date: 2026-06-30
+author: 吴晟
+description: "Horizon UI 系列第十六篇:Horizon 支持八种语言。本地化不是每次渲染时重新翻译,而是在服务端把翻译 
overlay 合并到同一套 template 上;用户可以从顶栏切换语言,也可以在 Translations 管理页点选任意 widget 直接补翻译,而 
OAP 返回的数据始终保持原样。"
+tags:
+  - Engineering
+  - Community
+---
+
+*译自英文原文:[Meet Horizon UI · 16/17: Localization in Eight 
Languages](/blog/2026-06-30-horizon-ui-localization-i18n/)。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第十六篇,仍然属于第五幕 **make it yours & adopt**。上一篇讲到,整个控制台都由 template 
驱动。本地化也建立在这个基础上:Horizon 支持**八种语言**,每种翻译都是覆盖在同一套 template 上的一层 **overlay**。它不是 
fork 出一份 dashboard,也不是每次渲染图表时重新翻译。
+
+## 翻译是 overlay,在服务端合并一次
+
+每个非英语 locale 都是一份 **overlay catalog**,覆盖在英语 **source template** 上。BFF 返回 
template 时,会根据请求头里的语言选择,把 overlay **合并到 source 上一次**,再返回本地化后的 
template。翻译只在服务端解析一次,不会在每个图表加载时再处理。合并逻辑也比较宽容:overlay 会 deep-merge 到 source 
上;没有翻译到的 leaf 会**回退到英语**,所以一份只翻了一半的 catalog 也是有效的。新增或修正语言,本质上就是编辑 overlay,不需要改 
source dashboard。
+
+这里有一条刻意划清的边界:哪些内容会翻译,哪些不会。会翻译的是界面 **chrome**,例如 widget title、tip、label、menu 
alias。但 **OAP 提供的数据不会翻译**:service、instance、endpoint 名称,tags,log line,alarm rule 
name,span operation,都会按后端返回的原样展示。SkyWalking、Kubernetes、Envoy 这类产品或协议名,MQE 
表达式,以及 RPM / P95 / SLA 这样的代码和缩写,也保持原样。
+
+## 点一下就能翻译
+
+本地化不需要手写 JSON。**Admin → Translations** 会给出目标语言的 live preview:选择 template 和 
language,**点击任意 widget**,右侧面板会列出可以翻译的字段:上方是英语 
source,下方是你的翻译。每种语言都有进度计数,模板那篇提到的草稿模型也同样适用:**Stage local** 把改动保存在浏览器里,**Check 
diff & push** 把 overlay 发布到 OAP,**Export / Import** 可以把某种语言的翻译作为 JSON 文件迁移。
+
+![图 1:Translations 管理页正在翻译法语:浮动面板中展示某个 widget 的 EN source 和目标语言字段;实时法语预览中,RPM 
/ P95 / SLA 标签保持原样。](/screenshots/horizon-0.7.0/p16-i18n-01-translations.webp)
+图 1:Translations 管理页:选择语言(这里是 Français),在 live preview 中点击任意 
widget,就可以输入翻译。title 和 tip 会翻译;`RPM` / `P95` / `SLA` 这类代码保持原样,OAP 
提供的所有值也保持原样。</br>
+
+## 八种语言,按设备选择
+
+Horizon 正式支持八种 locale:**English** 是 source,另外还有 
**Deutsch、Español、Français、日本語、한국어、Português、中文(简体)**。你可以从顶栏的 **language chip** 
切换语言;所有页面都支持,包括登录前的 login 页面。选择会按当前设备持久化。
+
+![图 2:顶栏 language menu 展开,列表从 English 开始,然后是 
Deutsch、Español、Français、Japanese、Korean、Português 和 
Chinese。](/screenshots/horizon-0.7.0/p16-i18n-02-locale-chip.webp)
+图 2:顶栏 language chip:八种正式支持的语言,English 加 
Deutsch、Español、Français、日本語、한국어、Português、中文。每个设备可以独立选择,登录页也能切换。</br>
+
+切换语言后,整个控制台都会跟着变。下面是中文里的 General Service dashboard:sidebar、tabs 和 widget title 
都已经本地化,而 API path、service name 和 metric value 仍然按 OAP 返回值展示。你也会看到少数 widget 
title 还是英语:那几个 leaf 还没有翻译,所以自然回退到 source。这正是 overlay 模型想要的降级方式。
+
+![图 3:以中文渲染的 General Service dashboard:sidebar(概览、服务仪表板、告警、通用服务)和 widget 
title(流量、错误率)已本地化,API paths 和 metric values 
保持不变。](/screenshots/horizon-0.7.0/p16-i18n-03-localized.webp)
+图 3:同一个 General Service dashboard 的中文版本:sidebar、tabs 和 widget title 
会本地化;service name、API path 和 metric value 仍然按 OAP 返回值展示。未翻译的 leaf 会回退到英语。</br>
+
+## 它在哪里运行
+
+Locale 解析发生在 **BFF 侧**,所以它兼容任意 OAP。发布翻译时,会通过 OAP 11 的 admin host,把 sibling 
overlay 写入 OAP 的 template store;权限由 `overview:write` 控制。八种 UI chrome message 
catalog 是随包内置的,切换时同步生效,不需要额外网络请求。CI 里的 `i18n:validate` 会检查每个 source template 
都有对应 locale 的 overlay,避免 source 和翻译脱节。字段参考,包括哪些字段可翻译、如何新增语言,可以看 [i18n 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/customization/i18n/)。
+
+下一篇,也就是这个系列的收官篇:[安装与迁移](/zh/2026-06-30-horizon-ui-getting-started-and-migration/):安装
 Horizon,并把它替换到现有 UI 的位置。
diff --git a/static/screenshots/horizon-0.7.0/p15-templates-01-layer-admin.webp 
b/static/screenshots/horizon-0.7.0/p15-templates-01-layer-admin.webp
new file mode 100644
index 00000000000..0ed924fd492
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p15-templates-01-layer-admin.webp differ
diff --git 
a/static/screenshots/horizon-0.7.0/p15-templates-02-widget-editor.webp 
b/static/screenshots/horizon-0.7.0/p15-templates-02-widget-editor.webp
new file mode 100644
index 00000000000..19fb755489a
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p15-templates-02-widget-editor.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p15-templates-03-diff-push.webp 
b/static/screenshots/horizon-0.7.0/p15-templates-03-diff-push.webp
new file mode 100644
index 00000000000..d76ab766c9f
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p15-templates-03-diff-push.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p15-templates-04-overview.webp 
b/static/screenshots/horizon-0.7.0/p15-templates-04-overview.webp
new file mode 100644
index 00000000000..b9bf36cb8e6
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p15-templates-04-overview.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p16-i18n-01-translations.webp 
b/static/screenshots/horizon-0.7.0/p16-i18n-01-translations.webp
new file mode 100644
index 00000000000..5f1be16286d
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p16-i18n-01-translations.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p16-i18n-02-locale-chip.webp 
b/static/screenshots/horizon-0.7.0/p16-i18n-02-locale-chip.webp
new file mode 100644
index 00000000000..f9f55bafadb
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p16-i18n-02-locale-chip.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p16-i18n-03-localized.webp 
b/static/screenshots/horizon-0.7.0/p16-i18n-03-localized.webp
new file mode 100644
index 00000000000..91573310937
Binary files /dev/null and 
b/static/screenshots/horizon-0.7.0/p16-i18n-03-localized.webp differ


Reply via email to