Last active
July 26, 2022 09:05
-
-
Save DmytroLisitsyn/ae10f0a71638d17e894cef07147a861b to your computer and use it in GitHub Desktop.
Localization constants generator.
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/bash | |
# | |
# Copyright (C) 2019 MadAppGang Pty Ltd | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in all | |
# copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
# | |
set -e | |
for FILE in "$@"; do | |
case $FILE in | |
*.strings) | |
STRINGS_FILE=$FILE;; | |
*.stringsdict) | |
DICT_FILE=$FILE;; | |
*.swift) | |
OUTPUT_FILE=$FILE;; | |
*) | |
echo "Unexpected file type: $FILE" | |
exit 1;; | |
esac | |
done | |
PARSED=() | |
PARSE_STRINGS_FILE() { | |
if [ ! -e "$STRINGS_FILE" ]; then | |
return 0 | |
fi | |
local RESULT=$(grep -Eoi "\".+\"[ ]*=[ ]*\".+\";" $STRINGS_FILE) # Finds localization key-values pairs. | |
RESULT=${RESULT//[$'\n'$'\t'\" ]/} # Removes newlines, quotations and spaces. | |
local ITEMS=() | |
IFS=';' read -ra ITEMS <<< "$RESULT" # Makes array from search result string. | |
unset IFS | |
ITEMS=("${ITEMS[@]//=*/}") # Remove value from key-value pair of match. | |
PARSED=("${PARSED[@]}" "${ITEMS[@]}") | |
return 0 | |
} | |
PARSE_DICT_FILE() { | |
if [ ! -e "$DICT_FILE" ]; then | |
return 0 | |
fi | |
local RESULT=$(<$DICT_FILE) | |
RESULT=${RESULT//[$'\n'$'\t' ]/} | |
RESULT=${RESULT#*<dict>} | |
RESULT=${RESULT/\<\/dict\>\<\/plist\>/} | |
RESULT=$(echo "$RESULT" | perl -pe 's/<dict><key>.*?<\/dict><\/dict>//g') | |
RESULT=$(echo "$RESULT" | perl -pe 's/<\/key><key>/;/g') | |
RESULT=$(echo "$RESULT" | perl -pe 's/<(\/)?key>//g') | |
local ITEMS=() | |
IFS=';' read -ra ITEMS <<< "$RESULT" # Makes array from search result string. | |
unset IFS | |
PARSED=("${PARSED[@]}" "${ITEMS[@]}") | |
return 0 | |
} | |
MAKE_SPACING() { | |
local DEPTH=$1 | |
local STEP=" " | |
local SPACING="" | |
for (( I=0; I<$DEPTH; I++ )); do | |
SPACING="$STEP$SPACING" | |
done | |
echo "$SPACING" | |
} | |
HANDLE_KEYWORD() { | |
case $1 in | |
"continue"|"switch"|"default"|"static"|"final"|"class"|"struct"|"import"|"extension"|"return"|"try"|"let"|"break"|"case"|"super"|"private"|"public"|"internal"|"guard"|"self"|"while"|"do"|"catch"|"as"|"true"|"false"|"override"|"lazy"|"get"|"set") | |
echo "\`$1\`";; | |
*) | |
echo $1;; | |
esac | |
} | |
LOWERCASE_FIRST_LETTER() { | |
echo "$(tr '[:upper:]' '[:lower:]' <<< ${1:0:1})${1:1}" | |
} | |
MAKE_PARAMETER_SWIFT_TYPE() { | |
case $1 in | |
*%@) | |
echo "String";; | |
*%d) | |
echo "Int";; | |
*) | |
echo "Unexpected parameter type: $1" | |
exit 1;; | |
esac | |
} | |
MAKE_ENTRY() { | |
local ENTRY=$1 | |
local KEY=$2 | |
local DEPTH=$3 | |
local SPACING=$(MAKE_SPACING $DEPTH) | |
local NAME=$(LOWERCASE_FIRST_LETTER $ENTRY) | |
NAME=${NAME//%[@d]/} | |
NAME=$(HANDLE_KEYWORD $NAME) | |
local PARAMETERS=$(echo $ENTRY | grep -Eo "[A-Z]*[a-z0-9]*%[@d]") | |
PARAMETERS=${PARAMETERS//[$'\n']/;} | |
IFS=';' read -ra PARAMETERS <<< "$PARAMETERS" | |
unset IFS | |
local PARAMETERS_LENGTH=${#PARAMETERS[@]} | |
if [ $PARAMETERS_LENGTH -eq 0 ]; then | |
echo "${SPACING}static let $NAME = \"$KEY\".localized()" | |
else | |
local INPUT_ARGS="" | |
local OUTPUT_ARGS="" | |
for (( I=0; I<$PARAMETERS_LENGTH; I++ )); do | |
local PARAMETER=$(LOWERCASE_FIRST_LETTER ${PARAMETERS[$I]}) | |
local TYPE=$(MAKE_PARAMETER_SWIFT_TYPE $PARAMETER) | |
PARAMETER=${PARAMETER//%[@d]/} | |
INPUT_ARGS="${INPUT_ARGS}$PARAMETER: $TYPE" | |
OUTPUT_ARGS="${OUTPUT_ARGS}$(HANDLE_KEYWORD $PARAMETER)" | |
if [ $I -lt $(expr $PARAMETERS_LENGTH - 1) ]; then | |
INPUT_ARGS="$INPUT_ARGS, " | |
OUTPUT_ARGS="${OUTPUT_ARGS}, " | |
fi | |
done | |
local KEY_SPACING=$(MAKE_SPACING $DEPTH+1) | |
echo "${SPACING}static func $NAME($INPUT_ARGS) -> String {\n${KEY_SPACING}return \"$KEY\".localized(arguments: $OUTPUT_ARGS)\n${SPACING}}" | |
fi | |
} | |
MAKE_ENTRIES() { | |
local DEPTH=$1 | |
local HIERARCHY=() | |
local HIERARCHY_DEPTH=0 | |
for KEY in "${PARSED[@]}"; do | |
local COMPONENTS=() | |
IFS='.' read -ra COMPONENTS <<< "$KEY" | |
unset IFS | |
local LENGTH=${#COMPONENTS[@]} | |
local NEW_HIERARCHY_DEPTH=$(expr $LENGTH - 1) | |
local NEW_HIERARCHY=(${COMPONENTS[@]:0:$NEW_HIERARCHY_DEPTH}) | |
local ENTRY=${COMPONENTS[$NEW_HIERARCHY_DEPTH]} | |
local MAX_COMMON_HIERARCHY_DEPTH=$(( $NEW_HIERARCHY_DEPTH<$HIERARCHY_DEPTH ? $NEW_HIERARCHY_DEPTH : $HIERARCHY_DEPTH )) | |
local COMMON_HIERARCHY_DEPTH=0 | |
for (( I=0; I<$MAX_COMMON_HIERARCHY_DEPTH; I++ )); do | |
if [[ "${HIERARCHY[$I]}" == "${NEW_HIERARCHY[$I]}" ]]; then | |
COMMON_HIERARCHY_DEPTH=$(expr $COMMON_HIERARCHY_DEPTH + 1) | |
else | |
break | |
fi | |
done | |
local BRACKETS_TO_CLOSE=$(expr $HIERARCHY_DEPTH - $COMMON_HIERARCHY_DEPTH) | |
for (( I=$HIERARCHY_DEPTH-1; I>=$COMMON_HIERARCHY_DEPTH; I-- )); do | |
local SPACING=$(MAKE_SPACING $(expr $I + $DEPTH)) | |
echo "${SPACING}}" | |
done | |
for (( I=$COMMON_HIERARCHY_DEPTH; I<$NEW_HIERARCHY_DEPTH; ++I )); do | |
local SPACING=$(MAKE_SPACING $(expr $I + $DEPTH)) | |
echo "${SPACING}enum ${COMPONENTS[$I]} {" | |
done | |
local ENTRY_DEPTH=$(expr $NEW_HIERARCHY_DEPTH + $DEPTH) | |
echo "$(MAKE_ENTRY $ENTRY $KEY $ENTRY_DEPTH)" | |
HIERARCHY=("${NEW_HIERARCHY[@]}") | |
HIERARCHY_DEPTH=$NEW_HIERARCHY_DEPTH | |
done | |
for (( I=$HIERARCHY_DEPTH-1; I>=0; I-- )); do | |
local SPACING=$(MAKE_SPACING $(expr $I + $DEPTH)) | |
echo "${SPACING}}" | |
done | |
} | |
PARSE_STRINGS_FILE | |
PARSE_DICT_FILE | |
IFS=$'\n' PARSED=($(sort <<< "${PARSED[*]}")) # Sorts array of source keys. | |
unset IFS | |
echo "// | |
// This file is generated by Kassandra - localization constants generator. | |
// | |
// If you have any issues or just want to say thanks, contact Dmytro ([email protected]). | |
// | |
import Foundation | |
enum Localizable { | |
$(MAKE_ENTRIES 1) | |
} | |
extension String { | |
public func localized(arguments: CVarArg..., comment: String = \"\") -> String { | |
if arguments.isEmpty { | |
return NSLocalizedString(self, comment: comment) | |
} else { | |
return withVaList(arguments) { arguments -> String in | |
let format = NSLocalizedString(self, comment: comment) | |
return NSString(format: format, arguments: arguments) as String | |
} | |
} | |
} | |
}" > $OUTPUT_FILE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment