#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ suggest_translation.py This script reads the outdated_pages.json file generated by wiki_compare.py, identifies English wiki pages that don't have a French translation, and posts a message on Mastodon suggesting that the page needs translation. Usage: python suggest_translation.py [--dry-run] Options: --dry-run Run the script without actually posting to Mastodon Output: - A post on Mastodon suggesting a wiki page for translation - Log messages about the selected page and posting status """ import json import random import argparse import logging import os from datetime import datetime import requests # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger(__name__) # Constants OUTDATED_PAGES_FILE = "outdated_pages.json" MASTODON_API_URL = "https://mastodon.instance/api/v1/statuses" # Replace with actual instance MASTODON_ACCESS_TOKEN = os.environ.get("MASTODON_ACCESS_TOKEN") def load_outdated_pages(): """ Load the outdated pages from the JSON file Returns: list: List of dictionaries containing outdated page information """ try: with open(OUTDATED_PAGES_FILE, 'r', encoding='utf-8') as f: pages = json.load(f) logger.info(f"Successfully loaded {len(pages)} pages from {OUTDATED_PAGES_FILE}") return pages except (IOError, json.JSONDecodeError) as e: logger.error(f"Error loading pages from {OUTDATED_PAGES_FILE}: {e}") return [] def find_missing_translations(pages): """ Find English pages that don't have a French translation Args: pages (list): List of dictionaries containing page information Returns: list: List of pages that need translation """ # Filter pages to include only those with a missing French page missing_translations = [page for page in pages if page.get('reason') == 'French page missing' and page.get('en_page') is not None and page.get('fr_page') is None] logger.info(f"Found {len(missing_translations)} pages without French translation") return missing_translations def select_random_page_for_translation(pages): """ Randomly select a page for translation from the list Args: pages (list): List of dictionaries containing page information Returns: dict: Randomly selected page or None if no suitable pages found """ if not pages: logger.warning("No pages found that need translation") return None # Randomly select a page selected_page = random.choice(pages) logger.info(f"Randomly selected page for key '{selected_page['key']}' for translation") return selected_page def create_mastodon_post(page): """ Create a Mastodon post suggesting a page for translation Args: page (dict): Dictionary containing page information Returns: str: Formatted Mastodon post text """ key = page['key'] en_url = page['en_page']['url'] fr_url = en_url.replace('/wiki/Key:', '/wiki/FR:Key:') # Get word count and sections from English page word_count = page['en_page']['word_count'] sections = page['en_page']['sections'] # Format the post post = f"""🔍 Clé OSM sans traduction française : #{key} Cette page wiki importante n'a pas encore de traduction française ! 📊 Statistiques de la page anglaise : • {word_count} mots • {sections} sections Vous pouvez aider en créant la traduction française ici : {fr_url} Page anglaise à traduire : {en_url} #OpenStreetMap #OSM #Wiki #Traduction #Contribution""" return post def post_to_mastodon(post_text, dry_run=False): """ Post the message to Mastodon Args: post_text (str): Text to post dry_run (bool): If True, don't actually post to Mastodon Returns: bool: True if posting was successful or dry run, False otherwise """ if dry_run: logger.info("DRY RUN: Would have posted to Mastodon:") logger.info(post_text) return True if not MASTODON_ACCESS_TOKEN: logger.error("MASTODON_ACCESS_TOKEN environment variable not set") return False headers = { "Authorization": f"Bearer {MASTODON_ACCESS_TOKEN}", "Content-Type": "application/json" } data = { "status": post_text, "visibility": "public" } try: response = requests.post(MASTODON_API_URL, headers=headers, json=data) response.raise_for_status() logger.info("Successfully posted to Mastodon") return True except requests.exceptions.RequestException as e: logger.error(f"Error posting to Mastodon: {e}") return False def main(): """Main function to execute the script""" parser = argparse.ArgumentParser(description="Suggest an OSM wiki page for translation on Mastodon") parser.add_argument("--dry-run", action="store_true", help="Run without actually posting to Mastodon") args = parser.parse_args() logger.info("Starting suggest_translation.py") # Load pages pages = load_outdated_pages() if not pages: logger.error("No pages found. Run wiki_compare.py first.") return # Find pages that need translation pages_for_translation = find_missing_translations(pages) if not pages_for_translation: logger.error("No pages found that need translation.") return # Select a random page for translation selected_page = select_random_page_for_translation(pages_for_translation) if not selected_page: logger.error("Could not select a page for translation.") return # Create the post text post_text = create_mastodon_post(selected_page) # Post to Mastodon success = post_to_mastodon(post_text, args.dry_run) if success: logger.info("Script completed successfully") else: logger.error("Script completed with errors") if __name__ == "__main__": main()