diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 220835ffa4..33827f673b 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -20,6 +20,7 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id("io.element.android-compose-application")
+ alias(libs.plugins.stem)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.anvil)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..fee1385c85
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ ignored
+
diff --git a/features/login/build.gradle.kts b/features/login/build.gradle.kts
index 29987189e9..623477f727 100644
--- a/features/login/build.gradle.kts
+++ b/features/login/build.gradle.kts
@@ -41,6 +41,7 @@ dependencies {
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:elementresources"))
implementation(libs.appyx.core)
+ implementation(project(":libraries:ui-strings"))
ksp(libs.showkase.processor)
testImplementation(libs.test.junit)
androidTestImplementation(libs.test.junitext)
diff --git a/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt b/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt
index 3afc697572..3700575b96 100644
--- a/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt
+++ b/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt
@@ -20,7 +20,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import io.element.android.x.core.uri.isValidUrl
import io.element.android.x.features.login.root.LoginFormState
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun loginError(
@@ -30,7 +30,7 @@ fun loginError(
return when {
data.login.isEmpty() -> "Please enter a login"
data.password.isEmpty() -> "Please enter a password"
- throwable != null -> stringResource(id = ElementR.string.auth_invalid_login_param)
+ throwable != null -> stringResource(id = StringR.string.auth_invalid_login_param)
else -> "No error provided"
}
}
@@ -42,7 +42,7 @@ fun changeServerError(
): String {
return when {
data.isEmpty() -> "Please enter a server URL"
- !data.isValidUrl() -> stringResource(id = ElementR.string.login_error_invalid_home_server)
+ !data.isValidUrl() -> stringResource(id = StringR.string.login_error_invalid_home_server)
throwable != null -> "That server doesn’t seem right. Please check the address."
else -> "No error provided"
}
diff --git a/features/login/src/main/java/io/element/android/x/features/login/root/LoginRootScreen.kt b/features/login/src/main/java/io/element/android/x/features/login/root/LoginRootScreen.kt
index aa7814ccf2..6e0f38886a 100644
--- a/features/login/src/main/java/io/element/android/x/features/login/root/LoginRootScreen.kt
+++ b/features/login/src/main/java/io/element/android/x/features/login/root/LoginRootScreen.kt
@@ -62,7 +62,7 @@ import io.element.android.x.core.compose.textFieldState
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.features.login.error.loginError
import io.element.android.x.matrix.core.SessionId
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -97,7 +97,7 @@ fun LoginRootScreen(
val isError = state.loggedInState is LoggedInState.ErrorLoggingIn
// Title
Text(
- text = stringResource(id = ElementR.string.ftue_auth_welcome_back_title),
+ text = stringResource(id = StringR.string.ftue_auth_welcome_back_title),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 48.dp),
@@ -140,7 +140,7 @@ fun LoginRootScreen(
.fillMaxWidth()
.padding(top = 60.dp),
label = {
- Text(text = stringResource(id = ElementR.string.login_signin_username_hint))
+ Text(text = stringResource(id = StringR.string.login_signin_username_hint))
},
onValueChange = {
loginFieldState = it
diff --git a/features/logout/build.gradle.kts b/features/logout/build.gradle.kts
index c7a28ef2d7..93f9c4f6f2 100644
--- a/features/logout/build.gradle.kts
+++ b/features/logout/build.gradle.kts
@@ -39,6 +39,7 @@ dependencies {
implementation(project(":libraries:matrix"))
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
ksp(libs.showkase.processor)
testImplementation(libs.test.junit)
androidTestImplementation(libs.test.junitext)
diff --git a/features/logout/src/main/java/io/element/android/x/features/logout/LogoutPreferenceScreen.kt b/features/logout/src/main/java/io/element/android/x/features/logout/LogoutPreferenceScreen.kt
index 75f29319dd..18c4e73b1e 100644
--- a/features/logout/src/main/java/io/element/android/x/features/logout/LogoutPreferenceScreen.kt
+++ b/features/logout/src/main/java/io/element/android/x/features/logout/LogoutPreferenceScreen.kt
@@ -30,7 +30,7 @@ import io.element.android.x.designsystem.components.ProgressDialog
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.x.designsystem.components.preferences.PreferenceCategory
import io.element.android.x.designsystem.components.preferences.PreferenceText
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun LogoutPreferenceView(
@@ -55,9 +55,9 @@ fun LogoutPreferenceView(
// Log out confirmation dialog
if (openDialog.value) {
ConfirmationDialog(
- title = stringResource(id = ElementR.string.action_sign_out),
- content = stringResource(id = ElementR.string.action_sign_out_confirmation_simple),
- submitText = stringResource(id = ElementR.string.action_sign_out),
+ title = stringResource(id = StringR.string.action_sign_out),
+ content = stringResource(id = StringR.string.action_sign_out_confirmation_simple),
+ submitText = stringResource(id = StringR.string.action_sign_out),
onCancelClicked = {
openDialog.value = false
},
@@ -80,9 +80,9 @@ fun LogoutPreferenceView(
fun LogoutPreferenceContent(
onClick: () -> Unit = {},
) {
- PreferenceCategory(title = stringResource(id = ElementR.string.settings_general_title)) {
+ PreferenceCategory(title = stringResource(id = StringR.string.settings_general_title)) {
PreferenceText(
- title = stringResource(id = ElementR.string.action_sign_out),
+ title = stringResource(id = StringR.string.action_sign_out),
icon = Icons.Default.Logout,
onClick = onClick
)
diff --git a/features/onboarding/build.gradle.kts b/features/onboarding/build.gradle.kts
index 4c25a25ea3..cdb646417a 100644
--- a/features/onboarding/build.gradle.kts
+++ b/features/onboarding/build.gradle.kts
@@ -28,6 +28,7 @@ android {
dependencies {
implementation(project(":libraries:core"))
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:architecture"))
implementation(libs.accompanist.pager)
diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt
index f6e0ed0db4..fb88a76db0 100644
--- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt
+++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt
@@ -52,7 +52,7 @@ import com.google.accompanist.pager.rememberPagerState
import io.element.android.x.designsystem.components.VectorButton
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@OptIn(ExperimentalPagerApi::class)
@Composable
@@ -120,7 +120,7 @@ fun OnBoardingScreen(
)
*/
VectorButton(
- text = stringResource(id = ElementR.string.login_splash_submit),
+ text = stringResource(id = StringR.string.login_splash_submit),
onClick = {
onSignIn()
},
diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt
index d12f83cfbe..c25fb89815 100644
--- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt
+++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt
@@ -17,7 +17,7 @@
package io.element.android.x.features.onboarding
import androidx.annotation.DrawableRes
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
class SplashCarouselStateFactory {
fun create(): SplashCarouselState {
@@ -32,8 +32,8 @@ class SplashCarouselStateFactory {
return SplashCarouselState(
listOf(
SplashCarouselState.Item(
- ElementR.string.ftue_auth_carousel_secure_title,
- ElementR.string.ftue_auth_carousel_secure_body,
+ StringR.string.ftue_auth_carousel_secure_title,
+ StringR.string.ftue_auth_carousel_secure_body,
hero(
R.drawable.ic_splash_conversations,
R.drawable.ic_splash_conversations_dark
@@ -41,20 +41,20 @@ class SplashCarouselStateFactory {
background(R.drawable.bg_carousel_page_1)
),
SplashCarouselState.Item(
- ElementR.string.ftue_auth_carousel_control_title,
- ElementR.string.ftue_auth_carousel_control_body,
+ StringR.string.ftue_auth_carousel_control_title,
+ StringR.string.ftue_auth_carousel_control_body,
hero(R.drawable.ic_splash_control, R.drawable.ic_splash_control_dark),
background(R.drawable.bg_carousel_page_2)
),
SplashCarouselState.Item(
- ElementR.string.ftue_auth_carousel_encrypted_title,
- ElementR.string.ftue_auth_carousel_encrypted_body,
+ StringR.string.ftue_auth_carousel_encrypted_title,
+ StringR.string.ftue_auth_carousel_encrypted_body,
hero(R.drawable.ic_splash_secure, R.drawable.ic_splash_secure_dark),
background(R.drawable.bg_carousel_page_3)
),
SplashCarouselState.Item(
collaborationTitle(),
- ElementR.string.ftue_auth_carousel_workplace_body,
+ StringR.string.ftue_auth_carousel_workplace_body,
hero(
R.drawable.ic_splash_collaboration,
R.drawable.ic_splash_collaboration_dark
@@ -68,7 +68,7 @@ class SplashCarouselStateFactory {
private fun collaborationTitle(): Int {
return when {
true -> R.string.cut_the_slack_from_teams
- else -> ElementR.string.ftue_auth_carousel_workplace_title
+ else -> StringR.string.ftue_auth_carousel_workplace_title
}
}
}
diff --git a/features/preferences/build.gradle.kts b/features/preferences/build.gradle.kts
index 32ad183d13..e8f5147642 100644
--- a/features/preferences/build.gradle.kts
+++ b/features/preferences/build.gradle.kts
@@ -42,6 +42,7 @@ dependencies {
implementation(project(":features:logout"))
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
implementation(libs.datetime)
implementation(libs.accompanist.placeholder)
testImplementation(libs.test.junit)
diff --git a/features/preferences/src/main/java/io/element/android/x/features/preferences/root/PreferencesRootView.kt b/features/preferences/src/main/java/io/element/android/x/features/preferences/root/PreferencesRootView.kt
index 95049803a3..5d3e1dab7b 100644
--- a/features/preferences/src/main/java/io/element/android/x/features/preferences/root/PreferencesRootView.kt
+++ b/features/preferences/src/main/java/io/element/android/x/features/preferences/root/PreferencesRootView.kt
@@ -22,12 +22,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.x.architecture.Async
import io.element.android.x.designsystem.components.preferences.PreferenceView
-import io.element.android.x.element.resources.R
import io.element.android.x.features.logout.LogoutPreferenceState
import io.element.android.x.features.logout.LogoutPreferenceView
import io.element.android.x.features.preferences.user.UserPreferences
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesState
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesView
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun PreferencesRootView(
@@ -41,7 +41,7 @@ fun PreferencesRootView(
PreferenceView(
modifier = modifier,
onBackPressed = onBackPressed,
- title = stringResource(id = R.string.settings)
+ title = stringResource(id = StringR.string.settings)
) {
UserPreferences(state.myUser)
RageshakePreferencesView(
diff --git a/features/rageshake/build.gradle.kts b/features/rageshake/build.gradle.kts
index 92f9b75aaa..b3f8b14ded 100644
--- a/features/rageshake/build.gradle.kts
+++ b/features/rageshake/build.gradle.kts
@@ -39,6 +39,7 @@ dependencies {
implementation(project(":anvilannotations"))
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
implementation(libs.squareup.seismic)
implementation(libs.androidx.datastore.preferences)
implementation(libs.coil)
diff --git a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/bugreport/BugReportView.kt b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/bugreport/BugReportView.kt
index 394cf69a5b..b22cc7c48c 100644
--- a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/bugreport/BugReportView.kt
+++ b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/bugreport/BugReportView.kt
@@ -56,7 +56,7 @@ import io.element.android.x.core.compose.textFieldState
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.designsystem.components.LabelledCheckbox
import io.element.android.x.designsystem.components.dialogs.ErrorDialog
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -96,7 +96,7 @@ fun BugReportView(
val isFormEnabled = state.sending !is Async.Loading
// Title
Text(
- text = stringResource(id = ElementR.string.send_bug_report),
+ text = stringResource(id = StringR.string.send_bug_report),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp),
@@ -106,7 +106,7 @@ fun BugReportView(
)
// Form
Text(
- text = stringResource(id = ElementR.string.send_bug_report_description),
+ text = stringResource(id = StringR.string.send_bug_report_description),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp),
@@ -123,10 +123,10 @@ fun BugReportView(
.padding(top = 16.dp),
enabled = isFormEnabled,
label = {
- Text(text = stringResource(id = ElementR.string.send_bug_report_placeholder))
+ Text(text = stringResource(id = StringR.string.send_bug_report_placeholder))
},
supportingText = {
- Text(text = stringResource(id = ElementR.string.send_bug_report_description_in_english))
+ Text(text = stringResource(id = StringR.string.send_bug_report_description_in_english))
},
onValueChange = {
descriptionFieldState = it
@@ -143,28 +143,28 @@ fun BugReportView(
checked = state.formState.sendLogs,
onCheckedChange = { eventSink(BugReportEvents.SetSendLog(it)) },
enabled = isFormEnabled,
- text = stringResource(id = ElementR.string.send_bug_report_include_logs)
+ text = stringResource(id = StringR.string.send_bug_report_include_logs)
)
if (state.hasCrashLogs) {
LabelledCheckbox(
checked = state.formState.sendCrashLogs,
onCheckedChange = { eventSink(BugReportEvents.SetSendCrashLog(it)) },
enabled = isFormEnabled,
- text = stringResource(id = ElementR.string.send_bug_report_include_crash_logs)
+ text = stringResource(id = StringR.string.send_bug_report_include_crash_logs)
)
}
LabelledCheckbox(
checked = state.formState.canContact,
onCheckedChange = { eventSink(BugReportEvents.SetCanContact(it)) },
enabled = isFormEnabled,
- text = stringResource(id = ElementR.string.you_may_contact_me)
+ text = stringResource(id = StringR.string.you_may_contact_me)
)
if (state.screenshotUri != null) {
LabelledCheckbox(
checked = state.formState.sendScreenshot,
onCheckedChange = { eventSink(BugReportEvents.SetSendScreenshot(it)) },
enabled = isFormEnabled,
- text = stringResource(id = ElementR.string.send_bug_report_include_screenshot)
+ text = stringResource(id = StringR.string.send_bug_report_include_screenshot)
)
if (state.formState.sendScreenshot) {
Box(
@@ -191,7 +191,7 @@ fun BugReportView(
.fillMaxWidth()
.padding(vertical = 32.dp)
) {
- Text(text = stringResource(id = ElementR.string.action_send))
+ Text(text = stringResource(id = StringR.string.action_send))
}
}
when (state.sending) {
diff --git a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/crash/ui/CrashDetectionScreen.kt b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/crash/ui/CrashDetectionScreen.kt
index 7c1e855455..13d174468b 100644
--- a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/crash/ui/CrashDetectionScreen.kt
+++ b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/crash/ui/CrashDetectionScreen.kt
@@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.Preview
import io.element.android.x.core.compose.LogCompositions
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun CrashDetectionView(
@@ -53,10 +53,10 @@ fun CrashDetectionContent(
onDismiss: () -> Unit = { },
) {
ConfirmationDialog(
- title = stringResource(id = ElementR.string.send_bug_report),
- content = stringResource(id = ElementR.string.send_bug_report_app_crashed),
- submitText = stringResource(id = ElementR.string.yes),
- cancelText = stringResource(id = ElementR.string.no),
+ title = stringResource(id = StringR.string.send_bug_report),
+ content = stringResource(id = StringR.string.send_bug_report_app_crashed),
+ submitText = stringResource(id = StringR.string.yes),
+ cancelText = stringResource(id = StringR.string.no),
onCancelClicked = onNoClicked,
onSubmitClicked = onYesClicked,
onDismiss = onDismiss,
diff --git a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/detection/RageshakeDetectionView.kt b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/detection/RageshakeDetectionView.kt
index 61e9f32150..6f647758ce 100644
--- a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/detection/RageshakeDetectionView.kt
+++ b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/detection/RageshakeDetectionView.kt
@@ -30,7 +30,7 @@ import io.element.android.x.core.screenshot.ImageResult
import io.element.android.x.core.screenshot.screenshot
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun RageshakeDetectionView(
@@ -83,11 +83,11 @@ fun RageshakeDialogContent(
onYesClicked: () -> Unit = { },
) {
ConfirmationDialog(
- title = stringResource(id = ElementR.string.send_bug_report),
- content = stringResource(id = ElementR.string.send_bug_report_alert_message),
- thirdButtonText = stringResource(id = ElementR.string.action_disable),
- submitText = stringResource(id = ElementR.string.yes),
- cancelText = stringResource(id = ElementR.string.no),
+ title = stringResource(id = StringR.string.send_bug_report),
+ content = stringResource(id = StringR.string.send_bug_report_alert_message),
+ thirdButtonText = stringResource(id = StringR.string.action_disable),
+ submitText = stringResource(id = StringR.string.yes),
+ cancelText = stringResource(id = StringR.string.no),
onCancelClicked = onNoClicked,
onThirdButtonClicked = onDisableClicked,
onSubmitClicked = onYesClicked,
diff --git a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/preferences/RageshakePreferencesView.kt b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/preferences/RageshakePreferencesView.kt
index e9142a2c2e..f5ce13440e 100644
--- a/features/rageshake/src/main/java/io/element/android/x/features/rageshake/preferences/RageshakePreferencesView.kt
+++ b/features/rageshake/src/main/java/io/element/android/x/features/rageshake/preferences/RageshakePreferencesView.kt
@@ -27,7 +27,7 @@ import io.element.android.x.designsystem.components.preferences.PreferenceCatego
import io.element.android.x.designsystem.components.preferences.PreferenceSlide
import io.element.android.x.designsystem.components.preferences.PreferenceSwitch
import io.element.android.x.designsystem.components.preferences.PreferenceText
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun RageshakePreferencesView(
@@ -44,24 +44,23 @@ fun RageshakePreferencesView(
}
Column(modifier = modifier) {
- PreferenceCategory(title = stringResource(id = ElementR.string.send_bug_report)) {
+ PreferenceCategory(title = stringResource(id = StringR.string.send_bug_report)) {
PreferenceText(
- title = stringResource(id = ElementR.string.send_bug_report),
+ title = stringResource(id = StringR.string.send_bug_report),
icon = Icons.Default.BugReport,
onClick = onOpenRageshake
)
}
-
- PreferenceCategory(title = stringResource(id = ElementR.string.settings_rageshake)) {
+ PreferenceCategory(title = stringResource(id = StringR.string.settings_rageshake)) {
if (state.isSupported) {
PreferenceSwitch(
- title = stringResource(id = ElementR.string.send_bug_report_rage_shake),
+ title = stringResource(id = StringR.string.send_bug_report_rage_shake),
isChecked = state.isEnabled,
onCheckedChange = ::onEnabledChanged
)
PreferenceSlide(
- title = stringResource(id = ElementR.string.settings_rageshake_detection_threshold),
- // summary = stringResource(id = ElementR.string.settings_rageshake_detection_threshold_summary),
+ title = stringResource(id = StringR.string.settings_rageshake_detection_threshold),
+ // summary = stringResource(id = StringR.string.settings_rageshake_detection_threshold_summary),
value = state.sensitivity,
enabled = state.isEnabled,
steps = 3 /* 5 possible values - steps are in ]0, 1[ */,
diff --git a/features/roomlist/build.gradle.kts b/features/roomlist/build.gradle.kts
index 674ec25d88..646d2175c4 100644
--- a/features/roomlist/build.gradle.kts
+++ b/features/roomlist/build.gradle.kts
@@ -41,6 +41,7 @@ dependencies {
implementation(project(":libraries:designsystem"))
implementation(libs.appyx.core)
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
implementation(libs.datetime)
implementation(libs.accompanist.placeholder)
testImplementation(libs.test.junit)
diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt
index a6db83f09d..d8fe56142b 100644
--- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt
+++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt
@@ -48,6 +48,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
@@ -55,6 +56,7 @@ import io.element.android.x.core.compose.LogCompositions
import io.element.android.x.core.compose.textFieldState
import io.element.android.x.designsystem.components.avatar.Avatar
import io.element.android.x.matrix.ui.model.MatrixUser
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun RoomListTopBar(
@@ -185,7 +187,7 @@ private fun DefaultRoomListTopBar(
title = {
Text(
fontWeight = FontWeight.Bold,
- text = "All Chats"
+ text = stringResource(id = StringR.string.all_chats)
)
},
navigationIcon = {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0a936ed73c..44c3f89979 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -51,6 +51,7 @@ jsoup = "1.15.3"
appyx = "1.0.1"
seismic = "1.0.3"
dependencycheck = "7.4.4"
+stem = "2.2.3"
# DI
dagger = "2.43"
@@ -150,3 +151,5 @@ ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
molecule = {id = "app.cash.molecule", version.ref = "molecule"}
dependencygraph = { id = "com.savvasdalkitsis.module-dependency-graph", version.ref = "dependencygraph" }
dependencycheck = { id = "org.owasp.dependencycheck", version.ref = "dependencycheck" }
+stem = { id = "com.likethesalad.stem", version.ref = "stem" }
+stemlibrary = { id = "com.likethesalad.stem-library", version.ref = "stem" }
diff --git a/libraries/designsystem/build.gradle.kts b/libraries/designsystem/build.gradle.kts
index 9c70a68b4b..597d8a4514 100644
--- a/libraries/designsystem/build.gradle.kts
+++ b/libraries/designsystem/build.gradle.kts
@@ -29,6 +29,7 @@ android {
implementation(libs.coil.compose)
implementation(libs.accompanist.systemui)
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
ksp(libs.showkase.processor)
}
}
diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt
index 349ec32f41..9d74a2da87 100644
--- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt
+++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt
@@ -29,15 +29,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun ConfirmationDialog(
title: String,
content: String,
modifier: Modifier = Modifier,
- submitText: String = stringResource(id = ElementR.string.ok),
- cancelText: String = stringResource(id = ElementR.string.action_cancel),
+ submitText: String = stringResource(id = StringR.string.ok),
+ cancelText: String = stringResource(id = StringR.string.action_cancel),
thirdButtonText: String? = null,
onSubmitClicked: () -> Unit = {},
onCancelClicked: () -> Unit = {},
diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ErrorDialog.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ErrorDialog.kt
index b46f3104a7..241d47fe9f 100644
--- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ErrorDialog.kt
+++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ErrorDialog.kt
@@ -28,14 +28,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun ErrorDialog(
content: String,
modifier: Modifier = Modifier,
- title: String = stringResource(id = ElementR.string.dialog_title_error),
- submitText: String = stringResource(id = ElementR.string.ok),
+ title: String = stringResource(id = StringR.string.dialog_title_error),
+ submitText: String = stringResource(id = StringR.string.ok),
onDismiss: () -> Unit = {},
) {
AlertDialog(
diff --git a/libraries/textcomposer/build.gradle.kts b/libraries/textcomposer/build.gradle.kts
index cda96fb319..41cc543ba2 100644
--- a/libraries/textcomposer/build.gradle.kts
+++ b/libraries/textcomposer/build.gradle.kts
@@ -31,6 +31,7 @@ android {
dependencies {
implementation(project(":libraries:elementresources"))
+ implementation(project(":libraries:ui-strings"))
implementation(project(":libraries:core"))
implementation(project(":libraries:matrix"))
implementation(libs.wysiwyg)
diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt
index eb51388ca3..7eb8d5dcda 100644
--- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt
+++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt
@@ -45,12 +45,13 @@ import io.element.android.wysiwyg.inputhandlers.models.InlineFormat
import io.element.android.x.core.ui.DimensionConverter
import io.element.android.x.core.ui.hideKeyboard
import io.element.android.x.core.ui.showKeyboard
-import io.element.android.x.element.resources.R as ElementR
import io.element.android.x.textcomposer.databinding.ComposerRichTextLayoutBinding
import io.element.android.x.textcomposer.databinding.ViewRichTextMenuButtonBinding
import io.element.android.x.textcomposer.tools.setTextIfDifferent
import uniffi.wysiwyg_composer.ActionState
import uniffi.wysiwyg_composer.ComposerAction
+import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
// Imported from Element Android
class RichTextComposerLayout @JvmOverloads constructor(
@@ -248,28 +249,28 @@ class RichTextComposerLayout @JvmOverloads constructor(
private fun setupRichTextMenu() {
addRichTextMenuItem(
R.drawable.ic_composer_bold,
- ElementR.string.rich_text_editor_format_bold,
+ StringR.string.rich_text_editor_format_bold,
ComposerAction.BOLD
) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Bold)
}
addRichTextMenuItem(
R.drawable.ic_composer_italic,
- ElementR.string.rich_text_editor_format_italic,
+ StringR.string.rich_text_editor_format_italic,
ComposerAction.ITALIC
) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Italic)
}
addRichTextMenuItem(
R.drawable.ic_composer_underlined,
- ElementR.string.rich_text_editor_format_underline,
+ StringR.string.rich_text_editor_format_underline,
ComposerAction.UNDERLINE
) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Underline)
}
addRichTextMenuItem(
R.drawable.ic_composer_strikethrough,
- ElementR.string.rich_text_editor_format_strikethrough,
+ StringR.string.rich_text_editor_format_strikethrough,
ComposerAction.STRIKE_THROUGH
) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.StrikeThrough)
@@ -495,16 +496,16 @@ class RichTextComposerLayout @JvmOverloads constructor(
*/
views.plainTextComposerEditText.setText(text)
}
- views.sendButton.contentDescription = resources.getString(ElementR.string.action_send)
+ views.sendButton.contentDescription = resources.getString(StringR.string.action_send)
hasRelatedMessage = false
}
views.sendButton.apply {
if (mode is MessageComposerMode.Edit) {
- contentDescription = resources.getString(ElementR.string.action_save)
+ contentDescription = resources.getString(StringR.string.action_save)
setImageResource(R.drawable.ic_composer_rich_text_save)
} else {
- contentDescription = resources.getString(ElementR.string.action_send)
+ contentDescription = resources.getString(StringR.string.action_send)
setImageResource(R.drawable.ic_rich_composer_send)
}
}
diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt
index d7a5788c68..8bb7aea485 100644
--- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt
+++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt
@@ -34,7 +34,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
-import io.element.android.x.element.resources.R as ElementR
+import io.element.android.x.ui.strings.R as StringR
@Composable
fun TextComposer(
@@ -137,7 +137,7 @@ private fun MessageComposerView.setup(isDarkMode: Boolean, composerMode: Message
}
editText.setTextColor(editTextColor)
editText.setHintTextColor(editTextColor)
- editText.setHint(ElementR.string.room_message_placeholder)
+ editText.setHint(StringR.string.room_message_placeholder)
emojiButton?.isVisible = true
sendButton.isVisible = true
editText.maxLines = MessageComposerView.MAX_LINES_WHEN_COLLAPSED
diff --git a/libraries/ui-strings/build.gradle.kts b/libraries/ui-strings/build.gradle.kts
new file mode 100644
index 0000000000..dc4693ad7f
--- /dev/null
+++ b/libraries/ui-strings/build.gradle.kts
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
+@Suppress("DSL_SCOPE_VIOLATION")
+plugins {
+ id("io.element.android-library")
+ alias(libs.plugins.stemlibrary)
+}
+
+android {
+ namespace = "io.element.android.x.ui.strings"
+}
+
+// forcing the stem string template generator to be cacheable, without this the templates
+// are regenerated causing the app module to recompile its sources
+tasks.withType(com.likethesalad.android.templates.common.tasks.BaseTask::class.java) {
+ outputs.cacheIf { true }
+}
diff --git a/libraries/ui-strings/src/main/AndroidManifest.xml b/libraries/ui-strings/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..8072ee00db
--- /dev/null
+++ b/libraries/ui-strings/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/libraries/ui-strings/src/main/res/values/array.xml b/libraries/ui-strings/src/main/res/values/array.xml
new file mode 100644
index 0000000000..26f7a39bf1
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values/array.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+ - @string/compression_opt_list_choose
+ - @string/compression_opt_list_original
+ - @string/compression_opt_list_large
+ - @string/compression_opt_list_medium
+ - @string/compression_opt_list_small
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+
+
+ - @string/media_source_choose
+ - @string/option_send_files
+ - @string/option_send_voice
+ - @string/option_send_sticker
+ - @string/option_take_photo
+ - @string/option_take_video
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+
+
+
+
+
+
+ - @string/system_theme
+ - @string/light_theme
+ - @string/dark_theme
+ - @string/black_theme
+
+
+
+ - system
+ - light
+ - dark
+ - black
+
+
+
+
+ - @string/media_saving_period_3_days
+ - @string/media_saving_period_1_week
+ - @string/media_saving_period_1_month
+ - @string/media_saving_period_forever
+
+
+
\ No newline at end of file
diff --git a/libraries/ui-strings/src/main/res/values/donottranslate.xml b/libraries/ui-strings/src/main/res/values/donottranslate.xml
new file mode 100755
index 0000000000..bfe751ef5a
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values/donottranslate.xml
@@ -0,0 +1,15 @@
+
+
+
+ …
+ –
+
+
+ Not implemented yet in ${app_name}
+
+
+ Cut the slack from teams.
+
+
+ © MapTiler © OpenStreetMap contributors
+
diff --git a/libraries/elementresources/src/main/res/values/strings.xml b/libraries/ui-strings/src/main/res/values/strings.xml
similarity index 94%
rename from libraries/elementresources/src/main/res/values/strings.xml
rename to libraries/ui-strings/src/main/res/values/strings.xml
index f257482aef..73cb60bb68 100644
--- a/libraries/elementresources/src/main/res/values/strings.xml
+++ b/libraries/ui-strings/src/main/res/values/strings.xml
@@ -1,20 +1,4 @@
-
-
@@ -150,6 +134,9 @@
** Unable to decrypt: %s **
The sender\'s device has not sent us the keys for this message.
+ %1$s ended a voice broadcast.
+ You ended a voice broadcast.
+
@@ -209,7 +196,7 @@
Initial sync:\nImporting account data
Initial sync request
- ElementX needs to perform a clear cache to be up to date, for the following reason:\n%s\n\nNote that this action will restart the app and it may take some time.
+ ${app_name} needs to perform a clear cache to be up to date, for the following reason:\n%s\n\nNote that this action will restart the app and it may take some time.
- Some users have been unignored
Message sent
@@ -432,6 +419,7 @@
Got it
Select all
Deselect all
+ Yes, Stop
Copied to clipboard
@@ -537,8 +525,8 @@
Are you sure that you want to start a voice call?
Are you sure that you want to start a video call?
-
- ElementX Call Failed
+
+ ${app_name} Call Failed
Failed to establish real time connection.\nPlease ask the administrator of your homeserver to configure a TURN server in order for calls to work reliably.
Select Sound Device
@@ -600,8 +588,8 @@
Re-request encryption keys from your other sessions.
-
- Please launch ElementX on another device that can decrypt the message so it can send the keys to this session.
+
+ Please launch ${app_name} on another device that can decrypt the message so it can send the keys to this session.
@@ -621,8 +609,8 @@
Calls
Prevent accidental call
Ask for confirmation before starting a call
-
- Use default ElementX ringtone for incoming calls
+
+ Use default ${app_name} ringtone for incoming calls
Incoming call ringtone
Select ringtone for calls:
@@ -659,12 +647,12 @@
Information
-
- ElementX needs permission to access your microphone to perform audio calls.
-
- ElementX needs permission to access your camera and your microphone to perform video calls.\n\nPlease allow access on the next pop-ups to be able to make the call.
-
- ElementX needs permission to display notifications. Notifications can display your messages, your invitations, etc.\n\nPlease allow access on the next pop-ups to be able to view notification.
+
+ ${app_name} needs permission to access your microphone to perform audio calls.
+
+ ${app_name} needs permission to access your camera and your microphone to perform video calls.\n\nPlease allow access on the next pop-ups to be able to make the call.
+
+ ${app_name} needs permission to display notifications. Notifications can display your messages, your invitations, etc.\n\nPlease allow access on the next pop-ups to be able to view notification.
To scan a QR code, you need to allow camera access.
Allow permission to access your contacts.
@@ -884,7 +872,7 @@
System Settings.
Notifications are enabled in the system settings.
Notifications are disabled in the system settings.\nPlease check system settings.
- ElementX needs the permission to show notifications.\nPlease grant the permission.
+ ${app_name} needs the permission to show notifications.\nPlease grant the permission.
Open Settings
Grant Permission
@@ -895,8 +883,8 @@
Session Settings.
Notifications are enabled for this session.
-
- Notifications are not enabled for this session.\nPlease check the ElementX settings.
+
+ Notifications are not enabled for this session.\nPlease check the ${app_name} settings.
Enable
Custom Settings.
@@ -905,19 +893,19 @@
Play Services Check
Google Play Services APK is available and up-to-date.
-
- ElementX uses Google Play Services to deliver push messages but it doesn’t seem to be configured correctly:\n%1$s
+
+ ${app_name} uses Google Play Services to deliver push messages but it doesn’t seem to be configured correctly:\n%1$s
Fix Play Services
Firebase Token
FCM token successfully retrieved:\n%1$s
Failed to retrieved FCM token:\n%1$s
-
- [%1$s]\nThis error is out of control of ElementX and according to Google, this error indicates that the device has too many apps registered with FCM. The error only occurs in cases where there are extreme numbers of apps, so it should not affect the average user.
-
- [%1$s]\nThis error is out of control of ElementX. It can occur for several reasons. Maybe it will work if you retry later, you can also check that Google Play Service is not restricted in data usage in the system settings, or that your device clock is correct, or it can happen on custom ROM.
-
- [%1$s]\nThis error is out of control of ElementX. There is no Google account on the phone. Please open the account manager and add a Google account.
+
+ [%1$s]\nThis error is out of control of ${app_name} and according to Google, this error indicates that the device has too many apps registered with FCM. The error only occurs in cases where there are extreme numbers of apps, so it should not affect the average user.
+
+ [%1$s]\nThis error is out of control of ${app_name}. It can occur for several reasons. Maybe it will work if you retry later, you can also check that Google Play Service is not restricted in data usage in the system settings, or that your device clock is correct, or it can happen on custom ROM.
+
+ [%1$s]\nThis error is out of control of ${app_name}. There is no Google account on the phone. Please open the account manager and add a Google account.
Add Account
Token Registration
@@ -939,20 +927,20 @@
Start on boot
Service will start when the device is restarted.
-
- The service will not start when the device is restarted, you will not receive notifications until ElementX has been opened once.
+
+ The service will not start when the device is restarted, you will not receive notifications until ${app_name} has been opened once.
Enable Start on boot
Check background restrictions
-
- Background restrictions are disabled for ElementX. This test should be run using mobile data (no WIFI).\n%1$s
-
- Background restrictions are enabled for ElementX.\nWork that the app tries to do will be aggressively restricted while it is in the background, and this could affect notifications.\n%1$s
+
+ Background restrictions are disabled for ${app_name}. This test should be run using mobile data (no WIFI).\n%1$s
+
+ Background restrictions are enabled for ${app_name}.\nWork that the app tries to do will be aggressively restricted while it is in the background, and this could affect notifications.\n%1$s
Disable restrictions
Battery Optimization
-
- ElementX is not affected by Battery Optimization.
+
+ ${app_name} is not affected by Battery Optimization.
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode. This prevents apps from accessing the network and defers their jobs, syncs, and standard alarms.
Ignore Optimization
@@ -992,11 +980,11 @@
Background synchronization
Background Sync Mode
Optimized for battery
-
- ElementX will sync in background in way that preserves the device’s limited resources (battery).\nDepending on your device resource state, the sync may be deferred by the operating system.
+
+ ${app_name} will sync in background in way that preserves the device’s limited resources (battery).\nDepending on your device resource state, the sync may be deferred by the operating system.
Optimized for real time
-
- ElementX will sync in background periodically at precise time (configurable).\nThis will impact radio and battery usage, there will be a permanent notification displayed stating that ElementX is listening for events.
+
+ ${app_name} will sync in background periodically at precise time (configurable).\nThis will impact radio and battery usage, there will be a permanent notification displayed stating that ${app_name} is listening for events.
No background sync
You will not be notified of incoming messages when the app is in background.
@@ -1048,6 +1036,8 @@
Use /confetti command or send a message containing ❄️ or 🎉
Autoplay animated images
Play animated images in the timeline as soon as they are visible
+ Enable direct share
+ Show recent chats in the system share menu
Show join and leave events
Invites, removes, and bans are unaffected.
Show account events
@@ -1075,12 +1065,12 @@
Analytics
Send analytics data
-
- ElementX collects anonymous analytics to allow us to improve the application.
+
+ ${app_name} collects anonymous analytics to allow us to improve the application.
- Help improve ElementX
+ Help improve ${app_name}
- Help us identify issues and improve ElementX by sharing anonymous usage data. To understand how people use multiple devices, we’ll generate a random identifier, shared by your devices.\n\nYou can read all our terms %s.
+ Help us identify issues and improve ${app_name} by sharing anonymous usage data. To understand how people use multiple devices, we’ll generate a random identifier, shared by your devices.\n\nYou can read all our terms %s.
here
We don\'t record or profile any account data
We don\'t share information with third parties
@@ -1099,7 +1089,7 @@
Allow integrations
Integration manager
- ElementX policy
+ ${app_name} policy
Your homeserver policy
Your identity server policy
Third party libraries
@@ -1520,8 +1510,8 @@
-
- Please delete the passphrase if you want ElementX to generate a recovery key.
+
+ Please delete the passphrase if you want ${app_name} to generate a recovery key.
Never lose encrypted messages
Messages in encrypted rooms are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.\n\nSecurely back up your keys to avoid losing them.
@@ -1658,7 +1648,10 @@
It looks like you’re trying to connect to another homeserver. Do you want to sign out?
Edit
+ Editing
Reply
+ Replying to %s
+ Quoting
Reply in thread
View In Room
@@ -1695,7 +1688,8 @@
Create New Room
Create New Space
No network. Please check your Internet connection.
- Something went wrong. Please check your network connection and try again.
+
+ Something went wrong. Please check your network connection and try again.
"Change network"
"Please wait…"
Updating your data…
@@ -1751,7 +1745,7 @@
Help
Help and support
- Get help with using ElementX
+ Get help with using ${app_name}
Versions
System settings
@@ -1980,8 +1974,8 @@
Secure and independent communication that gives you the same level of privacy as a face-to-face conversation in your own home.
Choose where your conversations are kept, giving you control and independence. Connected via Matrix.
End-to-end encrypted and no phone number required. No ads or datamining.
-
- ElementX is also great for the workplace. It’s trusted by the world’s most secure organisations.
+
+ ${app_name} is also great for the workplace. It’s trusted by the world’s most secure organisations.
Who will you chat to the most?
We\'ll help you get connected
@@ -2230,8 +2224,8 @@
Clear data
Clear all data currently stored on this device?\nSign in again to access your account data and messages.
You’ll lose access to secure messages unless you sign in to recover your encryption keys.
-
- The current session is for user %1$s and you provide credentials for user %2$s. This is not supported by ElementX.\nPlease first clear data, then sign in again on another account.
+
+ The current session is for user %1$s and you provide credentials for user %2$s. This is not supported by ${app_name}.\nPlease first clear data, then sign in again on another account.
Your matrix.to link was malformed
Cannot open this link: communities have been replaced by spaces
@@ -2253,8 +2247,8 @@
Showing only the first results, type more letters…
Fail-fast
-
- ElementX may crash more often when an unexpected error occurs
+
+ ${app_name} may crash more often when an unexpected error occurs
Show debug info on screen
Show some useful info to help debugging the application
@@ -2362,10 +2356,10 @@
Direct message
Jump to read receipt
-
- ElementX does not handle events of type \'%1$s\'
-
- ElementX encountered an issue when rendering content of event with id \'%1$s\'
+
+ ${app_name} does not handle events of type \'%1$s\'
+
+ ${app_name} encountered an issue when rendering content of event with id \'%1$s\'
Unignore
@@ -2491,12 +2485,15 @@
Keys are already up to date!
-
- ElementX Android
+
+ ${app_name} Android
Key Requests
Export Audit
+ Nightly build
+ Get the latest build (note: you may have trouble to sign in)
+
Unlock encrypted messages history
Refresh
@@ -2623,15 +2620,15 @@
Could not save media file
Set a new account password…
-
- Use the latest ElementX on your other devices, ElementX Web, ElementX Desktop, ElementX iOS, ElementX for Android, or another cross-signing capable Matrix client
-
- ElementX Web\nElementX Desktop
-
- ElementX iOS\nElementX Android
+
+ Use the latest ${app_name} on your other devices, ${app_name} Web, ${app_name} Desktop, ${app_name} iOS, ${app_name} for Android, or another cross-signing capable Matrix client
+
+ ${app_name} Web\n${app_name} Desktop
+
+ ${app_name} iOS\n${app_name} Android
or another cross-signing capable Matrix client
-
- Use the latest ElementX on your other devices:
+
+ Use the latest ${app_name} on your other devices:
Forces the current outbound group session in an encrypted room to be discarded
Only supported in encrypted rooms
@@ -2659,8 +2656,12 @@
Unencrypted
Encrypted by an unverified device
The authenticity of this encrypted message can\'t be guaranteed on this device.
- Review where you’re logged in
- Verify all your sessions to ensure your account & messages are safe
+
+ Review where you’re logged in
+
+ Verify all your sessions to ensure your account & messages are safe
+ You have unverified sessions
+ Review to ensure your account is safe
Verify the new login accessing your account: %1$s
@@ -2686,10 +2687,10 @@
Inviting users…
Invite Users
Invite friends
-
- Hey, talk to me on ElementX: %s
-
- 🔐️ Join me on ElementX
+
+ Hey, talk to me on ${app_name}: %s
+
+ 🔐️ Join me on ${app_name}
Invitation sent to %1$s
Invitations sent to %1$s and %2$s
"It's not a valid matrix QR code"
@@ -2710,13 +2711,13 @@
Open terms of %s
Disconnect from the identity server %s?
-
- This identity server is outdated. ElementX support only API V2.
+
+ This identity server is outdated. ${app_name} support only API V2.
This operation is not possible. The homeserver is outdated.
Please first configure an identity server.
Please first accepts the terms of the identity server in the settings.
-
- For your privacy, ElementX only supports sending hashed user email addresses and phone numbers.
+
+ For your privacy, ${app_name} only supports sending hashed user email addresses and phone numbers.
The association has failed.
There is no current association with this identifier.
The user consent has not been provided.
@@ -2810,17 +2811,17 @@
If you want to reset your PIN, tap Forgot PIN to logout and reset.
Enable biometrics
Enable device specific biometrics, like fingerprints and face recognition.
-
- PIN code is the only way to unlock ElementX.
+
+ PIN code is the only way to unlock ${app_name}.
Could not enable biometric authentication.
Show content in notifications
Show details like room names and message content.
Only display number of unread messages in a simple notification.
Require PIN after 2 minutes
-
- PIN code is required after 2 minutes of not using ElementX.
-
- PIN code is required every time you open ElementX.
+
+ PIN code is required after 2 minutes of not using ${app_name}.
+
+ PIN code is required every time you open ${app_name}.
Change PIN
Change your current PIN
Can\'t open a room where you are banned from.
@@ -2879,8 +2880,8 @@
Slide to end the call
Re-Authentication Needed
-
- ElementX requires you to enter your credentials to perform this action.
+
+ ${app_name} requires you to enter your credentials to perform this action.
Failed to authenticate
Screenshot
@@ -3035,7 +3036,7 @@
Auto Report Decryption Errors.
Your system will automatically send logs when an unable to decrypt error occurs
- Enable Thread Messages
+ Enable threaded messages
Note: app will be restarted
Show latest user info
Show the latest profile info (avatar and display name) for all the messages.
@@ -3104,18 +3105,24 @@
(%1$s)
Live
+ Live broadcast
+
+ Buffering…
Resume voice broadcast record
Pause voice broadcast record
Stop voice broadcast record
Play or resume voice broadcast
Pause voice broadcast
- Buffering
Fast backward 30 seconds
Fast forward 30 seconds
Can’t start a new voice broadcast
You don’t have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.
Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.
You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.
+
+ %1$s left
+ Stop live broadcasting?
+ Are you sure you want to stop your live broadcast? This will end the broadcast and the full recording will be available in the room.
Anyone in %s will be able to find and join this room - no need to manually invite everyone. You’ll be able to change this in room settings anytime.
Anyone in a parent space will be able to find and join this room - no need to manually invite everyone. You’ll be able to change this in room settings anytime.
@@ -3129,7 +3136,7 @@
Link this email address with your account
- %s in Settings to receive invites directly in ElementX.
+ %s in Settings to receive invites directly in ${app_name}.
Enable LaTeX mathematics
Restart the application for the change to take effect.
@@ -3200,8 +3207,8 @@
15 minutes
1 hour
8 hours
- ElementX could not access your location
- ElementX could not access your location. Please try again later.
+ ${app_name} could not access your location
+ ${app_name} could not access your location. Please try again later.
Open with
Failed to load map
Unable to load map\nThis home server may not be configured to display maps.
@@ -3214,7 +3221,7 @@
Stop
%1$s left
- ElementX Live Location
+ ${app_name} Live Location
Location sharing is in progress
Enable Live Location Sharing
Temporary implementation: locations persist in room history
@@ -3257,7 +3264,7 @@
Room notification
- ElementX Screen Sharing
+ ${app_name} Screen Sharing
Screen sharing is in progress
Choose how to receive notifications
@@ -3308,6 +3315,7 @@
Verify your current session for enhanced secure messaging.
Verify or sign out from this session for best security and reliability.
Verify your current session to reveal this session\'s verification status.
+ This session doesn\'t support encryption and thus can\'t be verified.
Verify Session
View Details
View All (%1$d)
@@ -3330,7 +3338,7 @@
- Consider signing out from old sessions (%1$d day or more) that you don’t use anymore.
- Consider signing out from old sessions (%1$d days or more) that you don’t use anymore.
- Current Session
+ Current session
Session
Device
@@ -3361,6 +3369,14 @@
No inactive sessions found.
Clear Filter
Select sessions
+ Sign out
+
+ - Sign out of %1$d session
+ - Sign out of %1$d sessions
+
+ Sign out of all other sessions
+ Show IP address
+ Hide IP address
Sign out of this session
Session details
Application, device, and activity information.
@@ -3389,7 +3405,10 @@
Unverified sessions
Unverified sessions are sessions that have logged in with your credentials but not been cross-verified.\n\nYou should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.
Verified sessions
- Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.
+
+ Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.
+ Verified sessions are anywhere you are using this account after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.
+ This session doesn\'t support encryption, so it can\'t be verified.\n\nYou won\'t be able to participate in rooms where encryption is enabled when using this session.\n\nFor best security and privacy, it is recommended to use Matrix clients that support encryption.
Renaming sessions
Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.
Enable new session manager
@@ -3404,14 +3423,14 @@
Spaces are a new way to group rooms and people. Add an existing room, or create a new one, using the bottom-right button.
- Welcome to ElementX,\n%s.
+ Welcome to ${app_name},\n%s.
The all-in-one secure chat app for teams, friends and organisations. Create a chat, or join an existing room, to get started.
Nothing to report.
This is where your unread messages will show up, when you have some.
Welcome to a new view!
- To simplify your ElementX, tabs are now optional. Manage them using the top-right menu.
+ To simplify your ${app_name}, tabs are now optional. Manage them using the top-right menu.
Access Spaces
Access your Spaces (bottom-right) faster and easier than ever before.
@@ -3460,11 +3479,26 @@
Confirm
Please ensure that you know the origin of this code. By linking devices, you will provide someone with full access to your account.
-
+
Apply bold format
Apply italic format
Apply strikethrough format
Apply underline format
+ Set link
Toggle full screen mode
+ Text
+ Link
+ Create a link
+ Edit link
+
+
+ In reply to
+ sent a file.
+ sent an audio file.
+ sent a voice message.
+ sent an image.
+ sent a video.
+ sent a sticker.
+ created a poll.
diff --git a/libraries/ui-strings/src/main/res/values/strings_no_weblate.xml b/libraries/ui-strings/src/main/res/values/strings_no_weblate.xml
new file mode 100644
index 0000000000..d9650bc797
--- /dev/null
+++ b/libraries/ui-strings/src/main/res/values/strings_no_weblate.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+ en
+ US
+
+ Latn
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 245c0b2402..2e1ed9af84 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -40,6 +40,7 @@ include(":libraries:matrix")
include(":libraries:matrixui")
include(":libraries:textcomposer")
include(":libraries:elementresources")
+include(":libraries:ui-strings")
include(":features:onboarding")
include(":features:login")
include(":features:logout")