繁体   English   中英

使用“resValue”本地化通过build.gradle添加的字符串资源

[英]Localizing string resources added via build.gradle using “resValue”

这是对这篇文章帮助我的答案的延续

我们可以从build.gradle添加如下字符串资源:

 productFlavors { main{ resValue "string", "app_name", "InTouch Messenger" } googlePlay{ resValue "string", "app_name", "InTouch Messenger: GPE Edition" } } 

它的作用就像一个魅力,并且每个风格都有不同的app名称。 (从strings.xml文件中删除原始app_name字符串资源。

但是,我们如何为从build.gradle添加的此字符串资源添加本地化字符串?

我们可以通过指定区域设置的附加参数吗? 或者可以使用gradle任务执行此操作?

注意:我无法使用strings.xml执行此操作(由于我的项目结构有多种方式,因此不可行)

关于生成的资源我的另一个答案可能对你的用例来说太过分了。 基于我目前对您的项目的了解,我认为这个更合适:(不是说您仍然可以将其与生成的资源相结合)

SRC / flavor1 / RES /值/ strings.xml中

<string name="app_name_base">InTouch Messenger"</string>
<string name="app_name_gpe">InTouch Messenger: GPE Edition"</string>

SRC / flavor1 / RES /值-HU / strings.xml中

<string name="app_name_base">InTouch Üzenetküldő"</string>
<string name="app_name_gpe">InTouch Üzenetküldő: GPE Változat"</string>

SRC / flavor2 / RES /值/ strings.xml中

<string name="app_name_base">Whatever Messenger"</string>
<string name="app_name_gpe">Whatever Messenger: GPE Edition"</string>

SRC / flavor2 / RES /值-HU / strings.xml`

<string name="app_name_base">Whatever Üzenetküldő"</string>
<string name="app_name_gpe">Whatever Üzenetküldő: GPE Változat"</string>

的build.gradle

android {
    sourceSets {
        [flavor1, flavor3].each {
            it.res.srcDirs = ['src/flavor1/res']
        }
        [flavor2, flavor4].each {
            it.res.srcDirs = ['src/flavor2/res']
        }
    }
    productFlavors { // notice the different numbers than sourceSets
        [flavor1, flavor2].each {
            it.resValue "string", "app_name", "@string/app_name_base"
        }
        [flavor3, flavor4].each {
            it.resValue "string", "app_name", "@string/app_name_gpe"
        }
    }
}

这意味着flavor1/2将有一个额外的未使用的app_name_gpe字符串资源,但这将由aapt处理:

android {
    buildTypes {
        release {
            shrinkResources true // http://tools.android.com/tech-docs/new-build-system/resource-shrinking
        }

如果您不必对这些字符串进行操作,最好的选择是移动到strings.xml ,但这会使您共享所有res文件夹之间的res文件夹。 如果你根据build.gradle上的某些属性生成这些字符串,那么我认为你运气不好。

编辑: 通过 上面 操作澄清我的意思 并添加一些选项:

通过对这些字符串进行操作,我的意思是在构建过程中使用构建参数,从命令行或环境变量读取某种类型的连接(例如,获取提交SHA1以便以后更容易跟踪错误)。 如果不需要任何操作, strings.xml可能是一个选项。 但是当你覆盖一个res文件夹的味道时,所有这些都被覆盖了,如果几种口味共享相同的res除了有限数量的字符串,这可能会造成问题。

如果每个APK都有自己的语言环境,那么它只是一个resValuebuildConfigField 您可以定义变量以便更轻松地重用值。 就像是

def myVar = "var"

...

flavor1 {
    resValue "string", "my_res_string", "${myVar}"
}

flavor2 {
    resValue "string", "my_res_string", "${myVar}"
}

但是如果在同一个APK中需要多个语言环境并且它将在运行时由Android选择,那么该字符串必须位于正确的values-<locale>文件夹中。

你在这里运行不同的级别, BuildConfig是代码,因此没有本地化,这就是为什么我们对硬编码字符串有Lint警告。 Android中的本地化是通过<string resources完成的,如果您希望系统根据用户设置在运行时选择语言,则无法解决这个问题。 有许多方法resValue资源: values文件夹, resValue中的resValue和生成的资源。

您应该在Gradle中查看buildSrc项目 ,例如我使用它从src/main/values/stuff.xml生成SQL Inserts。 这是一些开始的代码。

buildSrc /的build.gradle

// To enable developing buildSrc in IDEA import buildSrc/build.gradle as a separate project
// Create a settings.gradle in buildSrc as well to prevent importing as subproject
apply plugin: 'groovy'
repositories { jcenter() }
dependencies {
    compile localGroovy()
    compile gradleApi()
    testCompile 'junit:junit:4.12'
}

buildSrc / SRC /主/常规/ Plugin.groovy

import org.gradle.api.*
/**
 * Use it as
 * <code>
 *     apply plugin: MyPlugin
 *     myEntities {
 *         categories {
 *             input = file(path to Android res xml with Strings)
 *             output = file(path to asset SQL file)
 *             conversion = "structure|SQL"
 *         }
 *     }
 * </code>
 */
class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        def entities = project.container(MyEntity)
        // this gives the name for the block in build.gradle
        project.extensions.myEntities = entities

        def allTasks = project.task('generateYourStuff')
        def allTasksClean = project.task('cleanGenerateYourStuff')
        project.afterEvaluate {
            entities.all { entity ->
                //println "Creating task for ${entity.name} (${entity.input} --${entity.conversion}--> ${entity.output})"
                def task = project.task(type: GenerateTask, "generateYourStuff${entity.name.capitalize()}") {
                    input = entity.input
                    output = entity.output
                    conversion = entity.conversion
                }
                allTasks.dependsOn task
                // clean task is automagically generated for every task that has output
                allTasksClean.dependsOn "clean${task.name.capitalize()}"
            }
        }
    }
}
class MyEntity {
    def input
    def output
    String conversion

    final String name
    MyEntity(String name) {
        this.name = name
    }
}

buildSrc / SRC /主/常规/ GenerateTask.groovy

import net.twisterrob.inventory.database.*
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.*
class GenerateTask extends DefaultTask {
    @InputFile File input
    @OutputFile File output
    @Optional @Input String conversion
    @TaskAction void generate() {
        input.withReader { reader ->
            // you may need to treat output as a folder
            output.parentFile.mkdirs()
            output.withWriter { writer ->
                // custom transformation here read from reader, write to writer
            }
        }
    }
}

这只是你可以疯狂的框架,可以从这里做任何事情:例如,通过网络检索CSV并将内容传播到生成的variant*/res/values-*/gen.xml文件中。

您可以在需要时手动运行它,也可以在构建生命周期的正确位置运行它(在build.gradle

android.applicationVariants.all { com.android.build.gradle.api.ApplicationVariant variant ->
    variant.mergeAssets.dependsOn tasks.generateYourStuff
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM