feat: i18n + crowdin (#31)
This commit is contained in:
parent
6965f3128b
commit
e7e5193dd2
22 changed files with 315 additions and 160 deletions
42
.github/workflows/crowdin.yml
vendored
Normal file
42
.github/workflows/crowdin.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
name: Sync Crowdin
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- 'app/src/main/res/values/strings.xml'
|
||||||
|
- '.github/workflows/crowdin.yml'
|
||||||
|
schedule:
|
||||||
|
- cron: "0 17 * * 6" # "At 17:00 on Saturday."
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-crowdin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Crowdin
|
||||||
|
uses: crowdin/github-action@1.4.11
|
||||||
|
with:
|
||||||
|
config: crowdin.yml
|
||||||
|
upload_translations: true
|
||||||
|
download_translations: true
|
||||||
|
push_translations: true
|
||||||
|
create_pull_request: false
|
||||||
|
localization_branch_name: l10n
|
||||||
|
commit_message: 'chore(i18n): sync translations'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_ID }}
|
||||||
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
|
||||||
|
|
||||||
|
- name: Merge
|
||||||
|
run: |
|
||||||
|
sudo chmod -R ugo+rwX .
|
||||||
|
git checkout main
|
||||||
|
git add *
|
||||||
|
git merge l10n
|
||||||
|
git push
|
||||||
|
|
@ -7,6 +7,7 @@ import android.os.IBinder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.aliucord.manager.BuildConfig
|
import com.aliucord.manager.BuildConfig
|
||||||
|
import com.aliucord.manager.R
|
||||||
|
|
||||||
class InstallService : Service() {
|
class InstallService : Service() {
|
||||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||||
|
|
@ -21,19 +22,19 @@ class InstallService : Service() {
|
||||||
|
|
||||||
PackageInstaller.STATUS_SUCCESS -> Toast.makeText(
|
PackageInstaller.STATUS_SUCCESS -> Toast.makeText(
|
||||||
this,
|
this,
|
||||||
"Successfully installed Aliucord!",
|
getString(R.string.install_success),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
PackageInstaller.STATUS_FAILURE_ABORTED -> Toast.makeText(
|
PackageInstaller.STATUS_FAILURE_ABORTED -> Toast.makeText(
|
||||||
this,
|
this,
|
||||||
"Aborted installation",
|
getString(R.string.install_aborted),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Log.i(BuildConfig.TAG, "Installation failed: error code $statusCode")
|
Log.i(BuildConfig.TAG, "Install failed with error code $statusCode")
|
||||||
Toast.makeText(this, "Failed: Error $statusCode", Toast.LENGTH_LONG).show()
|
Toast.makeText(this, getString(R.string.install_failed, statusCode), Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ fun ContributorEntry(user: GithubUser) {
|
||||||
style = MaterialTheme.typography.bodyLarge
|
style = MaterialTheme.typography.bodyLarge
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.contributions, user.contributions),
|
text = stringResource(R.string.contributors_contributions, user.contributions),
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ fun LoadFailure(onRetry: () -> Unit) {
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.load_fail),
|
text = stringResource(R.string.network_load_fail),
|
||||||
style = MaterialTheme.typography.labelLarge.copy(fontSize = 16.sp),
|
style = MaterialTheme.typography.labelLarge.copy(fontSize = 16.sp),
|
||||||
color = MaterialTheme.colorScheme.error
|
color = MaterialTheme.colorScheme.error
|
||||||
)
|
)
|
||||||
|
|
@ -30,7 +30,7 @@ fun LoadFailure(onRetry: () -> Unit) {
|
||||||
onClick = onRetry,
|
onClick = onRetry,
|
||||||
shape = MaterialTheme.shapes.extraLarge
|
shape = MaterialTheme.shapes.extraLarge
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.retry))
|
Text(text = stringResource(R.string.action_retry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.*
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
@ -23,6 +23,7 @@ import coil.compose.AsyncImage
|
||||||
import com.aliucord.manager.R
|
import com.aliucord.manager.R
|
||||||
import com.aliucord.manager.network.dto.Commit
|
import com.aliucord.manager.network.dto.Commit
|
||||||
import com.aliucord.manager.ui.component.LoadFailure
|
import com.aliucord.manager.ui.component.LoadFailure
|
||||||
|
import com.aliucord.manager.ui.util.annotatingStringResource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -137,36 +138,27 @@ fun CommitItem(
|
||||||
model = "https://github.com/${commit.author.name}.png",
|
model = "https://github.com/${commit.author.name}.png",
|
||||||
contentDescription = commit.author.name
|
contentDescription = commit.author.name
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
buildAnnotatedString {
|
annotatingStringResource(
|
||||||
withStyle(
|
R.string.contributors_commit_title,
|
||||||
SpanStyle(
|
commit.author.name,
|
||||||
|
commit.sha.take(8)
|
||||||
|
) {
|
||||||
|
when (it) {
|
||||||
|
"name" -> SpanStyle(
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
) {
|
"middle" -> SpanStyle(
|
||||||
append(commit.author.name)
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
}
|
|
||||||
|
|
||||||
withStyle(
|
|
||||||
SpanStyle(
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(
|
|
||||||
alpha = 0.6f
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
) {
|
"commit" -> SpanStyle(
|
||||||
append(" authored ")
|
|
||||||
}
|
|
||||||
|
|
||||||
withStyle(
|
|
||||||
SpanStyle(
|
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
)
|
)
|
||||||
) {
|
else -> null
|
||||||
append(commit.sha.substring(0, 7))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.bodySmall
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.aliucord.manager.ui.component.home
|
package com.aliucord.manager.ui.component.home
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.text.appendInlineContent
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
|
|
@ -18,6 +20,7 @@ import com.aliucord.manager.R
|
||||||
fun InfoCard(
|
fun InfoCard(
|
||||||
packageName: String,
|
packageName: String,
|
||||||
supportedVersion: String,
|
supportedVersion: String,
|
||||||
|
@StringRes supportedVersionType: Int,
|
||||||
currentVersion: String,
|
currentVersion: String,
|
||||||
onDownloadClick: () -> Unit,
|
onDownloadClick: () -> Unit,
|
||||||
onUninstallClick: () -> Unit,
|
onUninstallClick: () -> Unit,
|
||||||
|
|
@ -31,22 +34,25 @@ fun InfoCard(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Aliucord${packageName.let { if (it != "com.aliucord") " ($it)" else "" }}",
|
text = "${stringResource(R.string.aliucord)} ($packageName)",
|
||||||
style = MaterialTheme.typography.titleLarge.copy(fontSize = 23.sp),
|
style = MaterialTheme.typography.titleLarge.copy(fontSize = 23.sp),
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
buildAnnotatedString {
|
buildAnnotatedString {
|
||||||
append("Supported version: ")
|
append(stringResource(R.string.version_supported))
|
||||||
|
|
||||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||||
|
append(" ")
|
||||||
append(supportedVersion)
|
append(supportedVersion)
|
||||||
|
append(" - ")
|
||||||
|
append(stringResource(supportedVersionType))
|
||||||
}
|
}
|
||||||
|
|
||||||
append("\nInstalled version: ")
|
append('\n')
|
||||||
|
append(stringResource(R.string.version_installed))
|
||||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||||
|
append(" ")
|
||||||
append(currentVersion)
|
append(currentVersion)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -61,9 +67,9 @@ fun InfoCard(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val (icon, description) = when (currentVersion) {
|
val (icon, description) = when (currentVersion) {
|
||||||
"-" -> Icons.Default.Download to R.string.install
|
"-" -> Icons.Default.Download to R.string.action_install
|
||||||
supportedVersion -> Icons.Default.Refresh to R.string.reinstall
|
supportedVersion -> Icons.Default.Refresh to R.string.action_reinstall
|
||||||
else -> Icons.Default.Update to R.string.update
|
else -> Icons.Default.Update to R.string.action_update
|
||||||
}
|
}
|
||||||
|
|
||||||
FilledTonalIconButton(
|
FilledTonalIconButton(
|
||||||
|
|
@ -98,7 +104,7 @@ fun InfoCard(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = stringResource(R.string.uninstall)
|
contentDescription = stringResource(R.string.action_uninstall)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +117,7 @@ fun InfoCard(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Launch,
|
imageVector = Icons.Default.Launch,
|
||||||
contentDescription = stringResource(R.string.launch)
|
contentDescription = stringResource(R.string.action_launch)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ fun Changelog(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.History,
|
imageVector = Icons.Default.History,
|
||||||
contentDescription = stringResource(R.string.view_plugin_changelog, plugin.manifest.name)
|
contentDescription = stringResource(R.string.plugins_view_changelog, plugin.manifest.name)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
title = { Text(plugin.manifest.name) },
|
title = { Text(plugin.manifest.name) },
|
||||||
|
|
@ -85,7 +85,7 @@ fun Changelog(
|
||||||
.heightIn(max = 90.dp)
|
.heightIn(max = 90.dp)
|
||||||
.clip(RoundedCornerShape(14.dp)),
|
.clip(RoundedCornerShape(14.dp)),
|
||||||
model = mediaUrl,
|
model = mediaUrl,
|
||||||
contentDescription = stringResource(R.string.changelog_media)
|
contentDescription = stringResource(R.string.plugins_changelog_media)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ fun Changelog(
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
Button(onClick = onDismiss) {
|
Button(onClick = onDismiss) {
|
||||||
Text(stringResource(R.string.close))
|
Text(stringResource(R.string.action_close))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.aliucord.manager.R
|
import com.aliucord.manager.R
|
||||||
import com.aliucord.manager.domain.model.Plugin
|
import com.aliucord.manager.domain.model.Plugin
|
||||||
|
import com.aliucord.manager.ui.util.annotatingStringResource
|
||||||
import com.aliucord.manager.ui.util.joinToAnnotatedString
|
import com.aliucord.manager.ui.util.joinToAnnotatedString
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -48,15 +49,19 @@ fun PluginCard(
|
||||||
Column {
|
Column {
|
||||||
// Name
|
// Name
|
||||||
Text(
|
Text(
|
||||||
buildAnnotatedString {
|
annotatingStringResource(
|
||||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
R.string.plugins_plugin_title,
|
||||||
append(plugin.manifest.name)
|
plugin.manifest.name,
|
||||||
|
plugin.manifest.version
|
||||||
|
) {
|
||||||
|
when (it) {
|
||||||
|
"plugin" -> SpanStyle(fontWeight = FontWeight.Bold)
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
append(" v${plugin.manifest.version}")
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: make this translatable
|
||||||
// Authors
|
// Authors
|
||||||
val authors = buildAnnotatedString {
|
val authors = buildAnnotatedString {
|
||||||
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) {
|
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) {
|
||||||
|
|
@ -139,7 +144,7 @@ fun PluginCard(
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
imageVector = Icons.Default.History,
|
imageVector = Icons.Default.History,
|
||||||
contentDescription = stringResource(R.string.view_plugin_changelog, plugin.manifest.name)
|
contentDescription = stringResource(R.string.plugins_view_changelog, plugin.manifest.name)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +155,7 @@ fun PluginCard(
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = stringResource(R.string.uninstall),
|
contentDescription = stringResource(R.string.action_uninstall),
|
||||||
tint = MaterialTheme.colorScheme.error
|
tint = MaterialTheme.colorScheme.error
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,16 +31,16 @@ fun InstallerDialog(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Download,
|
imageVector = Icons.Default.Download,
|
||||||
contentDescription = stringResource(R.string.download_method)
|
contentDescription = stringResource(R.string.selector_download_method)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
Text(stringResource(R.string.download_method))
|
Text(stringResource(R.string.selector_download_method))
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
Column {
|
Column {
|
||||||
mapOf(
|
mapOf(
|
||||||
DownloadMethod.DOWNLOAD to stringResource(R.string.download_apk),
|
DownloadMethod.DOWNLOAD to stringResource(R.string.selector_download_apk),
|
||||||
// DownloadMethod.SELECT to stringResource(R.string.select_apk)
|
// DownloadMethod.SELECT to stringResource(R.string.select_apk)
|
||||||
).forEach { (method, name) ->
|
).forEach { (method, name) ->
|
||||||
Column {
|
Column {
|
||||||
|
|
@ -75,7 +75,7 @@ fun InstallerDialog(
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.confirm))
|
Text(stringResource(R.string.action_confirm))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
|
|
@ -86,7 +86,7 @@ fun InstallerDialog(
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.dismiss))
|
Text(stringResource(R.string.action_dismiss))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDismissRequest = onDismissRequest
|
onDismissRequest = onDismissRequest
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ private fun ManageStorageDialog() {
|
||||||
.let { launcher.launch(it) }
|
.let { launcher.launch(it) }
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.open_settings))
|
Text(stringResource(R.string.action_open_settings))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = { Text(stringResource(R.string.permissions_grant)) },
|
title = { Text(stringResource(R.string.permissions_grant_title)) },
|
||||||
text = { Text(stringResource(R.string.permissions_grant_body)) },
|
text = { Text(stringResource(R.string.permissions_grant_body)) },
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
dismissOnBackPress = false,
|
dismissOnBackPress = false,
|
||||||
|
|
@ -69,10 +69,10 @@ private fun ExternalStorageDialog() {
|
||||||
onDismissRequest = {},
|
onDismissRequest = {},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
Button(onClick = writeStorageState::launchPermissionRequest) {
|
Button(onClick = writeStorageState::launchPermissionRequest) {
|
||||||
Text(stringResource(R.string.confirm))
|
Text(stringResource(R.string.action_confirm))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = { Text(stringResource(R.string.permissions_grant)) },
|
title = { Text(stringResource(R.string.permissions_grant_title)) },
|
||||||
text = { Text(stringResource(R.string.permissions_grant_body)) },
|
text = { Text(stringResource(R.string.permissions_grant_body)) },
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
dismissOnBackPress = false,
|
dismissOnBackPress = false,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ enum class HomeDestination(
|
||||||
val unselectedIcon: @RawValue ImageVector,
|
val unselectedIcon: @RawValue ImageVector,
|
||||||
@StringRes val label: Int
|
@StringRes val label: Int
|
||||||
) : Destination {
|
) : Destination {
|
||||||
HOME(Icons.Default.Home, Icons.Outlined.Home, R.string.home),
|
HOME(Icons.Default.Home, Icons.Outlined.Home, R.string.navigation_home),
|
||||||
PLUGINS(Icons.Default.Extension, Icons.Outlined.Extension, R.string.plugins),
|
PLUGINS(Icons.Default.Extension, Icons.Outlined.Extension, R.string.plugins_title),
|
||||||
SETTINGS(Icons.Default.Settings, Icons.Outlined.Settings, R.string.settings)
|
SETTINGS(Icons.Default.Settings, Icons.Outlined.Settings, R.string.navigation_settings)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,12 @@ fun AboutScreen(
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(R.string.about)) },
|
title = { Text(stringResource(R.string.navigation_about)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackClick) {
|
IconButton(onClick = onBackClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.ArrowBack,
|
imageVector = Icons.Default.ArrowBack,
|
||||||
contentDescription = stringResource(R.string.back)
|
contentDescription = stringResource(R.string.navigation_back)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,19 +68,19 @@ fun AboutScreen(
|
||||||
) {
|
) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = "https://github.com/Aliucord.png",
|
model = "https://github.com/Aliucord.png",
|
||||||
contentDescription = "Aliucord",
|
contentDescription = stringResource(R.string.aliucord),
|
||||||
modifier = Modifier.size(71.dp)
|
modifier = Modifier.size(71.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Aliucord",
|
text = stringResource(R.string.aliucord),
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
fontSize = 26.sp
|
fontSize = 26.sp
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.aliucord_description),
|
text = stringResource(R.string.app_description),
|
||||||
style = MaterialTheme.typography.titleSmall.copy(
|
style = MaterialTheme.typography.titleSmall.copy(
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ fun MainRootScreen(
|
||||||
IconButton(onClick = onAboutClick) {
|
IconButton(onClick = onAboutClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Info,
|
imageVector = Icons.Default.Info,
|
||||||
contentDescription = stringResource(R.string.about)
|
contentDescription = stringResource(R.string.navigation_about)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ fun HomeScreen(
|
||||||
InfoCard(
|
InfoCard(
|
||||||
packageName = viewModel.preferences.packageName,
|
packageName = viewModel.preferences.packageName,
|
||||||
supportedVersion = viewModel.supportedVersion,
|
supportedVersion = viewModel.supportedVersion,
|
||||||
|
supportedVersionType = viewModel.supportedVersionType,
|
||||||
currentVersion = viewModel.installedVersion,
|
currentVersion = viewModel.installedVersion,
|
||||||
onDownloadClick = {
|
onDownloadClick = {
|
||||||
if (viewModel.preferences.devMode) {
|
if (viewModel.preferences.devMode) {
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,12 @@ fun InstallerScreen(
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("Installer") },
|
title = { Text(stringResource(R.string.installer)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackClick) {
|
IconButton(onClick = onBackClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.NavigateBefore,
|
imageVector = Icons.Default.NavigateBefore,
|
||||||
contentDescription = stringResource(R.string.back)
|
contentDescription = stringResource(R.string.navigation_back)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,14 @@ fun PluginsScreen(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = stringResource(R.string.uninstall)
|
contentDescription = stringResource(R.string.action_uninstall)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
Text("${stringResource(R.string.uninstall)} ${plugin.manifest.name}")
|
Text("${stringResource(R.string.action_uninstall)} ${plugin.manifest.name}")
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
Text(stringResource(R.string.delete_plugin_body))
|
Text(stringResource(R.string.plugins_delete_plugin_body))
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
Button(
|
Button(
|
||||||
|
|
@ -98,19 +98,19 @@ fun PluginsScreen(
|
||||||
onValueChange = viewModel::search,
|
onValueChange = viewModel::search,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
label = { Text(stringResource(R.string.search)) },
|
label = { Text(stringResource(R.string.action_search)) },
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
if (viewModel.search.isNotBlank()) {
|
if (viewModel.search.isNotBlank()) {
|
||||||
IconButton(onClick = viewModel::clearSearch) {
|
IconButton(onClick = viewModel::clearSearch) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(R.string.clear)
|
contentDescription = stringResource(R.string.action_clear)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Search,
|
imageVector = Icons.Default.Search,
|
||||||
contentDescription = stringResource(R.string.search_plugins)
|
contentDescription = stringResource(R.string.plugins_search)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -150,7 +150,7 @@ fun PluginsScreen(
|
||||||
imageVector = Icons.Default.Extension,
|
imageVector = Icons.Default.Extension,
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
Text(stringResource(R.string.no_plugins_installed))
|
Text(stringResource(R.string.plugins_none_installed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,31 +42,31 @@ fun SettingsScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsHeader(stringResource(R.string.appearance))
|
SettingsHeader(stringResource(R.string.settings_appearance))
|
||||||
|
|
||||||
SettingsItem(
|
SettingsItem(
|
||||||
modifier = Modifier.clickable(onClick = viewModel::showThemeDialog),
|
modifier = Modifier.clickable(onClick = viewModel::showThemeDialog),
|
||||||
icon = { Icon(Icons.Default.Style, null) },
|
icon = { Icon(Icons.Default.Style, null) },
|
||||||
text = { Text(stringResource(R.string.theme)) }
|
text = { Text(stringResource(R.string.settings_theme)) }
|
||||||
) {
|
) {
|
||||||
FilledTonalButton(onClick = viewModel::showThemeDialog) {
|
FilledTonalButton(onClick = viewModel::showThemeDialog) {
|
||||||
Text(preferences.theme.displayName)
|
Text(preferences.theme.toDisplayName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
label = stringResource(R.string.dynamic_color),
|
label = stringResource(R.string.setting_dynamic_color),
|
||||||
pref = preferences.dynamicColor,
|
pref = preferences.dynamicColor,
|
||||||
icon = { Icon(Icons.Default.Palette, null) }
|
icon = { Icon(Icons.Default.Palette, null) }
|
||||||
) {
|
) {
|
||||||
preferences.dynamicColor = it
|
preferences.dynamicColor = it
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsHeader(stringResource(R.string.advanced))
|
SettingsHeader(stringResource(R.string.settings_advanced))
|
||||||
|
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
label = stringResource(R.string.replace_bg),
|
label = stringResource(R.string.setting_replace_icon),
|
||||||
secondaryLabel = stringResource(R.string.replace_bg_description),
|
secondaryLabel = stringResource(R.string.setting_replace_icon_desc),
|
||||||
pref = preferences.replaceIcon,
|
pref = preferences.replaceIcon,
|
||||||
icon = { Icon(Icons.Default.AppShortcut, null) }
|
icon = { Icon(Icons.Default.AppShortcut, null) }
|
||||||
) {
|
) {
|
||||||
|
|
@ -76,13 +76,13 @@ fun SettingsScreen(
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
SettingsTextField(
|
SettingsTextField(
|
||||||
label = stringResource(R.string.app_name_setting),
|
label = stringResource(R.string.setting_app_name),
|
||||||
pref = preferences.appName,
|
pref = preferences.appName,
|
||||||
onPrefChange = viewModel::setAppName
|
onPrefChange = viewModel::setAppName
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
label = stringResource(R.string.developer_options),
|
label = stringResource(R.string.settings_developer_options),
|
||||||
pref = preferences.devMode,
|
pref = preferences.devMode,
|
||||||
icon = { Icon(Icons.Default.Code, null) }
|
icon = { Icon(Icons.Default.Code, null) }
|
||||||
) {
|
) {
|
||||||
|
|
@ -98,20 +98,20 @@ fun SettingsScreen(
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
SettingsTextField(
|
SettingsTextField(
|
||||||
label = stringResource(R.string.package_name),
|
label = stringResource(R.string.setting_package_name),
|
||||||
pref = preferences.packageName,
|
pref = preferences.packageName,
|
||||||
onPrefChange = viewModel::setPackageName
|
onPrefChange = viewModel::setPackageName
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingsTextField(
|
SettingsTextField(
|
||||||
label = stringResource(R.string.version),
|
label = stringResource(R.string.setting_target_version),
|
||||||
pref = preferences.version,
|
pref = preferences.version,
|
||||||
onPrefChange = viewModel::setVersion
|
onPrefChange = viewModel::setVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
label = stringResource(R.string.debuggable),
|
label = stringResource(R.string.setting_debuggable),
|
||||||
secondaryLabel = stringResource(R.string.debuggable_description),
|
secondaryLabel = stringResource(R.string.setting_debuggable_desc),
|
||||||
pref = preferences.debuggable,
|
pref = preferences.debuggable,
|
||||||
icon = { Icon(Icons.Default.BugReport, null) }
|
icon = { Icon(Icons.Default.BugReport, null) }
|
||||||
) {
|
) {
|
||||||
|
|
@ -128,7 +128,7 @@ fun SettingsScreen(
|
||||||
onClick = viewModel::clearCacheDir
|
onClick = viewModel::clearCacheDir
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.clear_cache),
|
text = stringResource(R.string.setting_clear_cache),
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -148,10 +148,10 @@ fun ThemeDialog(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Style,
|
imageVector = Icons.Default.Style,
|
||||||
contentDescription = stringResource(R.string.theme)
|
contentDescription = stringResource(R.string.settings_theme)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
title = { Text(stringResource(R.string.theme)) },
|
title = { Text(stringResource(R.string.settings_theme)) },
|
||||||
text = {
|
text = {
|
||||||
Column {
|
Column {
|
||||||
Theme.values().forEach { theme ->
|
Theme.values().forEach { theme ->
|
||||||
|
|
@ -162,7 +162,7 @@ fun ThemeDialog(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = theme.displayName,
|
text = theme.toDisplayName(),
|
||||||
style = MaterialTheme.typography.labelLarge
|
style = MaterialTheme.typography.labelLarge
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -183,7 +183,7 @@ fun ThemeDialog(
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.apply))
|
Text(stringResource(R.string.action_apply))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.aliucord.manager.R
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -42,8 +44,15 @@ fun ManagerTheme(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Theme(val displayName: String) {
|
enum class Theme {
|
||||||
SYSTEM("System"),
|
SYSTEM,
|
||||||
LIGHT("Light"),
|
LIGHT,
|
||||||
DARK("Dark")
|
DARK;
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun toDisplayName() = when (this) {
|
||||||
|
SYSTEM -> stringResource(R.string.theme_system)
|
||||||
|
LIGHT -> stringResource(R.string.theme_light)
|
||||||
|
DARK -> stringResource(R.string.theme_dark)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package com.aliucord.manager.ui.util
|
package com.aliucord.manager.ui.util
|
||||||
|
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.*
|
||||||
|
|
||||||
context(AnnotatedString.Builder)
|
context(AnnotatedString.Builder)
|
||||||
inline fun <T> Iterable<T>.joinToAnnotatedString(
|
inline fun <T> Iterable<T>.joinToAnnotatedString(
|
||||||
|
|
@ -21,3 +24,55 @@ context(AnnotatedString.Builder)
|
||||||
}
|
}
|
||||||
postfix(this@Builder)
|
postfix(this@Builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This formats and styles string resources into an [AnnotatedString].
|
||||||
|
* By putting `§annotation_name§target string blah blah blah§` into the resource string it can be translated
|
||||||
|
* (assuming `annotation_name` is not changed between translations),
|
||||||
|
* when rendering [annotationHandler] will be called on each `annotation_name` and expected to return a target style on it.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
@Composable
|
||||||
|
inline fun annotatingStringResource(
|
||||||
|
@StringRes id: Int,
|
||||||
|
vararg args: Any,
|
||||||
|
crossinline annotationHandler: @Composable (annotationName: String) -> SpanStyle?
|
||||||
|
): AnnotatedString {
|
||||||
|
val string = stringResource(id, *args)
|
||||||
|
|
||||||
|
// TODO: figure out a way to put this in remember {} while still having @Composable annotationHandler
|
||||||
|
val markerIndexes = string
|
||||||
|
.mapIndexedNotNull { index, elem -> index.takeIf { elem == '§' } }
|
||||||
|
.takeIf { it.isNotEmpty() && it.size % 3 == 0 }
|
||||||
|
?: return AnnotatedString(string)
|
||||||
|
|
||||||
|
return buildAnnotatedString {
|
||||||
|
var lastIndex = 0
|
||||||
|
var offset = 0
|
||||||
|
|
||||||
|
for ((nameStart, nameEnd, valueEnd) in markerIndexes.chunked(3)) {
|
||||||
|
append(string.substring(lastIndex, nameStart))
|
||||||
|
append(string.substring(nameEnd + 1, valueEnd))
|
||||||
|
|
||||||
|
val annotationName = string.substring(nameStart + 1, nameEnd)
|
||||||
|
val newValueStart = nameEnd - annotationName.length - offset - 1
|
||||||
|
val newValueEnd = valueEnd - annotationName.length - offset - 2
|
||||||
|
|
||||||
|
addStringAnnotation(
|
||||||
|
tag = annotationName,
|
||||||
|
annotation = annotationName,
|
||||||
|
start = newValueStart,
|
||||||
|
end = newValueEnd,
|
||||||
|
)
|
||||||
|
|
||||||
|
annotationHandler(annotationName)?.let {
|
||||||
|
addStyle(it, newValueStart, newValueEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = valueEnd + 1
|
||||||
|
offset += 3 + annotationName.length
|
||||||
|
}
|
||||||
|
|
||||||
|
append(string.substring(lastIndex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.*
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.*
|
import androidx.paging.*
|
||||||
|
import com.aliucord.manager.R
|
||||||
import com.aliucord.manager.domain.manager.PreferencesManager
|
import com.aliucord.manager.domain.manager.PreferencesManager
|
||||||
import com.aliucord.manager.domain.repository.GithubRepository
|
import com.aliucord.manager.domain.repository.GithubRepository
|
||||||
import com.aliucord.manager.network.dto.Commit
|
import com.aliucord.manager.network.dto.Commit
|
||||||
|
|
@ -25,7 +26,10 @@ class HomeViewModel(
|
||||||
var supportedVersion by mutableStateOf("")
|
var supportedVersion by mutableStateOf("")
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var installedVersion by mutableStateOf("-")
|
var supportedVersionType by mutableStateOf(R.string.version_unknown)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var installedVersion by mutableStateOf("")
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val commits = Pager(PagingConfig(pageSize = 30)) {
|
val commits = Pager(PagingConfig(pageSize = 30)) {
|
||||||
|
|
@ -62,6 +66,7 @@ class HomeViewModel(
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
packageManager.getPackageInfo(preferences.packageName, 0).versionName
|
packageManager.getPackageInfo(preferences.packageName, 0).versionName
|
||||||
} catch (th: Throwable) {
|
} catch (th: Throwable) {
|
||||||
|
// TODO: translated error message
|
||||||
"-"
|
"-"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -70,16 +75,19 @@ class HomeViewModel(
|
||||||
private suspend fun _fetchSupportedVersion() {
|
private suspend fun _fetchSupportedVersion() {
|
||||||
val version = githubRepository.getVersion()
|
val version = githubRepository.getVersion()
|
||||||
|
|
||||||
supportedVersion = version.fold(
|
version.fold(
|
||||||
success = {
|
success = {
|
||||||
"${it.versionName} - " + when (it.versionCode[3]) {
|
supportedVersion = it.versionName
|
||||||
'0' -> "Stable"
|
supportedVersionType = when (it.versionCode[3]) {
|
||||||
'1' -> "Beta"
|
'0' -> R.string.version_stable
|
||||||
'2' -> "Alpha"
|
'1' -> R.string.version_beta
|
||||||
else -> throw NoWhenBranchMatchedException()
|
'2' -> R.string.version_alpha
|
||||||
|
else -> R.string.version_unknown
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail = { "Failed to retrieve version" }
|
fail = {
|
||||||
|
supportedVersionType = R.string.version_load_fail
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +103,7 @@ class HomeViewModel(
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
application.startActivity(launchIntent)
|
application.startActivity(launchIntent)
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(application, "Failed to launch Aliucord", Toast.LENGTH_LONG).show()
|
Toast.makeText(application, R.string.launch_aliucord_fail, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,88 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aliucord Manager</string>
|
<string name="app_name">Aliucord Manager</string>
|
||||||
<string name="clear_cache">Clear cache</string>
|
<string name="app_description">A modification for the Discord Android App</string>
|
||||||
<string name="commits">Commits</string>
|
|
||||||
<string name="dex_location">Dex location</string>
|
<string name="aliucord">Aliucord</string>
|
||||||
<string name="open_settings">Open settings</string>
|
|
||||||
<string name="replace_bg">Replace app icon</string>
|
|
||||||
<string name="replace_bg_description">Uses the Aliucord variant as opposed to Discord\'s own icon</string>
|
|
||||||
<string name="settings">Settings</string>
|
|
||||||
<string name="show_menu">Show menu</string>
|
|
||||||
<string name="theme">Theme</string>
|
|
||||||
<string name="use_dex_from_storage">Use Injector.dex from storage</string>
|
|
||||||
<string name="plugins">Plugins</string>
|
|
||||||
<string name="search">Search</string>
|
|
||||||
<string name="view_plugin_changelog">View changelog for %1$s</string>
|
|
||||||
<string name="delete_plugin_body">Are you sure you want to uninstall this plugin?</string>
|
|
||||||
<string name="close">Close</string>
|
|
||||||
<string name="support_server">Support Server</string>
|
|
||||||
<string name="back">Back</string>
|
|
||||||
<string name="home">Home</string>
|
|
||||||
<string name="install">Install</string>
|
|
||||||
<string name="reinstall">Reinstall</string>
|
|
||||||
<string name="update">Update</string>
|
|
||||||
<string name="developer_options">Developer options</string>
|
|
||||||
<string name="debuggable">Debuggable</string>
|
|
||||||
<string name="debuggable_description">Enable debuggable flag</string>
|
|
||||||
<string name="about">About</string>
|
|
||||||
<string name="team">Team</string>
|
|
||||||
<string name="contributors">Contributors</string>
|
|
||||||
<string name="search_plugins">Search Plugins</string>
|
|
||||||
<string name="github">GitHub</string>
|
<string name="github">GitHub</string>
|
||||||
|
<string name="support_server">Support Server</string>
|
||||||
|
<string name="commits">Commits</string>
|
||||||
|
<string name="team">Team</string>
|
||||||
<string name="website">Website</string>
|
<string name="website">Website</string>
|
||||||
<string name="installer">Installer</string>
|
<string name="installer">Installer</string>
|
||||||
<string name="contributions">%o contributions</string>
|
|
||||||
<string name="theme_setting_description">Manager appearance</string>
|
<string name="action_retry">Retry</string>
|
||||||
<string name="no_plugins_installed">No plugins installed!</string>
|
<string name="action_apply">Apply</string>
|
||||||
<string name="contributor">Contributor</string>
|
<string name="action_confirm">Confirm</string>
|
||||||
<string name="apply">Apply</string>
|
<string name="action_dismiss">Dismiss</string>
|
||||||
<string name="confirm">Confirm</string>
|
<string name="action_install">Install</string>
|
||||||
<string name="dismiss">Dismiss</string>
|
<string name="action_reinstall">Reinstall</string>
|
||||||
<string name="download_apk">Download APK</string>
|
<string name="action_update">Update</string>
|
||||||
<string name="select_apk">Select APK</string>
|
<string name="action_clear">Clear</string>
|
||||||
<string name="download_method">Download Method</string>
|
<string name="action_launch">Launch</string>
|
||||||
<string name="changelog_media">Changelog Media</string>
|
<string name="action_uninstall">Uninstall</string>
|
||||||
<string name="app_name_setting">App Name</string>
|
<string name="action_close">Close</string>
|
||||||
<string name="package_name">Package Name</string>
|
<string name="action_open_settings">Open settings</string>
|
||||||
<string name="clear">Clear</string>
|
<string name="action_search">Search</string>
|
||||||
<string name="launch">Launch</string>
|
<string name="action_loading_trailing">Loading…</string>
|
||||||
<string name="uninstall">Uninstall</string>
|
|
||||||
<string name="version">Download Version</string>
|
<string name="permissions_grant_title">Grant Permissions</string>
|
||||||
<string name="dynamic_color">Dynamic color</string>
|
|
||||||
<string name="appearance">Appearance</string>
|
|
||||||
<string name="advanced">Advanced</string>
|
|
||||||
<string name="permissions_grant">Grant Permissions</string>
|
|
||||||
<string name="permissions_grant_body">In order for Aliucord Manager to work properly, you need to grant file permissions. Since shared data in stored in ~/Aliucord, permissions are required in order for manager to function.</string>
|
<string name="permissions_grant_body">In order for Aliucord Manager to work properly, you need to grant file permissions. Since shared data in stored in ~/Aliucord, permissions are required in order for manager to function.</string>
|
||||||
<string name="aliucord_description">A modification for the Discord Android App</string>
|
|
||||||
<string name="load_fail">Failed to load</string>
|
<string name="install_success">Successfully installed Aliucord</string>
|
||||||
<string name="retry">Retry</string>
|
<string name="install_aborted">Aborted Aliucord installation</string>
|
||||||
|
<string name="install_failed">Installation failed with error %o</string>
|
||||||
|
<string name="launch_aliucord_fail">Failed to launch Aliucord</string>
|
||||||
|
|
||||||
|
<string name="settings_theme">Theme</string>
|
||||||
|
<string name="settings_advanced">Advanced</string>
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_developer_options">Developer options</string>
|
||||||
|
<string name="setting_clear_cache">Clear cache</string>
|
||||||
|
<string name="setting_dex_location">Dex location</string>
|
||||||
|
<string name="setting_use_dex_from_storage">Use Injector.dex from storage</string>
|
||||||
|
<string name="setting_replace_icon">Replace app icon</string>
|
||||||
|
<string name="setting_replace_icon_desc">Uses the Aliucord variant as opposed to Discord\'s own icon</string>
|
||||||
|
<string name="setting_debuggable">Debuggable</string>
|
||||||
|
<string name="setting_debuggable_desc">Enable debuggable flag</string>
|
||||||
|
<string name="setting_theme_desc">Manager appearance</string>
|
||||||
|
<string name="setting_app_name">App Name</string>
|
||||||
|
<string name="setting_package_name">Package Name</string>
|
||||||
|
<string name="setting_target_version">Download Version</string>
|
||||||
|
<string name="setting_dynamic_color">Dynamic color</string>
|
||||||
|
|
||||||
|
<string name="theme_system">System</string>
|
||||||
|
<string name="theme_dark">Dark</string>
|
||||||
|
<string name="theme_light">Light</string>
|
||||||
|
|
||||||
|
<string name="plugins_title">Plugins</string>
|
||||||
|
<string name="plugins_view_changelog">View changelog for %1$s</string>
|
||||||
|
<string name="plugins_delete_plugin_body">Are you sure you want to uninstall this plugin?</string>
|
||||||
|
<string name="plugins_search">Search Plugins</string>
|
||||||
|
<string name="plugins_none_installed">No plugins installed!</string>
|
||||||
|
<string name="plugins_changelog_media">Changelog Media</string>
|
||||||
|
<string name="plugins_plugin_title">§plugin§%1$s§ v%2$s</string>
|
||||||
|
|
||||||
|
<string name="navigation_back">Back</string>
|
||||||
|
<string name="navigation_home">Home</string>
|
||||||
|
<string name="navigation_about">About</string>
|
||||||
|
<string name="navigation_settings">Settings</string>
|
||||||
|
|
||||||
|
<string name="contributors">Contributors</string>
|
||||||
|
<string name="contributors_contributions">%o contributions</string>
|
||||||
|
<string name="contributors_contributor">Contributor</string>
|
||||||
|
<string name="contributors_commit_title">§name§%1$s§ §middle§authored§ §commit§%2$s§</string>
|
||||||
|
|
||||||
|
<string name="selector_download_apk">Download APK</string>
|
||||||
|
<string name="selector_select_apk">Select APK</string>
|
||||||
|
<string name="selector_download_method">Download Method</string>
|
||||||
|
|
||||||
|
<string name="network_load_fail">Failed to load</string>
|
||||||
|
|
||||||
|
<string name="version_supported">Supported version:</string>
|
||||||
|
<string name="version_installed">Installed version:</string>
|
||||||
|
<string name="version_stable">Stable</string>
|
||||||
|
<string name="version_beta">Beta</string>
|
||||||
|
<string name="version_alpha">Alpha</string>
|
||||||
|
<string name="version_unknown" translatable="false" />
|
||||||
|
<string name="version_load_fail">Failed to retrieve version</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
7
crowdin.yml
Normal file
7
crowdin.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
project_id_env: CROWDIN_PROJECT_ID
|
||||||
|
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||||
|
|
||||||
|
preserve_hierarchy: true
|
||||||
|
files:
|
||||||
|
- source: app/src/main/res/values/strings.xml
|
||||||
|
translation: app/src/main/res/values-%android_code%/strings.xml
|
||||||
Loading…
Add table
Reference in a new issue