mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-06-03 19:01:50 +00:00
i18n-json-check: removed empty nested structure.
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user