From 99f1b5a88e7e5381f2f17feda4723930a8dc2e02 Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Fri, 26 Dec 2025 23:07:20 +0900
Subject: [PATCH 1/8] enable locale config generation
---
app/build.gradle | 4 ++++
app/src/main/res/resources.properties | 1 +
2 files changed, 5 insertions(+)
create mode 100644 app/src/main/res/resources.properties
diff --git a/app/build.gradle b/app/build.gradle
index 64bebb1a..f2e4c15f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -126,6 +126,10 @@ android {
lint {
lintConfig = file("lint.xml")
}
+
+ androidResources {
+ generateLocaleConfig true
+ }
}
allOpen {
diff --git a/app/src/main/res/resources.properties b/app/src/main/res/resources.properties
new file mode 100644
index 00000000..467b3efe
--- /dev/null
+++ b/app/src/main/res/resources.properties
@@ -0,0 +1 @@
+unqualifiedResLocale=en-US
From 943a4dd0df7afdc3abb97e2b24981a7355699f58 Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Fri, 26 Dec 2025 23:11:27 +0900
Subject: [PATCH 2/8] add AppLocalesMetadataHolderService to manifest
---
app/src/main/AndroidManifest.xml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 672e2624..e2c13b7c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -55,5 +55,14 @@
+
+
+
+
From 83771c16ee56877f5b59e3ea5c2350da21c39b39 Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Sat, 27 Dec 2025 13:23:12 +0900
Subject: [PATCH 3/8] refactor LocaleUtils and update settings references
---
.../main/kotlin/com/vrem/util/LocaleUtils.kt | 82 +++++++++----------
.../settings/CountryPreference.kt | 4 +-
.../settings/LanguagePreference.kt | 4 +-
.../vrem/wifianalyzer/settings/Settings.kt | 10 +--
.../kotlin/com/vrem/util/LocaleUtilsTest.kt | 8 +-
.../wifianalyzer/settings/SettingsTest.kt | 8 +-
6 files changed, 57 insertions(+), 59 deletions(-)
diff --git a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
index 2fba582a..29cf2f2f 100644
--- a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
@@ -20,38 +20,13 @@ package com.vrem.util
import java.util.Locale
import java.util.SortedMap
-private object SyncAvoid {
- val defaultLocale: Locale = Locale.getDefault()
- val countryCodes: Set = Locale.getISOCountries().toSet()
- val availableLocales: List = Locale.getAvailableLocales().filter { countryCodes.contains(it.country) }
-
- val countriesLocales: SortedMap =
- availableLocales
- .associateBy { it.country.toCapitalize(Locale.getDefault()) }
- .toSortedMap()
- val supportedLocales: List =
- setOf(
- BULGARIAN,
- DUTCH,
- GREEK,
- HUNGARIAN,
- Locale.SIMPLIFIED_CHINESE,
- Locale.TRADITIONAL_CHINESE,
- Locale.ENGLISH,
- Locale.FRENCH,
- Locale.GERMAN,
- Locale.ITALIAN,
- Locale.JAPANESE,
- POLISH,
- PORTUGUESE_BRAZIL,
- PORTUGUESE_PORTUGAL,
- SPANISH,
- RUSSIAN,
- TURKISH,
- UKRAINIAN,
- defaultLocale,
- ).toList()
-}
+private val currentLocale: Locale get() = Locale.getDefault()
+private val countryCodes: Set = Locale.getISOCountries().toSet()
+private val availableLocales: List = Locale.getAvailableLocales().filter { countryCodes.contains(it.country) }
+private val countriesLocales: SortedMap =
+ availableLocales
+ .associateBy { it.country.toCapitalize(currentLocale) }
+ .toSortedMap()
val BULGARIAN: Locale = Locale.forLanguageTag("bg")
val DUTCH: Locale = Locale.forLanguageTag("nl")
@@ -65,27 +40,50 @@ val RUSSIAN: Locale = Locale.forLanguageTag("ru")
val TURKISH: Locale = Locale.forLanguageTag("tr")
val UKRAINIAN: Locale = Locale.forLanguageTag("uk")
+val baseSupportedLocales: List =
+ setOf(
+ BULGARIAN,
+ DUTCH,
+ GREEK,
+ HUNGARIAN,
+ Locale.SIMPLIFIED_CHINESE,
+ Locale.TRADITIONAL_CHINESE,
+ Locale.ENGLISH,
+ Locale.FRENCH,
+ Locale.GERMAN,
+ Locale.ITALIAN,
+ Locale.JAPANESE,
+ POLISH,
+ PORTUGUESE_BRAZIL,
+ PORTUGUESE_PORTUGAL,
+ SPANISH,
+ RUSSIAN,
+ TURKISH,
+ UKRAINIAN,
+ ).toList()
+
private const val SEPARATOR: String = "_"
fun findByCountryCode(countryCode: String): Locale =
- SyncAvoid.availableLocales.firstOrNull { countryCode.toCapitalize(Locale.getDefault()) == it.country }
- ?: SyncAvoid.defaultLocale
+ availableLocales.firstOrNull { countryCode.toCapitalize(Locale.getDefault()) == it.country }
+ ?: currentLocale
-fun allCountries(): List = SyncAvoid.countriesLocales.values.toList()
+fun allCountries(): List = countriesLocales.values.toList()
+
+fun supportedLanguages(): List =
+ (baseSupportedLocales + currentLocale).distinct()
fun findByLanguageTag(languageTag: String): Locale {
val languageTagPredicate: (Locale) -> Boolean = {
val locale: Locale = fromLanguageTag(languageTag)
it.language == locale.language && it.country == locale.country
}
- return SyncAvoid.supportedLocales.firstOrNull(languageTagPredicate) ?: SyncAvoid.defaultLocale
+ return supportedLanguages().firstOrNull(languageTagPredicate) ?: currentLocale
}
-fun supportedLanguages(): List = SyncAvoid.supportedLocales
-
-fun defaultCountryCode(): String = SyncAvoid.defaultLocale.country
+fun currentCountryCode(): String = currentLocale.country
-fun defaultLanguageTag(): String = toLanguageTag(SyncAvoid.defaultLocale)
+fun currentLanguageTag(): String = toLanguageTag(currentLocale)
fun toLanguageTag(locale: Locale): String = locale.language + SEPARATOR + locale.country
@@ -93,7 +91,7 @@ private fun fromLanguageTag(languageTag: String): Locale {
val codes: Array = languageTag.split(SEPARATOR).toTypedArray()
return when (codes.size) {
1 -> Locale.forLanguageTag(codes[0])
- 2 -> Locale.forLanguageTag("${codes[0]}-${codes[1].toCapitalize(Locale.getDefault())}")
- else -> SyncAvoid.defaultLocale
+ 2 -> Locale.forLanguageTag("${codes[0]}-${codes[1].toCapitalize(currentLocale)}")
+ else -> currentLocale
}
}
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
index 6aaf8ed2..7be4ce88 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
@@ -19,7 +19,7 @@ package com.vrem.wifianalyzer.settings
import android.content.Context
import android.util.AttributeSet
-import com.vrem.util.defaultCountryCode
+import com.vrem.util.currentCountryCode
import com.vrem.wifianalyzer.MainContext
import com.vrem.wifianalyzer.wifi.band.WiFiChannelCountry
import java.util.Locale
@@ -35,4 +35,4 @@ private fun data(): List {
class CountryPreference(
context: Context,
attrs: AttributeSet,
-) : CustomPreference(context, attrs, data(), defaultCountryCode())
+) : CustomPreference(context, attrs, data(), currentCountryCode())
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
index 4abf77fd..fe5727b3 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
@@ -19,7 +19,7 @@ package com.vrem.wifianalyzer.settings
import android.content.Context
import android.util.AttributeSet
-import com.vrem.util.defaultLanguageTag
+import com.vrem.util.currentLanguageTag
import com.vrem.util.supportedLanguages
import com.vrem.util.toCapitalize
import com.vrem.util.toLanguageTag
@@ -35,4 +35,4 @@ private fun map(it: Locale): Data = Data(toLanguageTag(it), it.getDisplayName(it
class LanguagePreference(
context: Context,
attrs: AttributeSet,
-) : CustomPreference(context, attrs, data(), defaultLanguageTag())
+) : CustomPreference(context, attrs, data(), currentLanguageTag())
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
index 8dc3b772..91f4ffb3 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
@@ -20,8 +20,8 @@ package com.vrem.wifianalyzer.settings
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import com.vrem.annotation.OpenClass
import com.vrem.util.buildMinVersionQ
-import com.vrem.util.defaultCountryCode
-import com.vrem.util.defaultLanguageTag
+import com.vrem.util.currentCountryCode
+import com.vrem.util.currentLanguageTag
import com.vrem.util.findByLanguageTag
import com.vrem.util.findOne
import com.vrem.util.findSet
@@ -67,11 +67,11 @@ class Settings(
fun wiFiBand(wiFiBand: WiFiBand): Unit = repository.save(R.string.wifi_band_key, wiFiBand.ordinal)
- fun countryCode(): String = repository.string(R.string.country_code_key, defaultCountryCode())
+ fun countryCode(): String = repository.string(R.string.country_code_key, currentCountryCode())
fun languageLocale(): Locale {
- val defaultLanguageTag = defaultLanguageTag()
- val languageTag = repository.string(R.string.language_key, defaultLanguageTag)
+ val currentLanguageTag = currentLanguageTag()
+ val languageTag = repository.string(R.string.language_key, currentLanguageTag)
return findByLanguageTag(languageTag)
}
diff --git a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
index c615260c..8ab3807f 100644
--- a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
+++ b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
@@ -123,12 +123,12 @@ class LocaleUtilsTest {
}
@Test
- fun currentDefaultCountryCode() {
- assertThat(defaultCountryCode()).isEqualTo(Locale.getDefault().country)
+ fun currentCurrentCountryCode() {
+ assertThat(currentCountryCode()).isEqualTo(Locale.getDefault().country)
}
@Test
- fun currentDefaultLanguageTag() {
- assertThat(defaultLanguageTag()).isEqualTo(toLanguageTag(Locale.getDefault()))
+ fun currentCurrentLanguageTag() {
+ assertThat(currentLanguageTag()).isEqualTo(toLanguageTag(Locale.getDefault()))
}
}
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
index 9ba01f56..bd0c4280 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
@@ -20,8 +20,8 @@ package com.vrem.wifianalyzer.settings
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.vrem.util.defaultCountryCode
-import com.vrem.util.defaultLanguageTag
+import com.vrem.util.currentCountryCode
+import com.vrem.util.currentLanguageTag
import com.vrem.util.ordinals
import com.vrem.util.toLanguageTag
import com.vrem.wifianalyzer.R
@@ -353,7 +353,7 @@ class SettingsTest {
@Test
fun countryCode() {
// setup
- val defaultValue = defaultCountryCode()
+ val defaultValue = currentCountryCode()
val expected = "WW"
doReturn(expected).whenever(repository).string(R.string.country_code_key, defaultValue)
// execute
@@ -366,7 +366,7 @@ class SettingsTest {
@Test
fun languageLocale() {
// setup
- val defaultValue = defaultLanguageTag()
+ val defaultValue = currentLanguageTag()
val expected = Locale.FRENCH
doReturn(toLanguageTag(expected)).whenever(repository).string(R.string.language_key, defaultValue)
// execute
From 96ec463d57301c1a53ff2a5c112d8ce57802150c Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Sat, 27 Dec 2025 14:58:14 +0900
Subject: [PATCH 4/8] add system_default string to translations
---
app/src/main/res/values-bg/strings.xml | 1 +
app/src/main/res/values-de/strings.xml | 1 +
app/src/main/res/values-el/strings.xml | 1 +
app/src/main/res/values-es/strings.xml | 1 +
app/src/main/res/values-fr/strings.xml | 1 +
app/src/main/res/values-hu/strings.xml | 1 +
app/src/main/res/values-it/strings.xml | 1 +
app/src/main/res/values-ja/strings.xml | 1 +
app/src/main/res/values-nl/strings.xml | 1 +
app/src/main/res/values-pl/strings.xml | 1 +
app/src/main/res/values-pt-rBR/strings.xml | 1 +
app/src/main/res/values-pt/strings.xml | 1 +
app/src/main/res/values-ru/strings.xml | 1 +
app/src/main/res/values-tr/strings.xml | 1 +
app/src/main/res/values-uk/strings.xml | 1 +
app/src/main/res/values-zh-rCN/strings.xml | 1 +
app/src/main/res/values-zh-rTW/strings.xml | 1 +
app/src/main/res/values/strings.xml | 1 +
18 files changed, 18 insertions(+)
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 5265d93f..49b11f26 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -103,4 +103,5 @@
"Изключи Wi-Fi при изход"
"Регулирането на Wi-Fi сканирането е изключено"
"Регулирането на Wi-Fi сканирането е включено"
+ Стандартно за системата
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index a448b204..44c9fa39 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -103,4 +103,5 @@
"WLAN beim Verlassen deaktivieren"
"Die WLAN-Scan-Drosselung ist deaktiviert"
"Die WLAN-Scan-Drosselung ist aktiviert"
+ Standardeinstellung des Systems
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 6eb67f2e..918fb8fe 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -103,4 +103,5 @@
"Απενεργοποίηση Wi-Fi κατά την έξοδο"
"Ο περιορισμός σάρωσης Wi-Fi είναι απενεργοποιημένος"
"Ο περιορισμός σάρωσης Wi-Fi είναι ενεργοποιημένος"
+ Προεπιλογή συστήματος
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index e5035666..874a3b16 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -103,4 +103,5 @@
"Apagar Wi-Fi al salir"
"La aceleración del escaneo de Wi-Fi está deshabilitada"
"La aceleración del escaneo de Wi-Fi está habilitada"
+ Predeterminado del sistema
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 829afd73..84cf463b 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -102,4 +102,5 @@
"Arrêter le Wi-Fi en quittant"
"La limitation de l'analyse Wi-Fi est désactivée"
"La limitation de l'analyse Wi-Fi est activée"
+ Paramètre système par défaut
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 2a0b5fcc..692549f2 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -102,5 +102,6 @@
"Wi‑Fi kikapcsolása kilépéskor"
"A Wi‑Fi szkennelés korlátozása tiltva"
"A Wi‑Fi szkennelés korlátozása engedélyezve"
+ Rendszerbeállítás
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index afff650e..12c6958f 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -103,4 +103,5 @@
"Spegni Wi-Fi all\'uscita"
"La limitazione della scansione Wi-Fi è disabilitata"
"La limitazione della scansione Wi-Fi è abilitata"
+ Predefinita di sistema
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index cb375412..551cbbc5 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -103,4 +103,5 @@
"閉じる時 Wi-Fi をオフにする"
"Wi-Fi スキャンのスロットリングが無効になっています"
"Wi-Fi スキャンのスロットルが有効になっています"
+ システムのデフォルト
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index aa7a1ff6..0d9fdc12 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -102,4 +102,5 @@
"Wifi uitsch. bij afsluiten"
"Wifi-scanbeperking is uitgeschakeld"
"Wifi-scanbeperking is ingeschakeld"
+ Systeemstandaard
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index fcd16e6a..12340e68 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -103,4 +103,5 @@
"Wyłączanie Wi-Fi przy wyjściu"
"Ograniczanie skanowania Wi-Fi jest wyłączone"
"Ograniczanie skanowania Wi-Fi jest włączone"
+ Ustawienie domyślne systemu
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index b14b11cb..037d4794 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -103,4 +103,5 @@
"Desativar o Wi-Fi ao sair"
"A limitação da busca por Wi-Fi está desativada"
"A limitação da busca por Wi-Fi está ativada"
+ Padrão do sistema
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index d5a7000c..df86f795 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -103,4 +103,5 @@
"Desligar o Wi-Fi ao sair"
"A limitação da procura de Wi-Fi está desativada"
"A limitação da procura de Wi-Fi está ativada"
+ Padrão do sistema
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 8f5704f5..64b9634a 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -103,4 +103,5 @@
"Wi-Fi выключен при выходе"
"Регулирование сканирования Wi-Fi отключено"
"Регулирование сканирования Wi-Fi включено"
+ Язык системы
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 5d9352bc..c92bbb4c 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -103,4 +103,5 @@
"Çıkışta Wi-Fi'yi kapat"
"Wi-Fi tarama kısıtlaması devre dışı"
"Wi-Fi tarama kısıtlaması etkin"
+ Sistem varsayılanı
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index a713d2f9..572020e6 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -114,4 +114,5 @@
"Wi-Fi вимкнений при виході"
"Регулювання сканування Wi-Fi вимкнено"
"Регулювання сканування Wi-Fi увімкнено"
+ Налаштування системи за умовчанням
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index cf09e803..ff868aed 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -103,4 +103,5 @@
"退出时关闭 Wi-Fi"
"WLAN 扫描调节已禁用"
"WLAN 扫描调节已启用"
+ 系统默认设置
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 8b432bbc..3f064206 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -103,4 +103,5 @@
"退出時關閉 Wi-Fi"
"Wi-Fi 掃描限制已停用"
"Wi-Fi 掃描限制已啟用"
+ 系統預設
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d2301aed..3fa5a579 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -217,4 +217,5 @@
"80 MHz"
"160 MHz"
"320 MHz"
+ System default
From 6d5cc0acd2834271d2e24464d1f09f8b7423fd6c Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Sat, 27 Dec 2025 15:18:15 +0900
Subject: [PATCH 5/8] update locale utils and language preference
---
.../main/kotlin/com/vrem/util/LocaleUtils.kt | 26 +++++++------------
.../main/kotlin/com/vrem/util/StringUtils.kt | 3 +++
.../settings/LanguagePreference.kt | 24 +++++++++--------
3 files changed, 25 insertions(+), 28 deletions(-)
diff --git a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
index 29cf2f2f..8858804f 100644
--- a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
@@ -62,8 +62,6 @@ val baseSupportedLocales: List =
UKRAINIAN,
).toList()
-private const val SEPARATOR: String = "_"
-
fun findByCountryCode(countryCode: String): Locale =
availableLocales.firstOrNull { countryCode.toCapitalize(Locale.getDefault()) == it.country }
?: currentLocale
@@ -73,25 +71,19 @@ fun allCountries(): List = countriesLocales.values.toList()
fun supportedLanguages(): List =
(baseSupportedLocales + currentLocale).distinct()
+fun supportedLanguageTags(): List =
+ listOf("") + baseSupportedLocales.map { it.toLanguageTag() }
+
fun findByLanguageTag(languageTag: String): Locale {
- val languageTagPredicate: (Locale) -> Boolean = {
- val locale: Locale = fromLanguageTag(languageTag)
+ if (languageTag.isEmpty()) return currentLocale
+ val locale = Locale.forLanguageTag(languageTag)
+ return baseSupportedLocales.firstOrNull {
it.language == locale.language && it.country == locale.country
- }
- return supportedLanguages().firstOrNull(languageTagPredicate) ?: currentLocale
+ } ?: currentLocale
}
fun currentCountryCode(): String = currentLocale.country
-fun currentLanguageTag(): String = toLanguageTag(currentLocale)
+fun currentLanguageTag(): String = currentLocale.toLanguageTag()
-fun toLanguageTag(locale: Locale): String = locale.language + SEPARATOR + locale.country
-
-private fun fromLanguageTag(languageTag: String): Locale {
- val codes: Array = languageTag.split(SEPARATOR).toTypedArray()
- return when (codes.size) {
- 1 -> Locale.forLanguageTag(codes[0])
- 2 -> Locale.forLanguageTag("${codes[0]}-${codes[1].toCapitalize(currentLocale)}")
- else -> currentLocale
- }
-}
+fun toLanguageTag(locale: Locale): String = locale.toLanguageTag()
diff --git a/app/src/main/kotlin/com/vrem/util/StringUtils.kt b/app/src/main/kotlin/com/vrem/util/StringUtils.kt
index e96df0c2..37cfda7b 100644
--- a/app/src/main/kotlin/com/vrem/util/StringUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/StringUtils.kt
@@ -27,3 +27,6 @@ fun String.Companion.nullToEmpty(value: String?): String = value ?: String.EMPTY
fun String.specialTrim(): String = this.trim { it <= ' ' }.replace(" +".toRegex(), String.SPACE_SEPARATOR)
fun String.toCapitalize(locale: Locale): String = this.replaceFirstChar { word -> word.uppercase(locale) }
+
+fun String.titlecaseFirst(locale: Locale): String =
+ replaceFirstChar { it.titlecase(locale) }
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
index fe5727b3..e94d8215 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/LanguagePreference.kt
@@ -19,20 +19,22 @@ package com.vrem.wifianalyzer.settings
import android.content.Context
import android.util.AttributeSet
-import com.vrem.util.currentLanguageTag
-import com.vrem.util.supportedLanguages
-import com.vrem.util.toCapitalize
-import com.vrem.util.toLanguageTag
+import com.vrem.util.supportedLanguageTags
+import com.vrem.util.titlecaseFirst
+import com.vrem.wifianalyzer.R
import java.util.Locale
-private fun data(): List =
- supportedLanguages()
- .map { map(it) }
- .sorted()
-
-private fun map(it: Locale): Data = Data(toLanguageTag(it), it.getDisplayName(it).toCapitalize(Locale.getDefault()))
+private fun data(context: Context): List =
+ supportedLanguageTags().map { tag ->
+ if (tag.isEmpty()) {
+ Data("", context.getString(R.string.system_default))
+ } else {
+ val locale = Locale.forLanguageTag(tag)
+ Data(tag, locale.getDisplayName(locale).titlecaseFirst(locale))
+ }
+ }
class LanguagePreference(
context: Context,
attrs: AttributeSet,
-) : CustomPreference(context, attrs, data(), currentLanguageTag())
+) : CustomPreference(context, attrs, data(context), "")
From 4758f5db924e110b422278b27726c37346a0ad01 Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Sun, 28 Dec 2025 00:08:37 +0900
Subject: [PATCH 6/8] refactor locale handling to use AppCompatDelegate for
application locales
---
.../main/kotlin/com/vrem/util/LocaleUtils.kt | 39 +++++++++++++------
.../com/vrem/wifianalyzer/MainActivity.kt | 21 ++++++----
.../com/vrem/wifianalyzer/MainReload.kt | 15 +------
.../settings/CountryPreference.kt | 2 +-
.../vrem/wifianalyzer/settings/Settings.kt | 15 ++++---
.../ChannelAvailableFragment.kt | 2 +-
.../kotlin/com/vrem/util/LocaleUtilsTest.kt | 14 +++----
.../com/vrem/wifianalyzer/MainReloadTest.kt | 24 ------------
.../wifianalyzer/settings/SettingsTest.kt | 2 +-
.../ChannelAvailableFragmentTest.kt | 4 +-
10 files changed, 65 insertions(+), 73 deletions(-)
diff --git a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
index 8858804f..ad0ca037 100644
--- a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
@@ -29,9 +29,18 @@ private val countriesLocales: SortedMap =
.toSortedMap()
val BULGARIAN: Locale = Locale.forLanguageTag("bg")
+
+val CHINESE_SIMPLIFIED: Locale = Locale.forLanguageTag("zh-Hans")
+
+val CHINESE_TRADITIONAL: Locale = Locale.forLanguageTag("zh-Hant")
val DUTCH: Locale = Locale.forLanguageTag("nl")
+val ENGLISH: Locale = Locale.forLanguageTag("en")
+val FRENCH: Locale = Locale.forLanguageTag("fr")
+val GERMAN: Locale = Locale.forLanguageTag("de")
val GREEK: Locale = Locale.forLanguageTag("el")
val HUNGARIAN: Locale = Locale.forLanguageTag("hu")
+val ITALIAN: Locale = Locale.forLanguageTag("it")
+val JAPANESE: Locale = Locale.forLanguageTag("ja")
val POLISH: Locale = Locale.forLanguageTag("pl")
val PORTUGUESE_PORTUGAL: Locale = Locale.forLanguageTag("pt-PT")
val PORTUGUESE_BRAZIL: Locale = Locale.forLanguageTag("pt-BR")
@@ -46,13 +55,13 @@ val baseSupportedLocales: List =
DUTCH,
GREEK,
HUNGARIAN,
- Locale.SIMPLIFIED_CHINESE,
- Locale.TRADITIONAL_CHINESE,
- Locale.ENGLISH,
- Locale.FRENCH,
- Locale.GERMAN,
- Locale.ITALIAN,
- Locale.JAPANESE,
+ CHINESE_SIMPLIFIED,
+ CHINESE_TRADITIONAL,
+ ENGLISH,
+ FRENCH,
+ GERMAN,
+ ITALIAN,
+ JAPANESE,
POLISH,
PORTUGUESE_BRAZIL,
PORTUGUESE_PORTUGAL,
@@ -76,10 +85,15 @@ fun supportedLanguageTags(): List =
fun findByLanguageTag(languageTag: String): Locale {
if (languageTag.isEmpty()) return currentLocale
- val locale = Locale.forLanguageTag(languageTag)
- return baseSupportedLocales.firstOrNull {
- it.language == locale.language && it.country == locale.country
- } ?: currentLocale
+
+ val target = Locale.forLanguageTag(languageTag)
+ if (target.language.isEmpty()) return currentLocale
+
+ return baseSupportedLocales.find { it == target }
+ ?: baseSupportedLocales.find { it.language == target.language && it.script == target.script }
+ ?: baseSupportedLocales.find { it.language == target.language && it.country == target.country }
+ ?: baseSupportedLocales.find { it.language == target.language }
+ ?: currentLocale
}
fun currentCountryCode(): String = currentLocale.country
@@ -87,3 +101,6 @@ fun currentCountryCode(): String = currentLocale.country
fun currentLanguageTag(): String = currentLocale.toLanguageTag()
fun toLanguageTag(locale: Locale): String = locale.toLanguageTag()
+
+fun Locale.toSupportedLocaleTag(): String =
+ findByLanguageTag(this.toLanguageTag()).toLanguageTag()
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
index 7c59a14d..9c77a6d6 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
@@ -17,7 +17,6 @@
*/
package com.vrem.wifianalyzer
-import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.content.res.Configuration
@@ -26,18 +25,17 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.os.LocaleListCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
import com.vrem.annotation.OpenClass
-import com.vrem.util.createContext
import com.vrem.wifianalyzer.navigation.NavigationMenu
import com.vrem.wifianalyzer.navigation.NavigationMenuControl
import com.vrem.wifianalyzer.navigation.NavigationMenuController
import com.vrem.wifianalyzer.navigation.options.OptionMenu
-import com.vrem.wifianalyzer.settings.Repository
-import com.vrem.wifianalyzer.settings.Settings
import com.vrem.wifianalyzer.wifi.accesspoint.ConnectionView
import com.vrem.wifianalyzer.wifi.scanner.ScannerService
@@ -52,15 +50,13 @@ class MainActivity :
internal lateinit var optionMenu: OptionMenu
internal lateinit var connectionView: ConnectionView
- override fun attachBaseContext(newBase: Context) =
- super.attachBaseContext(newBase.createContext(Settings(Repository(newBase)).languageLocale()))
-
override fun onCreate(savedInstanceState: Bundle?) {
val mainContext = MainContext.INSTANCE
mainContext.initialize(this, largeScreen)
val settings = mainContext.settings
settings.initializeDefaultValues()
+ settings.syncLanguage()
setTheme(settings.themeStyle().themeNoActionBar)
mainReload = MainReload(settings)
@@ -120,6 +116,17 @@ class MainActivity :
sharedPreferences: SharedPreferences,
key: String?,
) {
+ val languageKey = getString(R.string.language_key)
+ if (key == languageKey) {
+ val languageTag = sharedPreferences.getString(languageKey, "")
+ val locales = languageTag
+ ?.takeIf { it.isNotEmpty() }
+ ?.let(LocaleListCompat::forLanguageTags)
+ ?: LocaleListCompat.getEmptyLocaleList()
+
+ AppCompatDelegate.setApplicationLocales(locales)
+ }
+
val mainContext = MainContext.INSTANCE
if (mainReload.shouldReload(mainContext.settings)) {
MainContext.INSTANCE.scannerService.stop()
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
index 33caa01f..a8d087c2 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
@@ -20,7 +20,6 @@ package com.vrem.wifianalyzer
import com.vrem.wifianalyzer.settings.Settings
import com.vrem.wifianalyzer.settings.ThemeStyle
import com.vrem.wifianalyzer.wifi.accesspoint.ConnectionViewType
-import java.util.Locale
class MainReload(
settings: Settings,
@@ -29,11 +28,9 @@ class MainReload(
private set
var connectionViewType: ConnectionViewType
private set
- var languageLocale: Locale
- private set
fun shouldReload(settings: Settings): Boolean =
- themeChanged(settings) || connectionViewTypeChanged(settings) || languageChanged(settings)
+ themeChanged(settings) || connectionViewTypeChanged(settings)
private fun connectionViewTypeChanged(settings: Settings): Boolean {
val currentConnectionViewType = settings.connectionViewType()
@@ -53,18 +50,8 @@ class MainReload(
return themeChanged
}
- private fun languageChanged(settings: Settings): Boolean {
- val settingLanguageLocale = settings.languageLocale()
- val languageLocaleChanged = languageLocale != settingLanguageLocale
- if (languageLocaleChanged) {
- languageLocale = settingLanguageLocale
- }
- return languageLocaleChanged
- }
-
init {
themeStyle = settings.themeStyle()
connectionViewType = settings.connectionViewType()
- languageLocale = settings.languageLocale()
}
}
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
index 7be4ce88..b1bda240 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/CountryPreference.kt
@@ -25,7 +25,7 @@ import com.vrem.wifianalyzer.wifi.band.WiFiChannelCountry
import java.util.Locale
private fun data(): List {
- val currentLocale: Locale = MainContext.INSTANCE.settings.languageLocale()
+ val currentLocale: Locale = MainContext.INSTANCE.settings.appLocale()
return WiFiChannelCountry
.findAll()
.map { Data(it.countryCode, it.countryName(currentLocale)) }
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
index 91f4ffb3..311cbb6c 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
@@ -18,14 +18,15 @@
package com.vrem.wifianalyzer.settings
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import androidx.appcompat.app.AppCompatDelegate
import com.vrem.annotation.OpenClass
import com.vrem.util.buildMinVersionQ
import com.vrem.util.currentCountryCode
-import com.vrem.util.currentLanguageTag
import com.vrem.util.findByLanguageTag
import com.vrem.util.findOne
import com.vrem.util.findSet
import com.vrem.util.ordinals
+import com.vrem.util.toSupportedLocaleTag
import com.vrem.wifianalyzer.R
import com.vrem.wifianalyzer.navigation.MAIN_NAVIGATION
import com.vrem.wifianalyzer.navigation.NavigationMenu
@@ -69,10 +70,14 @@ class Settings(
fun countryCode(): String = repository.string(R.string.country_code_key, currentCountryCode())
- fun languageLocale(): Locale {
- val currentLanguageTag = currentLanguageTag()
- val languageTag = repository.string(R.string.language_key, currentLanguageTag)
- return findByLanguageTag(languageTag)
+ fun appLocale(): Locale =
+ findByLanguageTag(AppCompatDelegate.getApplicationLocales().toLanguageTags())
+
+ fun syncLanguage() {
+ val appLocaleTag = appLocale().toSupportedLocaleTag()
+ if (appLocaleTag != repository.string(R.string.language_key, "")) {
+ repository.save(R.string.language_key, appLocaleTag)
+ }
}
fun sortBy(): SortBy = settingsFind(SortBy.entries, R.string.sort_by_key, SortBy.STRENGTH)
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragment.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragment.kt
index f0063ea7..a9bf4b67 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragment.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragment.kt
@@ -44,7 +44,7 @@ class ChannelAvailableFragment : Fragment() {
private fun update() {
val settings = MainContext.INSTANCE.settings
val countryCode = settings.countryCode()
- val languageLocale = settings.languageLocale()
+ val languageLocale = settings.appLocale()
binding.apply {
val textViews =
listOf(
diff --git a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
index 8ab3807f..ddcfc2e4 100644
--- a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
+++ b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
@@ -97,13 +97,13 @@ class LocaleUtilsTest {
DUTCH,
GREEK,
HUNGARIAN,
- Locale.SIMPLIFIED_CHINESE,
- Locale.TRADITIONAL_CHINESE,
- Locale.ENGLISH,
- Locale.FRENCH,
- Locale.GERMAN,
- Locale.ITALIAN,
- Locale.JAPANESE,
+ CHINESE_SIMPLIFIED,
+ CHINESE_TRADITIONAL,
+ ENGLISH,
+ FRENCH,
+ GERMAN,
+ ITALIAN,
+ JAPANESE,
POLISH,
PORTUGUESE_BRAZIL,
PORTUGUESE_PORTUGAL,
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/MainReloadTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/MainReloadTest.kt
index bbb0191b..3d50b18d 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/MainReloadTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/MainReloadTest.kt
@@ -27,7 +27,6 @@ import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
-import java.util.Locale
class MainReloadTest {
private val settings = MainContextHelper.INSTANCE.settings
@@ -37,7 +36,6 @@ class MainReloadTest {
fun setUp() {
whenever(settings.themeStyle()).thenReturn(ThemeStyle.DARK)
whenever(settings.connectionViewType()).thenReturn(ConnectionViewType.COMPLETE)
- whenever(settings.languageLocale()).thenReturn(Locale.UK)
fixture = MainReload(settings)
}
@@ -45,7 +43,6 @@ class MainReloadTest {
fun tearDown() {
verify(settings, atLeastOnce()).themeStyle()
verify(settings, atLeastOnce()).connectionViewType()
- verify(settings, atLeastOnce()).languageLocale()
verifyNoMoreInteractions(settings)
MainContextHelper.INSTANCE.restore()
}
@@ -91,25 +88,4 @@ class MainReloadTest {
assertThat(actual).isTrue
assertThat(fixture.connectionViewType).isEqualTo(expected)
}
-
- @Test
- fun shouldNotReloadWithNoLanguageLocaleChanges() {
- // execute
- val actual = fixture.shouldReload(settings)
- // validate
- assertThat(actual).isFalse
- assertThat(fixture.languageLocale).isEqualTo(Locale.UK)
- }
-
- @Test
- fun shouldReloadWithLanguageLocaleChange() {
- // setup
- val expected = Locale.US
- whenever(settings.languageLocale()).thenReturn(expected)
- // execute
- val actual = fixture.shouldReload(settings)
- // validate
- assertThat(actual).isTrue
- assertThat(fixture.languageLocale).isEqualTo(expected)
- }
}
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
index bd0c4280..81f3a6fa 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
@@ -370,7 +370,7 @@ class SettingsTest {
val expected = Locale.FRENCH
doReturn(toLanguageTag(expected)).whenever(repository).string(R.string.language_key, defaultValue)
// execute
- val actual = fixture.languageLocale()
+ val actual = fixture.appLocale()
// validate
assertThat(actual).isEqualTo(expected)
verify(repository).string(R.string.language_key, defaultValue)
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragmentTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragmentTest.kt
index 27e3ea49..ff88c4bc 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragmentTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/channelavailable/ChannelAvailableFragmentTest.kt
@@ -62,13 +62,13 @@ class ChannelAvailableFragmentTest {
@Before
fun setUp() {
whenever(settings.countryCode()).thenReturn(locale.country)
- whenever(settings.languageLocale()).thenReturn(Locale.US)
+ whenever(settings.appLocale()).thenReturn(Locale.US)
}
@After
fun tearDown() {
verify(settings, atLeastOnce()).countryCode()
- verify(settings, atLeastOnce()).languageLocale()
+ verify(settings, atLeastOnce()).appLocale()
INSTANCE.restore()
}
From 730dc4f1290cef088f79f2d36ab826532cc308e9 Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Sun, 28 Dec 2025 14:00:09 +0900
Subject: [PATCH 7/8] update LocaleUtils and refactor language preference tests
---
.../main/kotlin/com/vrem/util/LocaleUtils.kt | 10 ++++---
.../vendor/model/VendorService.kt | 4 +--
.../kotlin/com/vrem/util/LocaleUtilsTest.kt | 19 ++++++++++----
.../settings/LanguagePreferenceTest.kt | 26 +++++++++++--------
.../wifianalyzer/settings/SettingsTest.kt | 17 +++++-------
.../wifi/band/WiFiChannelCountryTest.kt | 12 ++++++---
6 files changed, 52 insertions(+), 36 deletions(-)
diff --git a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
index ad0ca037..652d39c0 100644
--- a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
@@ -72,7 +72,7 @@ val baseSupportedLocales: List =
).toList()
fun findByCountryCode(countryCode: String): Locale =
- availableLocales.firstOrNull { countryCode.toCapitalize(Locale.getDefault()) == it.country }
+ availableLocales.firstOrNull { countryCode.uppercase(Locale.ROOT) == it.country }
?: currentLocale
fun allCountries(): List = countriesLocales.values.toList()
@@ -83,10 +83,14 @@ fun supportedLanguages(): List =
fun supportedLanguageTags(): List =
listOf("") + baseSupportedLocales.map { it.toLanguageTag() }
+private fun normalizeLanguageTag(languageTag: String): String =
+ languageTag.replace('_', '-').trim()
+
fun findByLanguageTag(languageTag: String): Locale {
- if (languageTag.isEmpty()) return currentLocale
+ val normalizedLanguageTag = normalizeLanguageTag(languageTag)
+ if (normalizedLanguageTag.isEmpty()) return currentLocale
- val target = Locale.forLanguageTag(languageTag)
+ val target = Locale.forLanguageTag(normalizedLanguageTag)
if (target.language.isEmpty()) return currentLocale
return baseSupportedLocales.find { it == target }
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/vendor/model/VendorService.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/vendor/model/VendorService.kt
index fba8fa11..09d1ad7f 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/vendor/model/VendorService.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/vendor/model/VendorService.kt
@@ -34,10 +34,10 @@ class VendorService(
fun findVendorName(address: String = String.EMPTY): String = vendorData.macs[address.clean()].orEmpty()
fun findMacAddresses(vendorName: String = String.EMPTY): List =
- vendorData.vendors[vendorName.uppercase(Locale.getDefault())].orEmpty()
+ vendorData.vendors[vendorName.uppercase(Locale.ROOT)].orEmpty()
fun findVendors(vendorName: String = String.EMPTY): List {
- val name = vendorName.uppercase(Locale.getDefault())
+ val name = vendorName.uppercase(Locale.ROOT)
return vendorData.vendors
.filterKeys { filter(it, name) }
.keys
diff --git a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
index ddcfc2e4..21c3c238 100644
--- a/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
+++ b/app/src/test/kotlin/com/vrem/util/LocaleUtilsTest.kt
@@ -69,8 +69,10 @@ class LocaleUtilsTest {
@Test
fun toLanguageTagWithKnownCode() {
- assertThat(toLanguageTag(Locale.US)).isEqualTo(Locale.US.language + "_" + Locale.US.country)
- assertThat(toLanguageTag(Locale.ENGLISH)).isEqualTo(Locale.ENGLISH.language + "_")
+ assertThat(toLanguageTag(Locale.US)).isEqualTo("en-US")
+ assertThat(toLanguageTag(ENGLISH)).isEqualTo("en")
+ assertThat(toLanguageTag(CHINESE_SIMPLIFIED)).isEqualTo("zh-Hans")
+ assertThat(toLanguageTag(CHINESE_TRADITIONAL)).isEqualTo("zh-Hant")
}
@Test
@@ -83,9 +85,16 @@ class LocaleUtilsTest {
@Test
fun findByLanguageTagWithKnownTag() {
- assertThat(findByLanguageTag(toLanguageTag(Locale.SIMPLIFIED_CHINESE))).isEqualTo(Locale.SIMPLIFIED_CHINESE)
- assertThat(findByLanguageTag(toLanguageTag(Locale.TRADITIONAL_CHINESE))).isEqualTo(Locale.TRADITIONAL_CHINESE)
- assertThat(findByLanguageTag(toLanguageTag(Locale.ENGLISH))).isEqualTo(Locale.ENGLISH)
+ // BCP-47 format (new)
+ assertThat(findByLanguageTag("zh-Hans")).isEqualTo(CHINESE_SIMPLIFIED)
+ assertThat(findByLanguageTag("zh-Hant")).isEqualTo(CHINESE_TRADITIONAL)
+ assertThat(findByLanguageTag("en")).isEqualTo(ENGLISH)
+ assertThat(findByLanguageTag("en-US")).isEqualTo(ENGLISH)
+
+ // Backward compatibility: underscore format (old)
+ assertThat(findByLanguageTag("zh_Hans")).isEqualTo(CHINESE_SIMPLIFIED)
+ assertThat(findByLanguageTag("zh_Hant")).isEqualTo(CHINESE_TRADITIONAL)
+ assertThat(findByLanguageTag("en_US")).isEqualTo(ENGLISH)
}
@Test
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/LanguagePreferenceTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/LanguagePreferenceTest.kt
index 32b90514..dd2ab5be 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/LanguagePreferenceTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/LanguagePreferenceTest.kt
@@ -19,9 +19,8 @@ package com.vrem.wifianalyzer.settings
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.vrem.util.supportedLanguages
-import com.vrem.util.toCapitalize
-import com.vrem.util.toLanguageTag
+import com.vrem.util.supportedLanguageTags
+import com.vrem.util.titlecaseFirst
import com.vrem.wifianalyzer.R
import com.vrem.wifianalyzer.RobolectricUtil
import org.assertj.core.api.Assertions.assertThat
@@ -35,7 +34,7 @@ import java.util.Locale
@Config(sdk = [Build.VERSION_CODES.BAKLAVA])
class LanguagePreferenceTest {
private val mainActivity = RobolectricUtil.INSTANCE.activity
- private val languages = supportedLanguages()
+ private val languageTags = supportedLanguageTags()
private val attributeSet = Robolectric.getAttributeSetFromXml(R.xml.test_attrs)
private val fixture = LanguagePreference(mainActivity, attributeSet)
@@ -44,9 +43,16 @@ class LanguagePreferenceTest {
// execute
val actual: Array = fixture.entries
// validate
- assertThat(actual).hasSize(languages.size)
- languages.forEach {
- assertThat(actual).contains(it.getDisplayName(it).toCapitalize(Locale.getDefault()))
+ assertThat(actual).hasSize(languageTags.size)
+
+ // Check system default entry
+ assertThat(actual[0]).isEqualTo(mainActivity.getString(R.string.system_default))
+
+ // Check language entries
+ languageTags.drop(1).forEachIndexed { index, tag ->
+ val locale = Locale.forLanguageTag(tag)
+ val displayName = locale.getDisplayName(locale).titlecaseFirst(locale)
+ assertThat(actual[index + 1]).isEqualTo(displayName)
}
}
@@ -55,9 +61,7 @@ class LanguagePreferenceTest {
// execute
val actual: Array = fixture.entryValues
// validate
- assertThat(actual).hasSize(languages.size)
- languages.forEach {
- assertThat(actual).contains(toLanguageTag(it))
- }
+ assertThat(actual).hasSize(languageTags.size)
+ assertThat(actual).containsExactlyElementsOf(languageTags)
}
}
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
index 81f3a6fa..cfb36c71 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/settings/SettingsTest.kt
@@ -21,9 +21,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vrem.util.currentCountryCode
-import com.vrem.util.currentLanguageTag
import com.vrem.util.ordinals
-import com.vrem.util.toLanguageTag
import com.vrem.wifianalyzer.R
import com.vrem.wifianalyzer.navigation.NavigationMenu
import com.vrem.wifianalyzer.wifi.accesspoint.AccessPointViewType
@@ -46,7 +44,6 @@ import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
import org.robolectric.annotation.Config
-import java.util.Locale
@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.BAKLAVA])
@@ -364,16 +361,14 @@ class SettingsTest {
}
@Test
- fun languageLocale() {
- // setup
- val defaultValue = currentLanguageTag()
- val expected = Locale.FRENCH
- doReturn(toLanguageTag(expected)).whenever(repository).string(R.string.language_key, defaultValue)
+ fun appLocale() {
+ // Note: appLocale() uses AppCompatDelegate.getApplicationLocales() which is system API
+ // and returns the current application locale (device default in test environment)
// execute
val actual = fixture.appLocale()
- // validate
- assertThat(actual).isEqualTo(expected)
- verify(repository).string(R.string.language_key, defaultValue)
+ // validate: should return a valid Locale (default in test)
+ assertThat(actual).isNotNull
+ assertThat(actual.language).isNotEmpty()
}
@Test
diff --git a/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/band/WiFiChannelCountryTest.kt b/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/band/WiFiChannelCountryTest.kt
index 42272a22..4082ca97 100644
--- a/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/band/WiFiChannelCountryTest.kt
+++ b/app/src/test/kotlin/com/vrem/wifianalyzer/wifi/band/WiFiChannelCountryTest.kt
@@ -30,10 +30,14 @@ class WiFiChannelCountryTest {
@Test
fun find() {
- val expected = Locale.US
- val actual = WiFiChannelCountry.find(expected.country)
- assertThat(actual.countryCode).isEqualTo(expected.country)
- assertThat(actual.countryName(expected)).isEqualTo(expected.displayCountry)
+ val countryLocale = Locale.US
+ val displayLocale = Locale.getDefault()
+
+ val actual = WiFiChannelCountry.find(countryLocale.country)
+
+ assertThat(actual.countryCode).isEqualTo(countryLocale.country)
+ assertThat(actual.countryName(displayLocale))
+ .isEqualTo(countryLocale.getDisplayCountry(displayLocale))
}
@Test
From 402dcca72306a44d617c0cd9b73d6c422f2530ed Mon Sep 17 00:00:00 2001
From: Akihiro Nagai <77012577+314systems@users.noreply.github.com>
Date: Mon, 29 Dec 2025 17:17:10 +0900
Subject: [PATCH 8/8] reformat
---
app/src/main/kotlin/com/vrem/util/LocaleUtils.kt | 12 ++++--------
app/src/main/kotlin/com/vrem/util/StringUtils.kt | 3 +--
.../kotlin/com/vrem/wifianalyzer/MainActivity.kt | 9 +++++----
.../main/kotlin/com/vrem/wifianalyzer/MainReload.kt | 3 +--
.../com/vrem/wifianalyzer/settings/Settings.kt | 3 +--
5 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
index 652d39c0..17395ae8 100644
--- a/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/LocaleUtils.kt
@@ -77,14 +77,11 @@ fun findByCountryCode(countryCode: String): Locale =
fun allCountries(): List = countriesLocales.values.toList()
-fun supportedLanguages(): List =
- (baseSupportedLocales + currentLocale).distinct()
+fun supportedLanguages(): List = (baseSupportedLocales + currentLocale).distinct()
-fun supportedLanguageTags(): List =
- listOf("") + baseSupportedLocales.map { it.toLanguageTag() }
+fun supportedLanguageTags(): List = listOf("") + baseSupportedLocales.map { it.toLanguageTag() }
-private fun normalizeLanguageTag(languageTag: String): String =
- languageTag.replace('_', '-').trim()
+private fun normalizeLanguageTag(languageTag: String): String = languageTag.replace('_', '-').trim()
fun findByLanguageTag(languageTag: String): Locale {
val normalizedLanguageTag = normalizeLanguageTag(languageTag)
@@ -106,5 +103,4 @@ fun currentLanguageTag(): String = currentLocale.toLanguageTag()
fun toLanguageTag(locale: Locale): String = locale.toLanguageTag()
-fun Locale.toSupportedLocaleTag(): String =
- findByLanguageTag(this.toLanguageTag()).toLanguageTag()
+fun Locale.toSupportedLocaleTag(): String = findByLanguageTag(this.toLanguageTag()).toLanguageTag()
diff --git a/app/src/main/kotlin/com/vrem/util/StringUtils.kt b/app/src/main/kotlin/com/vrem/util/StringUtils.kt
index 37cfda7b..afc68e67 100644
--- a/app/src/main/kotlin/com/vrem/util/StringUtils.kt
+++ b/app/src/main/kotlin/com/vrem/util/StringUtils.kt
@@ -28,5 +28,4 @@ fun String.specialTrim(): String = this.trim { it <= ' ' }.replace(" +".toRegex(
fun String.toCapitalize(locale: Locale): String = this.replaceFirstChar { word -> word.uppercase(locale) }
-fun String.titlecaseFirst(locale: Locale): String =
- replaceFirstChar { it.titlecase(locale) }
+fun String.titlecaseFirst(locale: Locale): String = replaceFirstChar { it.titlecase(locale) }
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
index 9c77a6d6..c0a9d2e3 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/MainActivity.kt
@@ -119,10 +119,11 @@ class MainActivity :
val languageKey = getString(R.string.language_key)
if (key == languageKey) {
val languageTag = sharedPreferences.getString(languageKey, "")
- val locales = languageTag
- ?.takeIf { it.isNotEmpty() }
- ?.let(LocaleListCompat::forLanguageTags)
- ?: LocaleListCompat.getEmptyLocaleList()
+ val locales =
+ languageTag
+ ?.takeIf { it.isNotEmpty() }
+ ?.let(LocaleListCompat::forLanguageTags)
+ ?: LocaleListCompat.getEmptyLocaleList()
AppCompatDelegate.setApplicationLocales(locales)
}
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
index a8d087c2..67b10edf 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/MainReload.kt
@@ -29,8 +29,7 @@ class MainReload(
var connectionViewType: ConnectionViewType
private set
- fun shouldReload(settings: Settings): Boolean =
- themeChanged(settings) || connectionViewTypeChanged(settings)
+ fun shouldReload(settings: Settings): Boolean = themeChanged(settings) || connectionViewTypeChanged(settings)
private fun connectionViewTypeChanged(settings: Settings): Boolean {
val currentConnectionViewType = settings.connectionViewType()
diff --git a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
index 311cbb6c..05563b27 100644
--- a/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
+++ b/app/src/main/kotlin/com/vrem/wifianalyzer/settings/Settings.kt
@@ -70,8 +70,7 @@ class Settings(
fun countryCode(): String = repository.string(R.string.country_code_key, currentCountryCode())
- fun appLocale(): Locale =
- findByLanguageTag(AppCompatDelegate.getApplicationLocales().toLanguageTags())
+ fun appLocale(): Locale = findByLanguageTag(AppCompatDelegate.getApplicationLocales().toLanguageTags())
fun syncLanguage() {
val appLocaleTag = appLocale().toSupportedLocaleTag()