feat: add in-app language picker

This commit is contained in:
a1denvalu3 2026-07-28 16:18:01 +02:00
parent 96340a35aa
commit 8f2585d8eb
40 changed files with 438 additions and 3 deletions

View File

@ -80,11 +80,21 @@
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:localeConfig="@xml/locales_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.BitchatAndroid"
tools:targetApi="31">
tools:targetApi="33">
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
<!-- FileProvider for sharing temp/cache files with external viewers -->
<provider
android:name="androidx.core.content.FileProvider"

View File

@ -37,6 +37,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.CloudDownload
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Public
import androidx.compose.material.icons.filled.Share
@ -52,6 +53,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -120,6 +122,114 @@ private fun ThemeChip(
}
}
@Composable
private fun LanguagePickerDialog(
languages: List<AppLanguage>,
selectedLanguageTag: String,
onLanguageSelected: (String) -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.about_select_language)) },
text = {
LazyColumn(modifier = Modifier.fillMaxWidth()) {
item(key = "system") {
LanguageOptionRow(
label = stringResource(R.string.about_system_default),
selected = selectedLanguageTag.isEmpty(),
onClick = { onLanguageSelected("") },
)
}
items(
count = languages.size,
key = { index -> languages[index].languageTag },
) { index ->
val language = languages[index]
LanguageOptionRow(
label = language.endonym,
selected = selectedLanguageTag == language.languageTag,
onClick = { onLanguageSelected(language.languageTag) },
)
}
}
},
confirmButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(android.R.string.cancel))
}
},
)
}
@Composable
private fun LanguageOptionRow(
label: String,
selected: Boolean,
onClick: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = selected,
onClick = null,
)
Spacer(modifier = Modifier.width(12.dp))
Text(
text = label,
style = MaterialTheme.typography.bodyLarge,
)
}
}
@Composable
private fun LanguageSettingsRow(
selectedLanguageName: String,
onClick: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(horizontal = 16.dp, vertical = 13.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
imageVector = Icons.Filled.Language,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(22.dp),
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = stringResource(R.string.about_language),
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
modifier = Modifier.weight(1f),
)
Text(
text = selectedLanguageName,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f, fill = false),
)
Spacer(modifier = Modifier.width(8.dp))
Icon(
imageVector = Icons.Filled.ChevronRight,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp),
)
}
}
/**
* Unified settings toggle row with icon, title, subtitle, and switch
* Apple-like design with proper spacing
@ -259,6 +369,28 @@ fun AboutSheet(
val colorScheme = MaterialTheme.colorScheme
val palette = LocalBitchatPalette.current
var selectedTab by remember { mutableStateOf(AboutTab.Info) }
val supportedLanguages = remember(context) {
LanguagePreferenceManager.supportedLanguages(context)
}
var selectedLanguageTag by remember {
mutableStateOf(LanguagePreferenceManager.currentLanguageTag())
}
var showLanguagePicker by remember { mutableStateOf(false) }
if (showLanguagePicker) {
LanguagePickerDialog(
languages = supportedLanguages,
selectedLanguageTag = selectedLanguageTag,
onLanguageSelected = { languageTag ->
showLanguagePicker = false
if (languageTag != selectedLanguageTag) {
selectedLanguageTag = languageTag
LanguagePreferenceManager.setLanguage(languageTag)
}
},
onDismiss = { showLanguagePicker = false },
)
}
if (isPresented) {
BitchatBottomSheet(
@ -342,6 +474,29 @@ fun AboutSheet(
}
}
item(key = "language") {
val selectedLanguageName = supportedLanguages
.firstOrNull { it.languageTag == selectedLanguageTag }
?.endonym
?: stringResource(R.string.about_system_default)
Column {
AboutSectionLabel(text = stringResource(R.string.about_language))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = AboutHorizontalPadding),
color = colorScheme.surface,
shape = AboutCardShape,
) {
LanguageSettingsRow(
selectedLanguageName = selectedLanguageName,
onClick = { showLanguagePicker = true },
)
}
}
}
// Settings Section - Unified Card with Toggles
item(key = "settings") {
LaunchedEffect(Unit) { PoWPreferenceManager.init(context) }

View File

@ -0,0 +1,61 @@
package com.bitchat.android.ui
import android.content.Context
import androidx.annotation.XmlRes
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import com.bitchat.android.R
import org.xmlpull.v1.XmlPullParser
import java.util.Locale
data class AppLanguage(
val languageTag: String,
val endonym: String,
)
object LanguagePreferenceManager {
fun currentLanguageTag(): String =
AppCompatDelegate.getApplicationLocales().toLanguageTags()
fun setLanguage(languageTag: String) {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(languageTag)
)
}
fun supportedLanguages(
context: Context,
@XmlRes localeConfig: Int = R.xml.locales_config,
): List<AppLanguage> = readLanguageTags(context, localeConfig)
.map { languageTag ->
val locale = Locale.forLanguageTag(languageTag)
AppLanguage(
languageTag = languageTag,
endonym = locale.getDisplayName(locale)
.replaceFirstChar { first ->
if (first.isLowerCase()) first.titlecase(locale) else first.toString()
},
)
}
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.endonym })
internal fun readLanguageTags(
context: Context,
@XmlRes localeConfig: Int,
): List<String> {
val parser = context.resources.getXml(localeConfig)
return buildList {
var event = parser.eventType
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && parser.name == "locale") {
parser.getAttributeValue(ANDROID_NAMESPACE, "name")
?.takeIf(String::isNotBlank)
?.let(::add)
}
event = parser.next()
}
}
}
private const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
}

View File

@ -2,14 +2,14 @@ package com.bitchat.android.ui
import android.content.pm.ActivityInfo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.appcompat.app.AppCompatActivity
import com.bitchat.android.utils.DeviceUtils
/**
* Base activity that automatically sets orientation based on device type.
* Tablets can rotate to landscape, phones are locked to portrait.
*/
abstract class OrientationAwareActivity : ComponentActivity() {
abstract class OrientationAwareActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">تحقّق من الملاحظات المتروكة هنا</string>
<string name="nearby_notes_one">تُركت ملاحظة واحدة هنا — انقر للقراءة</string>
<string name="nearby_notes_many">تُركت %d ملاحظات هنا — انقر للقراءة</string>
<string name="about_language">اللغة</string>
<string name="about_system_default">إعداد النظام الافتراضي</string>
<string name="about_select_language">اختر اللغة</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">এখানে রাখা নোট আছে কি না দেখুন</string>
<string name="nearby_notes_one">এখানে 1টি নোট রাখা আছে — পড়তে ট্যাপ করুন</string>
<string name="nearby_notes_many">এখানে %dটি নোট রাখা আছে — পড়তে ট্যাপ করুন</string>
<string name="about_language">ভাষা</string>
<string name="about_system_default">সিস্টেম ডিফল্ট</string>
<string name="about_select_language">ভাষা নির্বাচন করুন</string>
</resources>

View File

@ -390,4 +390,7 @@
<string name="nearby_notes_reveal">nachsehen, ob hier notizen hinterlassen wurden</string>
<string name="nearby_notes_one">1 notiz hier hinterlassen — tippen zum lesen</string>
<string name="nearby_notes_many">%d notizen hier hinterlassen — tippen zum lesen</string>
<string name="about_language">Sprache</string>
<string name="about_system_default">Systemstandard</string>
<string name="about_select_language">Sprache auswählen</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">buscar notas dejadas aquí</string>
<string name="nearby_notes_one">1 nota dejada aquí — toca para leer</string>
<string name="nearby_notes_many">%d notas dejadas aquí — toca para leer</string>
<string name="about_language">Idioma</string>
<string name="about_system_default">Predeterminado del sistema</string>
<string name="about_select_language">Seleccionar idioma</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">یادداشت‌های باقی‌مانده در اینجا را بررسی کنید</string>
<string name="nearby_notes_one">۱ یادداشت اینجا باقی مانده — برای خواندن ضربه بزنید</string>
<string name="nearby_notes_many">%d یادداشت اینجا باقی مانده — برای خواندن ضربه بزنید</string>
<string name="about_language">زبان</string>
<string name="about_system_default">پیش‌فرض سیستم</string>
<string name="about_select_language">انتخاب زبان</string>
</resources>

View File

@ -393,4 +393,7 @@
<string name="nearby_notes_reveal">tingnan kung may mga note na naiwan dito</string>
<string name="nearby_notes_one">1 note ang naiwan dito — i-tap para basahin</string>
<string name="nearby_notes_many">%d note ang naiwan dito — i-tap para basahin</string>
<string name="about_language">Wika</string>
<string name="about_system_default">Default ng system</string>
<string name="about_select_language">Pumili ng wika</string>
</resources>

View File

@ -407,4 +407,7 @@
<string name="nearby_notes_reveal">vérifier s\'il y a des notes laissées ici</string>
<string name="nearby_notes_one">1 note laissée ici — appuyez pour lire</string>
<string name="nearby_notes_many">%d notes laissées ici — appuyez pour lire</string>
<string name="about_language">Langue</string>
<string name="about_system_default">Langue du système</string>
<string name="about_select_language">Choisir la langue</string>
</resources>

View File

@ -57,4 +57,7 @@
<string name="nearby_notes_reveal">בדיקה אם הושארו כאן פתקים</string>
<string name="nearby_notes_one">פתק אחד הושאר כאן — הקש לקריאה</string>
<string name="nearby_notes_many">%d פתקים הושארו כאן — הקש לקריאה</string>
<string name="about_language">שפה</string>
<string name="about_system_default">ברירת המחדל של המערכת</string>
<string name="about_select_language">בחירת שפה</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">देखें कि यहाँ नोट छोड़े गए हैं या नहीं</string>
<string name="nearby_notes_one">यहाँ 1 नोट छोड़ा गया है — पढ़ने के लिए टैप करें</string>
<string name="nearby_notes_many">यहाँ %d नोट छोड़े गए हैं — पढ़ने के लिए टैप करें</string>
<string name="about_language">भाषा</string>
<string name="about_system_default">सिस्टम डिफ़ॉल्ट</string>
<string name="about_select_language">भाषा चुनें</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">periksa catatan yang ditinggalkan di sini</string>
<string name="nearby_notes_one">1 catatan ditinggalkan di sini — ketuk untuk membaca</string>
<string name="nearby_notes_many">%d catatan ditinggalkan di sini — ketuk untuk membaca</string>
<string name="about_language">Bahasa</string>
<string name="about_system_default">Default sistem</string>
<string name="about_select_language">Pilih bahasa</string>
</resources>

View File

@ -422,4 +422,7 @@
<string name="nearby_notes_reveal">controlla se ci sono note lasciate qui</string>
<string name="nearby_notes_one">1 nota lasciata qui — tocca per leggere</string>
<string name="nearby_notes_many">%d note lasciate qui — tocca per leggere</string>
<string name="about_language">Lingua</string>
<string name="about_system_default">Predefinita di sistema</string>
<string name="about_select_language">Seleziona lingua</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">ここに残されたメモを確認</string>
<string name="nearby_notes_one">ここに1件のメモがあります — タップして読む</string>
<string name="nearby_notes_many">ここに%d件のメモがあります — タップして読む</string>
<string name="about_language">言語</string>
<string name="about_system_default">システムのデフォルト</string>
<string name="about_select_language">言語を選択</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">აქ დატოვებული ჩანაწერების შემოწმება</string>
<string name="nearby_notes_one">აქ 1 ჩანაწერია დატოვებული — წასაკითხად შეეხეთ</string>
<string name="nearby_notes_many">აქ %d ჩანაწერია დატოვებული — წასაკითხად შეეხეთ</string>
<string name="about_language">ენა</string>
<string name="about_system_default">სისტემის ნაგულისხმევი</string>
<string name="about_select_language">ენის არჩევა</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">여기 남겨진 쪽지 확인</string>
<string name="nearby_notes_one">여기 남겨진 쪽지 1개 — 탭하여 읽기</string>
<string name="nearby_notes_many">여기 남겨진 쪽지 %d개 — 탭하여 읽기</string>
<string name="about_language">언어</string>
<string name="about_system_default">시스템 기본값</string>
<string name="about_select_language">언어 선택</string>
</resources>

View File

@ -402,4 +402,7 @@
<string name="nearby_notes_reveal">hizaha raha misy naoty navela teto</string>
<string name="nearby_notes_one">naoty 1 no navela teto — tsindrio raha hamaky</string>
<string name="nearby_notes_many">naoty %d no navela teto — tsindrio raha hamaky</string>
<string name="about_language">Fiteny</string>
<string name="about_system_default">Fiteninny rafitra</string>
<string name="about_select_language">Safidio ny fiteny</string>
</resources>

View File

@ -44,4 +44,7 @@
<string name="nearby_notes_reveal">semak nota yang ditinggalkan di sini</string>
<string name="nearby_notes_one">1 nota ditinggalkan di sini — ketik untuk baca</string>
<string name="nearby_notes_many">%d nota ditinggalkan di sini — ketik untuk baca</string>
<string name="about_language">Bahasa</string>
<string name="about_system_default">Lalai sistem</string>
<string name="about_select_language">Pilih bahasa</string>
</resources>

View File

@ -393,4 +393,7 @@
<string name="nearby_notes_reveal">यहाँ छोडिएका नोटहरू छन् कि हेर्नुहोस्</string>
<string name="nearby_notes_one">यहाँ 1 नोट छोडिएको छ — पढ्न ट्याप गर्नुहोस्</string>
<string name="nearby_notes_many">यहाँ %d नोटहरू छोडिएका छन् — पढ्न ट्याप गर्नुहोस्</string>
<string name="about_language">भाषा</string>
<string name="about_system_default">प्रणालीको पूर्वनिर्धारित</string>
<string name="about_select_language">भाषा छान्नुहोस्</string>
</resources>

View File

@ -420,4 +420,7 @@
<string name="nearby_notes_reveal">kijk of hier notities zijn achtergelaten</string>
<string name="nearby_notes_one">1 notitie hier achtergelaten — tik om te lezen</string>
<string name="nearby_notes_many">%d notities hier achtergelaten — tik om te lezen</string>
<string name="about_language">Taal</string>
<string name="about_system_default">Systeemstandaard</string>
<string name="about_select_language">Taal selecteren</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">ایتھے چھڈے نوٹس ویکھو</string>
<string name="nearby_notes_one">ایتھے 1 نوٹ چھڈیا گیا — پڑھݨ لئی ٹیپ کرو</string>
<string name="nearby_notes_many">ایتھے %d نوٹس چھڈے گئے — پڑھݨ لئی ٹیپ کرو</string>
<string name="about_language">بولی</string>
<string name="about_system_default">سسٹم دی ڈیفالٹ</string>
<string name="about_select_language">بولی چݨو</string>
</resources>

View File

@ -57,4 +57,7 @@
<string name="nearby_notes_reveal">sprawdź, czy zostawiono tutaj notatki</string>
<string name="nearby_notes_one">1 notatka zostawiona tutaj — stuknij, aby przeczytać</string>
<string name="nearby_notes_many">%d notatek zostawionych tutaj — stuknij, aby przeczytać</string>
<string name="about_language">Język</string>
<string name="about_system_default">Domyślny systemu</string>
<string name="about_select_language">Wybierz język</string>
</resources>

View File

@ -388,4 +388,7 @@
<string name="nearby_notes_reveal">ver se há notas deixadas aqui</string>
<string name="nearby_notes_one">1 nota deixada aqui — toque para ler</string>
<string name="nearby_notes_many">%d notas deixadas aqui — toque para ler</string>
<string name="about_language">Idioma</string>
<string name="about_system_default">Padrão do sistema</string>
<string name="about_select_language">Selecionar idioma</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">ver se há notas deixadas aqui</string>
<string name="nearby_notes_one">1 nota deixada aqui — toque para ler</string>
<string name="nearby_notes_many">%d notas deixadas aqui — toque para ler</string>
<string name="about_language">Idioma</string>
<string name="about_system_default">Predefinição do sistema</string>
<string name="about_select_language">Selecionar idioma</string>
</resources>

View File

@ -383,4 +383,7 @@
<string name="nearby_notes_reveal">проверить, есть ли здесь заметки</string>
<string name="nearby_notes_one">здесь оставлена 1 заметка — нажмите, чтобы прочитать</string>
<string name="nearby_notes_many">здесь оставлено заметок: %d — нажмите, чтобы прочитать</string>
<string name="about_language">Язык</string>
<string name="about_system_default">Системный язык</string>
<string name="about_select_language">Выбрать язык</string>
</resources>

View File

@ -381,4 +381,7 @@
<string name="nearby_notes_reveal">kolla om anteckningar lämnats här</string>
<string name="nearby_notes_one">1 anteckning lämnad här — tryck för att läsa</string>
<string name="nearby_notes_many">%d anteckningar lämnade här — tryck för att läsa</string>
<string name="about_language">Språk</string>
<string name="about_system_default">Systemstandard</string>
<string name="about_select_language">Välj språk</string>
</resources>

View File

@ -44,4 +44,7 @@
<string name="nearby_notes_reveal">இங்கே விடப்பட்ட குறிப்புகள் உள்ளதா எனப் பார்க்கவும்</string>
<string name="nearby_notes_one">இங்கே 1 குறிப்பு விடப்பட்டுள்ளது — படிக்க தட்டவும்</string>
<string name="nearby_notes_many">இங்கே %d குறிப்புகள் விடப்பட்டுள்ளன — படிக்க தட்டவும்</string>
<string name="about_language">மொழி</string>
<string name="about_system_default">கணினி இயல்புநிலை</string>
<string name="about_select_language">மொழியைத் தேர்ந்தெடுக்கவும்</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">ดูว่ามีโน้ตทิ้งไว้ที่นี่หรือไม่</string>
<string name="nearby_notes_one">มี 1 โน้ตทิ้งไว้ที่นี่ — แตะเพื่ออ่าน</string>
<string name="nearby_notes_many">มี %d โน้ตทิ้งไว้ที่นี่ — แตะเพื่ออ่าน</string>
<string name="about_language">ภาษา</string>
<string name="about_system_default">ค่าเริ่มต้นของระบบ</string>
<string name="about_select_language">เลือกภาษา</string>
</resources>

View File

@ -381,4 +381,7 @@
<string name="nearby_notes_reveal">buraya bırakılan notlara bak</string>
<string name="nearby_notes_one">buraya 1 not bırakıldı — okumak için dokun</string>
<string name="nearby_notes_many">buraya %d not bırakıldı — okumak için dokun</string>
<string name="about_language">Dil</string>
<string name="about_system_default">Sistem varsayılanı</string>
<string name="about_select_language">Dil seçin</string>
</resources>

View File

@ -44,4 +44,7 @@
<string name="nearby_notes_reveal">перевірити, чи залишено тут нотатки</string>
<string name="nearby_notes_one">тут залишено 1 нотатку — торкніться, щоб прочитати</string>
<string name="nearby_notes_many">тут залишено %d нотаток — торкніться, щоб прочитати</string>
<string name="about_language">Мова</string>
<string name="about_system_default">Системна мова</string>
<string name="about_select_language">Вибрати мову</string>
</resources>

View File

@ -389,4 +389,7 @@
<string name="nearby_notes_reveal">دیکھیں کہ یہاں نوٹ چھوڑے گئے ہیں یا نہیں</string>
<string name="nearby_notes_one">یہاں 1 نوٹ چھوڑا گیا ہے — پڑھنے کے لیے تھپتھپائیں</string>
<string name="nearby_notes_many">یہاں %d نوٹ چھوڑے گئے ہیں — پڑھنے کے لیے تھپتھپائیں</string>
<string name="about_language">زبان</string>
<string name="about_system_default">سسٹم ڈیفالٹ</string>
<string name="about_select_language">زبان منتخب کریں</string>
</resources>

View File

@ -376,4 +376,7 @@
<string name="nearby_notes_reveal">kiểm tra ghi chú để lại ở đây</string>
<string name="nearby_notes_one">có 1 ghi chú để lại ở đây — chạm để đọc</string>
<string name="nearby_notes_many">có %d ghi chú để lại ở đây — chạm để đọc</string>
<string name="about_language">Ngôn ngữ</string>
<string name="about_system_default">Mặc định hệ thống</string>
<string name="about_select_language">Chọn ngôn ngữ</string>
</resources>

View File

@ -56,4 +56,7 @@
<string name="nearby_notes_reveal">查看这里留下的留言</string>
<string name="nearby_notes_one">这里留有 1 条留言 — 点按阅读</string>
<string name="nearby_notes_many">这里留有 %d 条留言 — 点按阅读</string>
<string name="about_language">语言</string>
<string name="about_system_default">跟随系统</string>
<string name="about_select_language">选择语言</string>
</resources>

View File

@ -56,4 +56,7 @@
<string name="nearby_notes_reveal">查看這裡留下的留言</string>
<string name="nearby_notes_one">這裡留有 1 則留言 — 點按閱讀</string>
<string name="nearby_notes_many">這裡留有 %d 則留言 — 點按閱讀</string>
<string name="about_language">語言</string>
<string name="about_system_default">跟隨系統</string>
<string name="about_select_language">選擇語言</string>
</resources>

View File

@ -406,4 +406,7 @@
<string name="nearby_notes_reveal">查看这里留下的留言</string>
<string name="nearby_notes_one">这里留有 1 条留言 — 点按阅读</string>
<string name="nearby_notes_many">这里留有 %d 条留言 — 点按阅读</string>
<string name="about_language">语言</string>
<string name="about_system_default">跟随系统</string>
<string name="about_select_language">选择语言</string>
</resources>

View File

@ -567,4 +567,7 @@
</plurals>
<string name="bluetooth_recommended">Bluetooth Recommended</string>
<string name="about_language">Language</string>
<string name="about_system_default">System default</string>
<string name="about_select_language">Select language</string>
</resources>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="ar" />
<locale android:name="bn" />
<locale android:name="de" />
<locale android:name="es" />
<locale android:name="fa" />
<locale android:name="fil" />
<locale android:name="fr" />
<locale android:name="he" />
<locale android:name="hi" />
<locale android:name="id" />
<locale android:name="it" />
<locale android:name="ja" />
<locale android:name="ka" />
<locale android:name="ko" />
<locale android:name="mg" />
<locale android:name="ms" />
<locale android:name="ne" />
<locale android:name="nl" />
<locale android:name="pa-PK" />
<locale android:name="pl" />
<locale android:name="pt" />
<locale android:name="pt-BR" />
<locale android:name="ru" />
<locale android:name="sv" />
<locale android:name="ta" />
<locale android:name="th" />
<locale android:name="tr" />
<locale android:name="uk" />
<locale android:name="ur" />
<locale android:name="vi" />
<locale android:name="zh" />
<locale android:name="zh-CN" />
<locale android:name="zh-TW" />
</locale-config>

View File

@ -0,0 +1,71 @@
package com.bitchat.android.ui
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.File
class LanguageCatalogContractTest {
private val resourcesDirectory = File("src/main/res")
@Test
fun `locale config contains every shipped locale exactly once`() {
val shippedLanguageTags = resourcesDirectory
.listFiles()
.orEmpty()
.filter { it.isDirectory && it.name.startsWith("values-") }
.mapNotNull { directory -> directory.name.toLanguageTagOrNull() }
.toSet()
val configuredLanguageTags = Regex("""android:name="([^"]+)"""")
.findAll(File(resourcesDirectory, "xml/locales_config.xml").readText())
.map { match -> match.groupValues[1] }
.toList()
assertEquals(
"Locale configuration must not contain duplicate entries",
configuredLanguageTags.toSet().size,
configuredLanguageTags.size,
)
assertEquals(shippedLanguageTags, configuredLanguageTags.toSet())
}
@Test
fun `language picker strings exist in every locale pack`() {
val requiredKeys = setOf(
"about_language",
"about_system_default",
"about_select_language",
)
resourcesDirectory
.listFiles()
.orEmpty()
.filter { directory ->
directory.isDirectory &&
(directory.name == "values" || directory.name.toLanguageTagOrNull() != null)
}
.forEach { directory ->
val strings = File(directory, "strings.xml").readText()
requiredKeys.forEach { key ->
assertTrue(
"$key is missing from ${directory.name}/strings.xml",
"""name="$key""" in strings,
)
}
}
}
private fun String.toLanguageTagOrNull(): String? {
if (!startsWith("values-") || this == "values-night") return null
return removePrefix("values-")
.split("-")
.joinToString("-") { qualifier ->
if (qualifier.startsWith("r") && qualifier.length == 3) {
qualifier.drop(1)
} else {
qualifier
}
}
}
}