i18n-json-check: removed empty nested structure.

This commit is contained in:
ItsLemmy
2025-10-09 20:39:28 -04:00
parent 6b444cea07
commit c96eecedb3
6 changed files with 200 additions and 229 deletions
-48
View File
@@ -283,10 +283,6 @@
"section": {
"label": "Monitor-Anzeige",
"description": "Statusleiste auf bestimmten Monitoren anzeigen. Standard ist alle, wenn keine ausgewählt sind."
},
"only-same-output": {
"label": "Nur Apps vom gleichen Bildschirm",
"description": "Zeige nur Apps vom dem Bildschirm an, wo sich das Dock befindet."
}
}
},
@@ -748,50 +744,6 @@
"sectionName": "Schnelleinstellungen"
}
},
"quickSettings": {
"notifications": {
"label": "Benachrichtigungen",
"tooltip": {
"enable": "Nicht stören aktivieren",
"disable": "Nicht stören deaktivieren"
}
},
"wifi": {
"label": {
"wifi": "Wi-Fi",
"ethernet": "Netzwerk"
},
"tooltip": {
"wifi": {
"connected": "Wi-Fi verbunden",
"disconnected": "Wi-Fi getrennt"
},
"ethernet": {
"connected": "Ethernet verbunden"
}
}
},
"bluetooth": {
"label": "Bluetooth",
"tooltip": {
"enabled": "Bluetooth aktiviert",
"disabled": "Bluetooth deaktiviert"
}
},
"screenRecorder": {
"label": "Bildschirm",
"tooltip": {
"start": "Bildschirmaufnahme starten",
"stop": "Aufnahme beenden"
}
},
"powerProfile": {
"tooltip": {
"current": "Aktuell: {profile}",
"unavailable": "Energieprofile nicht verfügbar"
}
}
},
"hooks": {
"title": "Hooks",
"system-hooks": {
-44
View File
@@ -744,50 +744,6 @@
"sectionName": "Ajustes rápidos"
}
},
"quickSettings": {
"notifications": {
"label": "Notificaciones",
"tooltip": {
"enable": "Activar No molestar",
"disable": "Desactivar No molestar"
}
},
"wifi": {
"label": {
"wifi": "Wi-Fi",
"ethernet": "Red"
},
"tooltip": {
"wifi": {
"connected": "Wi-Fi conectado",
"disconnected": "Wi-Fi desconectado"
},
"ethernet": {
"connected": "Ethernet conectado"
}
}
},
"bluetooth": {
"label": "Bluetooth",
"tooltip": {
"enabled": "Bluetooth habilitado",
"disabled": "Bluetooth deshabilitado"
}
},
"screenRecorder": {
"label": "Pantalla",
"tooltip": {
"start": "Iniciar grabación de pantalla",
"stop": "Detener grabación"
}
},
"powerProfile": {
"tooltip": {
"current": "Actual: {profile}",
"unavailable": "Perfiles de energía no disponibles"
}
}
},
"hooks": {
"title": "Hooks",
"system-hooks": {
-44
View File
@@ -744,50 +744,6 @@
"sectionName": "Paramètres rapides"
}
},
"quickSettings": {
"notifications": {
"label": "Notifications",
"tooltip": {
"enable": "Activer Ne pas déranger",
"disable": "Désactiver Ne pas déranger"
}
},
"wifi": {
"label": {
"wifi": "Wi-Fi",
"ethernet": "Réseau"
},
"tooltip": {
"wifi": {
"connected": "Wi-Fi connecté",
"disconnected": "Wi-Fi déconnecté"
},
"ethernet": {
"connected": "Ethernet connecté"
}
}
},
"bluetooth": {
"label": "Bluetooth",
"tooltip": {
"enabled": "Bluetooth activé",
"disabled": "Bluetooth désactivé"
}
},
"screenRecorder": {
"label": "Écran",
"tooltip": {
"start": "Démarrer l'enregistrement d'écran",
"stop": "Arrêter l'enregistrement"
}
},
"powerProfile": {
"tooltip": {
"current": "Actuel : {profile}",
"unavailable": "Profils d'alimentation non disponibles"
}
}
},
"hooks": {
"title": "Hooks",
"system-hooks": {
-44
View File
@@ -710,50 +710,6 @@
"sectionName": "Configurações rápidas"
}
},
"quickSettings": {
"notifications": {
"label": "Notificações",
"tooltip": {
"enable": "Ativar Não perturbe",
"disable": "Desativar Não perturbe"
}
},
"wifi": {
"label": {
"wifi": "Wi-Fi",
"ethernet": "Rede"
},
"tooltip": {
"wifi": {
"connected": "Wi-Fi conectado",
"disconnected": "Wi-Fi desconectado"
},
"ethernet": {
"connected": "Ethernet conectado"
}
}
},
"bluetooth": {
"label": "Bluetooth",
"tooltip": {
"enabled": "Bluetooth habilitado",
"disabled": "Bluetooth desabilitado"
}
},
"screenRecorder": {
"label": "Tela",
"tooltip": {
"start": "Iniciar gravação de tela",
"stop": "Parar gravação"
}
},
"powerProfile": {
"tooltip": {
"current": "Atual: {profile}",
"unavailable": "Perfis de energia não disponíveis"
}
}
},
"hooks": {
"title": "Hooks",
"system-hooks": {
-44
View File
@@ -744,50 +744,6 @@
"sectionName": "快速设置"
}
},
"quickSettings": {
"notifications": {
"label": "通知",
"tooltip": {
"enable": "开启勿扰模式",
"disable": "关闭勿扰模式"
}
},
"wifi": {
"label": {
"wifi": "Wi-Fi",
"ethernet": "网络"
},
"tooltip": {
"wifi": {
"connected": "Wi-Fi 已连接",
"disconnected": "Wi-Fi 已断开"
},
"ethernet": {
"connected": "以太网已连接"
}
}
},
"bluetooth": {
"label": "蓝牙",
"tooltip": {
"enabled": "蓝牙已启用",
"disabled": "蓝牙已禁用"
}
},
"screenRecorder": {
"label": "屏幕录制",
"tooltip": {
"start": "开始屏幕录制",
"stop": "停止录制"
}
},
"powerProfile": {
"tooltip": {
"current": "当前:{profile}",
"unavailable": "电源配置文件不可用"
}
}
},
"hooks": {
"title": "钩子",
"system-hooks": {
+200 -5
View File
@@ -181,6 +181,40 @@ inject_translation() {
fi
}
# Function to remove a key from JSON file using jq
remove_json_key() {
local json_file=$1
local key_path=$2
# Split key path into array
local -a path_parts
IFS='.' read -ra path_parts <<< "$key_path"
# Build jq path array
local jq_path="["
for i in "${!path_parts[@]}"; do
if [[ $i -gt 0 ]]; then
jq_path+=","
fi
jq_path+="\"${path_parts[$i]}\""
done
jq_path+="]"
# Create a temporary file
local temp_file=$(mktemp)
# Use jq to delete the path
jq --argjson path "$jq_path" 'delpaths([$path])' "$json_file" > "$temp_file"
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$json_file"
return 0
else
rm -f "$temp_file"
return 1
fi
}
# Function to extract all keys from a JSON file recursively
extract_keys() {
local json_file=$1
@@ -207,6 +241,78 @@ extract_keys() {
' "$json_file" 2>/dev/null | sort
}
# Function to extract empty keys from a JSON file recursively
extract_empty_keys() {
local json_file=$1
if [[ ! -f "$json_file" ]]; then
echo "Error: File $json_file not found" >&2
return 1
fi
# Extract all keys with empty string or null values recursively using jq
jq -r '
def empty_keys_recursive:
if type == "object" then
keys[] as $k |
if (.[$k] | type) == "object" then
($k + "." + (.[$k] | empty_keys_recursive))
elif (.[$k] == "" or .[$k] == null) then
$k
else
empty
end
else
empty
end;
empty_keys_recursive
' "$json_file" 2>/dev/null | sort
}
# Function to remove empty objects recursively from JSON file
remove_empty_objects() {
local json_file=$1
# Create a temporary file
local temp_file=$(mktemp)
# Use jq to recursively remove empty objects
# This function walks the entire JSON tree and removes any object that contains no leaf values
jq '
def remove_empty:
if type == "object" then
to_entries |
map(
.value |= remove_empty
) |
map(
select(
.value != {} and
.value != [] and
.value != null and
.value != ""
)
) |
from_entries |
if length == 0 then empty else . end
elif type == "array" then
map(remove_empty) |
map(select(. != null and . != {} and . != [] and . != ""))
else
.
end;
remove_empty
' "$json_file" > "$temp_file" 2>/dev/null
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$json_file"
return 0
else
rm -f "$temp_file"
return 1
fi
}
# Function to get language files
get_language_files() {
find "$FOLDER_PATH" -maxdepth 1 -name "*.json" -type f | sort
@@ -223,15 +329,20 @@ generate_header() {
echo "Reference file: $REFERENCE_FILE"
echo "Folder: $(realpath "$FOLDER_PATH")"
if $TRANSLATE_MODE; then
echo "Mode: TRANSLATION ENABLED"
echo "Mode: TRANSLATION ENABLED (translates missing keys, removes extra/empty keys and empty objects)"
fi
echo ""
echo "Notes:"
echo "- Keys are compared recursively through all nested JSON objects"
echo "- Missing keys indicate incomplete translations"
echo "- Extra keys might indicate deprecated keys or translation-specific additions"
echo "- Empty keys are keys with empty string (\"\") or null values"
echo "- Empty objects are nested objects containing no actual values (only other empty objects)"
echo "- Translation completion percentage is calculated based on English reference"
echo "- Results are sorted by descending line numbers for easier editing"
if $TRANSLATE_MODE; then
echo "- In translation mode, extra keys, empty keys, and empty objects are automatically removed"
fi
echo ""
echo "This report compares all language JSON files against the English reference file"
echo "and identifies missing keys and extra keys in each language."
@@ -427,11 +538,92 @@ compare_language() {
done
rm -f "$temp_extra"
echo ""
# Remove extra keys if in translate mode
if $TRANSLATE_MODE; then
print_color $BLUE "Removing extra keys from $lang_name..." >&2
local removed_count=0
local failed_removal_count=0
while IFS= read -r key; do
if [[ -n "$key" ]]; then
print_color $YELLOW " Removing: $key" >&2
if remove_json_key "$lang_file" "$key"; then
print_color $GREEN " ✓ Removed: $key" >&2
removed_count=$((removed_count + 1))
else
print_color $RED " ✗ Failed to remove: $key" >&2
failed_removal_count=$((failed_removal_count + 1))
fi
fi
done <<< "$extra_keys"
echo ""
print_color $GREEN "Removal complete: $removed_count removed, $failed_removal_count failed" >&2
echo ""
fi
else
echo "✅ No extra keys in $lang_name"
echo ""
fi
# Handle empty keys in translate mode
if $TRANSLATE_MODE; then
local empty_keys=$(extract_empty_keys "$lang_file")
local empty_count=$(count_non_empty_lines "$empty_keys")
if [[ $empty_count -gt 0 && -n "$empty_keys" ]]; then
echo "EMPTY KEYS IN $lang_name:"
# Display empty keys
local counter=1
while IFS= read -r key; do
if [[ -n "$key" ]]; then
local lang_line=$(find_key_line_number "$lang_file" "$key")
printf " %3d. %s (%s:%s)\n" "$counter" "$key" "$(basename "$lang_file")" "$lang_line"
counter=$((counter + 1))
fi
done <<< "$empty_keys"
echo ""
print_color $BLUE "Removing empty keys from $lang_name..." >&2
local removed_empty_count=0
local failed_empty_removal_count=0
while IFS= read -r key; do
if [[ -n "$key" ]]; then
print_color $YELLOW " Removing empty key: $key" >&2
if remove_json_key "$lang_file" "$key"; then
print_color $GREEN " ✓ Removed: $key" >&2
removed_empty_count=$((removed_empty_count + 1))
else
print_color $RED " ✗ Failed to remove: $key" >&2
failed_empty_removal_count=$((failed_empty_removal_count + 1))
fi
fi
done <<< "$empty_keys"
echo ""
print_color $GREEN "Empty key removal complete: $removed_empty_count removed, $failed_empty_removal_count failed" >&2
echo ""
else
echo "✅ No empty keys in $lang_name"
echo ""
fi
# Remove empty objects (nested objects with no actual values)
print_color $BLUE "Cleaning up empty objects in $lang_name..." >&2
if remove_empty_objects "$lang_file"; then
print_color $GREEN "✓ Successfully removed all empty objects" >&2
echo ""
else
print_color $RED "✗ Failed to clean up empty objects" >&2
echo ""
fi
fi
# Clean up
rm -f "$lang_keys_file"
}
@@ -545,7 +737,7 @@ main() {
echo "Target language: $target_language"
fi
if $TRANSLATE_MODE; then
echo "Translation mode: ENABLED"
echo "Translation mode: ENABLED (translated missing keys, removed extra keys, removed empty keys and objects)"
fi
echo "Report generated: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
@@ -568,7 +760,9 @@ show_usage() {
echo "This script compares JSON language files in '$FOLDER_PATH' against the English reference." >&2
echo "" >&2
echo "Arguments:" >&2
echo " --translate Enable automatic translation of missing keys using Gemini API" >&2
echo " --translate Enable automatic translation of missing keys, removal of extra keys," >&2
echo " removal of empty keys (empty strings or null values), and removal of" >&2
echo " empty objects (nested objects containing no actual values)" >&2
echo " --list-models List all available Gemini models and exit" >&2
echo " language_code Optional. Compare only the specified language (e.g., 'fr', 'es', 'de')" >&2
echo " If not provided, all language files will be compared" >&2
@@ -581,8 +775,8 @@ show_usage() {
echo " $0 # Compare all languages" >&2
echo " $0 fr # Compare only French (fr.json)" >&2
echo " $0 --list-models # List available Gemini models" >&2
echo " $0 --translate # Compare all and translate missing keys" >&2
echo " $0 --translate fr # Translate missing keys for French only" >&2
echo " $0 --translate # Compare all, translate missing, remove extra/empty keys and objects" >&2
echo " $0 --translate fr # Translate and clean French only" >&2
echo "" >&2
echo "Requirements:" >&2
echo " - jq must be installed" >&2
@@ -595,6 +789,7 @@ show_usage() {
echo " - Comparison report is printed to stdout" >&2
echo " - Progress messages are printed to stderr" >&2
echo " - Results are sorted by descending line numbers for easier editing" >&2
echo " - In translate mode, extra keys, empty keys, and empty objects are removed" >&2
}
# Handle command line arguments