Created
January 26, 2026 05:13
-
-
Save adamcooper/0f944d8043d8cb59e2c881ac85c26b93 to your computer and use it in GitHub Desktop.
Arabic translation helper scripts for i18n-tasks with OpenAI backend
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
| #!/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." |
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
| #!/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