#!/bin/bash
#
# File:		y2makepot
# Package:	devtools
# Summary:	Build all translation files (*.pot) from a module
# Authors:	Holger Macht <hmacht@suse.de>
#
# Call this from a module toplevel directory to generate all
# translation files (*.pot)

# ##############################################################################
# -- function defininitions -- start -------------------------------------------
# ##############################################################################

# same function for this file and check-textdomain: get_domain_and_err()
CWD=`dirname $0`
. $CWD/gettextdomains

# Helper script to add c-format or ycp-format markers;
# this is assumed to be in the same directory as this script.
PO_ADD_FORMAT_HINTS=$CWD/po_add_format_hints

# use the local file when running from a Git checkout
if [ -f "$CWD/yast_control.its" ]; then
    CONTROL_ITS="$CWD/yast_control.its"
else
    CONTROL_ITS="/usr/share/YaST2/control/yast_control.its"
fi
if [ -f "$CWD/qt_ui.its" ]; then
    UI_ITS="$CWD/qt_ui.its"
else
    UI_ITS="/usr/share/YaST2/control/qt_ui.its"
fi

function add_xml_translations()
{
    XML_FILES=$1
    ITS_FILE=$2

    if [ -n "$XML_FILES" ]; then
        # a POT file was created from other files, we need to do the merge
        if [ -f "$MODULE.pot" ]; then
            mv "$MODULE.pot" "$MODULE.other.pot"
            xgettext_call "$MODULE" "$XML_FILES" "--omit-header --its=$ITS_FILE"
            if [ -f "$MODULE.pot" ]; then
                # new file was created, merge the files
                mv "$MODULE.pot" "$MODULE.xml.pot"
                echo "Merging the .pot files..."
                msgcat -o "$MODULE.pot" "$MODULE.other.pot" "$MODULE.xml.pot"
                rm "$MODULE.xml.pot" "$MODULE.other.pot"
            else
                # no new file created, just rename it back
                mv "$MODULE.other.pot" "$MODULE.pot"
            fi
        else
            # no merge needed, just run gettext and that's it
            xgettext_call "$MODULE" "$XML_FILES" "--its=$ITS_FILE"
        fi
    fi

}

function gettext_call()
{
    MODULE=$1
    SOURCE_FILES=$2
    SOURCE_RUBY_FILES=$3
    SOURCE_CONTROL_FILES=$4
    SOURCE_UI_FILES=$5

    # remove the old file
    rm -f "$MODULE.pot"

    # Is POT file merge needed? (both Ruby and non-Ruby files found)
    if [ -n "$SOURCE_FILES" -a -n "$SOURCE_RUBY_FILES" ]; then
        # only one header is sufficient when merging POT files,
        # more over it has undefined CHARSET which makes trouble
        # when merging with rxgettext POT file (declares UTF-8 charset)
        xgettext_call "$MODULE" "$SOURCE_FILES" "--omit-header"
        mv "$MODULE.pot" "$MODULE.xgettext.pot"

        rxgettext_call "$MODULE" "$SOURCE_RUBY_FILES"
        mv "$MODULE.pot" "$MODULE.rxgettext.pot"

        # merge the rxgettext POT with the xgettext POT file
        echo "Merging the .pot files..."
        msgcat -o "$MODULE.pot" "$MODULE.rxgettext.pot" "$MODULE.xgettext.pot"
        rm "$MODULE.xgettext.pot" "$MODULE.rxgettext.pot"
    else
        xgettext_call "$MODULE" "$SOURCE_FILES"
        rxgettext_call "$MODULE" "$SOURCE_RUBY_FILES"
    fi

    add_xml_translations "$SOURCE_CONTROL_FILES" "$CONTROL_ITS"
    add_xml_translations "$SOURCE_UI_FILES" "$UI_ITS"
}

function xgettext_call()
{
    MODULE=$1
    FILES=$2
    OPTIONS=$3

    if [ -n "$FILES" ]; then
        echo "Creating ./$MODULE.pot from $FILES ...";
        $XGETTEXT --no-wrap --add-comments="$POTCOMMENTS" --add-location \
            --keyword=_ --keyword=_:1,2 --keyword=__ \
            --foreign-user $OPTIONS \
            --copyright-holder="SuSE Linux Products GmbH, Nuernberg" \
            --default-domain=$MODULE --output=$MODULE.pot $FILES
    fi
}

function rxgettext_call()
{
    MODULE=$1
    FILES=$2

    if [ -n "$FILES" ]; then
        echo "Creating ./$MODULE.pot from $FILES ...";

        RXGETTEXT_PATH=`which $RXGETTEXT`

        # rubygem-gettext is a weak dependency, check if it is present
        if [ -x "$RXGETTEXT_PATH" ]; then
            $RXGETTEXT --copyright-holder="SuSE Linux Products GmbH, Nuernberg" \
                --add-comments="$POTCOMMENTS" --output=$MODULE.pot $FILES;

            # remove plural forms template, the dummy values are invalid
            # and do not pass the following check
            sed -i '/^"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;/d' $MODULE.pot

            # Add format marker hints for placeholders:
            #   %s %d etc. -> c-format
            #   %1 %2 etc. -> ycp-format
            #
            # msgfmt and msgmerge understand those formats and will check if a
            # translation has the same placeholders as the untranslated message.
            #
            # This can be overridden for each message in the source code with
            # the usual xgettext comments:
            #
            #   # xgettext:c-format
            #   # foo(_("... %1 ..."))
            $PO_ADD_FORMAT_HINTS $MODULE.pot

            # verify if the output is valid, rxgettext had some bugs resulting
            # in invalid file, be sure that GNU gettext is able to read it, huh :-(
            echo "Verifying $MODULE.pot validity..."
            msgfmt --check -o /dev/null $MODULE.pot

            if [ "$?" != "0" ]; then
                echo "ERROR: $MODULE.pot is not valid, it looks like a rxgettext bug..."
                exit 1
            fi

            echo "...OK"
        else
            echo "ERROR: $RXGETTEXT is missing; please install rubygem-gettext package" 1>&2
            exit 1
        fi
    fi
}

function usage()
{
    echo -e "create *.pot files from a source tree.";
    echo -e "\nOptions:\n\t-c\t Check in the newly created files to SVN"
    echo -e "\t-s\t Specify the source dir where to look for translatable files (recursive)"
    echo -e "\nYou can specify additional files to .pot creation in $SRCDIR/POTFILES"

    exit 0
}


function generate_potfiles()
{
    # call function in gettextdomains
    get_domains_and_err $SRCDIR

    # $ERR contains the files without textdomain (see gettextdomains)
    for F in $ERR; do
        echo "** ERROR: Missing textdomain in file $F" >&2;
    done
    if [ -n "$ERR" ]; then
        exit 2
    fi

    # all textdomains found by gettextdomains
    DOMAINS=`echo -en $DOMAINS | LC_COLLATE=C sort` ;
    MODULE=${DOMAINS%%:*};

    # gather files that share a domain to FILES and call xgettext
    FILES="";
    RUBY_FILES=""
    CONTROL_FILES=""
    UI_FILES=""

    for I in $DOMAINS; do
	D=${I%%:*} ;
	F=${I#*:} ;

	if [ "$D" != "$MODULE" ]; then
	    POT_DST="$POT_DST $MODULE.pot"

            gettext_call "$MODULE" "$FILES" "$RUBY_FILES"

	    MODULE=$D;
	    FILES=""
            RUBY_FILES=""
	fi

        # is it a Ruby file?
        if [[ "$F" =~ \.(erb|rb)$ ]]; then
            RUBY_FILES="$RUBY_FILES $F";
        elif [[ "$F" =~ \.glade$ || "$F" =~ \.ycontrol.x[ms]l$ ]]; then
            # TODO: later remove support for the .glade workaround,
            # it is kept just for the backward compatibility
            # follow symlinks to have correct file locations
            if [ -L "$F" ]; then
                CONTROL_FILES="$CONTROL_FILES `realpath --relative-to=. \"$F\"`";
            else
                CONTROL_FILES="$CONTROL_FILES $F";
            fi
        elif [[ "$F" =~ \.ui$ ]]; then
            UI_FILES="$UI_FILES $F"
        else
            FILES="$FILES $F" ;
        fi
    done

    POT_DST="$POT_DST $MODULE.pot"
    gettext_call "$MODULE" "$FILES" "$RUBY_FILES" "$CONTROL_FILES" "$UI_FILES"
}

# -- function defininitions -- end ---------------------------------------------


# ##############################################################################
# -- main -- start -------------------------------------------------------------
# ##############################################################################

# define global variables
CHECKIN=1
XGETTEXT="xgettext"
RXGETTEXT="rxgettext"

SRCDIR="."
POT_DST=""
# read the POTCOMMENTS file if it is present
POTCOMMENTS=`test -e "$SRCDIR/POTCOMMENTS" && cat "$SRCDIR/POTCOMMENTS"`

# parse command line options
while getopts "chfs::" opt; do
    case $opt in
	c)
	    echo "y2makepot: ignoring obsolete option -c"
            ;;
	f)
	    echo "y2makepot: ignoring obsolete option -f"
            ;;
	s)
            SRCDIR="$OPTARG"
            ;;
	*)
	    usage
            ;;
    esac
done

generate_potfiles

exit 0

# -- main -- end ---------------------------------------------------------------

