如果 strings.xml 中有未转义的撇号,如何使构建失败?

How to fail a build if there are unescaped apostrophes in strings.xml?

我有一个 Android 应用程序,对于这个应用程序,我会自动从 crowdin.com 下载翻译 - 这很好用。

一些语言使用撇号,众所周知,如果您的 strings.xml 中有撇号,那么 you should escape them

我想要做的是 如果在我的各种 strings.xml.

中有未转义的撇号,则构建失败

具体来说,我想搜索 src/main/res/ 中的所有 strings.xml,如果任何文件包含 ' 且前面没有 \,则抛出错误。据我所知,这对我来说是理想的,并与翻译人员一起更正源代码中的翻译。

或者,我希望替换未转义的撇号,但作为构建本身的一部分以自动方式替换。

这是一个在 "preBuild" 之前执行的 gradle 任务的简单示例,它检查它找到的所有 strings.xml 字符串值是否带有未转义的撇号。如果发现错误,则构建失败。根据下载任务的需要更改依赖项。

(请注意脚本在遇到第一个错误时失败 - 因此如果 en 版本和 es 版本都存在错误,则只有一个文件被报告为错误。)

(注 2 因为使用了 XML 解析器,所以它只处理字符串标记的值 - 因此也会忽略 xml 评论中的任何违规行为 - 这在第一个测试用例中很明显 no错误。)

(在模块中:应用程序(build.gradle))

task checkUnescapedApostrophes {
    doFirst {

        println("checkUnescapedApostrophes")

        fileTree("src").matching {
            include "**/strings.xml"
        }.each {
            def stringsFile = it
            def parser = (new XmlParser()).parse(stringsFile)
            println("Processing file: "+stringsFile)
            parser.'string'.each { m ->
                def s = m.text()
                def ss = "[^\\]\'"
                println "[" + m.@name + "]: " + s
                if (s =~ ss) {
                    throw new GradleException(
                        "Found a string value in " + stringsFile + 
                        " have unescaped apostrophe: "+s)
                }
            }
        }
        println("strings.xml OK")
    }
}

preBuild.dependsOn(checkUnescapedApostrophes)

在 strings.xml(默认语言环境 + es)的无错误情况下:

<resources>
<!--    <string name="test">some value with '</string> -->
    <string name="test2">some with escaped \'</string>
</resources>

<resources>
    <!--    <string name="test">algún valor con apóstrofe sin escape '</string> -->
    <string name="test2">algún valor con el apóstrofe escapado \'</string>
</resources>

构建输出:

> Configure project :app
checkUnescapedApostrophes
Processing file: ...\app\src\main\res\values\strings.xml
[test2]: some with escaped \'
Processing file: ....\app\src\main\res\values-es\strings.xml
[test2]: algún error con el apóstrofe escapado \'    
strings.xml OK

> Task :app:checkUnescapedApostrophes UP-TO-DATE
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:checkDebugManifest UP-TO-DATE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:prepareLintJar UP-TO-DATE
> Task :app:prepareLintJarForPublish UP-TO-DATE
> Task :app:generateDebugSources UP-TO-DATE

BUILD SUCCESSFUL in 1s
4 actionable tasks: 4 up-to-date

并且在 strings.xml 的错误情况下(在默认的本地和 es 中)

<resources>
    <string name="test">some value with '</string>
    <string name="test2">some with escaped \'</string>
</resources>

<resources>
    <string name="test">algún valor con apóstrofe sin escape '</string>
    <string name="test2">algún valor con el apóstrofe escapado \'</string>
</resources>

(请注意,在上述情况下,未转义的撇号在工作室中被标记为红色并出现错误 - 正如预期的那样。)

构建输出:

> Configure project :app
checkUnescapedApostrophes
Processing file: ...\app\src\main\res\values\strings.xml
[test]: some value with '

FAILURE: Build failed with an exception.

* Where:
Build file '...\app\build.gradle' line: 43

* What went wrong:
A problem occurred evaluating project ':app'.
> Found a string value in ...\app\src\main\res\values\strings.xml have unescaped apostrophe: some value with '

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s

一般 gradle 注意:当你自己测试和改变 build.gradle - 一定要 'Rebuild Project' 而不仅仅是 'Build Project' 因为任何 gradle 改变不要' 似乎在之前构建失败的情况下被拾起。


此外,作为您提到的替代方案,此任务将通过替换所有找到的 strings.xml 来转义未转义的撇号。这是一个就地更新 - 这里有一个更强大的方法:.

task replaceUnescapedApostrophes {
    doFirst {
        ant.replaceregexp(match: "([^\\])'", replace: "\1\\\\'",  byline: "true") {
            fileset(dir: 'src/', excludes: '*', includes: '**/*strings.xml')
        }
    }
}

//preBuild.dependsOn(checkUnescapedApostrophes)
preBuild.dependsOn(replaceUnescapedApostrophes)