Подтвердить что ты не робот

Локализация строковых ресурсов, добавленных через build.gradle с использованием "resValue"

Это продолжение ответа, который помог мне на этом сообщении

Мы можем добавить ресурс строки следующим образом из build.gradle:

productFlavors {
    main{
        resValue "string", "app_name", "InTouch Messenger"
    }

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

Он работает как шарм и служит для того, чтобы иметь разные имена приложений для каждого аромата. (с исходным файлом строки app_name, удаленным из файла strings.xml.

Но как мы добавляем локализованные строки для этого строкового ресурса, добавленного из build.gradle?

Есть ли дополнительный параметр, который мы можем передать, указав язык? ИЛИ Можно сделать это с помощью задачи gradle?

Примечание: Я не могу сделать это с помощью strings.xml (не выполнимо из-за нескольких способов структурирования моего проекта)

4b9b3361

Ответ 1

Мой другой ответ о сгенерированных ресурсах может быть излишним для использования вами. Основываясь на том, что я знаю о вашем проекте, я думаю, что это лучше подходит: (не то, что вы все равно можете объединить это с генерируемыми ресурсами)

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/значение-х/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/значение-х/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
        }

Ответ 2

Если вам не нужно работать с этими строками, лучший вариант переместится на strings.xml, но это позволит вам разделить все папки res между ароматами. Если вы создаете эти строки на основе некоторого свойства на build.gradle, то я думаю, что вам не повезло, к сожалению.

РЕДАКТИРОВАТЬ:, поясняя, что я имею в виду, действуя выше и добавляя некоторые параметры:

При работе с этими строками я подразумеваю какую-то конкатенацию с параметром build, чтение из командной строки или переменной среды во время процесса сборки (например, получение фиксации SHA1, чтобы было легче отслеживать ошибки позже). Если операция не требуется, 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>.

Ответ 3

Здесь вы работаете на разных уровнях, BuildConfig - это код и как таковой не локализован, поэтому у нас есть предупреждения Lint для жестко закодированных строк. Локализация в Android осуществляется через ресурсы <string, там нет способа обойти это, если вы хотите, чтобы система выбирала язык во время выполнения в зависимости от пользовательских настроек. Существует много способов иметь ресурсы: values folder, resValue в build.gradle и сгенерированные ресурсы.

Вы должны изучить проект buildSrc в Gradle, например, я использую его для создания SQL-вложений из src/main/values/stuff.xml. Вот несколько кодов для начала.

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/Основной/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/Основной/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
            }
        }
    }
}

Это просто скелет, в котором вы можете отправиться в дикую природу и сделать что-нибудь отсюда: например. извлекать CSV через сеть и распространять содержимое в сгенерированные файлы variant*/res/values-*/gen.xml.

Вы можете запустить его вручную, когда вам нужно или запустить его в нужную точку жизненного цикла сборки (в build.gradle:

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