Localization of string resources added via build.gradle using "resValue"

This is a continuation of the answer that helped me on this post.

We can add a line resource as follows from build.gradle :

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

It works like a charm and serves to have different application names for each fragrance. (with the original app_name string file removed from the strings.xml file.

But how do we add localized strings for this string resource added from build.gradle ?

Is there an additional parameter that we can pass by specifying the language? OR Can this be done using the gradle task?

Note: I cannot do this with strings.xml (not feasible due to several ways of structuring my project)

+12
android android-studio android-gradle android-resources android-productflavors
Mar 19 '16 at 18:27
source share
3 answers

My other answer about generated resources may be redundant for your use. Based on what I know about your project, I think it works better: (not that you can combine this with generated resources anyway)

Src / flavor1 / res / values ​​/ strings.xml

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

Src / flavor1 / res / x-value / 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 / values ​​/ strings.xml

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

Src / flavor2 / res / x-value / 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" } } } 

This means that flavor1/2 will have an extra unused line resource app_name_gpe , but aapt will take care of this:

 android { buildTypes { release { shrinkResources true // http://tools.android.com/tech-docs/new-build-system/resource-shrinking } 
+6
Mar 29 '16 at 10:37
source share

If you do not need to work with these lines, the best option will be moved to strings.xml , but this will allow you to split all res folders between flavors. If you create these lines based on some property on build.gradle , then I think you're out of luck, unfortunately.

EDIT: explaining what I mean by acting above and adding some parameters:

When working with these lines, I mean some kind of concatenation with the build parameter, reading from the command line or environment variable during the build process (for example, getting a SHA1 commit so that it is easier to track errors later). If no operation is required, strings.xml may be an option. But when you rewrite the res folder for flavor, all this is overwritten, and this can create a problem if several flavors have the same res , except for a limited number of lines.

If each APK has its own locale, then it's just resValue or buildConfigField in flavor. You can define variables for easier reuse of values. Something like

 def myVar = "var" ... flavor1 { resValue "string", "my_res_string", "${myVar}" } flavor2 { resValue "string", "my_res_string", "${myVar}" } 

But if several locales are required in one APK, and it will be selected while Android is running, then the line should be in the correct values-<locale> folder.

+3
Mar 29 '16 at 4:36
source share

You work at different levels here, BuildConfig is code and as such is not localized, so we have Lint warnings for hard-coded strings. Localization in Android is done via <string resources, there is no way around this if you want the system to choose a language at runtime depending on user settings. There are many ways to have resources: values folder, resValue in build.gradle and generated resources.

You should study the buildSrc project in Gradle , for example, I use it to create SQL attachments from src/main/values/stuff.xml . Here are some codes to get you started.

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 / Primary / groovy / 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 / Primary / groovy / 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 } } } } 

It’s just a skeleton in which you can go into the wild and do something from here: for example. extract CSV over the network and distribute the contents to the generated variant*/res/values-*/gen.xml .

You can run it manually when you need to, or run it at the desired point in the build life cycle (in build.gradle :

 android.applicationVariants.all { com.android.build.gradle.api.ApplicationVariant variant -> variant.mergeAssets.dependsOn tasks.generateYourStuff } 
+1
Mar 29 '16 at 10:14
source share



All Articles