Skip to content

Commit 12c92ca

Browse files
author
SPRINX0\prochazka
committed
Add Czech documentation for working with data in DbGate
- Created main index for "Práce s daty" with links to various features. - Added detailed pages for advanced data tools including "Pokročilé datové nástroje", "Datové archivy", "Data deployer", and "Replikátor dat". - Introduced AI features documentation including database chat and SQL assistant. - Added sections for visualizing data with charts and maps. - Documented data filtering capabilities with examples and syntax. - Included export and import functionalities with advanced configuration options. - Created pages for perspectives to manage complex nested data relationships.
1 parent 5bd0501 commit 12c92ca

63 files changed

Lines changed: 3465 additions & 5 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
name: translation
3+
description: Translate the Hugo docs site (content/en/**/*.md) into all supported languages using local Claude subagents. Incremental — skips files whose sourceHash is unchanged, and patches only changed paragraphs in articles. Use when the user asks to translate the docs, sync translations, or translate a specific page/language. Optional args narrow scope: a language code (cs,de,fr,es,sk,zh,pt,it,ja,ko), a path substring, and/or a type (md).
4+
---
5+
6+
# Docs translation (local Claude agent)
7+
8+
Translating is done by **local Claude subagents** — no API key. It is incremental:
9+
unchanged files are skipped by hash, and changed articles are patched
10+
paragraph-by-paragraph to save time and tokens.
11+
12+
Always run from the repository root: `c:\jenasoft\dbgate-docs`.
13+
14+
This is a port of the same skill in `../web-dbgate-io`. Keep the two in sync where
15+
practical — `translate_plan.py` and `set_hash.py` are intentionally near-identical
16+
so fixes flow both ways.
17+
18+
## Supported languages
19+
`cs` Czech · `de` German · `fr` French · `es` Spanish · `sk` Slovak ·
20+
`zh` Simplified Chinese · `pt` Portuguese (Brazil) · `it` Italian · `ja` Japanese · `ko` Korean
21+
22+
A language is only *published* once it has an entry in `hugo.toml`. Adding content
23+
under `content/<lang>/` without that entry does nothing; adding the entry without
24+
content publishes untranslated English duplicates under the prefix. Do both together.
25+
26+
## Step 1 — Build the work plan
27+
28+
Parse the user's args into optional filters and run the planner:
29+
30+
```
31+
python .claude/skills/translation/translate_plan.py [--lang cs,de] [--path working-with-data] [--type md]
32+
```
33+
34+
- A bare language code in the args → `--lang`.
35+
- Any other token (e.g. `working-with-data/`, a filename, a slug) → `--path`.
36+
- `md` → `--type`.
37+
- No args → full site (every language, every file) = 560 jobs.
38+
39+
The planner prints JSON: `summary`, `deletions` (stale translation files to remove),
40+
and `jobs`. Each job has `type`, `mode`, `lang`, `lang_name`, `en_path`, `out_path`,
41+
`en_hash`, and `base_rev`. **Save the JSON to a file** (e.g. `Write` it to
42+
`.translation-plan.json`) so subagents can read individual jobs without you holding
43+
the whole list in context.
44+
45+
## Step 2 — Confirm scope
46+
47+
Report `summary.jobs` and the per-language / per-type breakdown.
48+
49+
- If **jobs > 25 and the user gave no filter**, do NOT translate everything blindly —
50+
show the breakdown and ask whether to proceed with the full run or narrow scope
51+
(each job is a subagent call; a full run is a large token spend).
52+
- If scope is small or the user already specified a filter, proceed.
53+
54+
## Step 3 — Deletions
55+
56+
For every path in `deletions`, delete it (the English source was removed or marked
57+
`skipTranslation: true`). Use `rm`/`Remove-Item`.
58+
59+
## Step 4 — Translate (one subagent per job)
60+
61+
Spawn subagents with the **Agent** tool (subagent_type `general-purpose`), in parallel
62+
waves of up to ~8 at a time. Give each subagent its single job object and the rules
63+
below. The subagent **writes the output file and stamps the hash itself** — it must NOT
64+
return the translated content to you (that would waste tokens). Tell it to return only
65+
a one-line status.
66+
67+
After writing/editing the output file, every subagent finishes by stamping the hash:
68+
69+
```
70+
python .claude/skills/translation/set_hash.py md <out_path> <en_path> <lang>
71+
```
72+
73+
(`set_hash.py` is idempotent — it removes any old hash markers first.)
74+
75+
### Universal translation rules
76+
- Translate natural-language text only. Never translate or alter:
77+
- Hugo shortcodes `{{< … >}}`, `{{ … }}`, `{{% … %}}` — this site uses
78+
`{{< mdi "icon-name" >}}`, `{{< check >}}`, `{{< center "text" >}}`. The
79+
**argument of `center` is display text and IS translated**; `mdi` icon names
80+
are not.
81+
- anchor links `[text](#anchor)`, code blocks/spans, HTML tag names/attributes
82+
- placeholders, URLs of images (`![](...)`, `<img src>`) — images are not
83+
language-specific and are served from a shared path
84+
- Preserve all Markdown/HTML structure, indentation, and quoting exactly.
85+
- Keep the same quote style (single vs double) as the source.
86+
- Keep DbGate product/edition names untranslated: DbGate, DbGate Cloud, DbGate Central,
87+
Community, Premium, Team Premium. Database and vendor names too (MySQL, PostgreSQL…).
88+
89+
### md jobs (`content/en/…` → `content/<lang>/…`)
90+
91+
**Front matter:**
92+
- Translate only `title` (and `subtitle`, which exists on one page).
93+
- Keep `weight`, `icon`, `edition`, `demo_url`, `layout` and any other field unchanged.
94+
`weight` drives nav order and must stay identical to English.
95+
- Keep YAML valid — quote any value containing a colon.
96+
- **`aliases:` — delete the entire `aliases:` block from translated files.**
97+
Aliases are legacy *English* URLs. Hugo does **not** language-prefix them (it only
98+
does so for `IsMultihost` sites, which this is not), so a verbatim copy silently
99+
hijacks the English redirect: the translated page takes over `/maps/`, the prefixed
100+
route is never created, and **the build still exits 0 with no warning**. Which
101+
language wins depends on build order, so it shifts as languages are added.
102+
Translations must never contain an `aliases:` key. See Step 5's guard.
103+
104+
**Body links:** for internal **root-relative** links (`](/dbgate/…)`), prepend the
105+
language code → `](/cs/dbgate/…)`. Leave relative links (`](../dbgate-central/)`)
106+
alone — they already resolve correctly under the language prefix. Do not change
107+
image paths.
108+
109+
Note `content/en/dbgate/customization/env-variables.md` links to `/features/administration`,
110+
which lives on the **web-dbgate-io** site, not here. Prefixing is still correct
111+
(`/cs/features/administration` exists there). Do not convert links to `relref` — it
112+
would fail the build on that cross-site link.
113+
114+
**Modes:**
115+
- **mode `new`** — read `en_path`, translate the whole file per the rules, write to
116+
`out_path`, then `set_hash.py md <out_path> <en_path> <lang>`.
117+
- **mode `changed` with `base_rev`** — run `git diff <base_rev> -- <en_path>` to see
118+
exactly what changed in the English since the translation was last made. Read the
119+
existing `out_path`. Apply the *equivalent* translated changes with `Edit`, touching
120+
only the affected paragraphs/fields. Leave everything else verbatim. Then `set_hash.py`.
121+
- **mode `changed` without `base_rev`** — read `en_path` and the existing `out_path`.
122+
The translation is structurally parallel (same headings/order). Compare block by block;
123+
re-translate with `Edit` only the blocks whose translation no longer matches the English.
124+
Leave matching blocks untouched. Then `set_hash.py`.
125+
126+
### toml / yml jobs
127+
This repo has no `data/` dir and no project-level `i18n/en.toml` — the relearn theme
128+
supplies all UI strings, and it ships translations for every supported language except
129+
**`sk`**. So the planner emits no toml/yml jobs today; those code paths are guarded and
130+
inert, kept only for parity with web-dbgate-io.
131+
132+
If Slovak is rolled out, add a project-level `i18n/sk.toml` seeded from
133+
`themes/hugo-theme-relearn/i18n/en.toml` (~47 keys; Hugo merges project i18n over theme
134+
i18n). Once an `i18n/en.toml` exists, the toml job type reactivates on its own.
135+
136+
## Step 5 — Verify, then report
137+
138+
**The alias guard is mandatory after any md run** — it is the only thing standing in for
139+
the build error Hugo does not give you:
140+
141+
```bash
142+
# MUST return nothing:
143+
grep -rl "^aliases:" content/cs/
144+
145+
# generalized across all languages — an alias not prefixed with its own lang code is a hijack:
146+
for d in content/*/; do l=$(basename "$d"); [ "$l" = en ] && continue
147+
grep -rhoE '^\s+- /\S+' "$d" 2>/dev/null | grep -v "^ - /$l/" && echo "HIJACK RISK in $l"
148+
done
149+
```
150+
151+
Then `hugo` and confirm: the build is WARN/ERROR-free, English `Aliases` count is
152+
unchanged (26 — 25 content aliases plus Hugo's generated `/en/` → `/` redirect), and
153+
`<out>/maps/index.html` still redirects to an English target (`grep -o 'url=[^"]*'`
154+
must not contain a language prefix).
155+
156+
Summarize: files created, files patched, files deleted, per language. If any subagent
157+
failed, list those jobs so they can be retried. Finally delete the temporary
158+
`.translation-plan.json`.
159+
160+
## Notes
161+
- The hash format is identical to web-dbgate-io's, so the two repos' skills behave the same.
162+
- `skipTranslation: true` in an English article's front matter excludes it (and causes
163+
existing translations to be deleted). A translated file with `skipTranslation: true` is
164+
protected from deletion.
165+
- `set_hash.py` also stamps a `language:` field. It is inert under
166+
translation-by-directory but is kept for parity with web-dbgate-io.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python3
2+
"""Stamp the English source hash into a freshly translated file.
3+
4+
Idempotent: removes any existing hash markers first, then writes the current one,
5+
so it is safe to run after either a full or an incremental translation.
6+
7+
Usage:
8+
python .claude/skills/translation/set_hash.py <md|toml|yml> <out_path> <en_path> [lang]
9+
10+
md -> inserts `sourceHash:` and `language:` lines just after the opening `---`
11+
toml -> prepends `# sourceHash: <hash>` as the first line
12+
yml -> prepends `# sourceHash: <hash>` as the first line
13+
"""
14+
15+
import sys
16+
import hashlib
17+
18+
19+
def sha256_file(path):
20+
h = hashlib.sha256()
21+
with open(path, 'rb') as f:
22+
for chunk in iter(lambda: f.read(8192), b''):
23+
h.update(chunk)
24+
return h.hexdigest()
25+
26+
27+
def stamp_md(out_path, hash_value, lang):
28+
with open(out_path, 'r', encoding='utf-8') as f:
29+
lines = f.readlines()
30+
if not lines or lines[0].strip() != '---':
31+
raise SystemExit(f'{out_path}: missing opening front-matter "---"')
32+
# find closing --- of front matter
33+
end = None
34+
for i in range(1, len(lines)):
35+
if lines[i].strip() == '---':
36+
end = i
37+
break
38+
if end is None:
39+
raise SystemExit(f'{out_path}: missing closing front-matter "---"')
40+
body_fm = [ln for ln in lines[1:end]
41+
if not ln.startswith('sourceHash:') and not ln.startswith('language:')]
42+
new_lines = (['---\n', f'sourceHash: {hash_value}\n', f'language: {lang}\n']
43+
+ body_fm + lines[end:])
44+
with open(out_path, 'w', encoding='utf-8') as f:
45+
f.writelines(new_lines)
46+
47+
48+
def stamp_comment(out_path, hash_value):
49+
with open(out_path, 'r', encoding='utf-8') as f:
50+
lines = f.readlines()
51+
lines = [ln for ln in lines if not ln.startswith('# sourceHash:')]
52+
with open(out_path, 'w', encoding='utf-8') as f:
53+
f.write(f'# sourceHash: {hash_value}\n')
54+
f.writelines(lines)
55+
56+
57+
def main():
58+
if len(sys.argv) < 4:
59+
raise SystemExit(__doc__)
60+
kind, out_path, en_path = sys.argv[1], sys.argv[2], sys.argv[3]
61+
lang = sys.argv[4] if len(sys.argv) > 4 else ''
62+
hash_value = sha256_file(en_path)
63+
if kind == 'md':
64+
if not lang:
65+
raise SystemExit('md requires a lang argument')
66+
stamp_md(out_path, hash_value, lang)
67+
elif kind in ('toml', 'yml'):
68+
stamp_comment(out_path, hash_value)
69+
else:
70+
raise SystemExit(f'unknown kind: {kind}')
71+
print(f'stamped {out_path} ({hash_value[:12]}…)')
72+
73+
74+
if __name__ == '__main__':
75+
main()

0 commit comments

Comments
 (0)