i18n+filtering fork - fluent-templates v2
at main 8.5 kB view raw
1#!/bin/bash 2 3# Script to detect and remove duplicate keys in FTL files 4# Usage: ./clean_ftl_duplicates.sh [directory] 5 6set -e 7 8# Colors for display 9RED='\033[0;31m' 10GREEN='\033[0;32m' 11YELLOW='\033[1;33m' 12BLUE='\033[0;34m' 13NC='\033[0m' # No Color 14 15# Help function 16show_help() { 17 echo "Usage: $0 [OPTIONS] [DIRECTORY]" 18 echo "" 19 echo "Detects and removes duplicate keys in FTL files" 20 echo "" 21 echo "OPTIONS:" 22 echo " -h, --help Show this help" 23 echo " -l, --list List mode (does not modify files, only shows duplicates)" 24 echo " -v, --verbose Verbose mode" 25 echo " -i, --interactive Interactive mode (choose which occurrences to keep)" 26 echo "" 27 echo "ARGUMENTS:" 28 echo " DIRECTORY Directory containing FTL files (default: current directory)" 29 echo "" 30 echo "Examples:" 31 echo " $0 # Process current directory" 32 echo " $0 ./translations # Process ./translations directory" 33 echo " $0 -l ./translations # List mode" 34} 35 36# Default variables 37DIRECTORY="." 38LIST_ONLY=false 39VERBOSE=false 40INTERACTIVE=true # Default to interactive mode 41 42# Parse arguments 43while [[ $# -gt 0 ]]; do 44 case $1 in 45 -h|--help) 46 show_help 47 exit 0 48 ;; 49 -l|--list) 50 LIST_ONLY=true 51 shift 52 ;; 53 -v|--verbose) 54 VERBOSE=true 55 shift 56 ;; 57 -i|--interactive) 58 INTERACTIVE=true 59 shift 60 ;; 61 -*) 62 echo -e "${RED}Unknown option: $1${NC}" >&2 63 show_help 64 exit 1 65 ;; 66 *) 67 DIRECTORY="$1" 68 shift 69 ;; 70 esac 71done 72 73# Check that directory exists 74if [[ ! -d "$DIRECTORY" ]]; then 75 echo -e "${RED}Error: Directory '$DIRECTORY' does not exist${NC}" >&2 76 exit 1 77fi 78 79# Function to extract keys from an FTL file 80extract_keys() { 81 local file="$1" 82 # Extract keys (lines that start with non-space characters followed by =) 83 grep -E "^[^#[:space:]][^=]*=" "$file" 2>/dev/null | cut -d'=' -f1 | sed 's/[[:space:]]*$//' || true 84} 85 86# Function to get all occurrences of a key with their context 87get_key_occurrences() { 88 local key="$1" 89 shift 90 local files=("$@") 91 local -a occurrences 92 local index=0 93 94 for file in "${files[@]}"; do 95 local line_num=1 96 while IFS= read -r line; do 97 if [[ "$line" =~ ^[[:space:]]*"$key"[[:space:]]*= ]]; then 98 occurrences[$index]="$file:$line_num:$line" 99 ((index++)) 100 fi 101 ((line_num++)) 102 done < "$file" 103 done 104 105 printf '%s\n' "${occurrences[@]}" 106} 107 108# Function to display occurrences and let user choose 109choose_occurrence_to_keep() { 110 local key="$1" 111 shift 112 local files=("$@") 113 114 echo -e "${RED}Duplicate key found:${NC} '$key'" 115 echo "" 116 117 # Get all occurrences 118 local -a occurrences 119 mapfile -t occurrences < <(get_key_occurrences "$key" "${files[@]}") 120 121 if [[ ${#occurrences[@]} -eq 0 ]]; then 122 echo -e "${RED}Error: No occurrences found${NC}" 123 return 1 124 fi 125 126 # Display all occurrences 127 echo "Found ${#occurrences[@]} occurrences:" 128 for i in "${!occurrences[@]}"; do 129 local occurrence="${occurrences[$i]}" 130 IFS=':' read -r file line_num content <<< "$occurrence" 131 echo -e " ${YELLOW}[$((i+1))]${NC} $(basename "$file"):$line_num" 132 echo -e " $content" 133 echo "" 134 done 135 136 # Ask user to choose 137 while true; do 138 if [[ "$LIST_ONLY" == true ]]; then 139 echo -e "${YELLOW}LIST MODE: Showing duplicates only${NC}" 140 echo "" 141 return 0 142 fi 143 144 echo -e "${BLUE}Which occurrence do you want to KEEP?${NC} [1-${#occurrences[@]}] (or 's' to skip): " 145 read -r choice 146 147 if [[ "$choice" == "s" || "$choice" == "S" ]]; then 148 echo -e "${YELLOW}Skipping '$key'${NC}" 149 echo "" 150 return 0 151 fi 152 153 if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#occurrences[@]} ]]; then 154 local keep_index=$((choice-1)) 155 break 156 else 157 echo -e "${RED}Invalid choice. Please enter a number between 1 and ${#occurrences[@]}, or 's' to skip.${NC}" 158 fi 159 done 160 161 # Remove all occurrences except the chosen one 162 echo -e "Keeping occurrence #$choice, removing others..." 163 164 for i in "${!occurrences[@]}"; do 165 if [[ $i -ne $keep_index ]]; then 166 local occurrence="${occurrences[$i]}" 167 IFS=':' read -r file line_num content <<< "$occurrence" 168 remove_occurrence_at_line "$file" "$line_num" "$key" 169 fi 170 done 171 172 echo -e "${GREEN}${NC} Cleaned up duplicates for '$key'" 173 echo "" 174} 175 176# Function to remove a specific occurrence at a given line number 177remove_occurrence_at_line() { 178 local file="$1" 179 local target_line="$2" 180 local key="$3" 181 182 if [[ "$LIST_ONLY" == true ]]; then 183 echo -e "${YELLOW}[LIST MODE]${NC} Would remove line $target_line from $(basename "$file")" 184 return 185 fi 186 187 # Create temporary copy 188 local temp_file=$(mktemp) 189 local current_line=1 190 191 while IFS= read -r line; do 192 if [[ $current_line -eq $target_line ]]; then 193 if [[ "$VERBOSE" == true ]]; then 194 echo -e " ${RED}Removed:${NC} $(basename "$file"):$target_line: $line" 195 fi 196 # Skip this line (don't write it to temp file) 197 else 198 echo "$line" >> "$temp_file" 199 fi 200 ((current_line++)) 201 done < "$file" 202 203 # Replace original file 204 mv "$temp_file" "$file" 205 echo -e " ${GREEN}${NC} Removed line $target_line from $(basename "$file")" 206} 207 208# Main function 209main() { 210 echo -e "${BLUE}=== FTL Duplicate Key Cleanup ===${NC}" 211 echo -e "Directory: ${YELLOW}$DIRECTORY${NC}" 212 213 if [[ "$LIST_ONLY" == true ]]; then 214 echo -e "Mode: ${YELLOW}LIST ONLY${NC} (no files will be modified)" 215 fi 216 217 echo "" 218 219 # Find all FTL files 220 local ftl_files=($(find "$DIRECTORY" -maxdepth 1 -name "*.ftl" -type f)) 221 222 if [[ ${#ftl_files[@]} -eq 0 ]]; then 223 echo -e "${YELLOW}No FTL files found in '$DIRECTORY'${NC}" 224 exit 0 225 fi 226 227 echo -e "${BLUE}FTL files found: ${#ftl_files[@]}${NC}" 228 for file in "${ftl_files[@]}"; do 229 echo " - $(basename "$file")" 230 done 231 echo "" 232 233 # Collect all keys with their source files 234 declare -A key_files 235 declare -A key_counts 236 237 echo -e "${BLUE}Analyzing keys...${NC}" 238 239 for file in "${ftl_files[@]}"; do 240 if [[ "$VERBOSE" == true ]]; then 241 echo " Analyzing $(basename "$file")..." 242 fi 243 244 while IFS= read -r key; do 245 [[ -z "$key" ]] && continue 246 247 if [[ -z "${key_files[$key]}" ]]; then 248 key_files[$key]="$file" 249 key_counts[$key]=1 250 else 251 key_files[$key]="${key_files[$key]}|$file" 252 ((key_counts[$key]++)) 253 fi 254 done < <(extract_keys "$file") 255 done 256 257 # Find and process duplicates 258 local duplicates_found=false 259 260 echo -e "${BLUE}Searching for duplicates...${NC}" 261 echo "" 262 263 for key in "${!key_counts[@]}"; do 264 if [[ ${key_counts[$key]} -gt 1 ]]; then 265 duplicates_found=true 266 267 # Split files for this key 268 IFS='|' read -ra files <<< "${key_files[$key]}" 269 270 # Let user choose which occurrence to keep 271 choose_occurrence_to_keep "$key" "${files[@]}" 272 fi 273 done 274 275 if [[ "$duplicates_found" == false ]]; then 276 echo -e "${GREEN}✓ No duplicate keys found!${NC}" 277 else 278 if [[ "$LIST_ONLY" == true ]]; then 279 echo -e "${YELLOW}List mode completed. Run again without -l to apply changes.${NC}" 280 else 281 echo -e "${GREEN}✓ Cleanup completed!${NC}" 282 fi 283 fi 284} 285 286# Check dependencies 287command -v grep >/dev/null 2>&1 || { echo -e "${RED}Error: 'grep' is not installed${NC}" >&2; exit 1; } 288command -v cut >/dev/null 2>&1 || { echo -e "${RED}Error: 'cut' is not installed${NC}" >&2; exit 1; } 289command -v sed >/dev/null 2>&1 || { echo -e "${RED}Error: 'sed' is not installed${NC}" >&2; exit 1; } 290 291# Main execution 292main