iPhone and Linux

Monday, February 22, 2010

Final script for deleting iPhone language packs

This will probably be the final script for deleting language packs on the iPhone. As I have said before, it is a pain to keep up with the ever-changing languages. This started out as a script I threw together in an hour or two just because I was curious if I could write a self-referential script that listed the languages and allowed people to pick the ones to remove, but has become something popular that needs maintaining, and the developers who create the language packs don't seem to have any guidelines for naming them. As the languages changed, the older script got longer and asked the user more and more questions. This one changes that and makes it easier for me to maintain.

Although many things look the same, this version has many changes. There are some performance improvements, although they may not be evident since it's an interactive script. It will also end itself if it doesn't find anything to delete and, overall, it just "flows" better.

The most noticeable improvement is the interaction with the user. It will only ask about the languages which it finds on the system and it will only ask once for each language. So if it finds 6 differently named Spanish directories and 2 Germans, it will only ask if you want to delete Spanish and German. The user no longer has to answer yes or no for every single code for every single language.

It has 35 languages built in because that's what Apple says the iPhone supports, but most people won't have that many installed. I've included every language code I've found over the past couple of months for those 35 languages as well as every possibility a total of 270. It will also present unrecognized languages to the user if that language is not found in those 270.

I will no longer maintain my original script as this one does everything that one did and does it in a way that is less hassle for the user.

After this is out for a week or two and I make sure there aren't any bugs in the script, I'm considering my foray into iPhone languages finished. I will update this script with new languages and it would help greatly if people send me their log files (the info is in the script) but I simply don't have the time to do anything more.

My stripped down version for deleting everything except English will never be obsolete (unless Apple changes how languages are used) and, if that's the only language you want, would be simpler to use and will remove every language except English whether it is recognized or not.

Jailbroken iPhone/iTouch OS 3.x. Or 4.x. Several users have recently used this successfully on OS 4.0.

This script uses basic BASH shell builtins and unix core utilities. Both are installed by default when you install MobileTerminal on the iPhone. It's possible that you can install them separately, I don't know, but I suggest installing MobileTerminal and also recommend using MobileTerminal to execute the script and iFile to get the script on the phone.

I would love to use more powerful tools like sed or awk and cut this script down to a fraction of the length, but I'd rather have it use minimal dependencies.

How to use.
View this page on your iPhone.

Copy everything from "#! /bin/sh" to "# end of script"

If you have Safari downloading enabled on your phone, click here and download it directly to your phone. (having trouble with mediafire, please redownload if you downloaded in the past few minutes)

Or, create a new text file on the phone with iFile. You can name it anything, but I will use langpack2.sh as an example. You can do this anywhere, but for simplicity, I suggest creating it in /var/mobile (a.k.a. /private/var/mobile)

Paste the script into the text file and save it.

Open MobileTerminal, cd to the directory where langpack2.sh is located and type chmod 755 langpack2.sh and hit enter, then type ./langpack2.sh to run it.

There are other ways to do this but I'm a Linux guy and I don't have a Mac and use Windows about twice a year so I can't recommend anything else.

Windows can screw up the formatting of the text if it isn't transferred to the phone a certain way and I'm not going to research how to do it. I've never touched a Mac, so I can't help there either. One thing we all have in common is the phone and the two iPhone apps iFile and MobileTerminal are the recommended way to run this script. Using this method, it can be downloaded and executed while you're walking down the street, no computer needed.

Linux users should have no problem saving it on their computer, ssh'ing it to the phone and running it there. I did most of the testing in a Linux terminal with ssh, but MobileTerminal is still the one foolproof way to run it.

Another method to get this script using nothing but the phone is to install lynx from Cydia then run this command:
lynx -width=500 -dump http://tinyurl.com/356wmua | grep -B 182 "end of script$" > langpack2.2.sh
That will grab the text from this page and put it in the file called langpack2.2.sh.

You may also be interested in this script for identifying unrecognized language codes.

(May 17) I've gotten some hits from a couple of sites which have translated the text of the script to German and Hungarian, which may be useful for anyone speaking those languages.

(Dec 29 2010) Several users have reported that the script fails to recognize vi.lproj. This is Vietnamese and can be deleted if you don't need Vietnamese. The script looks for vi.lproj and worked fine for months, but started missing it all of a sudden. My iPhone is a gaming device for my daughter and is still on 3.1 and I have no plans to update it to the latest firmware so I will probably never fix this problem.

Creative Commons License
Langpack2 by Fubaya is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.
Based on a work at a-common-hades.blogspot.com.
#! /bin/sh
# Apr 15 2010
# Langpack2 by Fubaya. Licensed under CC "by-nc-nd"
# more info: http://creativecommons.org/licenses/by-nc-nd/3.0/us/

##### root test #####
# won't go any farther unless you're uid=0
[ `id -u` != 0 ] && exec echo "Oops, you need to be root to run this script"

##### hello, get ready, search for languages #####
clear; echo -e "\n\n--Langpack2- by Fubaya ($(echo 'ijdqas@gqail.coq' | tr q m))--
--http://a-common-hades.blogspot.com--\n" | tee langpack.log
echo -e "Let's delete a few thousand language packs.
You will have several chances to back out
before anything is deleted but if you want
to stop at any time just type $(tput bold; tput setaf 3)q$(tput sgr0).\n
If you want to see how it runs without
making any changes, just answer no when it
asks you which languages to delete.\n
Searching for language packs. Please wait...\n"

# set interrupt to "q"
tset -Q -i q

# clear out old temp files, if any, create new
rm -f .*_fubaya; touch {.alllist,.langlist,.deletelist,.rmlist,.yeslist}_fubaya

# update database, search for lproj, grep directories,
# filter out english, filter out strange "Scanner911" app languages, put rest in alllist
updatedb && locate lproj | grep -E lproj$ | grep -v -i -E '(English|\/en|.en.l|blue.lproj|camo.lproj|classic.lproj|desert.lproj|modern.lproj)' > .alllist_fubaya

# make sure alllist isn't empty, get basename of files, grep again just to be sure they're directories
# sort and get uniq names and now we have a list of all unique languages on the phone.
[[ -s .alllist_fubaya ]] && cat .alllist_fubaya | xargs -n1 basename | grep -E lproj$ | sort | uniq > .langlist_fubaya
##### end section #####

##### core function #####
# process languages, ask user to delete
language ()
# $* is all arguments to the "language" lines. If any of those appear in langlist...
if echo $* | grep -q -i -f .langlist_fubaya

# then start a loop to require yes or no
while [[ "$choice" != 'y' ]] && [[ "$choice" != 'n' ]]

# ask "delete the first argument, yes or no?"
do read -p "Delete: $(tput bold; tput setaf 3)${1%.*}$(tput sgr0) - y or n? " choice; done

# if yes
if [ $choice = "y" ]
# put that language's formal name in yeslist
echo ${1%.*} >> .yeslist_fubaya

# put that language's whole line in rmlist, replacing spaces with newlines
echo $* | tr ' ' '\n' >> .rmlist_fubaya

# confirm the choice
echo "${1%.*} will be deleted";

# if no, echo (that language's formal name) will be kept
else echo "${1%.*} will be kept"; fi

# log the language and choice
echo "known $1: $choice" >> langpack.log

unset choice # clear the variable because I'm too lazy to use a new one
echo # spacer

language Albanian.lproj alb.lproj sqi.lproj sq.lproj sq-sq.lproj sq_sq.lproj sq_al.lproj sq-al.lproj
language Amharic.lproj amh.lproj am.lproj am-am.lproj am_am.lproj
language Arabic.lproj ara.lproj ar.lproj ar-ar.lproj ar_ar.lproj ar_eg.lproj ar_sa.lproj
language Armenian.lproj arm.lproj hye.lproj hy.lproj hy_hy.lproj hy-hy.lproj
language Bulgarian.lproj bul.lproj bg.lproj bg_bg.lproj bg-bg.lproj
language Catalan.lproj ca.lproj cat.lproj ca_ca.lproj ca-ca.lproj ca_es.lproj
language Chinese.lproj chi.lproj zho.lproj zh.lproj zh-zh.lproj zh_zh.lproj zh-hans.lproj zh_hans.lproj zh-hant.lproj zh_hant.lproj zh_cn.lproj zh-cn.lproj zh-hk.lproj zh_hk.lproj zh-tw.lproj zh_tw.lproj
language Croatian.lproj hrv.lproj hr.lproj hr-hr.lproj hr_hr.lproj
language Czech.lproj cze.lproj ces.lproj cs.lproj cs-cs.lproj cs_cs.lproj cs-cz.lproj cs_cz.lproj cz.lproj cz_cz.lproj cz-cz.lproj
language Danish.lproj dan.lproj da.lproj da-da.lproj da_da.lproj da_dk.lproj da-dk.lproj
language Dutch.lproj dum.lproj dut.lproj nld.lproj nl.lproj nl-nl.lproj nl_nl.lproj
language Estonian.lproj est.lproj et.lproj et_ee.lproj et-ee.lproj
language Finnish.lproj fin.lproj fi.lproj fi-fi.lproj fi_fi.lproj
language French.lproj fra.lproj fre.lproj fr.lproj fr-fr.lproj fr_fr.lproj fr_ca.lproj fr-ca.lproj fr_fr.lproj fr-fr.lproj
language German.lproj deu.lproj ger.lproj de.lproj de-de.lproj de_de.lproj
language Greek.lproj gre.lproj ell.lproj el.lproj el-el.lproj el_el.lproj el_gr.lproj el-gr.lproj gr_el.lproj gr-el.lproj
language Gujarati.lproj guj.lproj gu.lproj gu_in.lproj
language Hebrew.lproj heb.lproj he.lproj he-he.lproj he_he.lproj he_il.lproj he-il.lproj hi_in.lproj hi-in.lproj
language Hindi.lproj hin.lproj hi.lproj hi_hi.lproj hi-hi.lproj
language Hungarian.lproj hun.lproj hu.lproj hu-hu.lproj hu_hu.lproj
language Icelandic.lproj ice.lproj isl.lproj is.lproj is_is.lproj is-is.lproj
language Indonesian.lproj ind.lproj id.lproj id-id.lproj id_id.lproj
language Iranian.lproj ira.lproj fa.lproj per.lproj fa_ir.lproj fa-ir.lproj fa-fa.lproj
language Italian.lproj ita.lproj it.lproj it-it.lproj it_it.lproj
language Japanese.lproj ja.lproj ja-ja.lproj ja_ja.lproj ja_jp.lproj ja-jp.lproj jp_jp.lproj jp-jp.lproj jpn.lproj
language Korean.lproj kor.lproj ko.lproj ko-ko.lproj ko_ko.lproj
language Latvian.lproj lav.lproj lv_lv.lproj
language Lithuanian.lproj lit.lproj lt.lproj lt-lt.lproj lt_lt.lproj
language Macedonian.lproj mk.lproj mac.lproj mk_mk.lproj mk-mk.lproj
language Malay.lproj may.lproj ms.lproj ms-ms.lproj ms_ms.lproj ms_my.lproj
language Norwegian.lproj nor.lproj nob.lproj nno.lproj nn_nn.lproj nn-nn.lproj no.lproj no-no.lproj no_no.lproj nb.lproj nb_nb.lproj nb-nb.lproj no_nb.lproj no-nb.lproj nb_no.lproj nb-no.lproj nn_no.lproj nn-no.lproj nn_nb.lproj nn-nb.lproj nb_nn.lproj nb-nn.lproj
language Panjabi.lproj pa.lproj pan.lproj pa_pa.lproj pa-pa.lproj pa_in.lproj pa-in.lproj
language Polish.lproj pol.lproj pl.lproj pl-pl.lproj pl_pl.lproj
language Portuguese.lproj por.lproj pt.lproj pt-pt.lproj pt_pt.lproj pt-br.lproj pt_br.lproj
language Romanian.lproj rup.lproj rum.lproj ron.lproj ro.lproj ro-ro.lproj ro_ro.lproj
language Russian.lproj rus.lproj ru.lproj ru-ru.lproj ru_ru.lproj
language Serbian.lproj sr.lproj sr-sr.lproj sr_sr.lproj sr_rs.lproj
language Slovak.lproj slk.lproj slo.lproj sk.lproj sk-sk.lproj sk_sk.lproj
language Slovenian.lproj slv.lproj sl.lproj sl-sl.lproj sl_sl.lproj sl_si.lproj sl-si.lproj
language Spanish.lproj spa.lproj sp.lproj sp-sp.lproj sp_sp.lproj es.lproj es_es.lproj es-es.lproj es_mx.lproj es_us.lproj es_419.lproj
language Swedish.lproj swe.lproj sv.lproj sv-sv.lproj sv_sv.lproj sv-se.lproj sv_se.lproj
language Thai.lproj tha.lproj th.lproj th-th.lproj th_th.lproj
language Turkish.lproj tur.lproj tr.lproj tr-tr.lproj tr_tr.lproj
language Ukrainian.lproj ukr.lproj uk.lproj uk_uk.lproj uk-uk.lproj uk_ua.lproj uk-ua.lproj
language Vietnamese.lproj vi.lproj vn.lproj vi-vi.lproj vi_vi.lproj vn-vn.lproj vn_vn.lproj vi_vn.lproj vi-vn.lproj vn-vi.lproj vn_vi.lproj
##### end section #####

##### look for unrecognized languages #####
# for every entry in langlist
for i in $(cat .langlist_fubaya)
# if that lproj doesn't appear in this script
if ! cat $0 | grep -q -i $i

# start a loop to require yes or no
while [[ $choice != 'y' ]] && [[ $choice != 'n' ]]; do

# ask "delete that unrecognized language pack, yes or no?"
read -p "Delete: $(tput bold; tput setaf 3)${i}$(tput sgr0) (unrecognized) - y or n? " choice

# if yes, confirm and put it in rmlist and yeslist
if [ $choice = "y" ]; then echo "$i will be deleted"
echo $i | tee -a .rmlist_fubaya .yeslist_fubaya > /dev/null

# if no, confirm
else echo "${i} will be kept"; fi

# log language and choice
echo "unknown: $i $choice" >> langpack.log
unset choice
##### end section #####

##### finalize, confirm or quit #####
# use rmlist to extract all directories to be deleted from alllist, put them in deletelist
grep -i -f .rmlist_fubaya .alllist_fubaya > .deletelist_fubaya

# if that failed, it's because there's nothing to delete. Dump out.
[ "$?" -ne "0" ] && rm -f .*_fubaya && exec echo "
Nothing to delete. Either I didnt find
any to delete or you answered no to
everything. See ya later."

# otherwise, display all languages that are going to be deleted
echo -------------------------------------
tput bold; tput setaf 3; tr '\n' ' ' < .yeslist_fubaya
echo; tput sgr0
echo -------------------------------------
unset choice

# start a loop to require yes or no, ask to final confirmation
while [[ "$choice" != 'y' ]] && [[ "$choice" != 'n' ]]; do
echo "This is your last chance. Are you sure
you want to delete the languages listed?"
read -p "Type y or n: " choice
##### end section #####

##### delete, clean up, good-bye #####
# if yes
if [ $choice = "y" ]

# say "please wait" and loop through deletelist file, removing directories
echo -e "Please wait while I delete the chosen language packs...\n"
while read file
do rm -rf "$file"
done < .deletelist_fubaya

# count how many directories were in deletelist
num=$(grep -c ^ .deletelist_fubaya)

# remove temp files
rm -f .*_fubaya

# long goodbye
echo -e "$num language pack directories have been
deleted. A log file has been created at
My contact information is at the top of
the log file and if you encountered any
unrecognized languages, I would appreciate
you emailing me that file so that I may keep
up with the ever-changing languages.\n
The only other thing left is me, this
script located at `pwd`/`basename $0`."
read -p "Do you want me to delete myself - y or n? " choice
[ $choice = "y" ] && echo "Deleting myself...blarg.. I'm dead" && exec rm $0
echo "Phwew, Thank you! I'm too young to die. I'll be here at `pwd`/`basename $0` if you need me."
##### end section #####

##### if DONT delete, then clean up and good-bye #####
# if user said no to final confirmation, remove temp file and exit
rm -f .*_fubaya
echo "Ok, I wont delete anything. If you made a mistake, just run me again."
##### end section #####
# end of script

Blog Archive