├── README.md └── update_storyboard_strings.sh /README.md: -------------------------------------------------------------------------------- 1 | **NOTE:** I cannot offer support for this script. I got some reports from users that it does not work correctly in some situations, especially in Xcode 6 (please check the [Issues](https://github.com/ole/Storyboard-Strings-Extraction/issues)). 2 | 3 | # Storyboard Strings Extraction 4 | 5 | Shell script to automatically extract translatable strings from Xcode storyboards and update `.strings` files. [Original version](http://forums.macrumors.com/showpost.php?p=16060008&postcount=4) by MacRumors forum user mikezang. Slightly updated by Ole Begemann. 6 | 7 | See my [accompanying blog post](http://oleb.net/blog/2013/02/automating-strings-extraction-from-storyboards-for-localization/) for details and usage instructions. 8 | 9 | Until August 2014, this script lived as a Gist at [https://gist.github.com/ole/5007019](https://gist.github.com/ole/5007019). Please refer to that page for earlier issues and comments. 10 | -------------------------------------------------------------------------------- /update_storyboard_strings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # update_storyboard_strings.sh - automatically extract translatable strings from storyboards and update strings files 4 | # Based on http://forums.macrumors.com/showpost.php?p=16060008&postcount=4 by mikezang 5 | # 6 | # Needed gawk: 7 | # brew install gawk 8 | # 9 | # Needed realpath: 10 | # brew tap iveney/mocha 11 | # brew install realpath 12 | # 13 | 14 | storyboardExt=".storyboard" 15 | stringsExt=".strings" 16 | newStringsExt=".strings.new" 17 | oldStringsExt=".strings.old" 18 | localeDirExt=".lproj" 19 | 20 | oldIFS=$IFS 21 | IFS=$'\n' 22 | 23 | # Find storyboard file full path inside project folder 24 | for storyboardPath in `find . -name "*$storyboardExt" -print` 25 | do 26 | # Get Base strings file full path 27 | baseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$stringsExt/") 28 | 29 | # Create base strings file if it doesn't exist 30 | if ! [ -f $baseStringsPath ]; then 31 | touch -r $storyboardPath $baseStringsPath 32 | # Make base strings file older than the storyboard file 33 | touch -A -01 $baseStringsPath 34 | fi 35 | 36 | # Create strings file only when storyboard file newer 37 | if find $storyboardPath -prune -newer $baseStringsPath -print | grep -q .; then 38 | 39 | # Get storyboard file name and folder 40 | storyboardFile=$(basename "$storyboardPath") 41 | storyboardDir=$(dirname "$storyboardPath") 42 | 43 | # Get New Base strings file full path and strings file name 44 | newBaseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$newStringsExt/") 45 | stringsFile=$(basename "$baseStringsPath") 46 | 47 | echo "Extracting strings file" 48 | ibtool --export-strings-file $newBaseStringsPath $storyboardPath 49 | 50 | # ibtool sometimes fails for unknown reasons with "Interface Builder could not open 51 | # the document XXX because it does not exist." 52 | # (maybe because Xcode is writing to the file at the same time?) 53 | # In that case, abort the script. 54 | if [[ $? -ne 0 ]] ; then 55 | echo "Exiting due to ibtool error. Please run `killall -9 ibtoold` and try again." 56 | exit 1 57 | fi 58 | 59 | # Only run iconv if $newBaseStringsPath exists to avoid overwriting existing 60 | if [ -f $newBaseStringsPath ]; then 61 | iconv -f UTF-16 -t UTF-8 $newBaseStringsPath > $baseStringsPath 62 | rm $newBaseStringsPath 63 | fi 64 | 65 | # Get all locale strings folder 66 | for localeStringsDir in `find .. -name "*$localeDirExt" -print` 67 | do 68 | # Skip Base strings folder 69 | rp1=$(realpath $storyboardDir) 70 | rp2=$(realpath $localeStringsDir) 71 | 72 | if [ $rp1 != $rp2 ]; then 73 | localeStringsPath=$localeStringsDir/$stringsFile 74 | # Just copy base strings file on first time 75 | if [ ! -e $localeStringsPath ]; then 76 | cp $baseStringsPath $localeStringsPath 77 | else 78 | oldLocaleStringsPath=$(echo "$localeStringsPath" | sed "s/$stringsExt/$oldStringsExt/") 79 | cp $localeStringsPath $oldLocaleStringsPath 80 | 81 | # Merge baseStringsPath to localeStringsPath 82 | gawk 'NR == FNR && /^\/\*/ {x=$0; getline; a[x]=$0; next} /^\/\*/ {x=$0; print; getline; $0=a[x]?a[x]:$0; printf $0"\n\n"}' $oldLocaleStringsPath $baseStringsPath > $localeStringsPath 83 | #awk 'NR == FNR && /^\/\*/ {x=$0; getline; a[x]=$0; next} /^\/\*/ {x=$0; print; getline; $0=a[x]?a[x]:$0; printf $0"\n\n"}' $oldLocaleStringsPath $baseStringsPath > $localeStringsPath 84 | 85 | rm $oldLocaleStringsPath 86 | fi 87 | fi 88 | done 89 | else 90 | echo "$storyboardPath file not modified." 91 | fi 92 | done 93 | 94 | IFS=$oldIFS 95 | --------------------------------------------------------------------------------