19 2025
Bá A Ṣe Pèsè Èdè 50

Nígbà tá a ṣe ìpinnu láti jẹ́ kí ojúlé wẹẹbù wa tó dá lórí GoHugo.io jẹ́ ọ̀pọ̀ èdè, a fẹ́ ọ̀nà tó rọrùn, tó lè gbooro, àti tó ní iye owó tó kéré láti ṣe ìtúmọ̀. Dípò kí a túmọ̀ ojúlé kọọkan lọ́wọ́, a lo API OpenAI láti ṣàkóso ìlànà náà. Àpilẹ̀kọ yìí ń tọ́ka bí a ṣe darapọ̀ API OpenAI pẹ̀lú Hugo, ní lílo àkópọ̀ àkóónú HugoPlate láti Zeon Studio, láti ṣe ìtúmọ̀ kíákíá àti pẹ̀lú ìtẹ́lọ́run.
Ìdí Tí A Fi Yàn OpenAI API fún Ìtúmọ̀
Ìṣẹ̀lẹ̀ ìtúmọ̀ àtijọ́ sábà máa ń bẹ̀rẹ̀ pẹ̀lú iṣẹ́ ọwọ́ púpọ̀, àti àwọn irinṣẹ́ àkóso bí Google Translate, bí ó tilẹ̀ jẹ́ pé wúlò, kò máa ń fún wa ní ìṣètò tó péye tó yẹ. API OpenAI fún wa láàyè láti:
- Ṣàkóso ìtúmọ̀ ní púpọ̀
- Ṣètò ara ìtúmọ̀ gẹ́gẹ́ bí a ṣe fẹ́
- Ṣètò ìṣàkóso tó dára jùlọ lórí didáàbò bo àyẹ̀wò
- Darapọ̀ pẹ̀lú ojúlé wẹẹbù wa tó dá lórí Hugo láìsí ìṣòro
- Ṣàmì ojúlé kọọkan fún ìtúmọ̀ lẹ́ẹ̀kansi
- Fikun àwọn èdè tuntun pẹ̀lú iṣẹ́ díẹ̀
Ìlànà Lẹ́sẹ̀kẹsẹ̀
1. Ṣíṣe Tó Ojúlé Wẹẹbù Hugo
Ojúlé wa ti ṣètò tán pẹ̀lú àkópọ̀ HugoPlate, tó ń ṣe àfihàn iṣẹ́ ọ̀pọ̀ èdè. Ìgbésẹ̀ àkọ́kọ́ ni láti jẹ́ kí àtìlẹ́yìn èdè wà nínú fáìlì config/_default/languages.toml Hugo wa:
```toml
################ English language ##################
[en]
languageName = "English"
languageCode = "en-us"
contentDir = "content/english"
weight = 1
################ Arabic language ##################
[ar]
languageName = "العربية"
languageCode = "ar"
contentDir = "content/arabic"
languageDirection = 'rtl'
weight = 2
```
Ìṣètò yìí dájú pé Hugo lè ṣe àfihàn àwọn àtúnṣe èdè tó yàtọ̀ fún àkóónú wa.
2. Ṣàkóso Ìtúmọ̀ Pẹ̀lú OpenAI API
A dá Bash script kan sílẹ̀ láti ṣàkóso ìtúmọ̀ àwọn fáìlì Markdown. Script yìí:
- Kà àwọn fáìlì
.mdèdè Gẹ̀ẹ́sì láti inú àpótí orísun. - Lo OpenAI API láti túmọ̀ ọ̀rọ̀ náà pẹ̀lú fífi àtúnṣe Markdown pamọ́.
- Kọ àkóónú tí a túmọ̀ sí àwọn àpótí èdè tó yẹ.
- Tọ́pa ìpẹ̀yà ìtúmọ̀ pẹ̀lú fáìlì JSON.
Ẹ wo script bash wa fún ṣàkóso ìtúmọ̀. Ẹ lè lo tàbí yí padà fún àwọn ìfẹ́ yín:
```bash
# MIT License
# Copyright (c) 2024 Williston Technical Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#!/bin/bash
# ===========================================
# Hugo Content Translation and Update Script (Sequential Processing & New-Language Cleanup)
# ===========================================
# This script translates Hugo Markdown (.md) files from English to all supported target languages
# sequentially (one file at a time). It updates a JSON status file after processing each file.
# At the end of the run, it checks translation_status.json and removes any language from
# translate_new_language.txt only if every file for that language is marked as "success".
# ===========================================
set -euo pipefail
# --- Simple Logging Function (writes to stderr) ---
log_step() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
}
# --- Environment Setup ---
export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH"
# (Removed "Script starting." log)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
log_step "SCRIPT_DIR set to: $SCRIPT_DIR"
if [ -f "$SCRIPT_DIR/.env" ]; then
log_step "Loading environment variables from .env"
set -o allexport
source "$SCRIPT_DIR/.env"
set +o allexport
fi
# Load new languages from translate_new_language.txt (if available)
declare -a NEW_LANGUAGES=()
if [ -f "$SCRIPT_DIR/translate_new_language.txt" ]; then
while IFS= read -r line || [[ -n "$line" ]]; do
NEW_LANGUAGES+=("$line")
done <"$SCRIPT_DIR/translate_new_language.txt"
else
log_step "No new languages file found; proceeding with empty NEW_LANGUAGES."
fi
API_KEY="${OPENAI_API_KEY:-}"
if [ -z "$API_KEY" ]; then
log_step "❌ Error: OPENAI_API_KEY environment variable is not set."
exit 1
fi
# Supported Languages (full list)
SUPPORTED_LANGUAGES=("ar" "bg" "bn" "cs" "da" "de" "el" "es" "fa" "fi" "fr" "ha" "he" "hi" "hr" "hu" "id" "ig" "it" "ja" "ko" "ml" "mr" "ms" "nl" "no" "pa" "pl" "pt" "ro" "ru" "sk" "sn" "so" "sr" "sv" "sw" "ta" "te" "th" "tl" "tr" "uk" "vi" "xh" "yo" "zh" "zu")
STATUS_FILE="$SCRIPT_DIR/translation_status.json"
SRC_DIR="$SCRIPT_DIR/Content/english"
log_step "Source directory: $SRC_DIR"
# Check dependencies
for cmd in jq curl; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_step "❌ Error: '$cmd' is required. Please install it."
exit 1
fi
done
MAX_RETRIES=5
WAIT_TIME=2 # seconds
# Create/initialize status file if missing
if [ ! -f "$STATUS_FILE" ]; then
echo "{}" >"$STATUS_FILE"
log_step "Initialized status file at: $STATUS_FILE"
fi
# --- Locking for Status Updates ---
lock_status() {
local max_wait=10
local start_time
start_time=$(date +%s)
while ! mkdir "$STATUS_FILE.lockdir" 2>/dev/null; do
sleep 0.01
local now
now=$(date +%s)
if ((now - start_time >= max_wait)); then
log_step "WARNING: Lock wait exceeded ${max_wait}s. Forcibly removing stale lock."
rm -rf "$STATUS_FILE.lockdir"
fi
done
}
unlock_status() {
rmdir "$STATUS_FILE.lockdir"
}
update_status() {
local file_path="$1" lang="$2" status="$3"
lock_status
jq --arg file "$file_path" --arg lang "$lang" --arg status "$status" \
'.[$file][$lang] = $status' "$STATUS_FILE" >"$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
unlock_status
}
# --- Translation Function ---
translate_text() {
local text="$1" lang="$2"
local retry_count=0
while [ "$retry_count" -lt "$MAX_RETRIES" ]; do
user_message="Translate the following text to $lang. Preserve all formatting exactly as in the original.
$text"
json_payload=$(jq -n \
--arg system "Translate from English to $lang. Preserve original formatting exactly." \
--arg user_message "$user_message" \
'{
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": $system},
{"role": "user", "content": $user_message}
],
"temperature": 0.3
}')
response=$(curl -s https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "$json_payload")
log_step "📥 Received API response."
local error_type
error_type=$(echo "$response" | jq -r '.error.type // empty')
local error_message
error_message=$(echo "$response" | jq -r '.error.message // empty')
if [ "$error_type" == "insufficient_quota" ]; then
sleep "$WAIT_TIME"
retry_count=$((retry_count + 1))
elif [[ "$error_type" == "rate_limit_reached" || "$error_type" == "server_error" || "$error_type" == "service_unavailable" ]]; then
sleep "$WAIT_TIME"
retry_count=$((retry_count + 1))
elif [ "$error_type" == "invalid_request_error" ]; then
return 1
elif [ -z "$error_type" ]; then
if ! translated_text=$(echo "$response" | jq -r '.choices[0].message.content' 2>/dev/null); then
return 1
fi
if [ "$translated_text" == "null" ] || [ -z "$translated_text" ]; then
return 1
else
translated_text=$(echo "$translated_text" | sed -e 's/^```[[:space:]]*//; s/[[:space:]]*```$//')
echo "$translated_text"
return 0
fi
else
return 1
fi
done
return 1
}
# --- Process a Single File (Sequential Version) ---
process_file() {
local src_file="$1" target_file="$2" lang="$3" rel_src="$4"
# If target file exists and is non-empty, mark status as success.
if [ -s "$target_file" ]; then
update_status "$rel_src" "$lang" "success"
return 0
fi
content=$(<"$src_file")
if [[ "$content" =~ ^[---|\+\+\+]([:space:)]*$ ]] && [[ "$content" =~ [[:space:]]*[---|\+\+\+\+]([:space:)]*$ ]]; then
front_matter=$(echo "$content" | sed -n '/^\(---\|\+\+\+\)$/,/^\(---\|\+\+\+\)$/p')
body_content=$(echo "$content" | sed -n '/^\(---\|\+\+\+\)$/,/^\(---\|\+\+\+\)$/d')
else
front_matter=""
body_content="$content"
fi
log_step "Translating [$rel_src] to $lang..."
translated_body=$(translate_text "$body_content" "$lang")
if [ $? -ne 0 ]; then
update_status "$rel_src" "$lang" "failed"
return 1
fi
mkdir -p "$(dirname "$target_file")"
if [ -n "$front_matter" ]; then
echo -e "$front_matter
$translated_body" >"$target_file"
else
echo -e "$translated_body" >"$target_file"
fi
updated_content=$(echo "$content" | sed -E 's/^retranslate:\s*true/retranslate: false/')
echo "$updated_content" >"$src_file"
update_status "$rel_src" "$lang" "success"
}
# --- Main Sequential Processing ---
ALL_SUCCESS=true
for TARGET_LANG in "${SUPPORTED_LANGUAGES[@]}"; do
log_step "Processing language: $TARGET_LANG"
TARGET_DIR="$SCRIPT_DIR/Content/$TARGET_LANG"
while IFS= read -r -d '' src_file; do
rel_src="${src_file#$SCRIPT_DIR/}"
target_file="$TARGET_DIR/${src_file#$SRC_DIR/}"
# If file is marked not to retranslate, check that target file exists and is non-empty.
if ! [[ " ${NEW_LANGUAGES[@]:-} " =~ " ${TARGET_LANG} " ]] && grep -q '^retranslate:\s*false' "$src_file"; then
if [ -s "$target_file" ]; then
update_status "$rel_src" "$TARGET_LANG" "success"
else
update_status "$rel_src" "$TARGET_LANG" "failed"
fi
continue
fi
process_file "$src_file" "$target_file" "$TARGET_LANG" "$rel_src"
done < <(find "$SRC_DIR" -type f -name "*.md" -print0)
done
log_step "Translation run completed."
end_time=$(date +%s)
duration=$((end_time - $(date +%s)))
log_step "Execution Time: $duration seconds"
if [ "$ALL_SUCCESS" = true ]; then
log_step "🎉 Translation completed successfully for all supported languages!"
else
log_step "⚠️ Translation completed with some errors."
fi
# --- Clean Up Fully Translated New Languages ---
if [ -f "$SCRIPT_DIR/translate_new_language.txt" ]; then
log_step "Cleaning up fully translated new languages..."
for lang in "${NEW_LANGUAGES[@]:-}"; do
incomplete=$(jq --arg lang "$lang" 'to_entries[] | select(.value[$lang] != null and (.value[$lang] != "success")) | .key' "$STATUS_FILE")
if [ -z "$incomplete" ]; then
log_step "All translations for new language '$lang' are marked as success. Removing from translate_new_language.txt."
sed -E -i '' "/^[[:space:]]*$lang[[:space:]]*$/d" "$SCRIPT_DIR/translate_new_language.txt"
else
log_step "Language '$lang' still has incomplete translations."
fi
done
fi
```
3. Ṣíṣàkóso Ìpẹ̀yà Ìtúmọ̀
Láti yára yàgò fún ìtúmọ̀ tó tún ṣe àtìlẹ́yìn àti láti tọ́pa ìtẹ̀síwájú, a lo fáìlì JSON (translation_status.json). Script náà máa ṣe àtúnṣe fáìlì yìí lẹ́yìn tí ó bá ti ṣe ìtúmọ̀ fáìlì kọọkan, tó jẹ́ kí a túmọ̀ àwọn àkóónú tuntun tàbí tí a ti ṣe àtúnṣe nìkan.
4. Ìṣàkóso Àṣìṣe àti Ìdènà Ìwọ̀n API
A ṣe àtúnṣe ìgbìmọ̀ àti ìṣàkóso àṣìṣe láti bá àwọn ìdènà ìwọ̀n, ìṣòro API, àti ìṣòro àfikún ṣiṣẹ́. Script náà máa dúró díẹ̀ kí ó tó tún gbìmọ̀ ṣe tí API OpenAI bá fi àṣìṣe hàn bíi rate_limit_reached tàbí service_unavailable.
5. Ìfọwọ́sowọ́pọ̀
Lẹ́yìn tí a bá ti ṣe àkóónú tí a túmọ̀, ṣiṣe hugo --minify máa kọ ojúlé wẹẹbù tó ní ọ̀pọ̀ èdè, tó ṣètò tán fún ìfọwọ́sowọ́pọ̀.
Àwọn Ìṣòro àti Ìtúnṣe
1. Ìtẹ́lọ́run Ìtúmọ̀
Bí ó tilẹ̀ jẹ́ pé ìtúmọ̀ OpenAI sábà máa péye, àwọn ọ̀rọ̀ amọ̀ràn kan lè nílò àyẹ̀wò ọwọ́, ṣùgbọ́n a jẹ́ ẹgbẹ́ méjì nìkan, torí náà a ń retí ohun tó dára jùlọ. A tún ṣe àtúnṣe àwọn ìbéèrè láti pa àkóónú àti ìtóka mọ́.
2. Ìṣòro Fọ́ọ̀mátì
Àwọn àmì Markdown máa ń yí padà nígbà ìtúmọ̀. Láti ṣètò yìí, a fi ọgbọ́n ìṣàkóso lẹ́yìn ìtúmọ̀ kún un láti pa fọ́ọ̀mátì mọ́.
3. Ìdínkù Owó API
Láti dín owó ku, a ṣe ìpamọ́ (caching) láti yára yàgò fún ìtúmọ̀ àkóónú tó kò yí padà.
4. Ṣíṣàkóso Ìtúmọ̀ Lẹ́ẹ̀kansi Ní Rọrun
Láti túmọ̀ ojúlé kan lẹ́ẹ̀kansi, a fi àfikún retranslate: true sí ìpẹ̀yà ìtẹ̀jáde ojúlé. Script náà máa túmọ̀ ojúlé tó ní àfikún yìí nìkan. Èyí ń jẹ́ kí a lè ṣe àtúnṣe ìtúmọ̀ nígbà tó bá yẹ láì ní láti tún gbogbo ojúlé ṣe.
Ìparí
Nípasẹ̀ ìdarapọ̀ API OpenAI pẹ̀lú Hugo, a ṣàkóso ìtúmọ̀ ojúlé wẹẹbù wa pẹ̀lú fífi àyẹ̀wò àti àfọwọ́kọ pamọ́. Ọ̀nà yìí fi àkókò pamọ́, dájú pé ohun gbogbo wà ní ìbámu, àti pé a lè gbooro rọrùn. Tí o bá fẹ́ jẹ́ kí ojúlé Hugo rẹ jẹ́ ọ̀pọ̀ èdè, API OpenAI jẹ́ ojútùú tó lágbára.
