web-dev-qa-db-ja.com

「resValue」を使用してbuild.gradleを介して追加された文字列リソースをローカライズする

これは私を助けてくれた答えの続きです この投稿

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を使用してこれを行うことはできません(プロジェクトの構造がいくつかあるため、実行できません)

ただし、生成されたリソースに関する他の回答は、ユースケースにとってはやり過ぎかもしれません。私があなたのプロジェクトについて現在知っていることを基にして、これがより適していると思います:(これを生成されたリソースと組み合わせることができるというわけではありません)

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/values-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/values/strings.xml

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

src/flavor2/res/values-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
        }
9
TWiStErRob

これらの文字列を操作する必要がない場合は、strings.xmlに移動するのが最善のオプションですが、これにより、フレーバー間ですべてのresフォルダーを共有できます。 build.gradleのプロパティに基づいてこれらの文字列を生成する場合、残念ながら運が悪いと思います。

編集:私が何を意味するのかを明確にする上記の操作といくつかのオプションの追加:

これらの文字列を操作するとはビルドパラメータ、コマンドラインからの読み取り、またはビルドプロセス中の環境変数とのある種の連結を意味します(例:後でバグを追跡しやすくするために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>フォルダーにある必要があります。

4
Douglas Drumond

ここではさまざまなレベルで操作しています。BuildConfigはコードであり、ローカライズされていないため、ハードコードされた文字列に対してLint警告が表示されます。 Androidは<stringリソースを介して行われます。ユーザー設定に応じて実行時にシステムに言語を選択させたい場合は、それを回避する方法はありません。リソースを取得する方法はたくさんあります。ただし、valuesフォルダー、build.gradleのresValue、および生成されたリソース。

GradleのbuildSrcプロジェクト を調べる必要があります。たとえば、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/main/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/main/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
}
1
TWiStErRob