Last active
February 18, 2019 10:08
-
-
Save talanov/497c6d15f8921818b6ee42720da6f4f1 to your computer and use it in GitHub Desktop.
Automatically extract translatable strings from Xcode storyboards and update .strings files. Original version: https://gist.github.com/ole/5007019. Updated for Xcode 10 & Swift 4.2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# | |
# update_storyboard_strings.sh - automatically extract translatable strings from storyboards and update strings files updated for Xcode 10.1 & Swift 4.2 | |
# Original script — https://gist.github.com/ole/5007019 | |
# Folder structure to eliminate duplicates & to make xib localization work. | |
# Instruction: | |
# 1. Go to XIB / Storyboard, check out right bar (Inspector), go to Localization and check out desired language. | |
# 2. Create Localizable.strings file @ LANGUAGECODE.lproj with localized strings. (// TODO: Make it global) | |
# 3. Build. | |
# **************************** | |
# FOLDER STRUCTURE | |
# **************************** | |
# |Storyboard folder | |
# |---| Base.lproj | |
# |---|--- FILE.storyboard | |
# |---| LANGUAGECODE.lproj | |
# |---|--- Localizable.strings | |
# | Folder | |
# |---| Base.lproj | |
# |---|--- FILE.xib | |
# |---| LANGUAGECODE.lproj | |
# |---|--- Localizable.strings | |
# **************************** | |
# FOLDER STRUCTURE END | |
# **************************** | |
storyboardExt=".storyboard" | |
xibExt=".xib" | |
stringsExt=".strings" | |
newStringsExt=".strings.new" | |
oldStringsExt=".strings.old" | |
bakStringsExt=".strings--" | |
localeDirExt=".lproj" | |
oldIFS=$IFS | |
IFS=$'\n' | |
# Find storyboard file full path inside project folder | |
for storyboardPath in `find . -name "*$storyboardExt" -print` | |
do | |
# Get Base strings file full path | |
baseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$stringsExt/") | |
echo "Base storyboard's string file path: "$baseStringsPath | |
# Create base strings file if it doesn't exist | |
if ! [ -f $baseStringsPath ]; then | |
touch -r $storyboardPath $baseStringsPath | |
# Make base strings file older than the storyboard file | |
touch -A -01 $baseStringsPath | |
fi | |
# Only run, if storyboard's newer. | |
if find $storyboardPath -prune -newer $baseStringsPath -print | grep -q .; then | |
# Get storyboard file name and folder | |
storyboardFile=$(basename "$storyboardPath") | |
storyboardDir=$(dirname "$storyboardPath") | |
echo "\nStoryboard File: $storyboardFile\n" | |
# Get New Base strings file full path and strings file name | |
newBaseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$newStringsExt/") | |
stringsFile=$(basename "$baseStringsPath") | |
echo "Extracting strings file" | |
ibtool --export-strings-file $newBaseStringsPath $storyboardPath | |
# ibtool sometimes fails for unknown reasons with "Interface Builder could not open | |
# the document XXX because it does not exist." | |
# (maybe because Xcode is writing to the file at the same time?) | |
# In that case, abort the script. | |
if [[ $? -ne 0 ]] ; then | |
echo "Exiting due to ibtool error. Please run `killall -9 ibtoold` and try again." | |
exit 1 | |
fi | |
# Only run iconv if $newBaseStringsPath exists to avoid overwriting existing | |
if [ -f $newBaseStringsPath ]; then | |
iconv -f UTF-16 -t UTF-8 $newBaseStringsPath > $baseStringsPath | |
rm $newBaseStringsPath | |
echo "Removing new file...\n" | |
fi | |
# Get all locale strings folder | |
for localeStringsDir in `find . -name "*$localeDirExt" -print` | |
do | |
echo "\n\nLocal string directory: $localeStringsDir\n" | |
# Base String File Path — базовый файл, из которого будет браться вся локаль. | |
baseStringFilePath="$localeStringsDir/Localizable""$stringsExt" | |
echo "Base strings file path: $baseStringFilePath" | |
# Storyboard folder | |
rp1=$(realpath $storyboardDir) | |
# Locale folder | |
rp2=$(realpath $localeStringsDir) | |
if [ -f "$baseStringFilePath" ] | |
then | |
echo "\n$baseStringFilePath found." | |
# Backing up Localizable. | |
cp $baseStringFilePath $localeStringsDir/../Localizable$stringsExt | |
else | |
echo "$baseStringFilePath not found." | |
# FILE NOT FOUND! | |
# Skip Base strings folder | |
if [ $rp2 == $rp1 ] || [[ $rp2 == *Base.lproj ]] | |
then | |
echo "Skip..." | |
else | |
echo $rp2 | |
exit 1 | |
fi | |
fi | |
if [ $rp1 != $rp2 ] | |
then | |
localeStringsPath=$localeStringsDir/$stringsFile | |
echo "Localized strings file: $localeStringsPath" | |
# If it doesn't exist -> Create. Don't forget to link it in pbxproj. | |
cp $baseStringsPath $localeStringsPath | |
echo "Created $localeStringsPath. Please link it to pbxproj." | |
oldLocaleStringsPath=$(echo "$localeStringsPath" | sed "s/$stringsExt/$oldStringsExt/") | |
echo "Temporary old file: $oldLocaleStringsPath" | |
cp $localeStringsPath $oldLocaleStringsPath | |
for string in $(cat "$baseStringFilePath") | |
do | |
# REGEX "*" = "*" | |
regex="\".*\".*=.*\".*\"" | |
if [[ $string =~ $regex ]] | |
then | |
IFS='=' | |
# ARRAY | |
STRINGS=() | |
for innerString in $string | |
do | |
innerInnerString=$(echo $innerString | awk 'match($0, /\"([^\"]|\\\")*\"/) { print substr( $0, RSTART, RLENGTH )}') | |
STRINGS+=($innerInnerString) | |
done | |
sed -i -- "s/${STRINGS[0]};$/${STRINGS[1]};/g" $localeStringsDir/*.strings | |
fi | |
IFS=$'\n' | |
done | |
rm $oldLocaleStringsPath | |
fi | |
# Restoring Base Localizable file | |
mv $localeStringsDir/../Localizable$stringsExt $baseStringFilePath | |
done | |
fi | |
done | |
# Cleaning... | |
find . -name "*$bakStringsExt" -exec rm -f {} \; | |
for stringFile in `find . -name "*$stringsExt" -print` | |
do | |
storyboard=$(echo $(dirname "$stringFile")/../Base.lproj/$(basename "$stringFile" | cut -d. -f1)$storyboardExt) | |
xib=$(echo $(dirname "$stringFile")/../Base.lproj/$(basename "$stringFile" | cut -d. -f1)$xibExt) | |
baseName=$(basename "$stringFile" | cut -d. -f1) | |
if [[ ( ! -f $storyboard ) && ( ! -f $xib ) && ! ( $baseName == "Localizable" || $baseName == "InfoPlist" ) ]] | |
then | |
rm $stringFile | |
echo "Removed duplicate: $stringFile with basename: $baseName" | |
fi | |
done | |
IFS=$oldIFS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Disclaimer: You shouldn't use it, unless you are trying to maintain a project which heavily relies on this script: https://gist.github.com/ole/5007019