Last active
December 22, 2025 21:48
-
-
Save kunofellasleep/9e460d5245241f62fd7ee8ffabcd54c2 to your computer and use it in GitHub Desktop.
translate-md-to-en.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # translate-md.sh - Translate Japanese Markdown to English via OpenAI API | |
| # | |
| # Usage: | |
| # chmod +x translate-md-to-en.sh | |
| # ./translate-md-to-en.sh article.md # creates article-en.md | |
| # cat input.md | ./translate-md.sh - # outputs to stdout | |
| # | |
| # Environment variables: | |
| # OPENAI_API_KEY (required) Your OpenAI API key | |
| # OPENAI_MODEL (optional) Model to use (default: gpt-4.1-mini) | |
| # | |
| set -euo pipefail | |
| # --- Configuration --- | |
| MODEL="${OPENAI_MODEL:-gpt-4.1-mini}" | |
| TEMPERATURE="0.2" | |
| API_URL="https://api.openai.com/v1/chat/completions" | |
| # --- Check dependencies --- | |
| if ! command -v curl &>/dev/null; then | |
| echo "Error: curl is required but not installed." >&2 | |
| exit 1 | |
| fi | |
| # --- Check API key --- | |
| if [[ -z "${OPENAI_API_KEY:-}" ]]; then | |
| echo "Error: OPENAI_API_KEY environment variable is not set." >&2 | |
| echo " export OPENAI_API_KEY='sk-...'" >&2 | |
| exit 1 | |
| fi | |
| # --- Parse arguments --- | |
| if [[ $# -lt 1 ]]; then | |
| echo "Usage: $0 <input.md | ->" >&2 | |
| echo " Use '-' to read from stdin" >&2 | |
| exit 1 | |
| fi | |
| INPUT_FILE="$1" | |
| OUTPUT_FILE="" | |
| # --- Read input --- | |
| if [[ "$INPUT_FILE" == "-" ]]; then | |
| INPUT_CONTENT=$(cat) | |
| elif [[ -f "$INPUT_FILE" ]]; then | |
| INPUT_CONTENT=$(cat "$INPUT_FILE") | |
| # Generate output filename: article.md -> article-en.md | |
| DIR=$(dirname "$INPUT_FILE") | |
| BASENAME=$(basename "$INPUT_FILE" .md) | |
| OUTPUT_FILE="${DIR}/${BASENAME}-en.md" | |
| else | |
| echo "Error: File not found: $INPUT_FILE" >&2 | |
| exit 1 | |
| fi | |
| if [[ -z "$INPUT_CONTENT" ]]; then | |
| echo "Error: Input is empty." >&2 | |
| exit 1 | |
| fi | |
| # --- Build system prompt --- | |
| SYSTEM_PROMPT="You are a professional technical translator specializing in software engineering content." | |
| # --- Build user prompt --- | |
| USER_PROMPT="Translate the following Japanese Markdown document into natural, concise technical English suitable for Medium articles. | |
| Rules: | |
| - Preserve all Markdown structure (headings, lists, links, etc.) | |
| - Do NOT modify content inside code blocks (\`\`\`) | |
| - Keep technical terms, library names, and proper nouns as-is | |
| - Prefer short, direct sentences | |
| - Remove unnecessary Japanese-style prefaces or greetings | |
| - Output ONLY the translated Markdown, no explanations | |
| --- | |
| $INPUT_CONTENT" | |
| # --- Escape strings for JSON using Python --- | |
| escape_json() { | |
| python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))" | |
| } | |
| ESCAPED_SYSTEM=$(echo -n "$SYSTEM_PROMPT" | escape_json) | |
| ESCAPED_USER=$(echo -n "$USER_PROMPT" | escape_json) | |
| # --- Build request body --- | |
| REQUEST_BODY=$(cat <<EOF | |
| { | |
| "model": "$MODEL", | |
| "temperature": $TEMPERATURE, | |
| "messages": [ | |
| {"role": "system", "content": $ESCAPED_SYSTEM}, | |
| {"role": "user", "content": $ESCAPED_USER} | |
| ] | |
| } | |
| EOF | |
| ) | |
| # --- Make API request --- | |
| TMPFILE=$(mktemp) | |
| trap 'rm -f "$TMPFILE"' EXIT | |
| HTTP_STATUS=$(curl -s -w "%{http_code}" -o "$TMPFILE" \ | |
| -X POST "$API_URL" \ | |
| -H "Content-Type: application/json; charset=utf-8" \ | |
| -H "Authorization: Bearer $OPENAI_API_KEY" \ | |
| -d "$REQUEST_BODY") | |
| RESPONSE_BODY=$(cat "$TMPFILE") | |
| # --- Check HTTP status --- | |
| if [[ "$HTTP_STATUS" -ne 200 ]]; then | |
| echo "Error: API request failed with HTTP status $HTTP_STATUS" >&2 | |
| echo "Response:" >&2 | |
| echo "$RESPONSE_BODY" >&2 | |
| exit 1 | |
| fi | |
| # --- Extract translated content --- | |
| extract_content() { | |
| if command -v jq &>/dev/null; then | |
| jq -r '.choices[0].message.content // empty' | |
| else | |
| python3 -c " | |
| import json, sys | |
| data = json.load(sys.stdin) | |
| content = data.get('choices', [{}])[0].get('message', {}).get('content', '') | |
| print(content) | |
| " | |
| fi | |
| } | |
| TRANSLATED=$(echo "$RESPONSE_BODY" | extract_content) | |
| if [[ -z "$TRANSLATED" ]]; then | |
| echo "Error: Failed to extract translated content from response." >&2 | |
| echo "Response:" >&2 | |
| echo "$RESPONSE_BODY" >&2 | |
| exit 1 | |
| fi | |
| # --- Output --- | |
| if [[ -n "$OUTPUT_FILE" ]]; then | |
| echo "$TRANSLATED" > "$OUTPUT_FILE" | |
| echo "Created: $OUTPUT_FILE" >&2 | |
| else | |
| echo "$TRANSLATED" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment