How to use gettext in bash script?
I only found this page, but I don't understand it.
Localization
My script is written like this:
#!/bin/bash
. lang_file.sh
echo $LANG_HELLO_WORLD
And lang_file.sh look like that:
#!/bin/bash
LANG_HELLO_WORLD="Hello World"
I want to change lang_file.sh to something using gettext, like this:
#!/bin/bash
LANG_HELLO_WORLD=`some gettext command to get string in user language`
I want to use the code in Launchpad, so other users can translate it (.po, .pot files)
Sorry for bad English, any suggestions?
You need to preform following steps:
Determine what's your project name, gettext calls it textdomain, you will need it to retrieve the translations for your project. Let's call it "PRJ".
Mark the strings to be translated. Following snippet gives example:
Let's call it PRJ.sh:
#!/bin/sh
alias GETTEXT='gettext "PRJ"'
## Use GETTEXT to mark the string you want to translate
HELLO_WORLD=$(GETTEXT "Hello world")
echo "$HELLO_WORLD"
Produce .pot file so translators can work on it.
Run the following command, it only looks for GETTEXT, the ones you actually want to translate.
xgettext -o PRJ.pot -L Shell --keyword --keyword=GETTEXT PRJ.sh
Optional: Generate .po files.
For each locale you want to cover.
msginit -i PRJ.pot -l fr.UTF-8
Note that "UTF-8" is sugggested, otherwise msginit may mistakenly choose some obsoleted encoding for you.
Retrieve completed .po files, and convert them to .mo file (the file that machine can read it)
msgfmt -v fr.po -o fr.mo
Install .mo files. Run:
sudo install fr.mo /usr/share/locale/fr/LC_MESSAGES/PRJ.mo
Now you can try the result:
LANGUAGE=fr ./PRJ.sh
and you should see French translation for Hello world.
There is a long-lost, never-documented and almost-deprecated builtin solution in bash.
LANG=foo_BAR.utf8
TEXTDOMAIN="test"
TEXTDOMAINDIR="/usr/share/locale"
echo $"fooMsgid"
# bash --dump-po-strings <scriptfile>
The gettext translation make use of an editable format *.po to store translation, and a compiled format *.mo for loading.
For info of the files format, reference here: section "3 The Format of PO Files" and "10 Producing Binary MO Files" of https://www.gnu.org/software/gettext/manual/html_node/index.html
Here I focus on how to try the gettext command to get a translation in short.
After you prepared a folder /path/to/your/locale with inside-hierarchy like <lang>/LC_MESSAGES/<textdomain>.mo (where <lang> is e.g. ko_KR for Korean), use the following code in your lang_file.sh:
#!/bin/bash
export LC_ALL=ko_KR.UTF-8 # if LC_ALL not work, you could try also "LANG" and "LANGUAGE"
export TEXTDOMAINDIR=/path/to/your/locale
# export TEXTDOMAIN="<textdomain>" # <- optional, set this to save the "<textdomain>" argument for `gettext` below
LANG_HELLO_WORLD="$( gettext "<textdomain>" "Your message to translate" )"
What you are looking to do is I think ask the user in the appropriate language? You would probably want the user to pick the language first. The other part of what you are asking is simply just embedding commands like $(get_some_str_func) inside of your variable.
I did not write this code but it might be along the lines of what you are trying to do? I'm not sure, i don't understand fully what you are asking.
function _configure_locale() { # [profile]
local profile=${1:-EN}
case ${profile} in
DE|DE_DE|de_DE)
LC_ALL="de_DE.UTF-8"
LANG="de_DE.UTF-8"
LANGUAGE="de_DE:de:en_US:en"
;;
EN|EN_US|en|en_US)
LC_ALL="en_US.UTF-8"
LANG="en_US.UTF-8"
LANGUAGE="en_US:en"
;;
*)
echo "ALERT" "${FUNCNAME}: unknown profile '${profile}'"
;;
esac
LC_PAPER="de_DE.UTF-8"; # independent from locale
LESSCHARSET="utf-8"; # independent from locale
MM_CHARSET="utf-8" # independent from locale
echo "locale settings" "${LANG}";
export LC_ALL LANG LANGUAGE LC_PAPER LESSCHARSET MM_CHARSET
}
Here is my attempt to create a demo example code for Creating Internationalized Scripts section from Bash Reference Manual.
Create a script file script.sh:
#!/bin/bash
# script.sh
TEXTDOMAIN=script
TEXTDOMAINDIR="$PWD"
LANG=$1
# or use following
LC_MESSAGES=$1
echo $"hi"
Make it executable chmod +x script.sh.
Create template(.pot) and PO(.po) files:
bash --dump-po-strings script.sh > script.pot
# spanish
cp script.pot es.po
# french
cp script.pot fr.po
Edit the es.po and fr.po files and add translations.
For example es.po:
#: script.sh:8
msgid "hi"
msgstr "hola"
Compile PO files to create .mo files
msgfmt -o es.mo es.po
msgfmt -o fr.mo fr.po
# copy to following folder structure in pwd
cp es.mo es/LC_MESSAGES/script.mo
cp fr.mo fr/LC_MESSAGES/script.mo
Run the script to use the locales:
# find valid locale names
locale -a | egrep 'es|fr'
# use the valid locales to execute script
./script.sh spanish
hola
./script.sh french
salut
./script.sh es_ES
hola
./script.sh fr_FR
salut
NOTE: The example used the translation files from local directory. And installation to other common place is not required.
Related
If source and destination path are being same, how to skip re-typing it?
For example, I need to take a back-up of a file or rename it:
# taking back-up
$ cp ~/project/uboot/u-boot.img ~/project/uboot/ver1-u-boot.img
# renaming it
$ mv ~/project/uboot/u-boot.img ~/project/uboot/ver1-u-boot.img
It's all about the curly braces!
$ cp ~/project/uboot/{,ver1-}u-boot.img
or to be more verbose
$ mv ~/project/uboot/{u-boot.img,ver1-u-boot.img}
The shell will reproduce what you have explicitly written in your question, which means you can write out the full path once. Here's a good link for further reading.
How about
( cd ~/project/u-name-it; cp_or_mv file ver1-file )
or
base=base-path cp_or_mv $base/file $base/ver1-file
However this very much looks like a use case for a script or function to me.
As these can become quite sophisticated of course (e.g. increasing the version would be nice) I prefer to give a simple example more as an incentive ;)
# Untested, test well before using; should work in zsh & bash IFIAC
# usage:
# bup directory [files...]
function bup
{
local dir=$1
shift
for file; do
cp $dir/$file $dir/ver1-$file
done
}
HTH
Robert
I'm using gedit and trying to wrestle it into a real IDE. What I want is to map ctrlshift| to run my tidy tool when the file type is "text/html" and my autopep8 tool when the file type is "text/x-python".
As it turns out (and I think this is a bug), gedit doesn't care what filetype you've specified. If you have a key combo set, it will run a tool whether or not the filetype matches. Related, but maybe not a bug, I can only set the keyboard shortcut to one external tool.
So I wrote one external tool that runs on ctrlshift| and runs autopep8 if the document is Python and tidy if the document is HTML:
#!/bin/sh
# [Gedit Tool]
# Save-files=document
# Shortcut=<Primary><Shift>bar
# Output=replace-document
# Name=Tidy by Filetype
# Applicability=all
# Input=document
if [ $GEDIT_CURRENT_DOCUMENT_TYPE = "text/x-python" ]; then
autopep8 - -v -a
elif [ $GEDIT_CURRENT_DOCUMENT_TYPE = "text/html" ]; then
#-i auto indents, -w 80 wrap at 80 chars, -c replace font tags w/CSS
exec tidy -utf8 -i -w 80 -c "$GEDIT_CURRENT_DOCUMENT_NAME"
elif [ $GEDIT_CURRENT_DOCUMENT_TYPE = "text/css" ]; then
#TK CSS tidy
else
echo "This seems to be " $GEDIT_CURRENT_DOCUMENT_TYPE " I don't know how to tidy that."
fi
That second to last line is the one that is breaking my heart. If I don't define any action for that last else it just deletes my existing document. If I run ctrlshift| and the file-type isn't one that I've accounted for, I'd like it to report the file type to the shell output, not replace the document contents with
This seems to be application/x-shellscript I don't know how to tidy
that.
Is there a way to write my tool so that I write some output to the shell and some to the document?
Having no experience with trying to make gedit more usable, I did find this: https://wiki.gnome.org/Apps/Gedit/Plugins/ExternalTools?action=AttachFile&do=view&target=external-tools-manager-with-gedit-3.png
The key construct here is
echo "..." > /dev/stderr
At least that should stop you from clobbering the contents of your file if it the mime-type doesn't match, but I'm not sure where it'll print out (hopefully somewhere sane).
Edit (for a more complete answer):
You will also need to cat $GEDIT_CURRENT_DOCUMENT_NAME to replace the file contents with itself. This was pointed out by #markku-k (thanks!)
First post, so Hi! Let me start by saying I'm a total noob regarding programming. I understand very basic stuff, but when it comes to checking exit codes or what the adequate term is, I'm at a loss. Apparently my searchfoo is really weak in this area, I guess it's a question of terminology.
Thanks in advance for taking your time to reading this/answering my question!
Description: I found a script that converts/repack .cbr files to .cbz files. These files are basically your average rar and zip files, however renamed to another extension as they are used for (comic)book applications such as comicrack, qcomicbook and what not. Surprisingly enough there no cbr -> cbz converters out there. The advantages of .cbz is besides escaping the proprietary rar file format, that one can store the metadata from Comic Vine with e. g comictagger.
Issue: Sometimes the repackaging of the files doesn't end well and would hopefully be alleviated by a integrity check & another go. I modified said script slightly to use p7zip as it can both pack/unpack 7z, zip-files and some others, i. e great for options. p7zip can test the archive by:
7z t comicfile.cbz tmpworkingdir
I guess it's a matter of using if & else here(?) to check the integrity and then give it another go, if there are any error.
Question/tl;dr: What would be the "best"/adequate approach to add a integrity file check to the script below?
#!/bin/bash
#Source: http://comicrack.cyolito.com/forum/13-scripts/30013-cbr3cbz-rar-to-zip-conversion-for-linux
echo "Converting CBRs to CBZs"
# Set the "field separator" to something other than spaces/newlines" so that spaces
# in the file names don't mess things up. I'm using the pipe symbol ("|") as it is very
# unlikely to appear in a file name.
IFS="|"
# Set working directory where to create the temp dir. The user you are using must have permission
# to write into this directory.
# For performance reasons I'm using ram disk (/dev/shm/) in Ubuntu server.
WORKDIR="/dev/shm/"
# Set name for the temp dir. This directory will be created under WORDDIR
TEMPDIR="cbr2cbz"
# The script should be invoked as "cbr2cbz {directory}", where "{directory}" is the
# top-level directory to be searched. Just to be paranoid, if no directory is specified,
# then default to the current working directory ("."). Let's put the name of the
# directory into a shell variable called SOURCEDIR.
# Note: "$1" = "The first command line argument"
if test -z "$1"; then
SOURCEDIR=`pwd`
else
SOURCEDIR="$1"
fi
echo "Working from directory $SOURCEDIR"
# We need an empty directory to work in, so we'll create a temp directory here
cd "$WORKDIR"
mkdir "$TEMPDIR"
# and step into it
cd "$TEMPDIR"
# Now, execute a loop, based on a "find" command in the specified directory. The
# "-printf "$p|" will cause the file names to be separated by the pipe symbol, rather than
# the default newline. Note the backtics ("`") (the key above the tab key on US
# keyboards).
for CBRFILE in `find "$SOURCEDIR" -name "*.cbr" -printf "%p|while read line; do
# Now for the actual work. First, extract the base file name (without the extension)
# using the "basename" command. Warning: more backtics.
BASENAME=`basename $CBRFILE ".cbr"`
# And the directory path for that file, so we know where to put the finished ".cbz"
# file.
DIRNAME=`dirname $CBRFILE`
# Now, build the "new" file name,
NEWNAME="$BASENAME.cbz"
# We use RAR file's name to create folder for unpacked files
echo "Processing $CBRFILE"
mkdir "$BASENAME"
# and unpack the rar file into it
7z x "$CBRFILE" -O"$BASENAME"
cd "$BASENAME"
# Lets ensure the permissions allow us to pack everything
sudo chmod 777 -R ./*
# Put all the extracted files into new ".cbz" file
7z a -tzip -mx=9 "$NEWNAME" *
# And move it to the directory where we found the original ".cbr" file
mv "$NEWNAME" $DIRNAME/"$NEWNAME"
# Finally, "cd" back to the original working directory, and delete the temp directory
# created earlier.
cd ..
rm -r "$BASENAME"
# Delete the RAR file also
rm "$CBRFILE"
done
# At the end we cleanup by removing the temp folder from ram disk
cd ..
echo "Conversion Done"
rm -r "$TEMPDIR"
Oh the humanity, not posting more than two links before 10 reputation and I linked the crap out of OP.. [edit]ah.. mh-mmm.. there we go..
[edit 2] I removed unrar as an dependency and use p7zip instead, as it can extract rar-files.
You will need two checks:
7z t will test the integrity of the archive
You should also test the integrity of all the image files in the archive. You can use at tools like ImageMagick for this.
A simple test would be identify file but that might read only the header. I'd use convert file -resize 5x5 png:- > /dev/null
This scales the image down to 5x5 pixels, converts it to PNG and then pipes the result to /dev/null (discarding it). For the scaling, the whole image has to be read. If this command fails with an error, something is wrong with the image file.
I am using handlebars.js to render client-side templates (using Jade on the node.js server-side) for our single-page app.
I want to precompile the handlebars templates on the server side and bundle them up as one JS file to send to the client.
Currently, I use handlebars to compile templates like so:
$ handlebars template1.handlebars template2.handlebars -f precompiled_templates.js
I'd like to write a bash script that can read all the *.handlebars files in a directory and then run them through the handlebars compiler. So, if I had a directory like so:
templates/
temp1.handlebars
temp2.handlebars
temp3.handlebars
temp4.handlebars
Running my bash script (or, one line command) in the templates directory would essentially run the following handlebars command:
$ handlebars temp1.handlebars temp2.handlebars temp3.handlebars temp4.handlebars -f precompiled_templates.js
Does anyone know how I could write a bash script to get all the handlebars files in a directory onto the command line like above?
It looks like you want something similar to
handlebars templates/*.handlebars -f precompiled_templates.js
except you would end up with 'templates' prefixed to each file. My preferred approach requires two lines:
files=( templates/*.handlebars )
handlebars "${files[#]#templates/}" -f precompiled_templates.js.
The first line puts all the desired files in an array. In the second line, we expand the contents of the array, but stripping the "templates/" prefix from each element in the resulting expansion.
In the templates directory do:
handlebars `find -name *.handlebars` -f precompiled_templates.js
The back-ticks means it will execute that command then return the result, so you in effect you run handlebars on each file it returns. As written above find will look in current and subdirectories for the files so make sure you run it from the right place.
In Bash, lists can be create with string within double quote :
FILES="/etc/hosts /etc/passwd"
for file in $FILES; do cat $file ; done
<cat all files>
You can also use find and exec commands.
man [find|exec] for more informations
I created the file:
tinymce_compressor.sh
$chmod +x tinymce_compressor.sh
$ tinymce_compressor
-bash: tinymce_compressor: command not found
How can I run this shell script in terminal?
Here's the full script:
#!/bin/sh
# Tinymce compressor shell script
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# (C) Copyright 2010 Gabor Vitez
#
#
# Concatenates the tinymce components into a single static file
# Can be used with any web server which can serve static files
# Note you have to re-run this script every time you upgrade tinymce,
# or change the required modules
#
# Usage: upon every invocation, the scipt will create a new
# "tinymceappended.js" file, which contains the requested components
#
# In your html pages you have to change
#
# <script type="text/javascript" src="<your installation path>/tiny_mce/tiny_mce.js"></script>
#
# to
#
# <script type="text/javascript" src="<your compressed tinymce url>/tinymceappended.js"> </script>
#
#config section
#where does tinymce live in the filesystem?
BASE="/Users/xxxx/Sites/cline/public/javascripts/tiny_mce/"
#under which URLs do the original tinymce components show up?
URLBASE="/tinymce"
#just as in the javascript config section
THEMES="advanced"
PLUGINS="safari spellchecker pagebreak style layer save advhr advimage advlink emotions iespell inlinepopups insertdatetime preview media searchreplace contextmenu paste directionality fullscreen noneditable visualchars nonbreaking xhtmlxtras"
LANGUAGES="en"
#end config section
(
LOADED=""
cd $BASE || exit 1
#cat tiny_mce.js
sed "s/tinymce._init();/tinymce.baseURL='\/tinymce';tinymce._init();/"<tiny_mce.js
#echo "tinyMCE_GZ.start();"
#cat tiny_mce_popup.js && LOADED="$LOADED $URLBASE/tiny_mce_popup.js"
for lang in $LANGUAGES
do
cat langs/$lang.js && LOADED="$LOADED $URLBASE/langs/$lang.js"
done
for theme in $THEMES
do
cat themes/$theme/editor_template.js && LOADED="$LOADED $URLBASE/themes/$theme/editor_template.js"
for lang in $LANGUAGES
do
cat themes/$theme/langs/$lang.js && LOADED="$LOADED $URLBASE/themes/$theme/langs/$lang.js"
done
done
for plugin in $PLUGINS
do
cat plugins/$plugin/editor_plugin.js && LOADED="$LOADED $URLBASE/plugins/$plugin/editor_plugin.js"
for lang in $LANGUAGES
do
cat plugins/$plugin/langs/$lang.js && LOADED="$LOADED $URLBASE/plugins/$plugin/langs/$lang.js"
done
done
echo
#echo $LOADED >&2
for i in $LOADED
do
echo "tinymce.ScriptLoader.markDone(tinyMCE.baseURI.toAbsolute(\"$i\"));"
done
#echo "tinyMCE_GZ.end();"
) >tinymceappended.js
Thanks
You have made it, just call
$ ./tinymce_compressor.sh
It seems that you come from Windows, where executables can be called without extensions and the current directory is always in PATH.
The script is in your current directory, but which is not in your path (which is what the shell uses to try and find commands to run) by default. So,
./tinymce_compressor.sh
should do the trick. For more information on the command search path, and why it may not be a good idea to include the current directory (aka ".") in the path, see "What's wrong with having '.' in your $PATH ?
" from the Unix frequently asked questions list..
By default the current directory isn't on the path; you need to specify that the script is in the current folder (.):
./tinymce_compressor.sh