Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In xcode is there a way to verify all NSLocalizedStrings' keys?

Aside from running every code path that has an NSLocalizedString in it, is there a way to verify that all NSLocalizedStrings have a key that actually exists in all your Localizable.strings files of all your bundles?

E.g. there wasn't a typo in one key such that NSLocalizedString won't find the key it's looking for?

like image 522
Joe C Avatar asked Aug 28 '13 19:08

Joe C


1 Answers

OK I wrote a bash script to accomplish the above. Here it is. It took me hours so don't forget to up-vote me if you like. Feel free to make improvements, etc. I added a few comments suggesting potential improvements.

#!/bin/sh

# VerNSLocalizedStrings

while getopts "vsl:" arg; do
    case $arg in
    v)
        verbose="yes"
        ;;
    s)
        stopOnMissing="yes"
        ;;
    l)
        lang=$OPTARG
        ;;
    esac
done

if [[ -z $lang ]] 
    then
    lang="en"
fi

searchDir=$lang.lproj
fileFound=`ls . | grep $searchDir`
if [[ -z $fileFound ]]
then
   echo "dir "$searchDir" not found."
   exit
fi

fileFound=`ls $searchDir/ | grep strings`
if [[ -z $fileFound ]]
then
   echo "No .strings files found in dir "$searchDir"."
   exit
fi

echo "Verifying NSLocalizationStrings in "$searchDir 

# Get all the NSLocalizedString Commands
output=$(grep -R NSLocalizedString . --include="*.m")

# Go thru the NSLocalizedString commands line for line
count=$(( 0 ))
missing=$(( 0 ))
unusable=$(( 0 ))
OIFS="${IFS}"
NIFS=$'\n'
IFS="${NIFS}"
for LINE in ${output} ; do
    IFS="${OIFS}"

    # Now extract the key from it
    # admittedly this only works if there are no line breaks between
    # NSLocalizedStrings and the entire key,
    # but it accounts for the keys it couldn't identify.
    quotes=`echo $LINE | awk -F\" '{ for(i=2; i<=NF; i=i+2){ a = a"\""$i"\"""^";} {print a; a="";}}'`
    key=`echo $quotes | cut -f1 -d"^"`

    # If we couldn't find the key then flag problem
    if [[ -z $key ]] 
    then
        (( unusable += 1 ))
    echo "Couldn't extract key: " $LINE
        if [ -n "$stopOnMissing" ] 
        then
            break
        else 
            continue
        fi
    fi

    # I don't know how grep works regarding length of string, only that
    # if the string is too long then it doesn't find it in the file
    keyLength=$(echo ${#key})
    if [ $keyLength -gt 79 ] 
    then
        (( unusable += 1 ))
    echo "Key too long ("$keyLength"): " $key
        if [ -n "$stopOnMissing" ] 
        then
            break
        else 
            continue
        fi
    fi

    # It would be nice if this were a regular expression that allowed as many 
    # spaces as you want, even a line break then forced the quotes on the 
    # other side of the equal sign.
    keyString=$key" ="

    # Search for the key
    found=$(iconv -sc -f utf-16 -t utf8 $searchDir/*.strings | grep "$keyString")

    # damned if I know why some strings files are utf-16 and others are utf8
    if [[ -z $found ]] 
    then
    found=$(grep -r "$keyString" $searchDir/ --include=*.strings)
    fi

    # analyze the result
    if [[ -z $found ]] 
    then
        (( missing += 1 ))
    echo "Missing:  " $key "\n from: " $LINE
        if [ -n "$stopOnMissing" ] 
        then
            break
        fi
    else
        if [ -n "$verbose" ]
        then
            echo "found:  " $key
        fi
    fi
    (( count += 1 ))

    IFS="${NIFS}" 
done

IFS="${OIFS}"

# It would also be nice if it went the other way and identified 
# extraneous unused items in the strings files.  But
# I've spent enough time on this for now

echo $count " keys analyzed"
echo $unusable " keys could not be determined"
echo $missing " keys missing"
like image 141
Joe C Avatar answered Oct 05 '22 13:10

Joe C