Localizing your scripts in BASH, part 2

This is a continuation of the article Localizing your scripts in BASH . In it, using arrays and indirect references, we learned to add additional languages ​​to our scripts and switch between them.





In this article, we will compile a list of built-in languages ​​and set the choice of language through the menu, building a multi-level menu for this. To prevent the article from turning into one big piece of code with a description of each line, I will post the code itself with detailed comments below, and here I will touch on only a few main points.





Menu creation

In the last article, we used a loop for



and a selection operator to display a menu on the screen and select the required item case



. Obviously, to create a multi-level menu, these steps will need to be repeated several times, that is, for each submenu. In this case, you will have to re-create the menu header, appearance, and so on.





A good way to avoid it - to make for



, case



and read



in a separate function (call it prints



), and then we will simply pass it to the required parameters. All scripts that will be executed when certain menu items are selected will also be transferred to the corresponding functions.





So, to add a new action to the script:





  • add words and phrases to the language array





  • into the array with the main or additional menu, insert the corresponding item and the command to call the function





  • add a function with the required code fragment





First, let's create a main menu, which will immediately appear on the screen when the script is launched:





menu0=("${lng[3]};main" "${lng[4]};gitadd" "${lng[5]};gitinit" "${lng[2]};options" "${lng[1]};exit")
      
      



: , ;



- , . , . , , .





main



:





main() {
    #    
    local menu0=("${lng[3]};main" "${lng[4]};gitadd" "${lng[5]};gitinit" "${lng[2]};options" "${lng[1]};exit")

    while true ; do

        #       
        #    ,     
        prints "menu0[@]" "${msg[1]}"
    done
}

main
      
      



, options



:





options() {
    local menu1=("${lng[2]};options" "${lng[7]} [$langset];langmenu" "${lng[1]};exit")
    prints "menu1[@]" "${msg[1]}"
      
      



prints



, . , . cut



:





if [[ "$1" == "text" ]] ; then
    #     
    echo "$2" | cut -d ";" -f 1
    return
elif [[ "$1" == "command" ]] ; then
    #    
    echo "$2" | cut -d ";" -f 2
    return
fi
      
      



, , ${prints "text" "${menu[0]}"}



, - .





, : . colors



. ANSI escape ( echo -e



) 256 .





, , pwds



, . , .





, .





prints



. , :





local menu=("${!1}")
      
      



- . , , 1 :





pwds
colors "title" "---$(prints "text" "${menu[0]}")---"
      
      



for



,



, read



case



:





for (( op=1; op < "${#menu[@]}"; op++ )); do
	colors "item" "$op ) $(prints "text" "${menu[$op]}")"
done
echo ----------
read -s -n1 -p "$(colors "item" "$2: ")" item	
case $item in
	[1-$((${#menu[@]}-1))] ) 
		#      
		colors "ok" "[$item]->: $(prints "text" "${menu[$item]}")"
		#     
		$(prints "command" "${menu[$item]}") ;;
		#    [q]
		"q" ) echo; exit;;
		#          
		* ) colors "err" "[$item]->: ${msg[2]}"; sleep 2 ;;
esac
      
      



This is what this menu will look like.

. , .





, , , . langmenu



.





, . . , sed



language_



. language_ru



ru



:





# [-r] -    
# [-n] -   ,    
local lng_sfx=($(sed -r -n "s/^\s?+language_(\w+)=.*/\1/p" "${0}"))
      
      



, , prints



. . langmenu



:





langmenu(){
    local lng_sfx=($(sed -r -n "s/^\s?+language_(\w+)=.*/\1/p" "${0}"))
    local menu2=("${lng[7]};langmenu")

    for a in ${lng_sfx[@]} ; do
        local d="language_$a[@]"; d=("${!d}")
        menu2+=("$d;languages set $a")
    done

    menu2+=("${lng[1]};exit")
    prints "menu2[@]" "${msg[6]}"
}
      
      



:









  1. . , 0



    ( ). : , ;



    , , languages



    .



    "English;languages set en"



    , set en



    - languages



    .









  2. prints



    . ,





Language selection menu

. sed



-i



-r



, -i



- () , -r



- .





: , langset=



langset=



:





sed -i -r "0,/^\s?+langset=/s/langset=[\"\']?\w*[\"\']?/langset=\"$langset\"/" "${0}"
exit
      
      



prints



. , , case



languages



, set



. languages



, . :





languages
if [ "$1" == "set" ] ; then
	#      
	langset="$2"
	local df="language_$langset"
	echo
	#       ,  
	colors "ok" "${msg[7]} ${!df}. ${msg[8]}"
	#   
	languages
	#       ,  
	colors "ok" "${msg[7]} ${lng[0]}. ${msg[8]}"
	echo
	#   langset=     
	sed -i -r "0,/^\s?+langset=/s/langset=[\"\']?\w*[\"\']?/langset=\"$langset\"/" "${0}"
	exit 
fi
      
      



Setting the language

In this and the previous article, we created a template that you can use to write your own scripts with the ability to display on-screen menus and messages in different languages. In this case, the script consists of one file and to add a new language it is enough to drop the array with words at the beginning of the script, and to add any action - create a function and register it in the menu.





Thanks for reading to the end.





All the code with comments is attached below.





The whole code
#!/bin/bash
#  
langset="ru"

#   
language_en=( "English" "Quit" "Options" "Main menu" "Git: add ALL files/commit" "Git init" "Change language" "Language selection" )
message_en=( "English" "Select item" "Wrong! This item does not exist" "Added all files" "Enter you commit" "Changes recorded" "Select a language" "The language has been changed to" "Start the program again" "Repository not found\nPlease, select Git init pepository" )

language_ru=( "" "" "" " " "Git:   /" "" "" " " )
message_ru=( "" " " "!    " "  " "  " " " " " "  " "  " "  \n,  ,  Git init" )

language_de=( "Deutsch" )
message_de=( "Deutsch" "" "" "" "" "" "" "" "Starten Sie das Programm neu" )

language_cn=( "中文" "出口" "设置" "主菜单")
message_cn=( "中文" "选择项目" "" "" "" "" "选择语言" "语言已改为" "重新启动程序" )

# Settings section

languages() {
	#        
	#      
	lng="language_$langset[@]"; lng=("${!lng}")
	msg="message_$langset[@]"; msg=("${!msg}")

	#       
	for b in ${!language_en[@]} ${!message_en[@]} ; do
	
		if [[ ! ${lng[$b]} ]] ; then
			lng[$b]=${language_en[$b]}
		fi
		if [[ ! ${msg[$b]} ]] ; then
			msg[$b]=${message_en[$b]}
		fi
	done

	#   
	if [ "$1" == "set" ] ; then
		
		#      
		langset="$2"

		local df="language_$langset"
		
		#        ,
		#   ,   
		echo
		colors "ok" "${msg[7]} ${!df}. ${msg[8]}"
		
		#   
		languages
		
		#        
		#   ,   
		colors "ok" "${msg[7]} ${lng[0]}. ${msg[8]}"
		echo
		#      
		#   langset=     
		# [-r] -    
		# [-i] -  
		# [0,] -   
		sed -i -r "0,/^\s?+langset=/s/langset=[\"\']?\w*[\"\']?/langset=\"$langset\"/" "${0}"
		exit 
	fi
}

#   
languages


colors() {
	#     .   ,
	#      ,   
	#  [48] -    , [38] - 
	# [5] - 8-   (0-255), [1] - ,
	# [22] -  , [0] -   
	case "$1" in
		# : - ()
		"tm" ) echo -e "\e[48;5;256;38;5;34;22m$2\e[0m" ;;
		# : -, :   (  )
		"pt" ) echo -e "\e[48;5;24;38;5;15;1m$2\e[0m" ;;
		# : -  ( )
		"cf" ) echo -e "\e[48;5;256;38;5;226;1m$2\e[0m" ;;
		# : -  (  )
		"ok" ) echo -e "\e[48;5;256;38;5;34;1m$2\e[0m" ;;
		# :   ( )
		"err" ) echo -e "\e[48;5;256;38;5;160;1m$2\e[0m" ;;
		# : - ( )
		"title" ) echo -e "\e[48;5;256;38;5;226;22m$2\e[0m" ;;
		# :  (    )
		"item" ) echo -e "\e[48;5;256;38;5;15;22m$2\e[0m" ;;
	esac	
}

pwds() {
	#        
	echo 
	echo ----------
	echo "$(colors 'tm' "[$(date +"%T")]") $(colors 'pt' "${PWD%/*}"/)$(colors 'cf'  "$(basename   "$PWD")")"
	echo ----------
}

prints() {
	#     
	
	#       ,    [;]
	if [[ "$1" == "text" ]] ; then
		echo "$2" | cut -d ";" -f 1
		return
	elif [[ "$1" == "command" ]] ; then
		echo "$2" | cut -d ";" -f 2
		return
	fi
	
	#    ,     
	local menu=("${!1}")
	
	#     
	pwds
		
	#     ,  
	#    1   	
	colors "title" "---$(prints "text" "${menu[0]}")---"
	
	#    
	for (( op=1; op < "${#menu[@]}"; op++ )); do
		
		#     ,  
		#      
		colors "item" "$op ) $(prints "text" "${menu[$op]}")"
	done
	
	echo ----------
	
	#   ,    
	read -s -n1 -p "$(colors "item" "$2: ")" item	
	
	#  
	case $item in
		#    1      1 (     0)
		#        
		#      
		[1-$((${#menu[@]}-1))] ) colors "ok" "[$item]->: $(prints "text" "${menu[$item]}")"
		
		#     ,   
		#      
		$(prints "command" "${menu[$item]}") ;;
		
		#    [q]
		"q" ) echo; exit;;
		
		#          
		* ) colors "err" "[$item]->: ${msg[2]}"; sleep 2 ;;
	esac	
}


# Application section

gitinit() {
	#  :    [git init]
	git init
}

gitadd() {
	#  :    [git add] -   
	git add .
	#  .       [0]
	#          
	if [[ "$?" != "0" ]] ; then
		colors "err" "${msg[9]}" 
		sleep 1
		return 1 
	fi
	
	echo "${msg[3]} ..."
	#    
	read -p "$(colors "item" "${msg[4]}: ")" comm
	git commit -m "$comm"
	#      
	colors "ok" "${msg[5]}"
}


# Menu section

langmenu() {
	#    
	#    ,    
	#    [language_*]      
	# [-r] -    
	# [-n] -   ,    
	local lng_sfx=($(sed -r -n "s/^\s?+language_(\w+)=.*/\1/p" "${0}"))
	
	#     	
	local menu2=("${lng[7]};langmenu")
	
	#       ,      ,
	#    0     (   )
	for a in ${lng_sfx[@]} ; do
		local d="language_$a[@]"; d=("${!d}")
		
		#       
		#         ,  
		#  [;],   ,    
		# [languages]       .   
		#  ["English;languages set en"],  [set en] -    [languages]
		menu2+=("$d;languages set $a")
	done
	#     
	menu2+=("${lng[1]};exit")
	
	#           
	#    ,     
	prints "menu2[@]" "${msg[6]}"
}

options() {
	#     
	#           ,
	#    [;],   ,     
	local menu1=("${lng[2]};options" "${lng[7]} [$langset];langmenu" "${lng[1]};exit")
	
	#       
	#    ,     
	prints "menu1[@]" "${msg[1]}"
}

main() {
	#    
	#           ,
	#    [;],   ,     
	#     ,  ,   -       
	#   ,              
	local menu0=("${lng[3]};main" "${lng[4]};gitadd" "${lng[5]};gitinit" "${lng[2]};options" "${lng[1]};exit")

	
	while true ; do
		#       
		#    ,     
		prints "menu0[@]" "${msg[1]}"
	done
}

main

exit 0
      
      










All Articles