From 4f0681b9e0c13c6849564b99626f24926f18caca Mon Sep 17 00:00:00 2001 From: Vladislav Frolov Date: Mon, 4 May 2026 11:39:17 +0200 Subject: [PATCH] Fix: Strings in the default folder are not updated when languages with country suffix are used --- .../com/appswithlove/loco/util/TaskUtils.kt | 23 +++- .../appswithlove/loco/util/TaskUtilsTest.kt | 100 +++++++++++++++++- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/com/appswithlove/loco/util/TaskUtils.kt b/lib/src/main/kotlin/com/appswithlove/loco/util/TaskUtils.kt index 571c54f..3635c4b 100644 --- a/lib/src/main/kotlin/com/appswithlove/loco/util/TaskUtils.kt +++ b/lib/src/main/kotlin/com/appswithlove/loco/util/TaskUtils.kt @@ -23,6 +23,8 @@ object TaskUtils { fetchAllLanguages(httpClient, locoConfig.apiKey).ifEmpty { emptyList() } } + val defaultLangEntry = findDefaultLangEntry(languages, locoConfig.defLang) + for (langEntry in languages) { var lang = langEntry var text = httpClient.fetchTranslation(locoConfig, lang) @@ -60,7 +62,9 @@ object TaskUtils { text = text.replaceFirst(wrongXmlString, expectedXmlString) } - if (lang == locoConfig.defLang) { + val isDefaultLang = langEntry == defaultLangEntry + + if (isDefaultLang) { if (locoConfig.ignoreMissingTranslationWarnings) { text = text.replaceFirst( ", defLang: String?): String? { + if (defLang == null) return null + return languages.firstOrNull { entry -> + val converted = if (entry.contains("-")) { + entry.replace("-", "-r") + } else { + entry + } + entry == defLang || converted == defLang || entry.startsWith("$defLang-") + } + } + private fun saveFile(locoConfig: LocoConfig, text: String, appendix: String = "") { val directory = File("${locoConfig.resDir}/values$appendix/") if (!directory.exists()) { diff --git a/lib/src/test/kotlin/com/appswithlove/loco/util/TaskUtilsTest.kt b/lib/src/test/kotlin/com/appswithlove/loco/util/TaskUtilsTest.kt index 3659b5a..e29a6a3 100644 --- a/lib/src/test/kotlin/com/appswithlove/loco/util/TaskUtilsTest.kt +++ b/lib/src/test/kotlin/com/appswithlove/loco/util/TaskUtilsTest.kt @@ -172,12 +172,16 @@ class TaskUtilsTest { TaskUtils.generate(config { ignoreMissingTranslationWarnings = true }, fake) - File(tempDir, "values/strings.xml").readText() shouldContain "tools:ignore=\"MissingTranslation\"" + File( + tempDir, + "values/strings.xml" + ).readText() shouldContain "tools:ignore=\"MissingTranslation\"" } @Test fun generate_withReplaceMap_replacesTextInOutput() { - fake.translationResponses["en"] = "Hello World" + fake.translationResponses["en"] = + "Hello World" TaskUtils.generate(config { replace = mapOf("World" to "Earth") }, fake) @@ -200,7 +204,10 @@ class TaskUtilsTest { @Test fun push_withValidConfig_pushesXmlForEachLocale() { File(tempDir, "values").mkdirs() - File(tempDir, "values/strings.xml").writeText("Hello") + File( + tempDir, + "values/strings.xml" + ).writeText("Hello") TaskUtils.push(config(), fake) @@ -289,6 +296,93 @@ class TaskUtilsTest { } } + @Test + fun generate_withCountrySuffixLangMatchingDefLang_savesFileInDefaultDirectory() { + fake.translationResponses["en-CA"] = "" + fake.translationResponses["fr-CA"] = "" + + TaskUtils.generate( + locoConfig = config { + defLang = "en" + lang = listOf("en-CA", "fr-CA") + }, + httpClient = fake, + ) + + File(tempDir, "values/strings.xml").exists() shouldBe true + File(tempDir, "values-en-rCA/strings.xml").exists() shouldBe false + File(tempDir, "values-fr-rCA/strings.xml").exists() shouldBe true + } + + @Test + fun generate_withCountrySuffixLangAndSaveDefLangDuplicate_savesFilesInBothDirectories() { + fake.translationResponses["en-CA"] = "" + + TaskUtils.generate( + locoConfig = config { + defLang = "en" + lang = listOf("en-CA") + saveDefLangDuplicate = true + }, + httpClient = fake, + ) + + File(tempDir, "values/strings.xml").exists() shouldBe true + File(tempDir, "values-en-rCA/strings.xml").exists() shouldBe true + } + + @Test + fun generate_withMultipleSameBaseLang_onlyFirstSavesToDefaultDirectory() { + fake.translationResponses["en-CA"] = + "CA" + fake.translationResponses["en-US"] = + "US" + + TaskUtils.generate( + locoConfig = config { + defLang = "en" + lang = listOf("en-CA", "en-US") + }, + httpClient = fake, + ) + + File(tempDir, "values/strings.xml").exists() shouldBe true + File(tempDir, "values/strings.xml").readText() shouldContain "CA" + File(tempDir, "values-en-rUS/strings.xml").exists() shouldBe true + } + + @Test + fun generate_withAndroidStyleDefLangWorkaround_stillSavesToDefaultDirectory() { + fake.translationResponses["en-CA"] = "" + + // Existing workaround: users set defLang to Android-style "en-rCA" + TaskUtils.generate( + locoConfig = config { + defLang = "en-rCA" + lang = listOf("en-CA") + }, + httpClient = fake, + ) + + File(tempDir, "values/strings.xml").exists() shouldBe true + } + + @Test + fun push_withCountrySuffixLangMatchingDefLang_readsFromDefaultDirectory() { + File(tempDir, "values").mkdirs() + File(tempDir, "values/strings.xml").writeText("") + + TaskUtils.push( + locoConfig = config { + defLang = "en" + lang = listOf("en-CA") + }, + httpClient = fake, + ) + + fake.capturedPushLocales shouldBe listOf("en-CA") + } + @Test fun generate_withNullApiKey_throwsGradleExceptionListingSources() { val exception = shouldThrow {