Skip to content

Instantly share code, notes, and snippets.

@adamcooper
Created January 26, 2026 05:13
Show Gist options
  • Select an option

  • Save adamcooper/0f944d8043d8cb59e2c881ac85c26b93 to your computer and use it in GitHub Desktop.

Select an option

Save adamcooper/0f944d8043d8cb59e2c881ac85c26b93 to your computer and use it in GitHub Desktop.
Arabic translation helper scripts for i18n-tasks with OpenAI backend
#!/bin/bash
# Script to translate missing Arabic locale keys in batches
# Uses i18n-tasks with OpenAI backend
set -e
# Load environment variables
export $(cat .env | grep -v '^#' | xargs)
# Function to translate a pattern with retry logic
translate_pattern() {
local pattern=$1
local max_retries=3
local retry=0
echo "Translating pattern: $pattern"
while [ $retry -lt $max_retries ]; do
if bundle exec i18n-tasks translate-missing ar --backend openai --skip-interpolation --pattern "$pattern" 2>&1; then
echo " Success: $pattern"
return 0
else
retry=$((retry + 1))
echo " Retry $retry/$max_retries for $pattern"
sleep 2
fi
done
echo " FAILED after $max_retries retries: $pattern"
return 1
}
echo "Starting Arabic translation generation..."
echo "==========================================="
# Top-level patterns (smaller chunks to avoid timeouts)
patterns=(
# Account section
"account.*"
# ActiveRecord
"activerecord.*"
# Admin section
"admin.*"
# Devise/Auth
"devise.*"
# Errors
"errors.*"
# Field sections (broken into smaller chunks)
"field.assessments.*"
"field.bulletins.*"
"field.calendar.*"
"field.communications.*"
"field.dashboard.*"
"field.daily_post.*"
"field.discuss.*"
"field.events.*"
"field.follow_ups.*"
"field.groups.*"
"field.highlights.*"
"field.learning.*"
"field.library.*"
"field.messages.*"
"field.notices.*"
"field.schedule.*"
"field.surveys.*"
"field.tasks.*"
"field.team.*"
"field.users.*"
"field.widgets.*"
# Helpers
"helpers.*"
# Layouts
"layouts.*"
# Mailers
"mailers.*"
# Publisher sections (broken into smaller chunks)
"publisher.assessments.*"
"publisher.bulletins.*"
"publisher.calendar.*"
"publisher.communications.*"
"publisher.dashboard.*"
"publisher.events.*"
"publisher.groups.*"
"publisher.learning.*"
"publisher.library.*"
"publisher.notices.*"
"publisher.reports.*"
"publisher.schedule.*"
"publisher.settings.*"
"publisher.surveys.*"
"publisher.tasks.*"
"publisher.users.*"
"publisher.widgets.*"
# Shared sections
"shared.address_book.*"
"shared.assessments.*"
"shared.communication.*"
"shared.components.*"
"shared.distribution.*"
"shared.events.*"
"shared.flash.*"
"shared.forms.*"
"shared.groups.*"
"shared.layout.*"
"shared.learning.*"
"shared.library.*"
"shared.pagination.*"
"shared.schedule.*"
"shared.surveys.*"
"shared.tasks.*"
"shared.users.*"
# Other top-level
"api.*"
"cable.*"
"components.*"
"javascript.*"
"number.*"
"support.*"
"views.*"
)
# Track results
succeeded=0
failed=0
failed_patterns=()
for pattern in "${patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
# Small delay between requests to avoid rate limiting
sleep 1
done
echo ""
echo "==========================================="
echo "Translation complete!"
echo "Succeeded: $succeeded"
echo "Failed: $failed"
if [ ${#failed_patterns[@]} -gt 0 ]; then
echo ""
echo "Failed patterns:"
for p in "${failed_patterns[@]}"; do
echo " - $p"
done
fi
# Final cleanup - try to catch any remaining keys with broader patterns
echo ""
echo "Running final pass for any remaining keys..."
bundle exec i18n-tasks translate-missing ar --backend openai --skip-interpolation 2>&1 || echo "Final pass completed with some errors (expected if patterns covered everything)"
echo ""
echo "Done! Check config/locales/ar.yml for the translations."
#!/bin/bash
# Script to translate ALL missing Arabic locale keys in manageable chunks
# Uses i18n-tasks with OpenAI backend
# Based on analysis showing 8,157 missing keys across various namespaces
set -e
# Load environment variables
export $(cat .env | grep -v '^#' | xargs)
# Check for required API key
if [ -z "$OPENAI_API_TRANSLATIONS_KEY" ]; then
echo "Error: OPENAI_API_TRANSLATIONS_KEY not set in .env"
exit 1
fi
# Log file for tracking progress
LOG_FILE="translation_output.log"
echo "Starting Arabic translation - $(date)" > "$LOG_FILE"
# Function to translate a pattern with retry logic
translate_pattern() {
local pattern=$1
local max_retries=3
local retry=0
echo "Translating: $pattern"
while [ $retry -lt $max_retries ]; do
if bundle exec i18n-tasks translate-missing ar --backend openai --pattern "$pattern" 2>&1 | tee -a "$LOG_FILE"; then
echo " Success: $pattern"
echo "SUCCESS: $pattern" >> "$LOG_FILE"
return 0
else
retry=$((retry + 1))
echo " Retry $retry/$max_retries for $pattern"
sleep 2
fi
done
echo " FAILED after $max_retries retries: $pattern"
echo "FAILED: $pattern" >> "$LOG_FILE"
return 1
}
echo "Starting Arabic translation generation..."
echo "==========================================="
echo "Total missing keys before: $(bundle exec i18n-tasks missing ar --format keys 2>/dev/null | wc -l)"
echo ""
# Track results
succeeded=0
failed=0
failed_patterns=()
# ============================================
# CHUNK 1-3: Learning namespace (1,221 keys)
# ============================================
echo ""
echo "=== Learning namespace ==="
learning_patterns=(
"learning.creator.*"
"learning.reporting.*"
"learning.learner.*"
"learning.shared.*"
"learning.progress.*"
"learning.quizzes.*"
"learning.coach.*"
"learning.admin.*"
)
for pattern in "${learning_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 4-6: Notification namespace (951 keys)
# ============================================
echo ""
echo "=== Notification namespace ==="
notification_patterns=(
"notification.email.*"
"notification.aws_sns.*"
"notification.application.*"
"notification.group.*"
"notification.notifier_and_group.*"
"notification.title.*"
"notification.test.*"
)
for pattern in "${notification_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 7-9: Settings namespace (822 keys)
# ============================================
echo ""
echo "=== Settings namespace ==="
settings_patterns=(
"settings.users.*"
"settings.dashboard_widgets.*"
"settings.webhook.*"
"settings.branding_packages.*"
"settings.settings.*"
"settings.email_workflows.*"
"settings.dashboard_widget_positions.*"
"settings.link_resources.*"
"settings.communication_templates.*"
"settings.hubs.*"
"settings.joint_publishing_team_configurations.*"
"settings.dashboard_widget_types.*"
"settings.distribution_lists.*"
"settings.teams.*"
"settings.dashboard_widget_preview.*"
)
for pattern in "${settings_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 10-11: Field namespace (672 keys)
# ============================================
echo ""
echo "=== Field namespace ==="
field_patterns=(
"field.overdue_task_report.*"
"field.insights.*"
"field.tour.*"
"field.day_sheets.*"
"field.calendars.*"
"field.team_tasks.*"
"field.reactions.*"
"field.timesheet.*"
"field.service_requests.*"
"field.team_task_schedules.*"
"field.publisher.*"
"field.daily_posts.*"
"field.today.*"
"field.shared.*"
"field.team_events.*"
"field.shared_communications.*"
"field.recognitions.*"
"field.my_tasks.*"
"field.email_to_zipline.*"
"field.search.*"
"field.bookmarks.*"
"field.day_sheet_comments.*"
"field.overdue_tasks.*"
"field.individual_tasks.*"
"field.task_follow_up.*"
"field.forms.*"
)
for pattern in "${field_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 12-13: Audit namespace (549 keys)
# ============================================
echo ""
echo "=== Audit namespace ==="
audit_patterns=(
"audit.assessments.*"
"audit.results.*"
"audit.publisher.*"
"audit.auditees.*"
)
for pattern in "${audit_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 14-15: Publisher namespace (541 keys)
# ============================================
echo ""
echo "=== Publisher namespace ==="
publisher_patterns=(
"publisher.editor.*"
"publisher.calendars.*"
"publisher.bundles.*"
"publisher.communication_targets.*"
"publisher.dropzone.*"
"publisher.email_preview.*"
"publisher.publications.*"
"publisher.tour.*"
"publisher.approvals.*"
"publisher.mailers.*"
"publisher.search.*"
"publisher.general.*"
)
for pattern in "${publisher_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 16: Reports namespace (512 keys)
# ============================================
echo ""
echo "=== Reports namespace ==="
if translate_pattern "reports.*"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("reports.*")
fi
sleep 1
# ============================================
# CHUNK 17: Shared + Resource Library (625 keys)
# ============================================
echo ""
echo "=== Shared and Resource Library namespaces ==="
shared_patterns=(
"shared.*"
"resource_library.*"
)
for pattern in "${shared_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 18: Survey, File Import, Discuss (622 keys)
# ============================================
echo ""
echo "=== Survey, File Import, Discuss namespaces ==="
survey_patterns=(
"survey.*"
"file_import.*"
"discuss.*"
)
for pattern in "${survey_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 19: Widgets, Report Builder, Communications (553 keys)
# ============================================
echo ""
echo "=== Widgets, Report Builder, Communications namespaces ==="
widgets_patterns=(
"widgets.*"
"report_builder.*"
"communications.*"
"communication.*"
)
for pattern in "${widgets_patterns[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# CHUNK 20: All remaining small namespaces (~1,089 keys)
# Split into 3 sub-batches to avoid timeout issues
# ============================================
echo ""
echo "=== Remaining small namespaces (batch 1/3) ==="
remaining_batch1=(
"ukg.*"
"schedule.*"
"activemodel.*"
"notification_mailer.*"
"user_mailer.*"
"ai.*"
"email_processor.*"
"summary.*"
"teams.*"
"messenger.*"
"forced_password_resets.*"
"training.*"
"system_mailer.*"
"highlights.*"
"video_attachments.*"
"switchboard.*"
"dictionary.*"
"commentable.*"
)
for pattern in "${remaining_batch1[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
echo ""
echo "=== Remaining small namespaces (batch 2/3) ==="
remaining_batch2=(
"timesheet.*"
"password_resets.*"
"sessions.*"
"service.*"
"saml.*"
"help_forums.*"
"data_imports.*"
"forgot_password.*"
"downloadable_reports.*"
"active_storage.*"
"onboard_setup.*"
"changelog.*"
"filterable.*"
"icons.*"
"insights.*"
"activerecord.*"
"system.*"
"summary_mailer.*"
)
for pattern in "${remaining_batch2[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
echo ""
echo "=== Remaining small namespaces (batch 3/3) ==="
remaining_batch3=(
"securable.*"
"search.*"
"integrations.*"
"datetime.*"
"vcard.*"
"user.*"
"mailer.*"
"joint_publishing_field.*"
"integration_activation_mailer.*"
"error_pages.*"
"downloadable_report_mailer.*"
"distribution.*"
"team_levels.*"
"team.*"
"task.*"
"related_resources.*"
"policies.*"
"person.*"
"password_reset.*"
"mobile.*"
"bookmarks.*"
"autosave.*"
"saved_filters.*"
"recurring_schedules.*"
"recognition.*"
"pins.*"
"global.*"
"favorites.*"
"widget.*"
"view_as.*"
"team_memberships.*"
"signatures.*"
"modal.*"
"kaminari.*"
"i18n.*"
"default_page_title.*"
"copy.*"
"calendar_feed.*"
)
for pattern in "${remaining_batch3[@]}"; do
if translate_pattern "$pattern"; then
succeeded=$((succeeded + 1))
else
failed=$((failed + 1))
failed_patterns+=("$pattern")
fi
sleep 1
done
# ============================================
# Final pass - catch any remaining keys
# ============================================
echo ""
echo "=== Final pass for any remaining keys ==="
bundle exec i18n-tasks translate-missing ar --backend openai 2>&1 | tee -a "$LOG_FILE" || echo "Final pass completed"
# ============================================
# Summary
# ============================================
echo ""
echo "==========================================="
echo "Translation complete!"
echo "==========================================="
echo "Pattern results:"
echo " Succeeded: $succeeded"
echo " Failed: $failed"
if [ ${#failed_patterns[@]} -gt 0 ]; then
echo ""
echo "Failed patterns:"
for p in "${failed_patterns[@]}"; do
echo " - $p"
done
fi
# Count remaining missing keys
remaining=$(bundle exec i18n-tasks missing ar --format keys 2>/dev/null | wc -l)
echo ""
echo "Missing keys remaining: $remaining"
echo ""
echo "Translation log saved to: $LOG_FILE"
echo "Check config/locales/ar.yml for the translations."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment