bash localization won't work with multilines strings (with strong syntax or through `eval`)

后端 未结 4 1936
日久生厌
日久生厌 2021-01-02 02:15

There is a nice feature in bash, about localization (language translation):

TEXTDOMAIN=coreutils
LANG=fr_CH.utf8
echo $\"system boot\"
démarrage système


        
相关标签:
4条回答
  • 2021-01-02 02:22

    If using eval is bad with arbitrary variables, there is a way to do this only when called/needed, in running eval only on message part:

    function lPrintf() {
        local sFormat="$(
            eval 'echo $"'"${1}"'"'.
        )"
        shift
        printf "${sFormat%.}" $@
    }
    
    lPrintf "system boot"
    démarrage système
    
    lPrintf  $'Written by %s, %s, %s,\nand %s.\n' techno moi lui-même bibi
    Écrit par techno, moi, lui-même,
    et bibi.
    

    ( The dot at end of translated string ensure that whole string, including leading line-break, where passed to variable sFormat. They will be dropped with ${sFormat%.} )

    0 讨论(0)
  • 2021-01-02 02:27

    OK I think finally got it right.

    iprintf() {
        msg="$2"
        domain="$1"
        shift
        shift
        imsg=$(gettext -ed "$domain" "$msg" ; echo EOF)
        imsg="${imsg%EOF}"
        printf "$imsg" "$@"
    }
    

    Usage example:

    LANG=fr_CH.utf8 iprintf coreutils "If FILE is not specified, use %s.  %s as FILE is common.\n\n" foo bar
    
    0 讨论(0)
  • 2021-01-02 02:43

    Well, there is my self answer:

    This seem not well implemented now. Work in many situations, but, while

    echo "$(gettext 'missing character class name `[::]'\')"
    caractère de nom de classe « [::] » manquant
    

    work simply, the same string seem impossible to translate using this bashism:

    echo $"missing character class name `[::]'"
    > 
    

    the console stay locked (waiting for such an end of string) adding `" would immerse bash in a complex interpretation process :->>

    > `"
    bash: command substitution: line 1: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « ' » correspondant
    bash: command substitution: line 2: Erreur de syntaxe : fin de fichier prématurée
    missing character class name 
    

    And, of course:

    echo $"missing character class name \`[::]'"
    missing character class name `[::]'
    

    make no translation. :-p

    While translating this string containing two backticks work finely:

    echo $"%s}: integer required between `{' and `}'"
    %s} : entier requis entre « { » et « } »
    

    There is a script where you may see some of mine unsuccessfull trys.

    #!/bin/bash
    
    echo "Localized tests"
    export TEXTDOMAIN=coreutils
    export LANG=fr_CH.UTF-8
    export WRITTERS=(Athos Portos Aramis Dartagnan\ Le\ Beau)
    
    echo '#First method# whitout eval'
    
    declare -A MyMessages;
    MyMessages[sysReboot]=$"system boot"
    MyMessages[writtenBy]=$"Written by %s, %s, %s,
    and %s.
    "
    MyMessages[intReq]=$"%s}: integer required between `{' and `}'"
    MyMessages[trClass]=$"when translating, the only character classes that may appear in
    string2 are `upper' and `lower'"
    # MyMessages[missClass]=$"missing character class name `[::]'" 
    
    for msgIdx in ${!MyMessages[@]} ;do
        printf "\n--- Test chain '%s' ---\n" $msgIdx
        case $msgIdx in
        writ* )
            printf "${MyMessages[$msgIdx]}\n" "${WRITTERS[@]}"
            ;;
        intReq )
            printf "ARRAY{${MyMessages[$msgIdx]}\n" NaN
            ;;
        * )
            printf "${MyMessages[$msgIdx]}\n"
            ;;
        esac
      done
    
    echo $'###\n#Second method# whith limited eval'
    unset MyMessages;
    
    declare -A MyMessages;
    
    lPrintf() {
        local sFormat="$(
            eval 'echo $"'"${1}"'"'.
        )"
        shift
        printf "${sFormat%.}" "$@"
    }
    
    MyMessages[sysReboot]="system boot"
    MyMessages[writtenBy]=$'Written by %s, %s, %s,\nand %s.\n'
    MyMessages[intReq]="%s}: integer required between \`{' and \`}'"
    MyMessages[trClass]="when translating, the only character classes that "
    MyMessages[trClass]+=$'may appear in\nstring2 '
    MyMessages[trClass]+="are \`upper' and \`lower'"
    MyMessages[missClass]="missing character class name \`[::]'"
    
    for msgIdx in ${!MyMessages[@]} ;do
        printf "\n--- Test chain '%s' ---\n" $msgIdx
        case $msgIdx in
        writ* )
            lPrintf "${MyMessages[$msgIdx]}" "${WRITTERS[@]}"
            ;;
        intReq )
            lPrintf "${MyMessages[$msgIdx]}" NaN
            ;;
        * )
            lPrintf "${MyMessages[$msgIdx]}"
            ;;
        esac
      done
    

    and his output:

    Localized tests
    #First method# whitout eval
    
    --- Test chain 'trClass' ---
    à la traduction, les seules classes de caractères qui peuvent apparaître
    dans string2 sont « upper » ou « lower »
    
    --- Test chain 'intReq' ---
    ARRAY{NaN} : entier requis entre « { » et « } »
    
    --- Test chain 'sysReboot' ---
    démarrage système
    
    --- Test chain 'writtenBy' ---
    Écrit par Athos, Portos, Aramis,
    et Dartagnan Le Beau.
    
    ###
    #Second method# whith limited eval
    
    --- Test chain 'trClass' ---
    à la traduction, les seules classes de caractères qui peuvent apparaître
    dans string2 sont « upper » ou « lower »
    --- Test chain 'missClass' ---
    ./localized.sh: eval: line 44: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « ` » correspondant
    ./localized.sh: eval: line 45: Erreur de syntaxe : fin de fichier prématurée
    
    --- Test chain 'intReq' ---
    NaN} : entier requis entre « { » et « } »
    --- Test chain 'sysReboot' ---
    démarrage système
    --- Test chain 'writtenBy' ---
    Écrit par Athos, Portos, Aramis,
    et Dartagnan Le Beau.
    

    If anyone could help my to remove comments and/or error message in this script!? ... (in less then 8 hours?!)

    At all, thanks to everyone. (My bounty will go to @gniourf_gniourf unless best answer in 8 hours. But thanks to @techno too, I like your lPrintf! )

    0 讨论(0)
  • 2021-01-02 02:47

    I've played a little bit with this feature and this is what I came up with: you can include the newline verbatim as:

    $ echo $"Written by %s.
    > "
    Écrit par %s.
    $ 
    

    In a script:

    #!/bin/bash
    
    message=$"Written by %s.
    "
    
    printf "$message" Gniourf
    

    This script will output:

    Écrit par Gniourf.
    

    Ok, this is not really an answer, but it might help a little bit (at least, we're not using the evil eval).

    Personal remark: I find this feature really clunky!

    0 讨论(0)
提交回复
热议问题