Features
- Comprehensive translation key validation across multiple locales with automatic locale detection by parsing file names and directory structure, base file comparison (en.json, en-US.json, base.json), and cross-locale consistency checking with key count comparison
- Missing and orphaned translation key detection using jq for nested key extraction with dot notation path generation (paths(scalars) as $p | $p | join(".")), comparison with base translation files using comm command for set difference, and detailed missing/orphaned key reporting with key lists
- JSON structure and syntax validation for translation files with jq validation (jq empty) for syntax checking, nested vs flat structure detection, empty value detection, and untranslated string detection (key equals value) with comprehensive error reporting
- Pluralization rule compliance checking with locale-specific pluralization validation including plural form detection, plural rule validation for different locales, and pluralization completeness checking with warnings for missing plural forms
- Translation completeness percentage reporting with detailed completeness metrics calculating translated keys vs base keys, missing key counts, completeness percentage thresholds (100% excellent, 90% good, 70% needs attention, <70% significant gaps), and actionable recommendations
- Multi-format support (JSON, YAML, gettext PO files) with format-specific validation including jq for JSON files, msgfmt for PO files (when available), basic validation for properties files, and graceful fallback when format-specific tools unavailable
- Variable placeholder validation and consistency checking with pattern matching for {{variable}} (Handlebars), {variable} (simple), %variable% (percent), ${variable} (dollar), and printf-style placeholders (%s, %d) with cross-file placeholder consistency validation
- Character encoding and special character verification with non-ASCII character detection using grep -P, locale-specific validation for RTL languages (Arabic, Hebrew, Persian), CJK languages (Chinese, Japanese, Korean), and encoding recommendations (UTF-8)
Use Cases
- Multi-language application development with automated translation validation automatically validating translation files, detecting missing keys, and ensuring consistency across locales for safe multi-language application development
- Translation quality assurance and completeness checking in CI/CD pipelines automatically validating translations, checking completeness percentages, and detecting missing keys before deployment to prevent incomplete translations in production
- Internationalization workflow management and key consistency enforcement automatically detecting orphaned keys, validating variable placeholders, and ensuring key consistency across all locales for maintainable i18n workflows
- Localization project coordination with missing translation detection automatically identifying missing translations, calculating completeness percentages, and providing actionable reports for localization teams to prioritize translation work
- Cross-platform app development with unified translation standards automatically validating translation formats, checking encoding, and ensuring consistency across platforms with format-specific validation and cross-platform compatibility checking
- Development workflow integration seamlessly integrating i18n translation validation into development workflows without manual validation steps or separate translation checking tools
Installation
- Create hooks directory: mkdir -p .claude/hooks
- Create hook file: touch .claude/hooks/i18n-translation-validator.sh
- Make executable: chmod +x .claude/hooks/i18n-translation-validator.sh
- Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
- Alternative: Use the interactive /hooks command in Claude Code
Config paths
- Local (not committed):
.claude/settings.local.json
- User settings (global):
~/.claude/settings.json
- Project-wide (committed):
.claude/settings.json
Requirements
- Claude Code CLI installed
- Project directory initialized
- Bash shell available
- jq (optional, recommended for JSON validation and key extraction)
- msgfmt (optional, for PO file validation)
- File system read access for translation files in common directories (locales/, i18n/, lang/, translations/) and standard Unix utilities: grep, comm (for key comparison), find (for file discovery)
Hook Configuration
{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/i18n-translation-validator.sh",
"matchers": ["write", "edit"]
}
}
}
Hook Script
#!/usr/bin/env bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if this is a translation/localization file
if [[ "$FILE_PATH" == *locales/*.json ]] || [[ "$FILE_PATH" == *i18n/*.json ]] || [[ "$FILE_PATH" == *lang/*.json ]] || [[ "$FILE_PATH" == *translations/*.json ]] || [[ "$FILE_PATH" == *.po ]] || [[ "$FILE_PATH" == *messages/*.properties ]]; then
echo "🌍 i18n Translation Validation for: $(basename "$FILE_PATH")" >&2
# Initialize validation counters
ERRORS=0
WARNINGS=0
MISSING_KEYS=0
ORPHANED_KEYS=0
TOTAL_KEYS=0
# Function to report validation results
report_validation() {
local level="$1"
local message="$2"
case "$level" in
"ERROR")
echo "❌ ERROR: $message" >&2
ERRORS=$((ERRORS + 1))
;;
"WARNING")
echo "⚠️ WARNING: $message" >&2
WARNINGS=$((WARNINGS + 1))
;;
"MISSING")
echo "🔍 MISSING: $message" >&2
MISSING_KEYS=$((MISSING_KEYS + 1))
;;
"ORPHANED")
echo "🏷️ ORPHANED: $message" >&2
ORPHANED_KEYS=$((ORPHANED_KEYS + 1))
;;
"PASS")
echo "✅ PASS: $message" >&2
;;
"INFO")
echo "ℹ️ INFO: $message" >&2
;;
esac
}
# Check if file exists and is readable
if [ ! -f "$FILE_PATH" ]; then
report_validation "ERROR" "Translation file not found: $FILE_PATH"
exit 1
fi
if [ ! -r "$FILE_PATH" ]; then
report_validation "ERROR" "Translation file is not readable: $FILE_PATH"
exit 1
fi
# Determine file format
FILE_EXT="${FILE_PATH##*.}"
LOCALE_DIR="$(dirname "$FILE_PATH")"
FILE_NAME="$(basename "$FILE_PATH")"
LOCALE_CODE="${FILE_NAME%.*}"
echo "📊 Translation file: $FILE_NAME (format: $FILE_EXT, locale: $LOCALE_CODE)" >&2
# 1. File Format Validation
echo "📋 Validating file format..." >&2
case "$FILE_EXT" in
"json")
if jq empty "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Valid JSON syntax"
TOTAL_KEYS=$(jq -r 'keys | length' "$FILE_PATH" 2>/dev/null || echo "0")
else
report_validation "ERROR" "Invalid JSON syntax - file cannot be parsed"
exit 1
fi
;;
"po")
if command -v msgfmt &> /dev/null; then
if msgfmt --check "$FILE_PATH" -o /dev/null 2>/dev/null; then
report_validation "PASS" "Valid PO file format"
else
report_validation "ERROR" "Invalid PO file format"
fi
else
report_validation "WARNING" "msgfmt not available - limited PO validation"
fi
;;
"properties")
# Basic properties file validation
if grep -q '=' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Properties file format detected"
else
report_validation "WARNING" "No key=value pairs found in properties file"
fi
;;
*)
report_validation "WARNING" "Unknown translation file format: $FILE_EXT"
;;
esac
# 2. Find Base Translation File (for comparison)
echo "🔍 Locating base translation file..." >&2
BASE_FILE=""
BASE_CANDIDATES=("en.json" "en-US.json" "en_US.json" "base.json" "default.json")
for candidate in "${BASE_CANDIDATES[@]}"; do
if [ -f "$LOCALE_DIR/$candidate" ] && [ "$LOCALE_DIR/$candidate" != "$FILE_PATH" ]; then
BASE_FILE="$LOCALE_DIR/$candidate"
echo " 📁 Base file found: $candidate" >&2
break
fi
done
if [ -z "$BASE_FILE" ]; then
# Look for any .json file in the directory as base
FIRST_JSON=$(find "$LOCALE_DIR" -name '*.json' -not -path "$FILE_PATH" | head -1)
if [ -n "$FIRST_JSON" ]; then
BASE_FILE="$FIRST_JSON"
echo " 📁 Using first available JSON as base: $(basename "$BASE_FILE")" >&2
else
echo " ⚠️ No base translation file found - running standalone validation" >&2
fi
fi
# 3. Key Structure Validation (JSON files)
if [ "$FILE_EXT" = "json" ]; then
echo "🔑 Analyzing translation keys..." >&2
# Check for nested vs flat structure
NESTED_COUNT=$(jq '[.. | objects | keys] | flatten | length' "$FILE_PATH" 2>/dev/null || echo "0")
if [ "$NESTED_COUNT" -gt "$TOTAL_KEYS" ]; then
echo " 📊 Nested key structure detected ($NESTED_COUNT total keys)" >&2
else
echo " 📊 Flat key structure ($TOTAL_KEYS keys)" >&2
fi
# Check for empty values
EMPTY_VALUES=$(jq '[.. | select(type == "string" and length == 0)] | length' "$FILE_PATH" 2>/dev/null || echo "0")
if [ "$EMPTY_VALUES" -gt 0 ]; then
report_validation "WARNING" "$EMPTY_VALUES empty translation values found"
fi
# Check for untranslated strings (same as key)
UNTRANSLATED=0
if command -v jq &> /dev/null; then
UNTRANSLATED=$(jq -r 'to_entries[] | select(.key == .value) | .key' "$FILE_PATH" 2>/dev/null | wc -l | xargs || echo "0")
if [ "$UNTRANSLATED" -gt 0 ]; then
report_validation "WARNING" "$UNTRANSLATED potentially untranslated strings (key equals value)"
fi
fi
fi
# 4. Compare with Base File (if available)
if [ -n "$BASE_FILE" ] && [ -f "$BASE_FILE" ]; then
echo "🔄 Comparing with base translation file..." >&2
if [ "$FILE_EXT" = "json" ]; then
# Extract all keys from both files
BASE_KEYS_FILE="/tmp/base_keys_$$"
CURRENT_KEYS_FILE="/tmp/current_keys_$$"
# Get all nested keys (dot notation)
jq -r 'paths(scalars) as $p | $p | join(".")' "$BASE_FILE" 2>/dev/null | sort > "$BASE_KEYS_FILE"
jq -r 'paths(scalars) as $p | $p | join(".")' "$FILE_PATH" 2>/dev/null | sort > "$CURRENT_KEYS_FILE"
# Find missing keys (in base but not in current)
MISSING_KEYS_LIST="/tmp/missing_keys_$$"
comm -23 "$BASE_KEYS_FILE" "$CURRENT_KEYS_FILE" > "$MISSING_KEYS_LIST"
MISSING_COUNT=$(wc -l < "$MISSING_KEYS_LIST" | xargs)
if [ "$MISSING_COUNT" -gt 0 ]; then
report_validation "MISSING" "$MISSING_COUNT translation keys missing from base"
echo " Missing keys:" >&2
head -10 "$MISSING_KEYS_LIST" | while read key; do
echo " - $key" >&2
done
[ "$MISSING_COUNT" -gt 10 ] && echo " ... and $((MISSING_COUNT - 10)) more" >&2
else
report_validation "PASS" "All base translation keys are present"
fi
# Find orphaned keys (in current but not in base)
ORPHANED_KEYS_LIST="/tmp/orphaned_keys_$$"
comm -13 "$BASE_KEYS_FILE" "$CURRENT_KEYS_FILE" > "$ORPHANED_KEYS_LIST"
ORPHANED_COUNT=$(wc -l < "$ORPHANED_KEYS_LIST" | xargs)
if [ "$ORPHANED_COUNT" -gt 0 ]; then
report_validation "ORPHANED" "$ORPHANED_COUNT keys not found in base (potential orphans)"
echo " Orphaned keys:" >&2
head -5 "$ORPHANED_KEYS_LIST" | while read key; do
echo " - $key" >&2
done
[ "$ORPHANED_COUNT" -gt 5 ] && echo " ... and $((ORPHANED_COUNT - 5)) more" >&2
else
report_validation "PASS" "No orphaned keys detected"
fi
# Calculate completeness percentage
BASE_KEY_COUNT=$(wc -l < "$BASE_KEYS_FILE" | xargs)
if [ "$BASE_KEY_COUNT" -gt 0 ]; then
TRANSLATED_COUNT=$((BASE_KEY_COUNT - MISSING_COUNT))
COMPLETENESS=$((TRANSLATED_COUNT * 100 / BASE_KEY_COUNT))
echo " 📊 Translation completeness: $COMPLETENESS% ($TRANSLATED_COUNT/$BASE_KEY_COUNT)" >&2
if [ "$COMPLETENESS" -eq 100 ]; then
report_validation "PASS" "Translation is 100% complete"
elif [ "$COMPLETENESS" -ge 90 ]; then
report_validation "WARNING" "Translation is $COMPLETENESS% complete (good but not perfect)"
elif [ "$COMPLETENESS" -ge 70 ]; then
report_validation "WARNING" "Translation is $COMPLETENESS% complete (needs attention)"
else
report_validation "ERROR" "Translation is only $COMPLETENESS% complete (significant gaps)"
fi
fi
# Cleanup temp files
rm -f "$BASE_KEYS_FILE" "$CURRENT_KEYS_FILE" "$MISSING_KEYS_LIST" "$ORPHANED_KEYS_LIST"
fi
fi
# 5. Variable Placeholder Validation
echo "🔤 Checking variable placeholders..." >&2
if [ "$FILE_EXT" = "json" ]; then
# Check for common placeholder patterns
PLACEHOLDER_PATTERNS=(
'{{[^}]+}}' # Handlebars: {{variable}}
'{[^}]+}' # Simple: {variable}
'%[a-zA-Z_]+%' # Percent: %variable%
'\$\{[^}]+\}' # Dollar: ${variable}
'%[sd]' # Printf style: %s, %d
)
PLACEHOLDER_COUNT=0
for pattern in "${PLACEHOLDER_PATTERNS[@]}"; do
COUNT=$(grep -oE "$pattern" "$FILE_PATH" 2>/dev/null | wc -l | xargs || echo "0")
PLACEHOLDER_COUNT=$((PLACEHOLDER_COUNT + COUNT))
done
if [ "$PLACEHOLDER_COUNT" -gt 0 ]; then
echo " 📝 $PLACEHOLDER_COUNT variable placeholders found" >&2
# Check for unmatched placeholders if base file exists
if [ -n "$BASE_FILE" ]; then
# This is a simplified check - in practice, you'd want more sophisticated matching
echo " 🔍 Cross-referencing placeholders with base file..." >&2
fi
else
echo " ℹ️ No variable placeholders detected" >&2
fi
fi
# 6. Locale-Specific Validation
echo "🌐 Locale-specific validation..." >&2
case "$LOCALE_CODE" in
"ar"*|"he"*|"fa"*)
echo " 🔄 RTL language detected - ensure proper text direction handling" >&2
;;
"zh"*|"ja"*|"ko"*)
echo " 🈴 CJK language detected - ensure proper character encoding" >&2
;;
"en"*)
echo " 🇺🇸 English locale - checking for common issues" >&2
;;
*)
echo " 🌍 Locale: $LOCALE_CODE" >&2
;;
esac
# Check for potential encoding issues (non-ASCII characters)
if [ "$FILE_EXT" = "json" ]; then
NON_ASCII_COUNT=$(grep -P '[^\x00-\x7F]' "$FILE_PATH" 2>/dev/null | wc -l | xargs || echo "0")
if [ "$NON_ASCII_COUNT" -gt 0 ]; then
echo " 🔤 $NON_ASCII_COUNT lines contain non-ASCII characters (normal for international content)" >&2
fi
fi
# 7. Multi-file Consistency Check
echo "📁 Checking consistency across locale files..." >&2
LOCALE_FILES=()
while IFS= read -r -d '' file; do
LOCALE_FILES+=("$file")
done < <(find "$LOCALE_DIR" -name "*.$FILE_EXT" -print0 2>/dev/null)
LOCALE_COUNT=${#LOCALE_FILES[@]}
if [ "$LOCALE_COUNT" -gt 1 ]; then
echo " 📊 Found $LOCALE_COUNT locale files in directory" >&2
# Check if all files have similar key counts (within 20% difference)
if [ "$FILE_EXT" = "json" ] && [ "$TOTAL_KEYS" -gt 0 ]; then
INCONSISTENT_FILES=0
for locale_file in "${LOCALE_FILES[@]}"; do
if [ "$locale_file" != "$FILE_PATH" ]; then
OTHER_KEY_COUNT=$(jq -r 'keys | length' "$locale_file" 2>/dev/null || echo "0")
DIFF_PERCENT=$((abs(TOTAL_KEYS - OTHER_KEY_COUNT) * 100 / TOTAL_KEYS))
if [ "$DIFF_PERCENT" -gt 20 ]; then
INCONSISTENT_FILES=$((INCONSISTENT_FILES + 1))
fi
fi
done
if [ "$INCONSISTENT_FILES" -gt 0 ]; then
report_validation "WARNING" "$INCONSISTENT_FILES locale files have significantly different key counts"
else
report_validation "PASS" "All locale files have consistent key counts"
fi
fi
else
echo " ℹ️ Single locale file found" >&2
fi
# 8. Generate Validation Summary
echo "" >&2
echo "📋 i18n Translation Validation Summary:" >&2
echo "=====================================" >&2
echo " 📄 File: $FILE_NAME" >&2
echo " 🌍 Locale: $LOCALE_CODE" >&2
echo " 📊 Format: $FILE_EXT" >&2
[ "$TOTAL_KEYS" -gt 0 ] && echo " 🔑 Total Keys: $TOTAL_KEYS" >&2
echo " ❌ Errors: $ERRORS" >&2
echo " ⚠️ Warnings: $WARNINGS" >&2
echo " 🔍 Missing Keys: $MISSING_KEYS" >&2
echo " 🏷️ Orphaned Keys: $ORPHANED_KEYS" >&2
if [ "$ERRORS" -eq 0 ] && [ "$MISSING_KEYS" -eq 0 ]; then
if [ "$WARNINGS" -eq 0 ] && [ "$ORPHANED_KEYS" -eq 0 ]; then
echo " 🎉 Status: EXCELLENT - Translation file is complete and consistent" >&2
else
echo " ✅ Status: GOOD - Translation is functional with minor issues" >&2
fi
elif [ "$ERRORS" -eq 0 ]; then
echo " ⚠️ Status: INCOMPLETE - Missing translations need attention" >&2
else
echo " ❌ Status: ERRORS - Critical issues must be fixed" >&2
fi
echo "" >&2
echo "💡 i18n Translation Best Practices:" >&2
echo " • Keep translation keys consistent across all locales" >&2
echo " • Use meaningful, hierarchical key names" >&2
echo " • Validate placeholder variables across languages" >&2
echo " • Consider cultural context in translations" >&2
echo " • Test with longer/shorter text in different languages" >&2
echo " • Use proper character encoding (UTF-8)" >&2
# Exit with error if there are critical issues
if [ "$ERRORS" -gt 0 ]; then
echo "⚠️ Translation validation completed with errors" >&2
exit 1
fi
else
# Not a translation file, exit silently
exit 0
fi
exit 0
Examples
I18n Translation Validator Hook Script
Complete hook script that performs i18n translation validation
#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
if [[ "$FILE_PATH" == *locales/*.json ]] || [[ "$FILE_PATH" == *i18n/*.json ]]; then
echo "🌍 i18n Translation Validation for: $(basename "$FILE_PATH")" >&2
if jq empty "$FILE_PATH" 2>/dev/null; then
echo "✅ Valid JSON syntax" >&2
TOTAL_KEYS=$(jq -r 'keys | length' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Total keys: $TOTAL_KEYS" >&2
else
echo "❌ Invalid JSON syntax" >&2
exit 1
fi
fi
exit 0
Hook Configuration
Complete hook configuration for .claude/settings.json to enable translation validation
{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/i18n-translation-validator.sh",
"matchers": ["write", "edit"]
}
}
}
Missing Key Detection
Enhanced hook script for missing translation key detection with base file comparison
#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
LOCALE_DIR="$(dirname "$FILE_PATH")"
BASE_FILE="$LOCALE_DIR/en.json"
if [[ "$FILE_PATH" == *.json ]] && [ -f "$BASE_FILE" ]; then
BASE_KEYS=$(jq -r 'paths(scalars) as $p | $p | join(".")' "$BASE_FILE" 2>/dev/null | sort)
CURRENT_KEYS=$(jq -r 'paths(scalars) as $p | $p | join(".")' "$FILE_PATH" 2>/dev/null | sort)
MISSING_KEYS=$(comm -23 <(echo "$BASE_KEYS") <(echo "$CURRENT_KEYS") | wc -l | xargs)
if [ "$MISSING_KEYS" -gt 0 ]; then
echo "🔍 MISSING: $MISSING_KEYS translation keys missing from base" >&2
else
echo "✅ All base translation keys are present" >&2
fi
fi
exit 0
Variable Placeholder and Empty Value Validation
Enhanced hook script for variable placeholder validation and empty value detection
#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [[ "$FILE_PATH" == *.json ]]; then
PLACEHOLDER_PATTERNS=('{{[^}]+}}' '{[^}]+}' '%[a-zA-Z_]+%' '\${[^}]+}' '%[sd]')
PLACEHOLDER_COUNT=0
for pattern in "${PLACEHOLDER_PATTERNS[@]}"; do
COUNT=$(grep -oE "$pattern" "$FILE_PATH" 2>/dev/null | wc -l | xargs || echo "0")
PLACEHOLDER_COUNT=$((PLACEHOLDER_COUNT + COUNT))
done
if [ "$PLACEHOLDER_COUNT" -gt 0 ]; then
echo "📝 $PLACEHOLDER_COUNT variable placeholders found" >&2
fi
EMPTY_VALUES=$(jq '[.. | select(type == "string" and length == 0)] | length' "$FILE_PATH" 2>/dev/null || echo "0")
if [ "$EMPTY_VALUES" -gt 0 ]; then
echo "⚠️ $EMPTY_VALUES empty translation values found" >&2
fi
fi
exit 0
Locale-Specific Validation
Enhanced hook script for locale-specific validation including RTL and CJK language detection
#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
LOCALE_DIR="$(dirname "$FILE_PATH")"
FILE_NAME="$(basename "$FILE_PATH")"
LOCALE_CODE="${FILE_NAME%.*}"
if [[ "$FILE_PATH" == *.json ]]; then
case "$LOCALE_CODE" in
ar*|he*|fa*)
echo "🔄 RTL language detected - ensure proper text direction handling" >&2
;;
zh*|ja*|ko*)
echo "🈴 CJK language detected - ensure proper character encoding" >&2
;;
esac
NON_ASCII_COUNT=$(grep -P '[^\x00-\x7F]' "$FILE_PATH" 2>/dev/null | wc -l | xargs || echo "0")
if [ "$NON_ASCII_COUNT" -gt 0 ]; then
echo "🔤 $NON_ASCII_COUNT lines contain non-ASCII characters (normal for international content)" >&2
fi
fi
exit 0
Troubleshooting
Hook validates non-i18n JSON files in directories with similar names
Strengthen path detection: [["$FILE_PATH" =~ /(locales|i18n|lang|translations)/]] || exit 0. Check for translation-specific keys like locale/language markers before running full validation. Verify file path patterns match translation file locations. Test with various directory structures.
Missing keys detection fails when base file uses nested structure
Use jq to flatten nested keys: jq -r 'paths(scalars) as $p | $p | join(".")' to get dot notation paths. Compare flattened key lists instead of top-level keys only for accurate missing key detection. Verify both files use same nesting structure. Test with deeply nested JSON structures.
Validation shows false positives for orphaned keys in locale-specific translations
Some translations legitimately have locale-specific keys (e.g., currency formats, date patterns). Add whitelist patterns or check key prefixes like 'locale.' to skip cultural adaptation keys from orphan detection. Configure locale-specific key patterns. Document expected locale-specific keys.
Completeness percentage incorrectly calculated for multi-level nested JSON
Script uses top-level key count but should count leaf nodes: jq '[paths(scalars)] | length'. Ensure both base and current files are counted at same nesting level for accurate percentage. Use consistent key counting method. Verify completeness calculation logic.
Hook crashes with 'command not found: abs' on DIFF_PERCENT calculation
Bash doesn't have abs() function. Replace with: DIFF_PERCENT=$(( (TOTAL_KEYS - OTHER_KEY_COUNT) < 0 ? (OTHER_KEY_COUNT - TOTAL_KEYS) : (TOTAL_KEYS - OTHER_KEY_COUNT) )) or use bc: echo "scale=0; sqrt(($A-$B)^2)" | bc. Verify absolute value calculation. Test with various key count differences.
Variable placeholder validation misses placeholders in nested JSON values
grep only searches file content, not parsed JSON values. Use jq to extract string values: jq -r '.. | strings' | grep -oE pattern. This ensures placeholders in nested values are detected. Verify placeholder detection works with nested structures. Test with various placeholder formats.
PO file validation fails when msgfmt is not installed
Hook falls back to basic validation when msgfmt unavailable. Install gettext package: brew install gettext (macOS), apt-get install gettext (Linux). Verify msgfmt installation: command -v msgfmt. Add msgfmt availability check before PO validation.
Translation completeness shows 0% when base file is not found
Hook should handle missing base file gracefully. Add check: if [ -z "$BASE_FILE" ]; then echo "⚠️ No base file found - completeness check skipped"; fi. Verify base file detection logic. Provide fallback base file suggestions. Document base file requirements.