diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 674eb3b..ba431a0 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -30,7 +30,13 @@ jobs: run: cp -r assets website/assets - name: Update asset paths - run: sed -i 's|\.\./assets/|assets/|g' website/index.html website/docs.html + run: | + # Update asset paths in all HTML files + for file in website/*.html; do + if [ -f "$file" ]; then + sed -i 's|\.\./assets/|assets/|g' "$file" + fi + done - name: Upload artifact uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/protect-translated-docs.yml b/.github/workflows/protect-translated-docs.yml new file mode 100644 index 0000000..7d499ff --- /dev/null +++ b/.github/workflows/protect-translated-docs.yml @@ -0,0 +1,59 @@ +# Protect Translated Documentation +# +# Prevents direct edits to auto-translated documentation. +# Only English docs should be edited by humans: +# - wiki/*.md (excluding language folders) +# - website/docs.html +# Translated docs are auto-generated and should not be manually modified: +# - wiki/ko/, wiki/zh/, wiki/ja/, wiki/es/, wiki/pt/ +# - website/docs-ko.html, website/docs-zh.html, etc. + +name: Protect Translated Docs + +on: + pull_request: + paths: + - 'wiki/ko/**' + - 'wiki/zh/**' + - 'wiki/ja/**' + - 'wiki/es/**' + - 'wiki/pt/**' + - 'website/docs-ko.html' + - 'website/docs-zh.html' + - 'website/docs-ja.html' + - 'website/docs-es.html' + - 'website/docs-pt.html' + +jobs: + check-translated-docs: + runs-on: ubuntu-latest + steps: + - name: Check for unauthorized translation edits + run: | + echo "::warning::This PR modifies auto-translated documentation." + echo "" + echo "Translated documentation is automatically generated:" + echo " - wiki/ko/, wiki/zh/, wiki/ja/, wiki/es/, wiki/pt/" + echo " - website/docs-{ko,zh,ja,es,pt}.html" + echo "" + echo "To update translations:" + echo "1. Edit the English documentation:" + echo " - wiki/*.md (for markdown docs)" + echo " - website/docs.html (for website)" + echo "2. Push to main branch" + echo "3. The translation workflow will automatically update all translations" + echo "" + echo "If you need to fix a translation issue, please edit the English source" + echo "and let the automation regenerate the translations." + echo "" + + # Check if this is from the translation bot + if [[ "${{ github.actor }}" == "github-actions[bot]" ]] || \ + [[ "${{ github.head_ref }}" == "docs/auto-translate" ]]; then + echo "This is an automated translation PR - allowing." + exit 0 + fi + + echo "::error::Direct edits to translated documentation are not allowed." + echo "Please edit the English source documentation instead." + exit 1 diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml new file mode 100644 index 0000000..73dff39 --- /dev/null +++ b/.github/workflows/translate-docs.yml @@ -0,0 +1,245 @@ +# Documentation Translation Workflow +# +# Automatically translates documentation to multiple languages when English docs change. +# Only English documentation should be edited by humans: +# - wiki/*.md, wiki/**/*.md (excluding language folders) +# - website/docs.html +# All other language files are auto-generated: +# - wiki/ko/, wiki/zh/, wiki/ja/, wiki/es/, wiki/pt/ +# - website/docs-ko.html, website/docs-zh.html, etc. +# +# Supported languages: +# - ko (Korean) - Strong crypto/prediction market community +# - zh (Chinese) - Largest developer population +# - ja (Japanese) - Strong tech community +# - es (Spanish) - Large global developer population +# - pt (Portuguese) - Large Brazilian developer community + +name: Translate Documentation + +on: + push: + branches: + - main + paths: + - 'wiki/**/*.md' + - 'website/docs.html' + - '!wiki/ko/**' + - '!wiki/zh/**' + - '!wiki/ja/**' + - '!wiki/es/**' + - '!wiki/pt/**' + workflow_dispatch: + inputs: + force_translate: + description: 'Force translate all documents' + required: false + default: 'false' + type: boolean + languages: + description: 'Languages to translate (comma-separated, e.g., ko,zh,ja)' + required: false + default: 'ko,zh,ja,es,pt' + type: string + +env: + SUPPORTED_LANGUAGES: 'ko,zh,ja,es,pt' + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + wiki_files: ${{ steps.changes.outputs.wiki_files }} + docs_html: ${{ steps.changes.outputs.docs_html }} + has_changes: ${{ steps.changes.outputs.has_changes }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Detect changed English documentation + id: changes + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.force_translate }}" == "true" ]]; then + # Force translate: get all English docs + WIKI_FILES=$(find wiki -name "*.md" -type f | grep -v -E "wiki/(ko|zh|ja|es|pt)/" | tr '\n' ',') + echo "wiki_files=$WIKI_FILES" >> $GITHUB_OUTPUT + echo "docs_html=website/docs.html" >> $GITHUB_OUTPUT + echo "has_changes=true" >> $GITHUB_OUTPUT + else + # Get changed files from the push + WIKI_CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'wiki/**/*.md' | grep -v -E "wiki/(ko|zh|ja|es|pt)/" || true) + DOCS_CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'website/docs.html' || true) + + if [ -n "$WIKI_CHANGED" ] || [ -n "$DOCS_CHANGED" ]; then + WIKI_FILES=$(echo "$WIKI_CHANGED" | tr '\n' ',' | sed 's/,$//') + echo "wiki_files=$WIKI_FILES" >> $GITHUB_OUTPUT + echo "docs_html=$DOCS_CHANGED" >> $GITHUB_OUTPUT + echo "has_changes=true" >> $GITHUB_OUTPUT + else + echo "wiki_files=" >> $GITHUB_OUTPUT + echo "docs_html=" >> $GITHUB_OUTPUT + echo "has_changes=false" >> $GITHUB_OUTPUT + fi + fi + + translate: + needs: detect-changes + if: needs.detect-changes.outputs.has_changes == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + id-token: write + strategy: + matrix: + lang: [ko, zh, ja, es, pt] + fail-fast: false + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Check if language should be translated + id: check_lang + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + LANGS="${{ inputs.languages }}" + else + LANGS="${{ env.SUPPORTED_LANGUAGES }}" + fi + if echo ",$LANGS," | grep -q ",${{ matrix.lang }},"; then + echo "should_translate=true" >> $GITHUB_OUTPUT + else + echo "should_translate=false" >> $GITHUB_OUTPUT + fi + + - name: Create translation prompt + if: steps.check_lang.outputs.should_translate == 'true' + id: prompt + run: | + LANG="${{ matrix.lang }}" + WIKI_FILES="${{ needs.detect-changes.outputs.wiki_files }}" + DOCS_HTML="${{ needs.detect-changes.outputs.docs_html }}" + + case $LANG in + ko) LANG_NAME="Korean" ;; + zh) LANG_NAME="Chinese (Simplified)" ;; + ja) LANG_NAME="Japanese" ;; + es) LANG_NAME="Spanish" ;; + pt) LANG_NAME="Portuguese (Brazilian)" ;; + esac + + cat << 'PROMPT_EOF' > /tmp/translate_prompt.txt + Translate documentation to TARGET_LANG. + + IMPORTANT TRANSLATION RULES: + 1. Preserve all formatting exactly (markdown, HTML structure, code blocks) + 2. DO NOT translate: + - Code snippets inside code blocks or
tags + - Variable names, function names, class names + - File paths and URLs + - CSS class names and HTML attributes + - Technical terms commonly kept in English (API, WebSocket, SDK, etc.) + 3. Translate: + - Prose text, descriptions, and visible UI text + - Comments inside code blocks (marked with # or //) + - Table descriptions (but not technical column names) + - HTML title and meta description + 4. Use natural, fluent TARGET_LANG that a native developer would use + 5. Keep technical accuracy - don't change the meaning + + TASK 1 - Wiki Markdown Files: + For each wiki file in WIKI_FILES (if any): + 1. Read the English source file from wiki/ + 2. Create the translated version in wiki/LANG_CODE/+ 3. Ensure directory structure is mirrored (e.g., wiki/exchanges/foo.md -> wiki/LANG_CODE/exchanges/foo.md) + + TASK 2 - Website Documentation HTML: + If DOCS_HTML is not empty: + 1. Read website/docs.html + 2. Create translated version at website/docs-LANG_CODE.html + 3. Update the to + 4. Keep the language selector working (don't modify the JavaScript) + + Wiki files to translate: WIKI_FILES + Docs HTML to translate: DOCS_HTML + Target language code: LANG_CODE + Target language name: TARGET_LANG + PROMPT_EOF + + sed -i "s/TARGET_LANG/$LANG_NAME/g" /tmp/translate_prompt.txt + sed -i "s/LANG_CODE/$LANG/g" /tmp/translate_prompt.txt + sed -i "s|WIKI_FILES|$WIKI_FILES|g" /tmp/translate_prompt.txt + sed -i "s|DOCS_HTML|$DOCS_HTML|g" /tmp/translate_prompt.txt + + PROMPT=$(cat /tmp/translate_prompt.txt) + echo "prompt< > $GITHUB_OUTPUT + echo "$PROMPT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Run Claude Code for translation + if: steps.check_lang.outputs.should_translate == 'true' + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + direct_prompt: ${{ steps.prompt.outputs.prompt }} + allowed_tools: | + Read + Write + Glob + Grep + timeout_minutes: 30 + + create-pr: + needs: [detect-changes, translate] + if: always() && needs.detect-changes.outputs.has_changes == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Check for translation changes + id: check_changes + run: | + git add -A + if git diff --staged --quiet; then + echo "has_translations=false" >> $GITHUB_OUTPUT + else + echo "has_translations=true" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + if: steps.check_changes.outputs.has_translations == 'true' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "docs: auto-translate documentation" + title: "docs: Update translated documentation" + body: | + ## Automated Documentation Translation + + This PR contains automatically translated documentation for the following languages: + - Korean (ko) + - Chinese (zh) + - Japanese (ja) + - Spanish (es) + - Portuguese (pt) + + ### Changed English files: + **Wiki files:** ${{ needs.detect-changes.outputs.wiki_files || 'none' }} + **Docs HTML:** ${{ needs.detect-changes.outputs.docs_html || 'none' }} + + --- + *Generated automatically by the translation workflow* + branch: docs/auto-translate + delete-branch: true + labels: documentation,automated diff --git a/website/docs.html b/website/docs.html index a2f89ce..aa16c67 100644 --- a/website/docs.html +++ b/website/docs.html @@ -145,6 +145,102 @@ height: 18px; } + /* Language Selector */ + .lang-selector { + position: relative; + display: inline-block; + } + + .lang-btn { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.9rem; + background: transparent; + border: 1px solid var(--border-subtle); + border-radius: 6px; + color: var(--text-primary); + font-size: 0.85rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s; + font-family: inherit; + } + + .lang-btn:hover { + border-color: var(--manhattan-blue); + background: rgba(0, 180, 255, 0.1); + } + + .lang-btn svg { + width: 14px; + height: 14px; + transition: transform 0.2s; + } + + .lang-selector.open .lang-btn svg { + transform: rotate(180deg); + } + + .lang-dropdown { + position: absolute; + top: calc(100% + 8px); + right: 0; + min-width: 160px; + background: var(--deep-space); + border: 1px solid var(--border-subtle); + border-radius: 8px; + padding: 0.5rem; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.2s; + z-index: 200; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); + } + + .lang-selector.open .lang-dropdown { + opacity: 1; + visibility: visible; + transform: translateY(0); + } + + .lang-option { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.6rem 0.75rem; + border-radius: 6px; + cursor: pointer; + transition: all 0.2s; + color: var(--text-secondary); + font-size: 0.85rem; + } + + .lang-option:hover { + background: rgba(0, 180, 255, 0.1); + color: var(--text-primary); + } + + .lang-option.active { + background: rgba(0, 180, 255, 0.15); + color: var(--manhattan-glow); + } + + .lang-option .flag { + font-size: 1.1rem; + } + + .lang-option .lang-name { + flex: 1; + } + + .lang-option .lang-code { + color: var(--text-muted); + font-size: 0.75rem; + text-transform: uppercase; + } + /* Main Layout */ .docs-layout { display: flex; @@ -534,6 +630,45 @@ Getting Started API Reference Exchanges + + +GitHub @@ -1203,6 +1338,78 @@+++ EN + English + en +++ KO + Korean + ko +++ ZH + Chinese + zh +++ JA + Japanese + ja +++ ES + Spanish + es +++ PT + Portuguese + pt ++MCP Server
window.addEventListener('scroll', highlightActiveSection); highlightActiveSection(); + + // Language selector functionality + const languages = { + en: { flag: 'EN', name: 'English' }, + ko: { flag: 'KO', name: 'Korean' }, + zh: { flag: 'ZH', name: 'Chinese' }, + ja: { flag: 'JA', name: 'Japanese' }, + es: { flag: 'ES', name: 'Spanish' }, + pt: { flag: 'PT', name: 'Portuguese' } + }; + + function toggleLangDropdown() { + document.getElementById('langSelector').classList.toggle('open'); + } + + function selectLanguage(lang) { + localStorage.setItem('preferredLanguage', lang); + updateLanguageUI(lang); + document.getElementById('langSelector').classList.remove('open'); + + // Redirect to language-specific docs if not English + if (lang !== 'en') { + const currentPath = window.location.pathname; + const basePath = currentPath.replace(/\/docs(-\w+)?\.html$/, ''); + window.location.href = basePath + '/docs-' + lang + '.html'; + } else { + const currentPath = window.location.pathname; + if (currentPath.includes('docs-')) { + const basePath = currentPath.replace(/\/docs(-\w+)?\.html$/, ''); + window.location.href = basePath + '/docs.html'; + } + } + } + + function updateLanguageUI(lang) { + const langData = languages[lang] || languages.en; + document.getElementById('currentLangFlag').textContent = langData.flag; + document.getElementById('currentLangName').textContent = langData.name; + + document.querySelectorAll('.lang-option').forEach(option => { + option.classList.remove('active'); + if (option.dataset.lang === lang) { + option.classList.add('active'); + } + }); + } + + // Close dropdown when clicking outside + document.addEventListener('click', function(e) { + const selector = document.getElementById('langSelector'); + if (!selector.contains(e.target)) { + selector.classList.remove('open'); + } + }); + + // Initialize language from localStorage or URL + (function initLanguage() { + const path = window.location.pathname; + const match = path.match(/docs-(\w+)\.html/); + let lang = 'en'; + + if (match && languages[match[1]]) { + lang = match[1]; + } else { + const saved = localStorage.getItem('preferredLanguage'); + if (saved && languages[saved]) { + lang = saved; + } + } + + updateLanguageUI(lang); + })();