【问题标题】:How to count empty translations in .po with grep (or other LSB tool)?如何使用 grep(或其他 LSB 工具)计算 .po 中的空翻译?
【发布时间】:2013-01-25 14:45:21
【问题描述】:

我可以使用如下命令在 vim 中搜索空翻译:

/""\n\n

但我的任务是找出未翻译字符串的数量。任何想法如何使用每个 linux 机器都应具有的 标准 工具(请不要单独的包)。

这里是 .po 文件的示例,其中包含 2 个已翻译字符串和 2 个未翻译字符串(长变体和短变体)。

msgid "translated string"
msgstr "some translation"

msgid "non-translated string"
msgstr ""

msgid ""
"Some long translated string which starts from new line "
"and can last for few lines"
msgstr ""
"Translation of some long string which starts from new line "
"and lasts for few lines"

msgid ""
"Some long NON-translated string which starts from new line "
"and can last for few lines"
msgstr ""

【问题讨论】:

    标签: linux bash grep gettext


    【解决方案1】:

    这是使用awk的一种方式:

    awk '$NF == "msgstr \"\"" { c++ } END { print c }' FS="\n" RS= file
    

    结果:

    2
    

    解释:

    awk 置于段落模式。然后测试每个块中的最后一行。如果最后一行与模式完全匹配,则计算它。然后,在脚本的最后,打印出计数。如果您稍后决定要计算已翻译字符串的数量,只需将 == 更改为 !=。 HTH。


    从下面的 cmets 中,处理包含空格的空行:

    您需要使用正则表达式,例如:RS="\n{2,}|\n([ \t]*\n)+|\n$"(这可能会被简化)。不过需要注意的是ability for RS to be a regex is a GNU awk extension.其他awk 将无法以某种方式处理多字符记录分隔符。幸运的是,上述文件格式看起来相当严格,因此不需要处理包含空格的行。

    如果遇到包含空格的分隔符,快速解决方法是调用sed

    < file sed 's/^ *$//' | awk ...
    

    【讨论】:

    • 在两个文件上测试过 - 似乎工作正常。我会再测试一点,如果没有问题,你会得到你的赏金和我最好的感谢 :)
    • 这是一个非常好的解决方案(我花了一段时间才理解它)。但要 100% 确定,如果空行有一些空格,有没有办法让 RS 处理?
    • @244an:谢谢。可以,但只有gawk 可以处理多字符记录分隔符。所以YMMV。请参阅上面的更新。
    • @Steve,如果没有找到未翻译的字符串,是否可以修改脚本以打印 0?当前版本只输出空行。
    • @SergeyP.akaazure:是的。只需将print c 更改为print c ? c : "0"。那是ternary operator。 HTH。
    【解决方案2】:

    我建议使用可用的gettext 工具,而不是尝试直接解析.po 文件:

    $ msggrep -v -T -e "." test.po 
    msgid "non-translated string"
    msgstr ""
    
    msgid ""
    "Some long NON-translated string which starts from new line and can last for "
    "few lines"
    msgstr ""
    

    msggrep 标志是:

    • -v 反转匹配
    • -T 将下一个模式应用于msgstr
    • -e搜索模式

    即显示任何与/./ 不匹配的msgstr,因此为空。

    由于msggrep 没有-c,单行中的计数是:

     msggrep -v -T -e "." test.po  | grep -c ^msgstr
    

    (自 2002 年 1 月 v0.11 起,msggrep 已成为 gettext 软件包的一部分。LSB 核心 又名 ISO/IEC 23360-1:2006(E) 仅强制使用 @987654336 @ 和 msgfmt 二进制文件,但我还没有看到没有它的系统,所以它应该能满足你的要求。)

    【讨论】:

      【解决方案3】:

      由于awk(不错的)解决方案已经给出,有4个其他方法:

      所有命令都使用您的示例和良好的.po 文件进行了测试。

      使用sed

      sed -ne '/msgstr ""/{N;s/\n$//p}' <poFile | wc -l
      2
      

      解释:每次我找到msgstr "",我都会合并下一行,如果我可以将换行符作为字符串的最后一个字符s/\n$//,我会打印它们p。最后计算行数。

      仅限 Bash

      不使用 bash 以外的任何二进制文件:

      total=0
      while read line;do
          if [ "$line" == 'msgstr ""' ] ;then
              read line
              [ -z "$line" ] && ((total++))
            fi
        done <poFile
      echo $total
      2
      

      说明:每次找到msgstr "",我都会读取下一行,如果为空,我会增加计数器。

      其他 bash 方式
      mapfile -t line <poFile
      count=0
      for ((i=${#line[@]};i--;));do
          [ -z "${line[i]}" ] && [ "${line[i-1]}" == 'msgstr ""' ] && ((count++))
        done
      echo $count
      2
      

      解释:在一个数组中读取整个 .po 文件,而不是浏览数组以查找前一个字段包含 msgstr "" 的空字段,递增计数器,而不是打印。

      Perl(在命令行模式下)

      perl -ne '$t++if/^$/&&$l=~/msgstr\s""\s*$/;$l=$_;END{printf"%d\n",$t}' <poFile
      2
      

      解释:每次我发现一个空行前一行(存储在变量$l)包含msgstr ""然后我增加计数器。

      破折号(不是 bash!)

      count=0
      while read line ; do
          [ "$line" = "" ] && [ "$prev" = 'msgstr ""' ] && true $((count=count+1))
          prev="$line"
        done <poFile
      echo $count
      2
      

      基于 perl 示例,这项工作适用于

      【讨论】:

        【解决方案4】:

        试试:

        grep -c '^""$'
        

        它计算唯一内容是两个“的行。

        编辑:

        根据您的评论,我发现上述内容不能满足您的需求。要执行多行匹配,您可以通过以下方式使用 GNU grep:

        grep -Pzo '^msgstr ""\n\n' en.po | grep -c msgstr
        

        使用 GNU grep 2.14 测试并发现它可以工作。但是,我不知道 GNU grep 对您来说是否足够标准。

        第一个 grep 的解释:

        -P 激活 Perl 正则表达式扩展。

        -z 将行尾的换行符替换为 null,允许 grep 跟踪新行。

        -o print 'only-matching',需要,因为-z 正在使用中;否则我们会打印整个文件。

        第二个grep的解释:

        -c 计算匹配的行数,在本例中为 msgstr。这必须在单独的 grep 语句中,因为如果与 -z 一起使用,-c 将返回 1。

        【讨论】:

        • msgstr "" - 这是未翻译字符串的行。而且它不会被这样的 grep 调用计算在内。
        • grep -Pzo '^msgstr ""\n\n' 语言/区域设置/en_US/LC_MESSAGES/messages.po | grep -c msgstr 0 并且文件包含许多字符串但没有翻译。示例: msgid "用户名" msgstr "" msgid "密码" msgstr "" msgid "忘记密码?" msgstr ""
        • grep -Pzo '^msgstr ""\n\n' language/locale/en_US/LC_MESSAGES/messages.po 是否产生任何输出?如果不尝试修改搜索字符串^msgstr ""\n\n,首先删除msgstr 之前没有文本的要求(删除^)。
        • grep -Pzo '^msgstr ""\n\n' language/locale/en_US/LC_MESSAGES/messages.po | grep -c msgstr 0 并且文件包含许多字符串但没有翻译。示例:` msgid "用户名" msgstr "" msgid "密码" msgstr "" msgid "忘记密码?" msgstr ""`
        • 是的,它可以产生一个字符串消息,文件确实包含与模式匹配的字符串
        【解决方案5】:
        grep -n ^msg your.po | grep -v '""' | uniq -D -f1
        

        这会查找以msg 开头的行,忽略那些只是空字符串的行(""),然后使用uniq 查找重复行(忽略msgid/msgstr 字段)。

        CUPS 文件的示例输出:

        $ grep -n ^msg /usr/share/locale/es/cups_es.po | grep -v '""' | uniq -D -f1
        3742:msgid "ParamCustominCutInterval"
        3743:msgstr "ParamCustominCutInterval"
        3745:msgid "ParamCustominTearInterval"
        3746:msgstr "ParamCustominTearInterval"
        3858:msgid "Quarto"
        3859:msgstr "Quarto"
        3967:msgid "Stylus Color Series"
        3968:msgstr "Stylus Color Series"
        3970:msgid "Stylus Photo Series"
        3971:msgstr "Stylus Photo Series"
        3973:msgid "Super A"
        3974:msgstr "Super A"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-05
          • 1970-01-01
          • 2017-05-26
          • 1970-01-01
          • 2012-12-30
          • 1970-01-01
          • 1970-01-01
          • 2013-08-29
          相关资源
          最近更新 更多