Lokalizace OpenClaw do ruštiny prostřednictvím proxy bez změny zdrojového kódu
Vývojáři OpenClaw nepředviděli infrastrukturu pro i18n: řetězce jsou pevně zakódované v JSX komponentách bez použití react-intl nebo i18next. Fork s ručním překladem je neefektivní kvůli denním aktualizacím. Řešením je transparentní proxy mezi nginx a aplikací, která vkládá skript překladu do HTML odpovědí.
Schéma provozu:
- nginx (port 443) → proxy (port 18790) → OpenClaw (port 18789).
Proxy upravuje pouze HTML, zachovává logiku aplikace. WebSocket spojení pro chat se přesměruje beze změn.
Server na Node.js (~150 řádků) používá http-proxy pro zachycení odpovědí. Klíčovým momentem je nahrazení res.write a res.end pro vyrovnávací paměť těla odpovědi.
import http from "node:http";
import httpProxy from "http-proxy";
const TARGET = process.env.TARGET_ORIGIN || "http://127.0.0.1:18789";
const proxy = httpProxy.createProxyServer({ target: TARGET, ws: true });
const server = http.createServer((req, res) => {
if (req.url === "/ru-overlay.js") {
// poskytneme skript překladu
res.writeHead(200, { "Content-Type": "application/javascript" });
res.end(overlayScript);
return;
}
// zachytáme odpověď
const _write = res.write.bind(res);
const _end = res.end.bind(res);
let chunks = [];
res.write = (chunk) => { chunks.push(chunk); };
res.end = (chunk) => {
if (chunk) chunks.push(chunk);
let body = Buffer.concat(chunks).toString("utf-8");
if (res.getHeader("content-type")?.includes("text/html")) {
body = body.replace(
"</body>",
`<script src="/ru-overlay.js"></script></body>`
);
}
// nutné odstranit content-length, jinak prohlížeč
// zkrátí odpověď – délka se změnila
res.removeHeader("content-length");
_write(body);
_end();
};
proxy.web(req, res);
});
Zpracování WebSocket vyžaduje sledování události upgrade:
server.on("upgrade", (req, socket, head) => {
proxy.ws(req, socket, head);
});
Klientský skript s MutationObserver
OpenClaw je SPA, DOM se dynamicky přestavuje při navigaci. Jednoduchý průchod textovými uzly při načtení nefunguje. MutationObserver sleduje přidávání uzlů a okamžitě je překládá.
Slovník překladů ve formátu JSON (~200 řádků):
const dict = {
"Settings": "Nastavení",
"New conversation": "Nový rozhovor",
"Send a message": "Odeslat zprávu",
"Skills": "Dovednosti",
"Memory": "Paměť",
"Schedule": "Rozvrh",
"Delete": "Smazat",
"Cancel": "Zrušit",
"Save": "Uložit",
// ... dalších 200 řádků
};
function translateNode(node) {
if (node.nodeType !== Node.TEXT_NODE) return;
const key = node.textContent.trim();
if (dict[key]) {
node.textContent = node.textContent.replace(key, dict[key]);
}
}
// primární průchod
const walker = document.createTreeWalker(
document.body, NodeFilter.SHOW_TEXT
);
while (walker.nextNode()) translateNode(walker.currentNode);
// sledujeme nové prvky
new MutationObserver((mutations) => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
const w = document.createTreeWalker(
node, NodeFilter.SHOW_TEXT
);
while (w.nextNode()) translateNode(w.currentNode);
} else {
translateNode(node);
}
}
}
}).observe(document.body, { childList: true, subtree: true });
Hlavní komponenty skriptu:
- TreeWalker pro procházení textových uzlů.
- MutationObserver s možnostmi
{ childList: true, subtree: true }. - Přesné shodné klíče po trim() pro minimalizaci kolizí.
Omezení přístupu
- Atributy placeholder: Nejsou zachyceny TreeWalkerem, vyžadují samostatného pozorovatele atributů input/select.
- Kontextové homonyma: "Run" v tlačítku a textu – různé překlady, slovník je nerozlišuje.
- Nové řádky: Při aktualizacích OpenClaw zůstávají nepřeložené prvky v angličtině, dokud se neaktualizuje slovník.
Výkon: prodleva překladu ~10–50 ms, uživatel ji nezaznamená.
Nasazení
Instalace skriptem:
git clone https://github.com/perfectinn/openclaw-ru-layercd openclaw-ru-layersudo bash scripts/install.sh --patch-nginx
Automaticky nastaví systemd službu a nginx. Odinstalace: sudo bash scripts/uninstall.sh.
Docker varianta:
docker build -t openclaw-ru-layer .
docker run --rm -p 18790:18790 \
-e TARGET_ORIGIN=http://host.docker.internal:18789 \
openclaw-ru-layer
Co je důležité:
- Proxy nepotřebuje změny v OpenClaw, funguje s aktuální verzí.
- MutationObserver zajišťuje překlad dynamického SPA obsahu.
- Aktualizace slovníku – přidání řádků do JSON bez restartu serveru.
- WebSocket se správně přesměruje pro zachování chatu.
- Minimální overhead: ~150 řádků kódu, 5–6 aktualizací slovníku za 2 měsíce.
Alternativy a škálování
PR do hlavního repozitáře není vhodný: vyžaduje refaktoring (vyňatí řetězců do JSON, obalení komponent i18n knihovnou). Současné řešení lze nasadit za minuty.
Pro jiné SPA jsou možné vylepšení:
- Shadow DOM: Další walker pro shadow roots.
- Virtual DOM diff: Hook na React DevTools API (experimentálně).
- Service Worker: Zachycení fetch požadavků na úrovni prohlížeče.
— Editorial Team
Zatím žádné komentáře.