Files
Android/build-logic/plugins/src/main/java/translations.gradle
2024-04-22 16:52:02 -04:00

129 lines
5.7 KiB
Groovy

import groovy.io.FileType
import groovy.transform.stc.ClosureParams
import groovy.transform.stc.SimpleType
import org.signal.buildtools.StaticIpResolver
def allStringsResourceFiles(@ClosureParams(value = SimpleType.class, options = ['java.io.File']) Closure c) {
file('src/main/res').eachFileRecurse(FileType.FILES) { f ->
if (f.name == 'strings.xml') {
c(f)
}
}
}
task replaceEllipsis {
group 'Static Files'
description 'Process strings for ellipsis characters.'
doLast {
allStringsResourceFiles { f ->
def before = f.text
def after = f.text.replace('...', '…')
if (before != after) {
f.text = after
logger.info("$f.parentFile.name/$f.name...updated")
}
}
}
}
task cleanApostropheErrors {
group 'Static Files'
description 'Fix transifex apostrophe string errors.'
doLast {
allStringsResourceFiles { f ->
def before = f.text
def after = before.replaceAll(/([^\\=08])(')/, '$1\\\\\'')
if (before != after) {
f.text = after
logger.info("$f.parentFile.name/$f.name...updated")
}
}
}
}
task excludeNonTranslatables {
group 'Static Files'
description 'Remove strings that are marked "translatable"="false" or are ExtraTranslations.'
doLast {
def englishFile = file('src/main/res/values/strings.xml')
def english = new XmlParser().parse(englishFile)
def nonTranslatable = english
.findAll { it['@translatable'] == 'false' }
.collect { it['@name'] }
.toSet()
def all = english.collect { it['@name'] }.toSet()
def translatable = all - nonTranslatable
def inMultiline = false
def endBlockName = ""
allStringsResourceFiles { f ->
if (f != englishFile) {
def newLines = f.readLines()
.collect { line ->
if (!inMultiline) {
def singleLineMatcher = line =~ /name="([^"]*)".*(<\/|\/>)/
if (singleLineMatcher.find()) {
def name = singleLineMatcher.group(1)
if (!line.contains('excludeNonTranslatables') && !translatable.contains(name)) {
return " <!-- Removed by excludeNonTranslatables ${line.trim()} -->"
}
} else {
def multilineStartMatcher = line =~ /<(.*) .?name="([^"]*)".*/
if (multilineStartMatcher.find()) {
endBlockName = multilineStartMatcher.group(1)
def name = multilineStartMatcher.group(2)
if (!line.contains('excludeNonTranslatables') && !translatable.contains(name)) {
inMultiline = true;
return " <!-- Removed by excludeNonTranslatables ${line.trim()}"
}
}
}
} else {
def multilineEndMatcher = line =~ /<\/${endBlockName}/
if (multilineEndMatcher.find()) {
inMultiline = false
return "${line} -->"
}
}
return line
}
f.write(newLines.join("\n") + "\n")
}
}
}
}
task postTranslateQa {
group 'Static Files'
description 'Runs QA to check validity of updated strings, and ensure presence of any new languages in internal lists.'
dependsOn ':qa'
}
task resolveStaticIps {
group 'Static Files'
description 'Fetches static IPs for core hosts and writes them to static-ips.gradle'
doLast {
def staticIpResolver = new StaticIpResolver()
new File(projectDir, "static-ips.gradle.kts").text = """
rootProject.extra["service_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("chat.signal.org")}\"\"\"
rootProject.extra["storage_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("storage.signal.org")}\"\"\"
rootProject.extra["cdn_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("cdn.signal.org")}\"\"\"
rootProject.extra["cdn2_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("cdn2.signal.org")}\"\"\"
rootProject.extra["cdn3_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("cdn3.signal.org")}\"\"\"
rootProject.extra["sfu_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("sfu.voip.signal.org")}\"\"\"
rootProject.extra["content_proxy_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("contentproxy.signal.org")}\"\"\"
rootProject.extra["svr2_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("svr2.signal.org")}\"\"\"
rootProject.extra["cdsi_ips"] = \"\"\"${staticIpResolver.resolveToBuildConfig("cdsi.signal.org")}\"\"\"
""".stripIndent().trim() + "\n"
}
}
task updateStaticFilesAndQa {
group 'Static Files'
description 'Runs tasks to update static files. This includes translations, static IPs, and licenses. Runs QA afterwards to verify all went well. Intended to be run before cutting a release.'
dependsOn replaceEllipsis, cleanApostropheErrors, excludeNonTranslatables, resolveStaticIps, postTranslateQa
}