这是对this post
帮助我的答案的延续我们可以从build.gradle
:
productFlavors { main{ resValue "string", "app_name", "InTouch Messenger" } googlePlay{ resValue "string", "app_name", "InTouch Messenger: GPE Edition" } }
它的功能就像一个魅力,并且每个风格都有不同的app名称。 (从app_name
文件中删除原始strings.xml
字符串资源。
但是,我们如何为从build.gradle
添加的字符串资源添加本地化字符串?
我们可以通过指定区域设置的附加参数吗?
或
可以使用gradle
任务来完成吗?
注意:我无法使用strings.xml
执行此操作(由于我的项目结构有多种方式,因此不可行)
答案 0 :(得分:7)
关于生成的资源我的另一个答案可能对你的用例来说太过分了。基于我目前对您的项目的了解,我认为这个更合适: (并不是说你仍然可以将它与生成的资源结合起来)
的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
}
答案 1 :(得分:4)
如果您不必对这些字符串进行操作,最好的选择是转移到strings.xml
,但这会让您在各种风格之间共享所有res
文件夹。
如果你根据build.gradle
上的某些属性生成这些字符串,那么我认为你运气不好。
编辑 澄清我的意思操作上面的并添加一些选项:
通过对这些字符串进行操作我的意思是在构建过程中使用构建参数,从命令行或环境变量读取某种类型的连接(例如,获取提交SHA1以便更容易跟踪bug后来)。如果不需要任何操作,strings.xml
可能是一个选项。但是当你覆盖一个res
文件夹的味道时,所有这些文件都会被覆盖,如果几种风格共享相同的res
,除了有限数量的字符串之外,这可能会造成问题。
如果每个APK都有自己的区域设置,那么它只是一个resValue
或buildConfigField
。您可以定义变量以便更轻松地重用值。像
def myVar = "var"
...
flavor1 {
resValue "string", "my_res_string", "${myVar}"
}
flavor2 {
resValue "string", "my_res_string", "${myVar}"
}
但是如果在同一个APK中需要多个区域设置并且它将在运行时由Android选择,那么该字符串必须位于正确的values-<locale>
文件夹中。
答案 2 :(得分:1)
你在这里操作不同的级别,BuildConfig
是代码,因此没有本地化,这就是为什么我们对硬编码字符串有Lint警告。 Android中的本地化是通过<string
资源完成的,如果您希望系统根据用户设置在运行时选择语言,则无法解决这个问题。有许多方法可以获得资源:values
文件夹,build.gradle中的resValue
和生成的资源。
您应该查看buildSrc
project in Gradle,例如我使用它来从src/main/values/stuff.xml
生成SQL插入内容。这是一些开始的代码。
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
}