mirror of
https://github.com/amir1376/ab-download-manager.git
synced 2025-02-20 11:43:24 +08:00
add "Meet the Translators" page
This commit is contained in:
parent
d0c6ae5806
commit
db0ad87734
@ -200,6 +200,12 @@ buildConfig {
|
||||
"https://github.com/amir1376/ab-download-manager"
|
||||
}
|
||||
)
|
||||
buildConfigField(
|
||||
"PROJECT_TRANSLATIONS",
|
||||
provider {
|
||||
"https://crowdin.com/project/ab-download-manager"
|
||||
}
|
||||
)
|
||||
buildConfigField(
|
||||
"INTEGRATION_CHROME_LINK",
|
||||
provider {
|
||||
|
@ -743,6 +743,14 @@ class AppComponent(
|
||||
showOpenSourceLibraries.update { false }
|
||||
}
|
||||
|
||||
fun openTranslatorsPage() {
|
||||
showTranslators.update { true }
|
||||
}
|
||||
|
||||
fun closeTranslatorsPage() {
|
||||
showTranslators.update { false }
|
||||
}
|
||||
|
||||
fun openQueues() {
|
||||
scope.launch {
|
||||
showQueuesSlot.value.child?.instance.let {
|
||||
@ -820,6 +828,7 @@ class AppComponent(
|
||||
// val updater = UpdateComponent(childContext("updater"))
|
||||
val showAboutPage = MutableStateFlow(false)
|
||||
val showOpenSourceLibraries = MutableStateFlow(false)
|
||||
val showTranslators = MutableStateFlow(false)
|
||||
val theme = appRepository.theme
|
||||
// val uiScale = appRepository.uiScale
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ interface BaseConstants{
|
||||
val packageName:String
|
||||
val projectWebsite:String
|
||||
val projectSourceCode:String
|
||||
val projectTranslations: String
|
||||
val browserIntegrations:List<BrowserIntegrationModel>
|
||||
val telegramGroupUrl:String
|
||||
val telegramChannelUrl:String
|
||||
@ -17,6 +18,7 @@ object SharedConstants:BaseConstants{
|
||||
override val appName: String = BuildConfig.APP_NAME
|
||||
override val packageName: String = BuildConfig.PACKAGE_NAME
|
||||
override val projectWebsite: String= BuildConfig.PROJECT_WEBSITE
|
||||
override val projectTranslations: String = BuildConfig.PROJECT_TRANSLATIONS
|
||||
override val projectSourceCode: String= BuildConfig.PROJECT_SOURCE_CODE
|
||||
override val browserIntegrations: List<BrowserIntegrationModel> = listOf(
|
||||
BrowserIntegrationModel(
|
||||
|
@ -167,6 +167,12 @@ val openOpenSourceThirdPartyLibraries = simpleAction(
|
||||
) {
|
||||
appComponent.openOpenSourceLibraries()
|
||||
}
|
||||
val openTranslators = simpleAction(
|
||||
title = Res.string.meet_the_translators.asStringSource(),
|
||||
icon = MyIcons.language,
|
||||
) {
|
||||
appComponent.openTranslatorsPage()
|
||||
}
|
||||
|
||||
val supportActionGroup = MenuItem.SubMenu(
|
||||
title = Res.string.support_and_community.asStringSource(),
|
||||
|
@ -22,6 +22,9 @@ fun ShowAboutDialog(appComponent: AppComponent) {
|
||||
},
|
||||
onRequestShowOpenSourceLibraries = {
|
||||
appComponent.openOpenSourceLibraries()
|
||||
},
|
||||
onRequestShowTranslators = {
|
||||
appComponent.openTranslatorsPage()
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -31,19 +34,21 @@ fun ShowAboutDialog(appComponent: AppComponent) {
|
||||
fun AboutDialog(
|
||||
onClose: () -> Unit,
|
||||
onRequestShowOpenSourceLibraries: () -> Unit,
|
||||
onRequestShowTranslators: () -> Unit,
|
||||
) {
|
||||
CustomWindow(
|
||||
resizable = false,
|
||||
onRequestToggleMaximize = null,
|
||||
state = rememberWindowState(
|
||||
size = DpSize(400.dp, 300.dp)
|
||||
size = DpSize(400.dp, 330.dp)
|
||||
),
|
||||
onCloseRequest = onClose
|
||||
) {
|
||||
WindowTitle(myStringResource(Res.string.about))
|
||||
AboutPage(
|
||||
close = onClose,
|
||||
onRequestShowOpenSourceLibraries = onRequestShowOpenSourceLibraries
|
||||
onRequestShowOpenSourceLibraries = onRequestShowOpenSourceLibraries,
|
||||
onRequestShowTranslators = onRequestShowTranslators
|
||||
)
|
||||
}
|
||||
}
|
@ -40,10 +40,12 @@ import ir.amirab.util.compose.resources.myStringResource
|
||||
fun AboutPage(
|
||||
close: () -> Unit,
|
||||
onRequestShowOpenSourceLibraries: () -> Unit,
|
||||
onRequestShowTranslators: () -> Unit,
|
||||
) {
|
||||
Column(Modifier.padding(16.dp)) {
|
||||
RenderAppInfo(
|
||||
onRequestShowOpenSourceLibraries = onRequestShowOpenSourceLibraries
|
||||
onRequestShowOpenSourceLibraries = onRequestShowOpenSourceLibraries,
|
||||
onRequestShowTranslators = onRequestShowTranslators,
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
Row(Modifier.fillMaxWidth().wrapContentWidth(Alignment.End)) {
|
||||
@ -58,6 +60,7 @@ fun AboutPage(
|
||||
@Composable
|
||||
fun RenderAppInfo(
|
||||
onRequestShowOpenSourceLibraries: () -> Unit,
|
||||
onRequestShowTranslators: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth()
|
||||
@ -114,6 +117,15 @@ fun RenderAppInfo(
|
||||
onRequestShowOpenSourceLibraries()
|
||||
}
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(myStringResource(Res.string.localized_by_translators))
|
||||
Text(
|
||||
myStringResource(Res.string.meet_the_translators),
|
||||
style = LocalTextStyle.current.merge(LinkStyle),
|
||||
modifier = Modifier.clickable {
|
||||
onRequestShowTranslators()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ fun AddMultiDownloadTable(
|
||||
content = it
|
||||
)
|
||||
},
|
||||
wrapItem = { item, content ->
|
||||
wrapItem = { _, item, content ->
|
||||
val shape = RoundedCornerShape(12.dp)
|
||||
WithContentAlpha(1f) {
|
||||
val isSelected = remember(item, component.selectionList) {
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.abdownloadmanager.desktop.pages.credits.translators
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class LanguageTranslationInfo(
|
||||
val locale: String,// en,es_ES etc...
|
||||
val englishName: String,//Persian etc...
|
||||
val nativeName: String,//فارسی ...
|
||||
val translators: List<Translator>,
|
||||
)
|
||||
|
||||
typealias TranslatorData = @Serializable Map<String, List<Translator>>
|
||||
|
||||
@Serializable
|
||||
data class Translator(
|
||||
@SerialName("name")
|
||||
val name: String,
|
||||
@SerialName("link")
|
||||
val link: String,
|
||||
)
|
@ -0,0 +1,281 @@
|
||||
package com.abdownloadmanager.desktop.pages.credits.translators
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.abdownloadmanager.desktop.di.Di
|
||||
import com.abdownloadmanager.desktop.pages.about.MaybeLinkText
|
||||
import com.abdownloadmanager.desktop.ui.theme.LocalMyColors
|
||||
import com.abdownloadmanager.desktop.ui.theme.myColors
|
||||
import com.abdownloadmanager.desktop.ui.theme.myTextSizes
|
||||
import com.abdownloadmanager.desktop.ui.widget.ActionButton
|
||||
import com.abdownloadmanager.desktop.ui.widget.Text
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.Table
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.TableState
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.styled.MyStyledTableHeader
|
||||
import com.abdownloadmanager.desktop.utils.AppInfo
|
||||
import com.abdownloadmanager.desktop.utils.div
|
||||
import com.abdownloadmanager.resources.Res
|
||||
import com.abdownloadmanager.utils.compose.LocalContentColor
|
||||
import com.abdownloadmanager.utils.compose.WithContentAlpha
|
||||
import ir.amirab.util.UrlUtils
|
||||
import ir.amirab.util.compose.localizationmanager.LanguageNameProvider
|
||||
import ir.amirab.util.compose.localizationmanager.MyLocale
|
||||
import ir.amirab.util.compose.resources.myStringResource
|
||||
import kotlinx.serialization.json.Json
|
||||
import okio.FileSystem
|
||||
import okio.Path.Companion.toPath
|
||||
import okio.buffer
|
||||
import org.koin.core.component.get
|
||||
|
||||
@Composable
|
||||
internal fun Translators(modifier: Modifier) {
|
||||
Column(
|
||||
modifier
|
||||
) {
|
||||
TranslatorsTable(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp)
|
||||
.weight(1f)
|
||||
)
|
||||
ContributionNotice(
|
||||
modifier = Modifier,
|
||||
onUserWantsToContribute = {
|
||||
UrlUtils.openUrl(AppInfo.translationsUrl)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContributionNotice(
|
||||
modifier: Modifier,
|
||||
onUserWantsToContribute: () -> Unit,
|
||||
) {
|
||||
Column(modifier) {
|
||||
Spacer(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(myColors.onBackground / 0.15f)
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(myColors.surface / 0.5f)
|
||||
.padding(horizontal = 32.dp)
|
||||
.padding(vertical = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
myStringResource(Res.string.translators_page_thanks),
|
||||
modifier = Modifier,
|
||||
fontSize = myTextSizes.lg,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Spacer(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
.height(1.dp)
|
||||
.background(myColors.surface)
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
myStringResource(Res.string.translators_contribute_title),
|
||||
fontSize = myTextSizes.lg,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
myStringResource(Res.string.translators_contribute_description),
|
||||
fontSize = myTextSizes.base,
|
||||
color = LocalContentColor.current / 0.75f
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(32.dp))
|
||||
PrimaryMainConfigActionButton(
|
||||
text = myStringResource(Res.string.contribute),
|
||||
onClick = onUserWantsToContribute,
|
||||
modifier = Modifier,
|
||||
enabled = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PrimaryMainConfigActionButton(
|
||||
text: String,
|
||||
modifier: Modifier,
|
||||
enabled: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val backgroundColor = Brush.horizontalGradient(
|
||||
myColors.primaryGradientColors.map {
|
||||
it / 30
|
||||
}
|
||||
)
|
||||
val borderColor = Brush.horizontalGradient(
|
||||
myColors.primaryGradientColors
|
||||
)
|
||||
val disabledBorderColor = Brush.horizontalGradient(
|
||||
myColors.primaryGradientColors.map {
|
||||
it / 50
|
||||
}
|
||||
)
|
||||
ActionButton(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
onClick = onClick,
|
||||
backgroundColor = backgroundColor,
|
||||
disabledBackgroundColor = backgroundColor,
|
||||
borderColor = borderColor,
|
||||
disabledBorderColor = disabledBorderColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TranslatorsTable(
|
||||
modifier: Modifier,
|
||||
) {
|
||||
val tableState = remember {
|
||||
TableState(
|
||||
cells = TranslatorsCells.all()
|
||||
)
|
||||
}
|
||||
val itemHorizontalPadding = 16.dp
|
||||
Table(
|
||||
modifier = modifier,
|
||||
list = rememberLanguageTranslationInfo(),
|
||||
state = rememberLazyListState(),
|
||||
tableState = tableState,
|
||||
wrapHeader = {
|
||||
MyStyledTableHeader(
|
||||
itemHorizontalPadding = itemHorizontalPadding,
|
||||
content = it,
|
||||
)
|
||||
},
|
||||
wrapItem = { index, _, rowContent ->
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
Box(
|
||||
Modifier
|
||||
.widthIn(getTableSize().visibleWidth)
|
||||
.hoverable(interactionSource)
|
||||
.indication(
|
||||
interactionSource,
|
||||
LocalIndication.current,
|
||||
)
|
||||
.background(
|
||||
if (index % 2 == 0) Color.Transparent else myColors.surface / 0.35f
|
||||
)
|
||||
.padding(vertical = 12.dp, horizontal = itemHorizontalPadding)
|
||||
) {
|
||||
rowContent()
|
||||
}
|
||||
},
|
||||
renderCell = { libraryCell, translationInfo ->
|
||||
when (libraryCell) {
|
||||
TranslatorsCells.LanguageName -> {
|
||||
Column {
|
||||
WithContentAlpha(1f) {
|
||||
Text(
|
||||
translationInfo.nativeName,
|
||||
fontSize = myTextSizes.base,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
WithContentAlpha(0.75f) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
translationInfo.englishName,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
fontSize = myTextSizes.base,
|
||||
)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(
|
||||
translationInfo.locale,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
fontSize = myTextSizes.base,
|
||||
color = myColors.primary,
|
||||
modifier = Modifier
|
||||
.background(myColors.primary / 10)
|
||||
.padding(vertical = 0.dp, horizontal = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TranslatorsCells.Translators -> {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
translationInfo.translators.forEach {
|
||||
MaybeLinkText(
|
||||
it.name,
|
||||
it.link,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertLanguageToMyLocale(language: String): MyLocale {
|
||||
return language.split("-").run {
|
||||
MyLocale(
|
||||
languageCode = get(0),
|
||||
countryCode = getOrNull(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberLanguageTranslationInfo(): List<LanguageTranslationInfo> {
|
||||
return remember {
|
||||
val json = Di.get<Json>()
|
||||
val translatorData = FileSystem.RESOURCES.source(
|
||||
"/com/abdownloadmanager/resources/credits/translators.json".toPath()
|
||||
).buffer().readUtf8().let {
|
||||
json.decodeFromString<TranslatorData>(it)
|
||||
}
|
||||
translatorData.map {
|
||||
val name = LanguageNameProvider.getName(convertLanguageToMyLocale(it.key))
|
||||
LanguageTranslationInfo(
|
||||
locale = it.key,
|
||||
englishName = name.englishName,
|
||||
nativeName = name.nativeName,
|
||||
translators = it.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.abdownloadmanager.desktop.pages.credits.translators
|
||||
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.CellSize
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.SortableCell
|
||||
import com.abdownloadmanager.desktop.ui.widget.customtable.TableCell
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.abdownloadmanager.resources.Res
|
||||
import ir.amirab.util.compose.StringSource
|
||||
import ir.amirab.util.compose.asStringSource
|
||||
|
||||
sealed interface TranslatorsCells : TableCell<LanguageTranslationInfo> {
|
||||
data object LanguageName : TranslatorsCells,
|
||||
SortableCell<LanguageTranslationInfo> {
|
||||
override fun sortBy(item: LanguageTranslationInfo): Comparable<*> = item.locale
|
||||
override val id: String = "language"
|
||||
override val name: StringSource = Res.string.language.asStringSource()
|
||||
override val size: CellSize = CellSize.Resizeable(100.dp..1000.dp, 200.dp)
|
||||
}
|
||||
|
||||
data object Translators : TranslatorsCells {
|
||||
override val id: String = "translators"
|
||||
override val name: StringSource = Res.string.translators.asStringSource()
|
||||
override val size: CellSize = CellSize.Resizeable(100.dp..1000.dp, 350.dp)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun all() = listOf(
|
||||
LanguageName,
|
||||
Translators,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.abdownloadmanager.desktop.pages.credits.translators
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import com.abdownloadmanager.desktop.AppComponent
|
||||
import com.abdownloadmanager.desktop.ui.customwindow.CustomWindow
|
||||
import com.abdownloadmanager.desktop.ui.customwindow.WindowTitle
|
||||
import com.abdownloadmanager.resources.Res
|
||||
import ir.amirab.util.compose.resources.myStringResource
|
||||
|
||||
|
||||
@Composable
|
||||
fun ShowTranslators(
|
||||
appComponent: AppComponent,
|
||||
) {
|
||||
TranslatorsWindow(
|
||||
isVisible = appComponent.showTranslators.collectAsState().value,
|
||||
onRequestClose = {
|
||||
appComponent.closeTranslatorsPage()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TranslatorsWindow(
|
||||
isVisible: Boolean,
|
||||
onRequestClose: () -> Unit,
|
||||
) {
|
||||
if (!isVisible) return
|
||||
CustomWindow(
|
||||
onCloseRequest = onRequestClose,
|
||||
state = rememberWindowState(
|
||||
size = DpSize(650.dp, 500.dp)
|
||||
)
|
||||
) {
|
||||
WindowTitle(myStringResource(Res.string.meet_the_translators))
|
||||
Translators(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ private fun OpenSourceLibraries(
|
||||
content = it,
|
||||
)
|
||||
},
|
||||
wrapItem = { item, rowContent ->
|
||||
wrapItem = { _, item, rowContent ->
|
||||
Box(Modifier
|
||||
.clickable {
|
||||
currentDialog = item
|
||||
|
@ -563,6 +563,7 @@ class HomeComponent(
|
||||
+supportActionGroup
|
||||
separator()
|
||||
+openOpenSourceThirdPartyLibraries
|
||||
+openTranslators
|
||||
+openAboutAction
|
||||
}
|
||||
}.filterIsInstance<MenuItem.SubMenu>()
|
||||
|
@ -154,7 +154,7 @@ fun DownloadList(
|
||||
wrapHeader = {
|
||||
MyStyledTableHeader(itemHorizontalPadding = itemHorizontalPadding, content = it)
|
||||
},
|
||||
wrapItem = { item, rowContent ->
|
||||
wrapItem = { _, item, rowContent ->
|
||||
val isSelected = selectionList.contains(item.id)
|
||||
var shouldWaitForSecondClick by remember {
|
||||
mutableStateOf(false)
|
||||
|
@ -130,8 +130,8 @@ fun SingleDownloadPage(singleDownloadComponent: SingleDownloadComponent) {
|
||||
Spacer(Modifier.size(8.dp))
|
||||
}
|
||||
val resizingState = LocalSingleDownloadPageSizing.current
|
||||
LaunchedEffect(resizingState.resizingPartInfo){
|
||||
if (resizingState.partInfoHeight<=0.dp){
|
||||
LaunchedEffect(resizingState.resizingPartInfo) {
|
||||
if (resizingState.partInfoHeight <= 0.dp) {
|
||||
setShowPartInfo(false)
|
||||
}
|
||||
}
|
||||
@ -317,7 +317,7 @@ fun ColumnScope.RenderPartInfo(itemState: ProcessingDownloadItemState) {
|
||||
cells = PartInfoCells.all()
|
||||
)
|
||||
},
|
||||
wrapItem = { _, content ->
|
||||
wrapItem = { _, _, content ->
|
||||
WithContentAlpha(1f) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val isHovered by interactionSource.collectIsHoveredAsState()
|
||||
@ -375,7 +375,7 @@ fun ColumnScope.RenderPartInfo(itemState: ProcessingDownloadItemState) {
|
||||
val singleDownloadPageSizing = LocalSingleDownloadPageSizing.current
|
||||
val mutableInteractionSource = remember { MutableInteractionSource() }
|
||||
val isDraggingHandle by mutableInteractionSource.collectIsDraggedAsState()
|
||||
LaunchedEffect(isDraggingHandle){
|
||||
LaunchedEffect(isDraggingHandle) {
|
||||
singleDownloadPageSizing.resizingPartInfo = isDraggingHandle
|
||||
}
|
||||
Handle(
|
||||
|
@ -29,6 +29,7 @@ import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.window.*
|
||||
import com.abdownloadmanager.desktop.pages.batchdownload.BatchDownloadWindow
|
||||
import com.abdownloadmanager.desktop.pages.category.ShowCategoryDialogs
|
||||
import com.abdownloadmanager.desktop.pages.credits.translators.ShowTranslators
|
||||
import com.abdownloadmanager.desktop.pages.editdownload.EditDownloadWindow
|
||||
import com.abdownloadmanager.desktop.pages.home.HomeWindow
|
||||
import com.abdownloadmanager.desktop.pages.settings.ThemeManager
|
||||
@ -98,6 +99,7 @@ object Ui : KoinComponent {
|
||||
NewQueueDialog(appComponent)
|
||||
ShowMessageDialogs(appComponent)
|
||||
ShowOpenSourceLibraries(appComponent)
|
||||
ShowTranslators(appComponent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ override val back get() = "/icons/back.svg".asIconSource()
|
||||
override val appearance: IconSource get() = "/icons/color.svg".asIconSource()
|
||||
override val downloadEngine: IconSource get() = "/icons/down_speed.svg".asIconSource()
|
||||
override val network: IconSource get() = "/icons/network.svg".asIconSource()
|
||||
override val language: IconSource get() = "/icons/language.svg".asIconSource()
|
||||
|
||||
override val externalLink: IconSource get() = "/icons/external_link.svg".asIconSource()
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ fun <T, C : TableCell<T>> Table(
|
||||
renderHeaderCell: @Composable (C) -> Unit = { DefaultRenderHeader(it) },
|
||||
drawOnEmpty: @Composable BoxScope.() -> Unit = {},
|
||||
wrapHeader: @Composable TableScope.(rowContent: @Composable () -> Unit) -> Unit = { content -> content() },
|
||||
wrapItem: @Composable TableScope.(item: T, rowContent: @Composable () -> Unit) -> Unit = { _, content -> content() },
|
||||
renderCell: @Composable TableScope.(C, T) -> Unit
|
||||
wrapItem: @Composable TableScope.(index: Int, item: T, rowContent: @Composable () -> Unit) -> Unit = { _, _, content -> content() },
|
||||
renderCell: @Composable TableScope.(C, T) -> Unit,
|
||||
) {
|
||||
val scope = TableScope
|
||||
|
||||
@ -151,8 +151,11 @@ fun <T, C : TableCell<T>> Table(
|
||||
.fillMaxHeight(),
|
||||
state = state,
|
||||
) {
|
||||
items(sortedList, key = key) { item ->
|
||||
scope.wrapItem(item) {
|
||||
itemsIndexed(
|
||||
sortedList,
|
||||
key = if (key != null) { _, item -> key(item) } else null
|
||||
) { index, item ->
|
||||
scope.wrapItem(index, item) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
@ -10,6 +10,7 @@ object AppInfo {
|
||||
val packageName = SharedConstants.packageName
|
||||
val website = SharedConstants.projectWebsite
|
||||
val sourceCode = SharedConstants.projectSourceCode
|
||||
val translationsUrl = SharedConstants.projectTranslations
|
||||
|
||||
|
||||
val version = AppVersion.get()
|
||||
|
4
desktop/app/src/main/resources/icons/language.svg
Normal file
4
desktop/app/src/main/resources/icons/language.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.87 15.07L10.33 12.56L10.36 12.53C12.0547 10.6475 13.3205 8.41951 14.07 6H17V4H10V2H8V4H1V6H12.17C11.5 7.92 10.44 9.75 9 11.35C8.07 10.32 7.3 9.19 6.69 8H4.69C5.42 9.63 6.42 11.17 7.67 12.56L2.58 17.58L4 19L9 14L12.11 17.11L12.87 15.07ZM18.5 10H16.5L12 22H14L15.12 19H19.87L21 22H23L18.5 10ZM15.88 17L17.5 12.67L19.12 17H15.88Z"
|
||||
fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 473 B |
@ -77,5 +77,6 @@ interface IMyIcons {
|
||||
val downloadEngine: IconSource
|
||||
val browserIntegration: IconSource
|
||||
val network: IconSource
|
||||
val language: IconSource
|
||||
val externalLink: IconSource
|
||||
}
|
@ -4,143 +4,158 @@ import java.util.Locale
|
||||
|
||||
interface ILanguageNameProvider {
|
||||
fun getNativeName(myLocale: MyLocale): String
|
||||
fun getEnglishName(myLocale: MyLocale): String
|
||||
fun getName(myLocale: MyLocale): LanguageName
|
||||
}
|
||||
|
||||
data class LanguageName(
|
||||
val nativeName: String,
|
||||
val englishName: String,
|
||||
)
|
||||
|
||||
object LanguageNameProvider : ILanguageNameProvider {
|
||||
private val list = mapOf(
|
||||
"af" to "Afrikaans",
|
||||
"ak" to "Akan",
|
||||
"am" to "አማርኛ",
|
||||
"ar" to "العربية",
|
||||
"as" to "অসমীয়া",
|
||||
"az" to "azərbaycan",
|
||||
"be" to "беларуская",
|
||||
"bg" to "български",
|
||||
"bm" to "bamanakan",
|
||||
"bn" to "বাংলা",
|
||||
"bo" to "བོད་སྐད་",
|
||||
"br" to "brezhoneg",
|
||||
"bs" to "bosanski",
|
||||
"ca" to "català",
|
||||
"cs" to "čeština",
|
||||
"cy" to "Cymraeg",
|
||||
"da" to "dansk",
|
||||
"de" to "Deutsch",
|
||||
"de_AT" to "Österreichisches Deutsch",
|
||||
"de_CH" to "Schweizer Hochdeutsch",
|
||||
"dz" to "རྫོང་ཁ",
|
||||
"ee" to "eʋegbe",
|
||||
"el" to "Ελληνικά",
|
||||
"en" to "English",
|
||||
"eo" to "esperanto",
|
||||
"es" to "español",
|
||||
"et" to "eesti",
|
||||
"eu" to "euskara",
|
||||
"fa" to "فارسی",
|
||||
"ff" to "Pulaar",
|
||||
"fi" to "suomi",
|
||||
"fo" to "føroyskt",
|
||||
"fr" to "français",
|
||||
"fr_CA" to "français canadien",
|
||||
"fr_CH" to "français suisse",
|
||||
"fy" to "West-Frysk",
|
||||
"ga" to "Gaeilge",
|
||||
"gd" to "Gàidhlig",
|
||||
"gl" to "galego",
|
||||
"gu" to "ગુજરાતી",
|
||||
"gv" to "Gaelg",
|
||||
"ha" to "Hausa",
|
||||
"he" to "עברית",
|
||||
"hi" to "हिंदी",
|
||||
"hr" to "hrvatski",
|
||||
"hu" to "magyar",
|
||||
"hy" to "հայերեն",
|
||||
"id" to "Bahasa Indonesia",
|
||||
"ig" to "Igbo",
|
||||
"ii" to "ꆈꌠꉙ",
|
||||
"is" to "íslenska",
|
||||
"it" to "italiano",
|
||||
"ja" to "日本語",
|
||||
"ka" to "ქართული",
|
||||
"ki" to "Gikuyu",
|
||||
"kk" to "қазақ тілі",
|
||||
"kl" to "kalaallisut",
|
||||
"km" to "ខ្មែរ",
|
||||
"kn" to "ಕನ್ನಡ",
|
||||
"ko" to "한국어",
|
||||
"ks" to "کٲشُر",
|
||||
"kw" to "kernewek",
|
||||
"ky" to "кыргызча",
|
||||
"lb" to "Lëtzebuergesch",
|
||||
"lg" to "Luganda",
|
||||
"ln" to "lingála",
|
||||
"lo" to "ລາວ",
|
||||
"lt" to "lietuvių",
|
||||
"lu" to "Tshiluba",
|
||||
"lv" to "latviešu",
|
||||
"mg" to "Malagasy",
|
||||
"mk" to "македонски",
|
||||
"ml" to "മലയാളം",
|
||||
"mn" to "монгол",
|
||||
"mr" to "मराठी",
|
||||
"ms" to "Bahasa Melayu",
|
||||
"mt" to "Malti",
|
||||
"my" to "ဗမာ",
|
||||
"nb" to "norsk bokmål",
|
||||
"nd" to "isiNdebele",
|
||||
"ne" to "नेपाली",
|
||||
"nl" to "Nederlands",
|
||||
"nl_BE" to "Vlaams",
|
||||
"nn" to "nynorsk",
|
||||
"no" to "norsk",
|
||||
"om" to "Oromoo",
|
||||
"or" to "ଓଡ଼ିଆ",
|
||||
"os" to "ирон",
|
||||
"pa" to "ਪੰਜਾਬੀ",
|
||||
"pl" to "polski",
|
||||
"ps" to "پښتو",
|
||||
"pt" to "português",
|
||||
"pt_BR" to "português do Brasil",
|
||||
"qu" to "Runasimi",
|
||||
"rm" to "rumantsch",
|
||||
"rn" to "Ikirundi",
|
||||
"ro" to "română",
|
||||
"ro_MD" to "moldovenească",
|
||||
"ru" to "русский",
|
||||
"rw" to "Kinyarwanda",
|
||||
"se" to "davvisámegiella",
|
||||
"sg" to "Sängö",
|
||||
"sh" to "Srpskohrvatski",
|
||||
"si" to "සිංහල",
|
||||
"sk" to "slovenčina",
|
||||
"sl" to "slovenščina",
|
||||
"sn" to "chiShona",
|
||||
"so" to "Soomaali",
|
||||
"sq" to "shqip",
|
||||
"sr" to "српски",
|
||||
"sv" to "svenska",
|
||||
"sw" to "Kiswahili",
|
||||
"ta" to "தமிழ்",
|
||||
"te" to "తెలుగు",
|
||||
"th" to "ไทย",
|
||||
"ti" to "ትግርኛ",
|
||||
"tl" to "Tagalog",
|
||||
"to" to "lea fakatonga",
|
||||
"tr" to "Türkçe",
|
||||
"ug" to "ئۇيغۇرچە",
|
||||
"uk" to "українська",
|
||||
"ur" to "اردو",
|
||||
"uz" to "oʻzbekcha",
|
||||
"vi" to "Tiếng Việt",
|
||||
"yi" to "ייִדיש",
|
||||
"yo" to "Èdè Yorùbá",
|
||||
"zh" to "中文",
|
||||
"zh_CN" to "简体中文",
|
||||
"zh_TW" to "正體中文",
|
||||
"zu" to "isiZulu",
|
||||
"af" to LanguageName("Afrikaans", "Afrikaans"),
|
||||
"ak" to LanguageName("Akan", "Akan"),
|
||||
"am" to LanguageName("አማርኛ", "Amharic"),
|
||||
"ar" to LanguageName("العربية", "Arabic"),
|
||||
"as" to LanguageName("অসমীয়া", "Assamese"),
|
||||
"az" to LanguageName("azərbaycan", "Azerbaijani"),
|
||||
"be" to LanguageName("беларуская", "Belarusian"),
|
||||
"bg" to LanguageName("български", "Bulgarian"),
|
||||
"bm" to LanguageName("bamanakan", "Bambara"),
|
||||
"bn" to LanguageName("বাংলা", "Bengali"),
|
||||
"bo" to LanguageName("བོད་སྐད་", "Tibetan"),
|
||||
"br" to LanguageName("brezhoneg", "Breton"),
|
||||
"bs" to LanguageName("bosanski", "Bosnian"),
|
||||
"ca" to LanguageName("català", "Catalan"),
|
||||
"cs" to LanguageName("čeština", "Czech"),
|
||||
"cy" to LanguageName("Cymraeg", "Welsh"),
|
||||
"da" to LanguageName("dansk", "Danish"),
|
||||
"de" to LanguageName("Deutsch", "German"),
|
||||
"de_AT" to LanguageName("Österreichisches Deutsch", "Austrian German"),
|
||||
"de_CH" to LanguageName("Schweizer Hochdeutsch", "Swiss German"),
|
||||
"dz" to LanguageName("རྫོང་ཁ", "Dzongkha"),
|
||||
"ee" to LanguageName("eʋegbe", "Ewe"),
|
||||
"el" to LanguageName("Ελληνικά", "Greek"),
|
||||
"en" to LanguageName("English", "English"),
|
||||
"eo" to LanguageName("esperanto", "Esperanto"),
|
||||
"es" to LanguageName("español", "Spanish"),
|
||||
"et" to LanguageName("eesti", "Estonian"),
|
||||
"eu" to LanguageName("euskara", "Basque"),
|
||||
"fa" to LanguageName("فارسی", "Persian"),
|
||||
"ff" to LanguageName("Pulaar", "Fulah"),
|
||||
"fi" to LanguageName("suomi", "Finnish"),
|
||||
"fo" to LanguageName("føroyskt", "Faroese"),
|
||||
"fr" to LanguageName("français", "French"),
|
||||
"fr_CA" to LanguageName("français canadien", "Canadian French"),
|
||||
"fr_CH" to LanguageName("français suisse", "Swiss French"),
|
||||
"fy" to LanguageName("West-Frysk", "Western Frisian"),
|
||||
"ga" to LanguageName("Gaeilge", "Irish"),
|
||||
"gd" to LanguageName("Gàidhlig", "Scottish Gaelic"),
|
||||
"gl" to LanguageName("galego", "Galician"),
|
||||
"gu" to LanguageName("ગુજરાતી", "Gujarati"),
|
||||
"gv" to LanguageName("Gaelg", "Manx"),
|
||||
"ha" to LanguageName("Hausa", "Hausa"),
|
||||
"he" to LanguageName("עברית", "Hebrew"),
|
||||
"hi" to LanguageName("हिंदी", "Hindi"),
|
||||
"hr" to LanguageName("hrvatski", "Croatian"),
|
||||
"hu" to LanguageName("magyar", "Hungarian"),
|
||||
"hy" to LanguageName("հայերեն", "Armenian"),
|
||||
"id" to LanguageName("Bahasa Indonesia", "Indonesian"),
|
||||
"ig" to LanguageName("Igbo", "Igbo"),
|
||||
"ii" to LanguageName("ꆈꌠꉙ", "Sichuan Yi"),
|
||||
"is" to LanguageName("íslenska", "Icelandic"),
|
||||
"it" to LanguageName("italiano", "Italian"),
|
||||
"ja" to LanguageName("日本語", "Japanese"),
|
||||
"ka" to LanguageName("ქართული", "Georgian"),
|
||||
"ki" to LanguageName("Gikuyu", "Kikuyu"),
|
||||
"kk" to LanguageName("қазақ тілі", "Kazakh"),
|
||||
"kl" to LanguageName("kalaallisut", "Greenlandic"),
|
||||
"km" to LanguageName("ខ្មែរ", "Khmer"),
|
||||
"kn" to LanguageName("ಕನ್ನಡ", "Kannada"),
|
||||
"ko" to LanguageName("한국어", "Korean"),
|
||||
"ks" to LanguageName("کٲشُر", "Kashmiri"),
|
||||
"kw" to LanguageName("kernewek", "Cornish"),
|
||||
"ky" to LanguageName("кыргызча", "Kyrgyz"),
|
||||
"lb" to LanguageName("Lëtzebuergesch", "Luxembourgish"),
|
||||
"lg" to LanguageName("Luganda", "Ganda"),
|
||||
"ln" to LanguageName("lingála", "Lingala"),
|
||||
"lo" to LanguageName("ລາວ", "Lao"),
|
||||
"lt" to LanguageName("lietuvių", "Lithuanian"),
|
||||
"lu" to LanguageName("Tshiluba", "Luba-Katanga"),
|
||||
"lv" to LanguageName("latviešu", "Latvian"),
|
||||
"mg" to LanguageName("Malagasy", "Malagasy"),
|
||||
"mk" to LanguageName("македонски", "Macedonian"),
|
||||
"ml" to LanguageName("മലയാളം", "Malayalam"),
|
||||
"mn" to LanguageName("монгол", "Mongolian"),
|
||||
"mr" to LanguageName("मराठी", "Marathi"),
|
||||
"ms" to LanguageName("Bahasa Melayu", "Malay"),
|
||||
"mt" to LanguageName("Malti", "Maltese"),
|
||||
"my" to LanguageName("ဗမာ", "Burmese"),
|
||||
"nb" to LanguageName("norsk bokmål", "Norwegian Bokmål"),
|
||||
"nd" to LanguageName("isiNdebele", "North Ndebele"),
|
||||
"ne" to LanguageName("नेपाली", "Nepali"),
|
||||
"nl" to LanguageName("Nederlands", "Dutch"),
|
||||
"nl_BE" to LanguageName("Vlaams", "Flemish"),
|
||||
"nn" to LanguageName("nynorsk", "Norwegian Nynorsk"),
|
||||
"no" to LanguageName("norsk", "Norwegian"),
|
||||
"om" to LanguageName("Oromoo", "Oromo"),
|
||||
"or" to LanguageName("ଓଡ଼ିଆ", "Odia"),
|
||||
"os" to LanguageName("ирон", "Ossetic"),
|
||||
"pa" to LanguageName("ਪੰਜਾਬੀ", "Punjabi"),
|
||||
"pl" to LanguageName("polski", "Polish"),
|
||||
"ps" to LanguageName("پښتو", "Pashto"),
|
||||
"pt" to LanguageName("português", "Portuguese"),
|
||||
"pt_BR" to LanguageName("português do Brasil", "Brazilian Portuguese"),
|
||||
"qu" to LanguageName("Runasimi", "Quechua"),
|
||||
"rm" to LanguageName("rumantsch", "Romansh"),
|
||||
"rn" to LanguageName("Ikirundi", "Rundi"),
|
||||
"ro" to LanguageName("română", "Romanian"),
|
||||
"ro_MD" to LanguageName("moldovenească", "Moldovan"),
|
||||
"ru" to LanguageName("русский", "Russian"),
|
||||
"rw" to LanguageName("Kinyarwanda", "Kinyarwanda"),
|
||||
"se" to LanguageName("davvisámegiella", "Northern Sami"),
|
||||
"sg" to LanguageName("Sängö", "Sango"),
|
||||
"sh" to LanguageName("Srpskohrvatski", "Serbo-Croatian"),
|
||||
"si" to LanguageName("සිංහල", "Sinhala"),
|
||||
"sk" to LanguageName("slovenčina", "Slovak"),
|
||||
"sl" to LanguageName("slovenščina", "Slovene"),
|
||||
"sn" to LanguageName("chiShona", "Shona"),
|
||||
"so" to LanguageName("Soomaali", "Somali"),
|
||||
"sq" to LanguageName("shqip", "Albanian"),
|
||||
"sr" to LanguageName("српски", "Serbian"),
|
||||
"sv" to LanguageName("svenska", "Swedish"),
|
||||
"sw" to LanguageName("Kiswahili", "Swahili"),
|
||||
"ta" to LanguageName("தமிழ்", "Tamil"),
|
||||
"te" to LanguageName("తెలుగు", "Telugu"),
|
||||
"th" to LanguageName("ไทย", "Thai"),
|
||||
"ti" to LanguageName("ትግርኛ", "Tigrinya"),
|
||||
"tl" to LanguageName("Tagalog", "Tagalog"),
|
||||
"to" to LanguageName("lea fakatonga", "Tongan"),
|
||||
"tr" to LanguageName("Türkçe", "Turkish"),
|
||||
"ug" to LanguageName("ئۇيغۇرچە", "Uyghur"),
|
||||
"uk" to LanguageName("українська", "Ukrainian"),
|
||||
"ur" to LanguageName("اردو", "Urdu"),
|
||||
"uz" to LanguageName("oʻzbekcha", "Uzbek"),
|
||||
"vi" to LanguageName("Tiếng Việt", "Vietnamese"),
|
||||
"yi" to LanguageName("ייִדיש", "Yiddish"),
|
||||
"yo" to LanguageName("Èdè Yorùbá", "Yoruba"),
|
||||
"zh" to LanguageName("中文", "Chinese"),
|
||||
"zh_CN" to LanguageName("简体中文", "Simplified Chinese"),
|
||||
"zh_TW" to LanguageName("正體中文", "Traditional Chinese"),
|
||||
"zu" to LanguageName("isiZulu", "Zulu")
|
||||
)
|
||||
|
||||
override fun getNativeName(myLocale: MyLocale): String {
|
||||
return getName(myLocale).nativeName
|
||||
}
|
||||
|
||||
override fun getEnglishName(myLocale: MyLocale): String {
|
||||
return getName(myLocale).englishName
|
||||
}
|
||||
|
||||
override fun getName(myLocale: MyLocale): LanguageName {
|
||||
val languageCode = myLocale.languageCode
|
||||
val countryCode = myLocale.countryCode
|
||||
if (countryCode != null) {
|
||||
@ -151,9 +166,9 @@ object LanguageNameProvider : ILanguageNameProvider {
|
||||
list[languageCode]?.let {
|
||||
return it
|
||||
}
|
||||
return default(myLocale)
|
||||
return default(myLocale).let { LanguageName(it, it) }
|
||||
}
|
||||
|
||||
|
||||
private fun default(myLocale: MyLocale): String {
|
||||
return myLocale
|
||||
.toLocale()
|
||||
|
@ -0,0 +1,132 @@
|
||||
{
|
||||
"ar": [
|
||||
{
|
||||
"name": "Hani Rouatbi (lamjed001)",
|
||||
"link": "https://crowdin.com/profile/lamjed001"
|
||||
},
|
||||
{
|
||||
"name": "Mohamed Mahmoud (master3lwa)",
|
||||
"link": "https://crowdin.com/profile/master3lwa"
|
||||
},
|
||||
{
|
||||
"name": "amirhosseinshammari (hosseinSh1379)",
|
||||
"link": "https://crowdin.com/profile/hosseinSh1379"
|
||||
}
|
||||
],
|
||||
"bn": [
|
||||
{
|
||||
"name": "Md Shariful Islam (Shariful7972)",
|
||||
"link": "https://crowdin.com/profile/Shariful7972"
|
||||
}
|
||||
],
|
||||
"de": [
|
||||
{
|
||||
"name": "u!^DEV (uDEV)",
|
||||
"link": "https://crowdin.com/profile/uDEV"
|
||||
}
|
||||
],
|
||||
"es-ES": [
|
||||
{
|
||||
"name": "seniordevops",
|
||||
"link": "https://crowdin.com/profile/seniordevops"
|
||||
},
|
||||
{
|
||||
"name": "c-sanchez",
|
||||
"link": "https://crowdin.com/profile/c-sanchez"
|
||||
}
|
||||
],
|
||||
"fa": [
|
||||
{
|
||||
"name": "AmirHossein Abdolmotallebi (amira1376)",
|
||||
"link": "https://crowdin.com/profile/amira1376"
|
||||
}
|
||||
],
|
||||
"fr": [
|
||||
{
|
||||
"name": "Gooseman (realgooseman)",
|
||||
"link": "https://crowdin.com/profile/realgooseman"
|
||||
},
|
||||
{
|
||||
"name": "Hani Rouatbi (lamjed001)",
|
||||
"link": "https://crowdin.com/profile/lamjed001"
|
||||
}
|
||||
],
|
||||
"id": [
|
||||
{
|
||||
"name": "kuydukuy (hilmy2nd)",
|
||||
"link": "https://crowdin.com/profile/hilmy2nd"
|
||||
},
|
||||
{
|
||||
"name": "Christian Elbrianno (crse)",
|
||||
"link": "https://crowdin.com/profile/crse"
|
||||
}
|
||||
],
|
||||
"pt-BR": [
|
||||
{
|
||||
"name": "Guilherme (whatahelll)",
|
||||
"link": "https://crowdin.com/profile/whatahelll"
|
||||
},
|
||||
{
|
||||
"name": "Davy J. (deaveipslon)",
|
||||
"link": "https://crowdin.com/profile/deaveipslon"
|
||||
}
|
||||
],
|
||||
"ru": [
|
||||
{
|
||||
"name": "in-ferno",
|
||||
"link": "https://crowdin.com/profile/in-ferno"
|
||||
}
|
||||
],
|
||||
"sq": [
|
||||
{
|
||||
"name": "Mario Balla (marjob1234)",
|
||||
"link": "https://crowdin.com/profile/marjob1234"
|
||||
}
|
||||
],
|
||||
"tr": [
|
||||
{
|
||||
"name": "𝗦𝗵𝗟𝗲𝗿𝗣 (mikropsoft)",
|
||||
"link": "https://crowdin.com/profile/mikropsoft"
|
||||
}
|
||||
],
|
||||
"uk": [
|
||||
{
|
||||
"name": "YALdysse",
|
||||
"link": "https://crowdin.com/profile/YALdysse"
|
||||
},
|
||||
{
|
||||
"name": "Misha Dyshlenko (lony_official)",
|
||||
"link": "https://crowdin.com/profile/lony_official"
|
||||
},
|
||||
{
|
||||
"name": "YALdysse_",
|
||||
"link": "https://crowdin.com/profile/YALdysse_"
|
||||
}
|
||||
],
|
||||
"vi": [
|
||||
{
|
||||
"name": "Zenfast",
|
||||
"link": "https://crowdin.com/profile/Zenfast"
|
||||
}
|
||||
],
|
||||
"zh-CN": [
|
||||
{
|
||||
"name": "Pylogmon (pylogmon)",
|
||||
"link": "https://crowdin.com/profile/pylogmon"
|
||||
},
|
||||
{
|
||||
"name": "Pesy Wu (GamerNoTitle)",
|
||||
"link": "https://crowdin.com/profile/GamerNoTitle"
|
||||
},
|
||||
{
|
||||
"name": "Sendevia",
|
||||
"link": "https://crowdin.com/profile/Sendevia"
|
||||
}
|
||||
],
|
||||
"zh-TW": [
|
||||
{
|
||||
"name": "ɴᴇᴋᴏ (NeKoOuO)",
|
||||
"link": "https://crowdin.com/profile/NeKoOuO"
|
||||
}
|
||||
]
|
||||
}
|
@ -289,4 +289,12 @@ use_authentication=Use Authentication
|
||||
warning_you_may_have_to_restart_the_download_later=You may have to restart the download later!
|
||||
edit_download_title=Edit Download
|
||||
edit_download_update_from_download_page=Update from Download Page
|
||||
edit_download_update_from_download_page_description=When this window is open, you can go to the Download Page and click the download button. The app will capture and update the new download credentials so you can save them.
|
||||
edit_download_update_from_download_page_description=When this window is open, you can go to the Download Page and click the download button. The app will capture and update the new download credentials so you can save them.
|
||||
translators_page_thanks=With Gratitude to Those Who Helped Translate This Project ❤️
|
||||
translators=Translators
|
||||
language=Language
|
||||
translators_contribute_title=Improve Translations
|
||||
translators_contribute_description=Want to help improve this project? If your language is missing or needs some tweaks, you can contribute your translations and make it better!
|
||||
contribute=Contribute
|
||||
meet_the_translators=Meet the Translators
|
||||
localized_by_translators=Localized by Translators
|
Loading…
x
Reference in New Issue
Block a user