Merge pull request #1380 from davotoula/684-add-auto-translate-config-to-settings
Add auto translate config to new user specific settings
This commit is contained in:
@@ -113,6 +113,10 @@ class AccountSyncedSettings(
|
|||||||
security.warnAboutPostsWithReports = syncedSettingsInternal.security.warnAboutPostsWithReports
|
security.warnAboutPostsWithReports = syncedSettingsInternal.security.warnAboutPostsWithReports
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dontTranslateFromFilteredBySpokenLanguages(): Set<String> {
|
||||||
|
return languages.dontTranslateFrom - getLanguagesSpokenByUser()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchScreen
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NIP47SetupScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NIP47SetupScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SecurityFiltersScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SecurityFiltersScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsScreen
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.UserSettingsScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.ThreadScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.ThreadScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.VideoScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.VideoScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.AddAccountDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedOff.AddAccountDialog
|
||||||
@@ -123,6 +124,7 @@ fun AppNavigation(
|
|||||||
composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) }
|
composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) }
|
||||||
composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) }
|
composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) }
|
||||||
composableFromEnd<Route.Settings> { SettingsScreen(sharedPreferencesViewModel, accountViewModel, nav) }
|
composableFromEnd<Route.Settings> { SettingsScreen(sharedPreferencesViewModel, accountViewModel, nav) }
|
||||||
|
composableFromEnd<Route.UserSettings> { UserSettingsScreen(accountViewModel, nav) }
|
||||||
composableFromBottomArgs<Route.Nip47NWCSetup> { NIP47SetupScreen(accountViewModel, nav, it.nip47) }
|
composableFromBottomArgs<Route.Nip47NWCSetup> { NIP47SetupScreen(accountViewModel, nav, it.nip47) }
|
||||||
composableFromEndArgs<Route.EditRelays> { AllRelayListScreen(it.toAdd, accountViewModel, nav) }
|
composableFromEndArgs<Route.EditRelays> { AllRelayListScreen(it.toAdd, accountViewModel, nav) }
|
||||||
|
|
||||||
@@ -251,9 +253,6 @@ private fun NavigateIfIntentRequested(
|
|||||||
}
|
}
|
||||||
|
|
||||||
nav.newStack(Route.NewPost(message = message, attachment = media.toString()))
|
nav.newStack(Route.NewPost(message = message, attachment = media.toString()))
|
||||||
|
|
||||||
media = null
|
|
||||||
message = null
|
|
||||||
} else {
|
} else {
|
||||||
var newAccount by remember { mutableStateOf<String?>(null) }
|
var newAccount by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import androidx.compose.material.icons.outlined.CloudUpload
|
|||||||
import androidx.compose.material.icons.outlined.Drafts
|
import androidx.compose.material.icons.outlined.Drafts
|
||||||
import androidx.compose.material.icons.outlined.GroupAdd
|
import androidx.compose.material.icons.outlined.GroupAdd
|
||||||
import androidx.compose.material.icons.outlined.Key
|
import androidx.compose.material.icons.outlined.Key
|
||||||
|
import androidx.compose.material.icons.outlined.Person
|
||||||
import androidx.compose.material.icons.outlined.Security
|
import androidx.compose.material.icons.outlined.Security
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
@@ -66,7 +67,6 @@ import androidx.compose.runtime.derivedStateOf
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -74,7 +74,6 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.text.LinkAnnotation
|
import androidx.compose.ui.text.LinkAnnotation
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
@@ -427,8 +426,6 @@ fun ListContent(
|
|||||||
|
|
||||||
var backupDialogOpen by remember { mutableStateOf(false) }
|
var backupDialogOpen by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
Column(modifier) {
|
Column(modifier) {
|
||||||
NavigationRow(
|
NavigationRow(
|
||||||
title = R.string.profile,
|
title = R.string.profile,
|
||||||
@@ -508,6 +505,14 @@ fun ListContent(
|
|||||||
route = Route.Settings,
|
route = Route.Settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
NavigationRow(
|
||||||
|
title = R.string.user_preferences,
|
||||||
|
icons = listOf(Icons.Outlined.Person, Icons.Outlined.Settings),
|
||||||
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
nav = nav,
|
||||||
|
route = Route.UserSettings,
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
IconRow(
|
IconRow(
|
||||||
@@ -584,11 +589,28 @@ fun NavigationRow(
|
|||||||
tint: Color,
|
tint: Color,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
route: Route,
|
route: Route,
|
||||||
|
) {
|
||||||
|
NavigationRow(
|
||||||
|
title = title,
|
||||||
|
icons = listOf(icon),
|
||||||
|
tint = tint,
|
||||||
|
nav = nav,
|
||||||
|
route = route,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NavigationRow(
|
||||||
|
title: Int,
|
||||||
|
icons: List<ImageVector>,
|
||||||
|
tint: Color,
|
||||||
|
nav: INav,
|
||||||
|
route: Route,
|
||||||
) {
|
) {
|
||||||
IconRow(
|
IconRow(
|
||||||
title,
|
title = title,
|
||||||
icon,
|
icons = icons,
|
||||||
tint,
|
tint = tint,
|
||||||
onClick = {
|
onClick = {
|
||||||
nav.closeDrawer()
|
nav.closeDrawer()
|
||||||
nav.nav(route)
|
nav.nav(route)
|
||||||
@@ -636,6 +658,21 @@ fun IconRow(
|
|||||||
icon: ImageVector,
|
icon: ImageVector,
|
||||||
tint: Color,
|
tint: Color,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
IconRow(
|
||||||
|
title = title,
|
||||||
|
icons = listOf(icon),
|
||||||
|
tint = tint,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun IconRow(
|
||||||
|
title: Int,
|
||||||
|
icons: List<ImageVector>,
|
||||||
|
tint: Color,
|
||||||
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -650,12 +687,15 @@ fun IconRow(
|
|||||||
modifier = IconRowModifier,
|
modifier = IconRowModifier,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Icon(
|
icons.forEach { icon ->
|
||||||
imageVector = icon,
|
Icon(
|
||||||
contentDescription = stringRes(title),
|
imageVector = icon,
|
||||||
modifier = Size22Modifier,
|
contentDescription = stringRes(title),
|
||||||
tint = tint,
|
modifier = Size22Modifier.padding(end = 4.dp),
|
||||||
)
|
tint = tint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
modifier = IconRowTextModifier,
|
modifier = IconRowTextModifier,
|
||||||
text = stringRes(title),
|
text = stringRes(title),
|
||||||
@@ -709,8 +749,6 @@ fun BottomContent(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
// store the dialog open or close state
|
// store the dialog open or close state
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ sealed class Route {
|
|||||||
|
|
||||||
@Serializable object Settings : Route()
|
@Serializable object Settings : Route()
|
||||||
|
|
||||||
|
@Serializable object UserSettings : Route()
|
||||||
|
|
||||||
@Serializable object EditProfile : Route()
|
@Serializable object EditProfile : Route()
|
||||||
|
|
||||||
@Serializable data class EditRelays(
|
@Serializable data class EditRelays(
|
||||||
|
|||||||
+4
@@ -898,6 +898,10 @@ class AccountViewModel(
|
|||||||
|
|
||||||
fun dontTranslateFrom() = account.settings.syncedSettings.languages.dontTranslateFrom
|
fun dontTranslateFrom() = account.settings.syncedSettings.languages.dontTranslateFrom
|
||||||
|
|
||||||
|
fun dontTranslateFromFilteredBySpokenLanguages() = account.settings.syncedSettings.dontTranslateFromFilteredBySpokenLanguages()
|
||||||
|
|
||||||
|
fun toggleDontTranslateFrom(languageCode: String) = account.toggleDontTranslateFrom(languageCode)
|
||||||
|
|
||||||
fun translateTo() = account.settings.syncedSettings.languages.translateTo
|
fun translateTo() = account.settings.syncedSettings.languages.translateTo
|
||||||
|
|
||||||
fun defaultZapType() = account.settings.syncedSettings.zaps.defaultZapType.value
|
fun defaultZapType() = account.settings.syncedSettings.zaps.defaultZapType.value
|
||||||
|
|||||||
+8
-7
@@ -119,12 +119,13 @@ fun getLanguageIndex(
|
|||||||
sharedPreferencesViewModel: SharedPreferencesViewModel,
|
sharedPreferencesViewModel: SharedPreferencesViewModel,
|
||||||
): Int {
|
): Int {
|
||||||
val language = sharedPreferencesViewModel.sharedPrefs.language
|
val language = sharedPreferencesViewModel.sharedPrefs.language
|
||||||
var languageIndex = -1
|
var languageIndex: Int
|
||||||
if (language != null) {
|
languageIndex =
|
||||||
languageIndex = languageEntries.values.toTypedArray().indexOf(language)
|
if (language != null) {
|
||||||
} else {
|
languageEntries.values.toTypedArray().indexOf(language)
|
||||||
languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag())
|
} else {
|
||||||
}
|
languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag())
|
||||||
|
}
|
||||||
if (languageIndex == -1) {
|
if (languageIndex == -1) {
|
||||||
languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language)
|
languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language)
|
||||||
}
|
}
|
||||||
@@ -365,7 +366,7 @@ fun SettingsRow(
|
|||||||
text = stringRes(description),
|
text = stringRes(description),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = Color.Gray,
|
color = Color.Gray,
|
||||||
maxLines = 2,
|
maxLines = 3,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+154
@@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MenuAnchorType
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.EmptyNav
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.TopBarWithBackButton
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.Locale as JavaLocale
|
||||||
|
|
||||||
|
@Preview(device = "spec:width=2160px,height=2340px,dpi=440")
|
||||||
|
@Composable
|
||||||
|
fun UserSettingsScreenPreview() {
|
||||||
|
val accountViewModel = mockAccountViewModel()
|
||||||
|
val nav = EmptyNav
|
||||||
|
ThemeComparisonRow {
|
||||||
|
UserSettingsScreen(accountViewModel, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UserSettingsScreen(
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: INav,
|
||||||
|
) {
|
||||||
|
DisappearingScaffold(
|
||||||
|
isInvertedLayout = false,
|
||||||
|
topBar = {
|
||||||
|
TopBarWithBackButton(stringRes(id = R.string.user_preferences), nav::popBack)
|
||||||
|
},
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
) {
|
||||||
|
Column(Modifier.padding(it)) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(top = Size10dp, start = Size20dp, end = Size20dp)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
DontTranslateFromSetting(accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun DontTranslateFromSetting(accountViewModel: AccountViewModel) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
val selectedLanguages = accountViewModel.dontTranslateFromFilteredBySpokenLanguages().toMutableSet()
|
||||||
|
|
||||||
|
Column {
|
||||||
|
SettingsRow(
|
||||||
|
name = R.string.dont_translate_from,
|
||||||
|
description = R.string.dont_translate_from_description,
|
||||||
|
) {
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = expanded,
|
||||||
|
onExpandedChange = { expanded = !expanded },
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = stringRes(R.string.quick_action_select),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||||
|
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryEditable),
|
||||||
|
)
|
||||||
|
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false },
|
||||||
|
) {
|
||||||
|
selectedLanguages.forEach { languageCode ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = JavaLocale.forLanguageTag(languageCode).displayName) },
|
||||||
|
onClick = {
|
||||||
|
accountViewModel.viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
accountViewModel.toggleDontTranslateFrom(
|
||||||
|
languageCode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
selectedLanguages.remove(languageCode)
|
||||||
|
expanded = false
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = "Remove $languageCode",
|
||||||
|
tint = Color.Red,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -675,6 +675,7 @@
|
|||||||
<string name="add_sensitive_content_description">Adds sensitive content warning before showing this content</string>
|
<string name="add_sensitive_content_description">Adds sensitive content warning before showing this content</string>
|
||||||
|
|
||||||
<string name="preferences">App Preferences</string>
|
<string name="preferences">App Preferences</string>
|
||||||
|
<string name="user_preferences">User Preferences</string>
|
||||||
|
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="connectivity_type_always">Always</string>
|
<string name="connectivity_type_always">Always</string>
|
||||||
@@ -1178,4 +1179,7 @@
|
|||||||
<string name="share_image">Share image…</string>
|
<string name="share_image">Share image…</string>
|
||||||
|
|
||||||
<string name="search_by_hashtag">Search hashtag: #%1$s</string>
|
<string name="search_by_hashtag">Search hashtag: #%1$s</string>
|
||||||
|
|
||||||
|
<string name="dont_translate_from">Don\'t Translate From</string>
|
||||||
|
<string name="dont_translate_from_description">Languages shown here will not be translated. Select a language to remove it and have it translated again.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user