diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f394199 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.todos/ + +# Sidecar worktree state files +.sidecar/ +.sidecar-agent +.sidecar-task +.sidecar-pr +.sidecar-start.sh +.sidecar-base +.td-root diff --git a/skills/doc-translator/SKILL.md b/skills/doc-translator/SKILL.md new file mode 100644 index 0000000..47911dc --- /dev/null +++ b/skills/doc-translator/SKILL.md @@ -0,0 +1,252 @@ +--- +name: doc-translator +description: "Translates external documentation websites to specified language(s) and publishes to Outline wiki. Use when: (1) Translating SaaS/product documentation into German or Czech, (2) Publishing translated docs to Outline wiki, (3) Re-hosting external images to Outline. Triggers: 'translate docs', 'translate documentation', 'translate to German', 'translate to Czech', 'publish to wiki', 'doc translation', 'TEEM translation'." +compatibility: opencode +--- + +# Doc Translator + +Translate external documentation websites to German (DE) and/or Czech (CZ), then publish to the company Outline wiki at `https://wiki.az-gruppe.com`. All images are re-hosted on Outline. UI terms use TEEM format. + +## Core Workflow + +### 1. Validate Input & Clarify + +Before starting, confirm: + +1. **URL accessibility** - Check with `curl -sI ` for HTTP 200 +2. **Target language(s)** - Always ask explicitly using the `question` tool: + +``` +question: "Which language(s) should I translate to?" +options: ["German (DE)", "Czech (CZ)", "Both (DE + CZ)"] +``` + +3. **Scope** - If URL is an index page with multiple sub-pages, ask: + +``` +question: "This page links to multiple sub-pages. What should I translate?" +options: ["This page only", "This page + all linked sub-pages", "Let me pick specific pages"] +``` + +4. **Target collection** - Use `Outline_list_collections` to show available collections, then ask which one to publish to + +If URL fetch fails, use `question` to ask for an alternative URL or manual content paste. + +### 2. Fetch & Parse Content + +Use the `webfetch` tool to retrieve page content: + +``` +webfetch(url="", format="markdown") +``` + +From the result: +- Extract main content body (ignore navigation, footers, sidebars, cookie banners) +- Preserve document structure (headings, lists, tables, code blocks) +- Collect all image URLs into a list for Step 3 +- Note any embedded videos or interactive elements (these cannot be translated) + +For multi-page docs, repeat for each page. + +### 3. Download Images + +Download all images to a temporary directory: + +```bash +mkdir -p /tmp/doc-images + +# For each image URL: +curl -sL "IMAGE_URL" -o "/tmp/doc-images/$(basename IMAGE_URL)" +``` + +Track a mapping of: `original_url -> local_filename -> outline_attachment_url` + +If an image download fails, log it and continue. Use a placeholder in the final document: + +```markdown +> **[Image unavailable]** Original: IMAGE_URL +``` + +### 4. Upload Images to Outline + +mcp-outline cannot create attachments. Use direct API calls via `bash`. + +**Required env:** `OUTLINE_API_KEY` + +For each downloaded image: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_PATH="/tmp/doc-images/screenshot.png" +IMAGE_NAME="$(basename "$IMAGE_PATH")" +CONTENT_TYPE="image/png" # Detect from extension: png->image/png, jpg/jpeg->image/jpeg, gif->image/gif, svg->image/svg+xml, webp->image/webp + +# 1. Get file size (cross-platform) +FILESIZE=$(stat -f%z "$IMAGE_PATH" 2>/dev/null || stat -c%s "$IMAGE_PATH") + +# 2. Create attachment record +RESPONSE=$(curl -s -X POST "https://wiki.az-gruppe.com/api/attachments.create" \ + -H "Authorization: Bearer $OUTLINE_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{ + \"name\": \"$IMAGE_NAME\", + \"contentType\": \"$CONTENT_TYPE\", + \"size\": $FILESIZE + }") + +# 3. Extract URLs from response +UPLOAD_URL=$(echo "$RESPONSE" | jq -r '.data.uploadUrl') +ATTACHMENT_URL=$(echo "$RESPONSE" | jq -r '.data.attachment.url') + +# 4. Check for errors +if [ "$UPLOAD_URL" = "null" ] || [ -z "$UPLOAD_URL" ]; then + echo "ERROR: Failed to create attachment. Response: $RESPONSE" >&2 + exit 1 +fi + +# 5. Upload binary to signed URL +curl -s -X PUT "$UPLOAD_URL" \ + -H "Content-Type: $CONTENT_TYPE" \ + --data-binary "@$IMAGE_PATH" + +# 6. Output the attachment URL for use in markdown +echo "$ATTACHMENT_URL" +``` + +Replace image references in the translated markdown: +```markdown +![description](ATTACHMENT_URL) +``` + +**Content-Type detection by extension:** + +| Extension | Content-Type | +|-----------|-------------| +| `.png` | `image/png` | +| `.jpg`, `.jpeg` | `image/jpeg` | +| `.gif` | `image/gif` | +| `.svg` | `image/svg+xml` | +| `.webp` | `image/webp` | + +### 5. Translate with TEEM Format + +Translate the entire document into each target language. Apply TEEM format to UI elements. + +#### TEEM Rules + +**Format:** `**English UI Term** (Translation)` + +**Apply TEEM to:** +- Button labels +- Menu items and navigation tabs +- Form field labels +- Dialog/modal titles +- Toolbar icons with text +- Status messages from the app + +**Translate normally (no TEEM):** +- Your own explanatory text +- Document headings you create +- General descriptions and conceptual explanations +- Code blocks and technical identifiers + +#### German Examples + +```markdown +Click **Settings** (Einstellungen) to open preferences. +Navigate to **Dashboard** (Übersicht) > **Reports** (Berichte). +Press the **Submit** (Absenden) button. +In the **File** (Datei) menu, select **Export** (Exportieren). +``` + +#### Czech Examples + +```markdown +Click **Settings** (Nastavení) to open preferences. +Navigate to **Dashboard** (Přehled) > **Reports** (Sestavy). +Press the **Submit** (Odeslat) button. +In the **File** (Soubor) menu, select **Export** (Exportovat). +``` + +#### Ambiguous UI Terms + +If a UI term has multiple valid translations depending on context, use the `question` tool: + +``` +question: "The term 'Board' appears in the UI. Which translation fits this context?" +options: ["Pinnwand (pinboard/bulletin)", "Tafel (whiteboard)", "Gremium (committee)"] +``` + +### 6. Publish to Outline + +Use mcp-outline tools to publish: + +1. **Find or create collection:** + - `Outline_list_collections` to find target collection + - `Outline_create_collection` if needed + +2. **Create document:** + - `Outline_create_document` with translated markdown content + - Set `publish: true` for immediate visibility + - Use `parent_document_id` if nesting under an existing doc + +3. **For multi-language:** Create one document per language, clearly titled: + - `[Product Name] - Dokumentation (DE)` + - `[Product Name] - Dokumentace (CZ)` + +## Error Handling + +| Issue | Action | +|-------|--------| +| URL fetch fails | Use `question` to ask for alternative URL or manual paste | +| Image download fails | Continue with placeholder, note in completion report | +| Outline API error (attachments) | Save markdown to `/tmp/doc-translator-backup-TIMESTAMP.md`, report error | +| Outline API error (document) | Save markdown to `/tmp/doc-translator-backup-TIMESTAMP.md`, report error | +| Ambiguous UI term | Use `question` to ask user for correct translation | +| Large document (>5000 words) | Ask user if splitting into multiple docs is preferred | +| Multi-page docs | Ask user about scope before proceeding | +| Rate limiting | Wait and retry with exponential backoff | + +If Outline publish fails, always save the translated markdown locally as backup before reporting the error. + +## Completion Report + +After each translation, output: + +``` +Translation Complete + +Documents Created: +- DE: [Document Title] - ID: [xxx] - URL: https://wiki.az-gruppe.com/doc/[slug] +- CZ: [Document Title] - ID: [xxx] - URL: https://wiki.az-gruppe.com/doc/[slug] + +Images Processed: X of Y successfully uploaded + +Items Needing Review: +- [Any sections with complex screenshots] +- [Any failed image uploads with original URLs] +- [Any unclear UI terms that were best-guessed] +``` + +## Language Codes + +| Code | Language | Native Name | +|------|----------|-------------| +| DE | German | Deutsch | +| CZ | Czech | Čeština | + +## Environment Variables + +| Variable | Purpose | +|----------|---------| +| `OUTLINE_API_KEY` | Bearer token for wiki.az-gruppe.com API | + +## Integration with Other Skills + +| Need | Skill | When | +|------|-------|------| +| Wiki document management | outline | Managing existing translated docs | +| Browser-based content extraction | playwright / dev-browser | When webfetch cannot access content (login-required pages) |