Add multilanguage support (i18n) initial implementation

This commit is contained in:
jeffersoncarlospedroso 2025-12-10 23:06:37 +00:00
parent 489e27b038
commit 0d174f1550
12 changed files with 364 additions and 65 deletions

View File

@ -8,7 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.compose.ui.res.stringResource
@Composable
fun BottomNavigationBar(navController: NavController) {
@ -26,8 +26,8 @@ fun BottomNavigationBar(navController: NavController) {
items.forEach { item ->
NavigationBarItem (
icon = { Icon(painter = painterResource(item.icon), contentDescription = item.label) },
label = { Text(item.label) },
icon = { Icon(painter = painterResource(item.icon), contentDescription = stringResource(item.label)) },
label = { Text(text = stringResource(item.label)) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {

View File

@ -1,25 +1,101 @@
package com.github.nacabaro.vbhelper.navigation
import com.github.nacabaro.vbhelper.R
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
sealed class NavigationItems(
var route: String,
var icon: Int,
var label: String
val route: String,
@DrawableRes val icon: Int,
@StringRes val label: Int
) {
object Scan : NavigationItems("Scan/{characterId}", R.drawable.baseline_nfc_24, "Scan")
object Battles : NavigationItems("Battle", R.drawable.baseline_swords_24, "Battle")
object Home : NavigationItems("Home", R.drawable.baseline_cottage_24, "Home")
object Dex : NavigationItems("Dex", R.drawable.baseline_menu_book_24, "Dex")
object CardAdventure : NavigationItems("CardAdventure/{cardId}", R.drawable.baseline_fort_24, "Card adventure")
object Storage : NavigationItems("Storage", R.drawable.baseline_catching_pokemon_24, "Storage")
object Settings : NavigationItems("Settings", R.drawable.baseline_settings_24, "Settings")
object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer")
object CardView : NavigationItems("Card/{cardId}", R.drawable.baseline_image_24, "Card")
object Items : NavigationItems("Items", R.drawable.baseline_data_24, "Items")
object MyItems : NavigationItems("MyItems", R.drawable.baseline_data_24, "My items")
object ItemsStore : NavigationItems("ItemsStore", R.drawable.baseline_data_24, "Items store")
object ApplyItem : NavigationItems("ApplyItem/{itemId}", R.drawable.baseline_data_24, "Apply item")
object Adventure : NavigationItems("Adventure", R.drawable.baseline_fort_24, "Adventure")
object Credits : NavigationItems("Credits", R.drawable.baseline_data_24, "Credits")
object Scan : NavigationItems(
"Scan/{characterId}",
R.drawable.baseline_nfc_24,
R.string.nav_scan
)
object Battles : NavigationItems(
"Battle",
R.drawable.baseline_swords_24,
R.string.nav_battle
)
object Home : NavigationItems(
"Home",
R.drawable.baseline_cottage_24,
R.string.nav_home
)
object Dex : NavigationItems(
"Dex",
R.drawable.baseline_menu_book_24,
R.string.nav_dex
)
object CardAdventure : NavigationItems(
"CardAdventure/{cardId}",
R.drawable.baseline_fort_24,
R.string.nav_card_adventure
)
object Storage : NavigationItems(
"Storage",
R.drawable.baseline_catching_pokemon_24,
R.string.nav_storage
)
object Settings : NavigationItems(
"Settings",
R.drawable.baseline_settings_24,
R.string.nav_settings
)
object Viewer : NavigationItems(
"Viewer",
R.drawable.baseline_image_24,
R.string.nav_viewer
)
object CardView : NavigationItems(
"Card/{cardId}",
R.drawable.baseline_image_24,
R.string.nav_card
)
object Items : NavigationItems(
"Items",
R.drawable.baseline_data_24,
R.string.nav_items
)
object MyItems : NavigationItems(
"MyItems",
R.drawable.baseline_data_24,
R.string.nav_my_items
)
object ItemsStore : NavigationItems(
"ItemsStore",
R.drawable.baseline_data_24,
R.string.nav_items_store
)
object ApplyItem : NavigationItems(
"ApplyItem/{itemId}",
R.drawable.baseline_data_24,
R.string.nav_apply_item
)
object Adventure : NavigationItems(
"Adventure",
R.drawable.baseline_fort_24,
R.string.nav_adventure
)
object Credits : NavigationItems(
"Credits",
R.drawable.baseline_data_24,
R.string.nav_credits
)
}

View File

@ -18,6 +18,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
import com.github.nacabaro.vbhelper.components.TopBanner
@ -29,6 +30,7 @@ import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
import kotlinx.coroutines.delay
import java.time.Instant
import com.github.nacabaro.vbhelper.R
@Composable
fun AdventureScreen(
@ -61,7 +63,7 @@ fun AdventureScreen(
Scaffold(
topBar = {
TopBanner(
text = "Adventure",
text = stringResource(R.string.adventure_title),
onBackClick = {
navController.popBackStack()
}
@ -76,7 +78,7 @@ fun AdventureScreen(
.padding(top = contentPadding.calculateTopPadding())
.fillMaxSize()
) {
Text(text = "Nothing to see here")
Text(text = stringResource(R.string.adventure_empty_state))
}
} else {
LazyColumn(

View File

@ -8,8 +8,10 @@ import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.github.nacabaro.vbhelper.R
@Composable
fun BetaWarning(
@ -24,21 +26,21 @@ fun BetaWarning(
.padding(16.dp)
) {
Text(
text = "This application is currently in alpha and it is not complete. Do not use to store important characters for you, as any future updates might delete all your characters. Sorry for the inconvenience!"
text = stringResource(R.string.beta_warning_message_main)
)
Spacer(modifier = Modifier.padding(8.dp))
Text(
text = "Application should work now with the original VB and the VH."
text = stringResource(R.string.beta_warning_message_compatibility)
)
Spacer(modifier = Modifier.padding(8.dp))
Text(
text = "Thank you for your understanding and patience. Sincerely, the dev team."
text = stringResource(R.string.beta_warning_message_thanks)
)
Spacer(modifier = Modifier.padding(8.dp))
Button(
onClick = onDismissRequest
) {
Text(text = "Dismiss")
Text(text = stringResource(R.string.beta_warning_button_dismiss))
}
}
}

View File

@ -19,6 +19,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
@ -39,6 +40,7 @@ import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
import com.github.nacabaro.vbhelper.source.StorageRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.github.nacabaro.vbhelper.R
@Composable
fun HomeScreen(
@ -81,7 +83,7 @@ fun HomeScreen(
Scaffold (
topBar = {
TopBanner(
text = "VB Helper",
text = stringResource(R.string.home_title),
onScanClick = {
navController.navigate(NavigationItems.Scan.route)
},
@ -99,7 +101,7 @@ fun HomeScreen(
.fillMaxSize()
.padding(top = contentPadding.calculateTopPadding())
) {
Text(text = "Nothing to see here")
Text(text = stringResource(R.string.adventure_empty_state))
}
} else {
if (activeMon.value!!.isBemCard) {
@ -154,7 +156,7 @@ fun HomeScreen(
.padding(16.dp)
) {
Text(
text = "One of your characters has finished their adventure mission!",
text = stringResource(R.string.home_adventure_mission_finished),
textAlign = TextAlign.Center
)
Button(
@ -165,7 +167,7 @@ fun HomeScreen(
.padding(8.dp)
.fillMaxWidth()
) {
Text(text = "Dismiss")
Text(text = stringResource(R.string.beta_warning_button_dismiss))
}
}
}

View File

@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import androidx.compose.ui.res.stringResource
@Composable
fun ItemsScreen(
@ -37,7 +38,7 @@ fun ItemsScreen(
) {
items.forEachIndexed { index, item ->
Tab(
text = { Text(item.label) },
text = { Text(text = stringResource(item.label)) },
selected = selectedTabItem == index,
onClick = { selectedTabItem = index }
)

View File

@ -12,10 +12,12 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.R
@Composable
fun ChooseConnectOption(
@ -26,7 +28,7 @@ fun ChooseConnectOption(
Scaffold(
topBar = {
TopBanner(
text = "Scan a Vital Bracelet",
text = stringResource(R.string.scan_title),
onBackClick = {
navController.popBackStack()
}
@ -41,13 +43,13 @@ fun ChooseConnectOption(
.padding(contentPadding)
) {
ScanButton(
text = "Vital Bracelet to App",
text = stringResource(R.string.scan_vb_to_app),
disabled = onClickRead == null,
onClick = onClickRead?: { },
)
Spacer(modifier = Modifier.height(16.dp))
ScanButton(
text = "App to Vital Bracelet",
text = stringResource(R.string.scan_app_to_vb),
disabled = onClickWrite == null,
onClick = onClickWrite?: { },
)

View File

@ -25,6 +25,7 @@ import com.github.nacabaro.vbhelper.source.proto.Secrets
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import com.github.nacabaro.vbhelper.R
const val SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER = "SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER"
@ -93,9 +94,9 @@ fun ScanScreen(
else -> {
{
if(secrets == null) {
Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.scan_secrets_not_initialized), Toast.LENGTH_SHORT).show()
} else if(secrets?.isMissingSecrets() == true) {
Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.scan_secrets_not_imported), Toast.LENGTH_SHORT).show()
} else {
readingScreen = true // kicks off nfc adapter in DisposableEffect
}
@ -107,9 +108,9 @@ fun ScanScreen(
else -> {
{
if(secrets == null) {
Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.scan_secrets_not_initialized), Toast.LENGTH_SHORT).show()
} else if(secrets?.isMissingSecrets() == true) {
Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.scan_secrets_not_imported), Toast.LENGTH_SHORT).show()
} else {
writingScreen = true // kicks off nfc adapter in DisposableEffect
}

View File

@ -25,6 +25,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import com.github.nacabaro.vbhelper.R
class ScanScreenControllerImpl(
override val secretsFlow: Flow<Secrets>,
@ -38,7 +39,7 @@ class ScanScreenControllerImpl(
init {
val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(componentActivity)
if (maybeNfcAdapter == null) {
Toast.makeText(componentActivity, "No NFC on device!", Toast.LENGTH_SHORT).show()
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_no_nfc_on_device), Toast.LENGTH_SHORT).show()
}
nfcAdapter = maybeNfcAdapter
checkSecrets()
@ -94,7 +95,7 @@ class ScanScreenControllerImpl(
val nfcData = NfcA.get(tag)
if (nfcData == null) {
componentActivity.runOnUiThread {
Toast.makeText(componentActivity, "Tag detected is not VB", Toast.LENGTH_SHORT).show()
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_tag_not_vb), Toast.LENGTH_SHORT).show()
}
}
nfcData.connect()
@ -112,7 +113,7 @@ class ScanScreenControllerImpl(
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
if(secretsFlow.stateIn(componentActivity.lifecycleScope).value.isMissingSecrets()) {
componentActivity.runOnUiThread {
Toast.makeText(componentActivity, "Missing Secrets. Go to settings and import Vital Arena APK", Toast.LENGTH_SHORT).show()
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_missing_secrets), Toast.LENGTH_SHORT).show()
}
}
}
@ -135,10 +136,10 @@ class ScanScreenControllerImpl(
tagCommunicator.sendCharacter(castNfcCharacter)
}
onComplete.invoke()
"Sent character successfully!"
componentActivity.getString(R.string.scan_sent_character_success)
} catch (e: Throwable) {
Log.e("TAG", e.stackTraceToString())
"Whoops"
componentActivity.getString(R.string.scan_error_generic)
}
}
}
@ -151,13 +152,13 @@ class ScanScreenControllerImpl(
handleTag(secrets) { tagCommunicator ->
tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId)
onComplete.invoke()
"Sent DIM successfully!"
componentActivity.getString(R.string.scan_sent_dim_success)
}
}
// EXTRACTED DIRECTLY FROM EXAMPLE APP
private fun showWirelessSettings() {
Toast.makeText(componentActivity, "NFC must be enabled", Toast.LENGTH_SHORT).show()
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_nfc_must_be_enabled), Toast.LENGTH_SHORT).show()
componentActivity.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
}

View File

@ -16,12 +16,15 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.R
@Composable
fun SettingsScreen(
@ -33,7 +36,7 @@ fun SettingsScreen(
Scaffold(
topBar = {
TopBanner(
text = "Settings",
text = stringResource(R.string.settings_title),
onBackClick = {
navController.popBackStack()
}
@ -48,28 +51,51 @@ fun SettingsScreen(
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
SettingsSection("NFC Communication")
SettingsEntry(title = "Import APK", description = "Import Secrets From Vital Arena 2.1.0 APK") {
SettingsSection(title = stringResource(R.string.settings_section_nfc))
SettingsEntry(
title = stringResource(R.string.settings_import_apk_title),
description = stringResource(R.string.settings_import_apk_desc)
) {
settingsScreenController.onClickImportApk()
}
SettingsSection("DiM/BEm management")
SettingsEntry(title = "Import card", description = "Import DiM/BEm card file") {
SettingsSection(title = stringResource(R.string.settings_section_dim_bem))
SettingsEntry(
title = stringResource(R.string.settings_import_card_title),
description = stringResource(R.string.settings_import_card_desc)
) {
settingsScreenController.onClickImportCard()
}
SettingsSection("About and credits")
SettingsEntry(title = "Credits", description = "Credits") {
SettingsSection(title = stringResource(R.string.settings_section_about))
SettingsEntry(
title = stringResource(R.string.settings_credits_title),
description = stringResource(R.string.settings_credits_desc)
) {
navController.navigate(NavigationItems.Credits.route)
}
SettingsEntry(title = "About", description = "About") {
SettingsEntry(
title = stringResource(R.string.settings_about_title),
description = stringResource(R.string.settings_about_desc)
) {
val browserIntent = Intent(
Intent.ACTION_VIEW, Uri.parse("https://github.com/nacabaro/vbhelper/"))
Intent.ACTION_VIEW,
Uri.parse("https://github.com/nacabaro/vbhelper/")
)
context.startActivity(browserIntent)
}
SettingsSection("Data management")
SettingsEntry(title = "Export data", description = "Export application database") {
SettingsSection(title = stringResource(R.string.settings_section_data))
SettingsEntry(
title = stringResource(R.string.settings_export_data_title),
description = stringResource(R.string.settings_export_data_desc)
) {
settingsScreenController.onClickOpenDirectory()
}
SettingsEntry(title = "Import data", description = "Import application database") {
SettingsEntry(
title = stringResource(R.string.settings_import_data_title),
description = stringResource(R.string.settings_import_data_desc)
) {
settingsScreenController.onClickImportDatabase()
}
}
@ -103,7 +129,7 @@ fun SettingsSection(
) {
Box(
modifier = Modifier
.padding(start = 16.dp)
.padding(start = 16.dp, top = 16.dp, bottom = 4.dp)
) {
Text(
text = title,

View File

@ -0,0 +1,92 @@
<resources>
<string name="app_name">VBHelper</string>
<string name="beta_warning_message_main">
Este aplicativo ainda está em versão alfa e não está completo. Não o use para armazenar personagens importantes para você, pois futuras atualizações podem apagar todos os seus personagens. Desculpe pelo transtorno!
</string>
<string name="beta_warning_message_compatibility">
O aplicativo agora deve funcionar com o VB original e com o VH.
</string>
<string name="beta_warning_message_thanks">
Obrigado pela compreensão e pela paciência. Atenciosamente, a equipe de desenvolvimento.
</string>
<string name="beta_warning_button_dismiss">Fechar</string>
<string name="nav_scan">Escanear</string>
<string name="nav_battle">Batalhas</string>
<string name="nav_home">Início</string>
<string name="nav_dex">Dex</string>
<string name="nav_card_adventure">Aventura do card</string>
<string name="nav_storage">Armazenamento</string>
<string name="nav_settings">Configurações</string>
<string name="nav_viewer">Visualizador</string>
<string name="nav_card">Card</string>
<string name="nav_items">Itens</string>
<string name="nav_my_items">Meus itens</string>
<string name="nav_items_store">Loja de itens</string>
<string name="nav_apply_item">Aplicar item</string>
<string name="nav_adventure">Aventura</string>
<string name="nav_credits">Créditos</string>
<string name="adventure_title">Aventura</string>
<string name="adventure_empty_state">Nada para ver aqui</string>
<string name="home_title">VB Helper</string>
<string name="home_adventure_mission_finished">
Um dos seus personagens terminou a missão de aventura!
</string>
<string name="scan_secrets_not_initialized">
Os segredos ainda não foram inicializados. Tente novamente.
</string>
<string name="scan_secrets_not_imported">
Os segredos ainda não foram importados. Vá em Configurações e importe o APK.
</string>
<string name="scan_title">Escanear um Vital Bracelet</string>
<string name="scan_vb_to_app">Vital Bracelet para o app</string>
<string name="scan_app_to_vb">App para o Vital Bracelet</string>
<string name="scan_no_nfc_on_device">O dispositivo não possui NFC!</string>
<string name="scan_tag_not_vb">A tag detectada não é do Vital Bracelet.</string>
<string name="scan_missing_secrets">
Segredos ausentes. Vá em Configurações e importe o APK do Vital Arena.
</string>
<string name="scan_sent_character_success">Personagem enviado com sucesso!</string>
<string name="scan_error_generic">Ops!</string>
<string name="scan_sent_dim_success">DIM enviado com sucesso!</string>
<string name="scan_nfc_must_be_enabled">O NFC precisa estar ativado.</string>
<string name="settings_title">Configurações</string>
<string name="settings_section_nfc">Comunicação NFC</string>
<string name="settings_section_dim_bem">Gerenciamento de DiM/BEm</string>
<string name="settings_section_about">Sobre e créditos</string>
<string name="settings_section_data">Gerenciamento de dados</string>
<string name="settings_import_apk_title">Importar APK</string>
<string name="settings_import_apk_desc">
Importar segredos do APK do Vital Arena 2.1.0
</string>
<string name="settings_import_card_title">Importar card</string>
<string name="settings_import_card_desc">
Importar arquivo de card DiM/BEm
</string>
<string name="settings_credits_title">Créditos</string>
<string name="settings_credits_desc">Créditos</string>
<string name="settings_about_title">Sobre</string>
<string name="settings_about_desc">Sobre</string>
<string name="settings_export_data_title">Exportar dados</string>
<string name="settings_export_data_desc">
Exportar banco de dados do aplicativo
</string>
<string name="settings_import_data_title">Importar dados</string>
<string name="settings_import_data_desc">
Importar banco de dados do aplicativo
</string>
</resources>

View File

@ -1,3 +1,97 @@
<resources>
<string name="app_name">VBHelper</string>
<string name="beta_warning_message_main">
This application is currently in alpha and it is not complete. Do not use it to store important characters for you, as any future updates might delete all your characters. Sorry for the inconvenience!
</string>
<string name="beta_warning_message_compatibility">
The application should now work with the original VB and the VH.
</string>
<string name="beta_warning_message_thanks">
Thank you for your understanding and patience. Sincerely, the dev team.
</string>
<string name="beta_warning_button_dismiss">
Dismiss
</string>
<string name="nav_scan">Scan</string>
<string name="nav_battle">Battle</string>
<string name="nav_home">Home</string>
<string name="nav_dex">Dex</string>
<string name="nav_card_adventure">Card adventure</string>
<string name="nav_storage">Storage</string>
<string name="nav_settings">Settings</string>
<string name="nav_viewer">Viewer</string>
<string name="nav_card">Card</string>
<string name="nav_items">Items</string>
<string name="nav_my_items">My items</string>
<string name="nav_items_store">Items store</string>
<string name="nav_apply_item">Apply item</string>
<string name="nav_adventure">Adventure</string>
<string name="nav_credits">Credits</string>
<string name="adventure_title">Adventure</string>
<string name="adventure_empty_state">Nothing to see here</string>
<string name="home_title">VB Helper</string>
<string name="home_adventure_mission_finished">
One of your characters has finished their adventure mission!
</string>
<string name="scan_secrets_not_initialized">
Secrets is not yet initialized. Try again.
</string>
<string name="scan_secrets_not_imported">
Secrets not yet imported. Go to Settings and Import APK.
</string>
<string name="scan_title">Scan a Vital Bracelet</string>
<string name="scan_vb_to_app">Vital Bracelet to App</string>
<string name="scan_app_to_vb">App to Vital Bracelet</string>
<string name="scan_no_nfc_on_device">No NFC on device!</string>
<string name="scan_tag_not_vb">Tag detected is not VB</string>
<string name="scan_missing_secrets">
Missing Secrets. Go to settings and import Vital Arena APK.
</string>
<string name="scan_sent_character_success">Sent character successfully!</string>
<string name="scan_error_generic">Whoops</string>
<string name="scan_sent_dim_success">Sent DIM successfully!</string>
<string name="scan_nfc_must_be_enabled">NFC must be enabled</string>
<string name="settings_title">Settings</string>
<string name="settings_section_nfc">NFC Communication</string>
<string name="settings_section_dim_bem">DiM/BEm management</string>
<string name="settings_section_about">About and credits</string>
<string name="settings_section_data">Data management</string>
<string name="settings_import_apk_title">Import APK</string>
<string name="settings_import_apk_desc">
Import Secrets From Vital Arena 2.1.0 APK
</string>
<string name="settings_import_card_title">Import card</string>
<string name="settings_import_card_desc">
Import DiM/BEm card file
</string>
<string name="settings_credits_title">Credits</string>
<string name="settings_credits_desc">Credits</string>
<string name="settings_about_title">About</string>
<string name="settings_about_desc">About</string>
<string name="settings_export_data_title">Export data</string>
<string name="settings_export_data_desc">
Export application database
</string>
<string name="settings_import_data_title">Import data</string>
<string name="settings_import_data_desc">
Import application database
</string>
</resources>