Internationalization WIP

This commit is contained in:
shabinder 2021-06-25 19:16:38 +05:30
parent e50cf82f6a
commit 6e517e0049
11 changed files with 94 additions and 82 deletions

View File

@ -19,6 +19,7 @@ package com.shabinder.spotiflyer
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.common.translations.Strings
import com.shabinder.spotiflyer.di.appModule import com.shabinder.spotiflyer.di.appModule
import org.acra.config.httpSender import org.acra.config.httpSender
import org.acra.config.notification import org.acra.config.notification
@ -77,10 +78,10 @@ class App: Application(), KoinComponent {
* Obeying `F-Droid Inclusion Privacy Rules` * Obeying `F-Droid Inclusion Privacy Rules`
* */ * */
notification { notification {
title = getString(R.string.acra_notification_title) title = Strings.acraNotificationTitle()
text = getString(R.string.acra_notification_text) text = Strings.acraNotificationText()
channelName = getString(R.string.acra_notification_channel) channelName = "SpotiFlyer_Crashlytics"
channelDescription = getString(R.string.acra_notification_channel_desc) channelDescription = "Notification Channel to send Spotiflyer Crashes."
sendOnClick = true sendOnClick = true
} }
// Send Crash Report to self hosted Acrarium (FOSS) // Send Crash Report to self hosted Acrarium (FOSS)

View File

@ -43,6 +43,7 @@ import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.event.coroutines.SuspendableEvent import com.shabinder.common.models.event.coroutines.SuspendableEvent
import com.shabinder.common.models.event.coroutines.failure import com.shabinder.common.models.event.coroutines.failure
import com.shabinder.common.translations.Strings
import com.shabinder.spotiflyer.utils.autoclear.AutoClear import com.shabinder.spotiflyer.utils.autoclear.AutoClear
import com.shabinder.spotiflyer.utils.autoclear.autoClear import com.shabinder.spotiflyer.utils.autoclear.autoClear
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -237,7 +238,7 @@ class ForegroundService : LifecycleService() {
lifecycleScope.launch { lifecycleScope.launch {
logger.d(TAG) { "Killing Self" } logger.d(TAG) { "Killing Self" }
messageList = messageList.getEmpty().apply { messageList = messageList.getEmpty().apply {
set(index = 0, Message("Cleaning And Exiting",DownloadStatus.NotDownloaded)) set(index = 0, Message(Strings.cleaningAndExiting(),DownloadStatus.NotDownloaded))
} }
downloadService.value.close() downloadService.value.close()
downloadService.reset() downloadService.reset()
@ -257,7 +258,7 @@ class ForegroundService : LifecycleService() {
private fun createNotification(): Notification = NotificationCompat.Builder(this, CHANNEL_ID).run { private fun createNotification(): Notification = NotificationCompat.Builder(this, CHANNEL_ID).run {
setSmallIcon(R.drawable.ic_download_arrow) setSmallIcon(R.drawable.ic_download_arrow)
setContentTitle("Total: $total Completed:$converted Failed:$failed") setContentTitle("${Strings.total()}: $total ${Strings.completed()}:$converted ${Strings.failed()}:$failed")
setSilent(true) setSilent(true)
setProgress(total,failed+converted,false) setProgress(total,failed+converted,false)
setStyle( setStyle(
@ -269,7 +270,7 @@ class ForegroundService : LifecycleService() {
addLine(messageList[messageList.size - 5].asString()) addLine(messageList[messageList.size - 5].asString())
} }
) )
addAction(R.drawable.ic_round_cancel_24, "Exit", cancelIntent) addAction(R.drawable.ic_round_cancel_24, Strings.exit(), cancelIntent)
build() build()
} }

View File

@ -1,6 +1,7 @@
package com.shabinder.spotiflyer.service package com.shabinder.spotiflyer.service
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.translations.Strings
typealias Message = Pair<String, DownloadStatus> typealias Message = Pair<String, DownloadStatus>
@ -11,9 +12,9 @@ val Message.downloadStatus: DownloadStatus get() = second
val Message.progress: String get() = when (downloadStatus) { val Message.progress: String get() = when (downloadStatus) {
is DownloadStatus.Downloading -> "-> ${(downloadStatus as DownloadStatus.Downloading).progress}%" is DownloadStatus.Downloading -> "-> ${(downloadStatus as DownloadStatus.Downloading).progress}%"
is DownloadStatus.Converting -> "-> 100%" is DownloadStatus.Converting -> "-> 100%"
is DownloadStatus.Downloaded -> "-> Done" is DownloadStatus.Downloaded -> "-> ${Strings.downloadDone}"
is DownloadStatus.Failed -> "-> Failed" is DownloadStatus.Failed -> "-> ${Strings.failed()}"
is DownloadStatus.Queued -> "-> Queued" is DownloadStatus.Queued -> "-> ${Strings.queued()}"
is DownloadStatus.NotDownloaded -> "" is DownloadStatus.NotDownloaded -> ""
} }
@ -23,8 +24,8 @@ val emptyMessage = Message("",DownloadStatus.NotDownloaded)
// all Progress data is emitted all together from fun // all Progress data is emitted all together from fun
fun Message.asString(): String { fun Message.asString(): String {
val statusString = when(downloadStatus){ val statusString = when(downloadStatus){
is DownloadStatus.Downloading -> "Downloading" is DownloadStatus.Downloading -> Strings.downloading()
is DownloadStatus.Converting -> "Processing" is DownloadStatus.Converting -> Strings.processing()
else -> "" else -> ""
} }
return "$statusString $title ${""/*progress*/}".trim() return "$statusString $title ${""/*progress*/}".trim()

View File

@ -1,37 +0,0 @@
<!--
~ Copyright (c) 2021 Shabinder Singh
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">SpotiFlyer</string>
<string name="home_about">About</string>
<string name="home_history">History</string>
<string name="supported_platform">Supported Platforms</string>
<string name="support_development">Support Development</string>
<string name="github_star">Star / Fork the project on Github.</string>
<string name="github">GitHub</string>
<string name="translate">Translate</string>
<string name="help_us_translate">Help us translate this app in your local language.</string>
<string name="donate">Donate</string>
<string name="donate_subtitle">If you think I deserve to get paid for my work, you can leave me some money here.</string>
<string name="share">Share</string>
<string name="share_subtitle">Share this app with your friends and family.</string>
<string name="made_with_love">Made with</string>
<string name="in_india">in India</string>
<string name="acra_notification_title">OOPS, SpotiFlyer Crashed</string>
<string name="acra_notification_text">Please Send Crash Report to App Developers, So this unfortunate event may not happen again.</string>
<string name="acra_notification_channel">SpotiFlyer_Crashlytics</string>
<string name="acra_notification_channel_desc">Notification Channel to send Spotiflyer Crashes.</string>
</resources>

View File

@ -26,6 +26,7 @@ import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import com.shabinder.common.database.R import com.shabinder.common.database.R
import com.shabinder.common.translations.Strings
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
actual fun montserratFont() = FontFamily( actual fun montserratFont() = FontFamily(
@ -43,7 +44,7 @@ actual fun pristineFont() = FontFamily(
actual fun DownloadImageTick() { actual fun DownloadImageTick() {
Image( Image(
painterResource(R.drawable.ic_tick), painterResource(R.drawable.ic_tick),
"Download Done" Strings.downloadDone()
) )
} }
@ -51,7 +52,7 @@ actual fun DownloadImageTick() {
actual fun DownloadImageError() { actual fun DownloadImageError() {
Image( Image(
painterResource(R.drawable.ic_error), painterResource(R.drawable.ic_error),
"Error! Cant Download this track" Strings.downloadError()
) )
} }
@ -59,7 +60,7 @@ actual fun DownloadImageError() {
actual fun DownloadImageArrow(modifier: Modifier) { actual fun DownloadImageArrow(modifier: Modifier) {
Image( Image(
painterResource(R.drawable.ic_arrow), painterResource(R.drawable.ic_arrow),
"Start Download", Strings.downloadStart(),
modifier modifier
) )
} }

View File

@ -25,6 +25,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.shabinder.common.models.methods import com.shabinder.common.models.methods
import com.shabinder.common.translations.Strings
@OptIn(ExperimentalAnimationApi::class) @OptIn(ExperimentalAnimationApi::class)
@Composable @Composable
@ -44,7 +45,7 @@ actual fun DonationDialog(
) { ) {
Column(Modifier.padding(16.dp)) { Column(Modifier.padding(16.dp)) {
Text( Text(
"We Need Your Support!", Strings.supportUs(),
style = SpotiFlyerTypography.h5, style = SpotiFlyerTypography.h5,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = colorAccent, color = colorAccent,
@ -69,7 +70,7 @@ actual fun DonationDialog(
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = "Worldwide Donations", text = Strings.worldWideDonations(),
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
@ -92,7 +93,7 @@ actual fun DonationDialog(
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = "International Donations (Outside India).", text = Strings.worldWideDonations(),
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
@ -115,7 +116,7 @@ actual fun DonationDialog(
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = "Indian Donations (UPI / PayTM / PhonePe / Cards).", text = "${Strings.indianDonations()} (UPI / PayTM / PhonePe / Cards).",
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
@ -127,10 +128,10 @@ actual fun DonationDialog(
modifier = Modifier.padding(horizontal = 4.dp).fillMaxWidth() modifier = Modifier.padding(horizontal = 4.dp).fillMaxWidth()
) { ) {
OutlinedButton(onClick = onDismiss) { OutlinedButton(onClick = onDismiss) {
Text("Dismiss.") Text(Strings.dismiss())
} }
TextButton(onClick = onSnooze, colors = ButtonDefaults.buttonColors()) { TextButton(onClick = onSnooze, colors = ButtonDefaults.buttonColors()) {
Text("Remind Later!") Text(Strings.remindLater())
} }
} }
} }

View File

@ -54,6 +54,7 @@ import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.methods import com.shabinder.common.models.methods
import com.shabinder.common.translations.Strings
import com.shabinder.common.uikit.dialogs.DonationDialogComponent import com.shabinder.common.uikit.dialogs.DonationDialogComponent
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@ -67,7 +68,7 @@ fun SpotiFlyerListContent(
LaunchedEffect(model.errorOccurred) { LaunchedEffect(model.errorOccurred) {
/*Handle if Any Exception Occurred*/ /*Handle if Any Exception Occurred*/
model.errorOccurred?.let { model.errorOccurred?.let {
methods.value.showPopUpMessage(it.message ?: "An Error Occurred, Check your Link / Connection") methods.value.showPopUpMessage(it.message ?: Strings.errorOccurred())
component.onBackPressed() component.onBackPressed()
} }
} }
@ -79,7 +80,7 @@ fun SpotiFlyerListContent(
Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally) { Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator() CircularProgressIndicator()
Spacer(modifier.padding(8.dp)) Spacer(modifier.padding(8.dp))
Text("Loading..", style = appNameStyle, color = colorPrimary) Text("${Strings.loading()}...", style = appNameStyle, color = colorPrimary)
} }
} else { } else {
@ -142,7 +143,7 @@ fun TrackCard(
ImageLoad( ImageLoad(
track.albumArtURL, track.albumArtURL,
{ loadImage() }, { loadImage() },
"Album Art", Strings.albumArt(),
modifier = Modifier modifier = Modifier
.width(70.dp) .width(70.dp)
.height(70.dp) .height(70.dp)
@ -156,7 +157,7 @@ fun TrackCard(
modifier = Modifier.padding(horizontal = 8.dp).fillMaxSize() modifier = Modifier.padding(horizontal = 8.dp).fillMaxSize()
) { ) {
Text("${track.artists.firstOrNull()}...", fontSize = 12.sp, maxLines = 1) Text("${track.artists.firstOrNull()}...", fontSize = 12.sp, maxLines = 1)
Text("${track.durationSec / 60} min, ${track.durationSec % 60} sec", fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) Text("${track.durationSec / 60} ${Strings.minute()}, ${track.durationSec % 60} ${Strings.second()}", fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
} }
} }
when (track.downloaded) { when (track.downloaded) {
@ -202,7 +203,7 @@ fun CoverImage(
ImageLoad( ImageLoad(
coverURL, coverURL,
{ loadImage(coverURL, true) }, { loadImage(coverURL, true) },
"Cover Image", Strings.coverImage(),
modifier = Modifier modifier = Modifier
.padding(12.dp) .padding(12.dp)
.width(190.dp) .width(190.dp)
@ -225,9 +226,9 @@ fun CoverImage(
@Composable @Composable
fun DownloadAllButton(onClick: () -> Unit, modifier: Modifier = Modifier) { fun DownloadAllButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
ExtendedFloatingActionButton( ExtendedFloatingActionButton(
text = { Text("Download All") }, text = { Text(Strings.downloadAll()) },
onClick = onClick, onClick = onClick,
icon = { Icon(DownloadAllImage(), "Download All Button", tint = Color(0xFF000000)) }, icon = { Icon(DownloadAllImage(), Strings.downloadAll() + Strings.button(), tint = Color(0xFF000000)) },
backgroundColor = colorAccent, backgroundColor = colorAccent,
modifier = modifier modifier = modifier
) )

View File

@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.shabinder.common.translations.Strings
import com.shabinder.common.uikit.HeartIcon import com.shabinder.common.uikit.HeartIcon
import com.shabinder.common.uikit.SpotiFlyerLogo import com.shabinder.common.uikit.SpotiFlyerLogo
import com.shabinder.common.uikit.SpotiFlyerTypography import com.shabinder.common.uikit.SpotiFlyerTypography
@ -55,7 +56,7 @@ fun Splash(modifier: Modifier = Modifier, onTimeout: () -> Unit) {
delay(SplashWaitTime) delay(SplashWaitTime)
currentOnTimeout() currentOnTimeout()
} }
Image(SpotiFlyerLogo(), "SpotiFlyer Logo") Image(SpotiFlyerLogo(), Strings.spotiflyerLogo())
MadeInIndia(Modifier.align(Alignment.BottomCenter)) MadeInIndia(Modifier.align(Alignment.BottomCenter))
} }
} }
@ -73,21 +74,21 @@ fun MadeInIndia(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
text = "Made with ", text = "${Strings.madeWith()} ",
color = colorPrimary, color = colorPrimary,
fontSize = 22.sp fontSize = 22.sp
) )
Spacer(modifier = Modifier.padding(start = 4.dp)) Spacer(modifier = Modifier.padding(start = 4.dp))
Icon(HeartIcon(), "Love", tint = Color.Unspecified) Icon(HeartIcon(), Strings.love(), tint = Color.Unspecified)
Spacer(modifier = Modifier.padding(start = 4.dp)) Spacer(modifier = Modifier.padding(start = 4.dp))
Text( Text(
text = " in India", text = " ${Strings.inIndia()}",
color = colorPrimary, color = colorPrimary,
fontSize = 22.sp fontSize = 22.sp
) )
} }
Text( Text(
"by: Shabinder Singh", Strings.byDeveloperName(),
style = SpotiFlyerTypography.h6, style = SpotiFlyerTypography.h6,
color = colorAccent, color = colorAccent,
fontSize = 14.sp fontSize = 14.sp

View File

@ -20,9 +20,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.v1.Dialog import androidx.compose.ui.window.v1.Dialog
import com.shabinder.common.models.methods import com.shabinder.common.models.methods
import com.shabinder.common.translations.Strings
@OptIn(ExperimentalAnimationApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class) @OptIn(ExperimentalAnimationApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class)
@Composable @Composable
@ -42,7 +42,7 @@ actual fun DonationDialog(
) { ) {
Column(Modifier.padding(16.dp)) { Column(Modifier.padding(16.dp)) {
Text( Text(
"Support Us", Strings.supportUs(),
style = SpotiFlyerTypography.h5, style = SpotiFlyerTypography.h5,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = colorAccent, color = colorAccent,
@ -67,7 +67,7 @@ actual fun DonationDialog(
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = "International Donations (Outside India).", text = Strings.worldWideDonations(),
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
@ -90,7 +90,7 @@ actual fun DonationDialog(
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = "Indian Donations (UPI / PayTM / PhonePe / Cards).", text = "${Strings.indianDonations()} (UPI / PayTM / PhonePe / Cards).",
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }

View File

@ -1,41 +1,43 @@
package com.shabinder.common.models package com.shabinder.common.models
import com.shabinder.common.translations.Strings
sealed class SpotiFlyerException(override val message: String): Exception(message) { sealed class SpotiFlyerException(override val message: String): Exception(message) {
data class FeatureNotImplementedYet(override val message: String = "Feature not yet implemented."): SpotiFlyerException(message) data class FeatureNotImplementedYet(override val message: String = Strings.featureUnImplemented()): SpotiFlyerException(message)
data class NoInternetException(override val message: String = "Check Your Internet Connection"): SpotiFlyerException(message) data class NoInternetException(override val message: String = Strings.checkInternetConnection()): SpotiFlyerException(message)
data class MP3ConversionFailed( data class MP3ConversionFailed(
val extraInfo:String? = null, val extraInfo:String? = null,
override val message: String = "MP3 Converter unreachable, probably BUSY ! \nCAUSE:$extraInfo" override val message: String = "${Strings.mp3ConverterBusy()} \nCAUSE:$extraInfo"
): SpotiFlyerException(message) ): SpotiFlyerException(message)
data class UnknownReason( data class UnknownReason(
val exception: Throwable? = null, val exception: Throwable? = null,
override val message: String = "Unknown Error" override val message: String = Strings.unknownError()
): SpotiFlyerException(message) ): SpotiFlyerException(message)
data class NoMatchFound( data class NoMatchFound(
val trackName: String? = null, val trackName: String? = null,
override val message: String = "$trackName : NO Match Found!" override val message: String = "$trackName : ${Strings.noMatchFound()}"
): SpotiFlyerException(message) ): SpotiFlyerException(message)
data class YoutubeLinkNotFound( data class YoutubeLinkNotFound(
val videoID: String? = null, val videoID: String? = null,
override val message: String = "No Downloadable link found for videoID: $videoID" override val message: String = "${Strings.noLinkFound()}: $videoID"
): SpotiFlyerException(message) ): SpotiFlyerException(message)
data class DownloadLinkFetchFailed( data class DownloadLinkFetchFailed(
val trackName: String, val trackName: String,
val jioSaavnError: Throwable, val jioSaavnError: Throwable,
val ytMusicError: Throwable, val ytMusicError: Throwable,
override val message: String = "No Downloadable link found for track: $trackName," + override val message: String = "${Strings.noLinkFound()}: $trackName," +
" \n JioSaavn Error's StackTrace: ${jioSaavnError.stackTraceToString()} \n " + " \n JioSaavn Error's StackTrace: ${jioSaavnError.stackTraceToString()} \n " +
" \n YtMusic Error's StackTrace: ${ytMusicError.stackTraceToString()} \n " " \n YtMusic Error's StackTrace: ${ytMusicError.stackTraceToString()} \n "
): SpotiFlyerException(message) ): SpotiFlyerException(message)
data class LinkInvalid( data class LinkInvalid(
val link: String? = null, val link: String? = null,
override val message: String = "Entered Link is NOT Valid!\n ${link ?: ""}" override val message: String = "${Strings.linkNotValid()}\n ${link ?: ""}"
): SpotiFlyerException(message) ): SpotiFlyerException(message)
} }

View File

@ -19,10 +19,48 @@ status = Status
analytics = Analytics analytics = Analytics
analyticsDescription = Your Data is Anonymized and never shared with 3rd party service. analyticsDescription = Your Data is Anonymized and never shared with 3rd party service.
noHistoryAvailable = No History Available noHistoryAvailable = No History Available
cleaningAndExiting = Cleaning And Exiting
total = Total
completed = Completed
failed = Failed
exit = Exit
downloading = Downloading
processing = Processing
queued = Queued
acraNotificationTitle = OOPS, SpotiFlyer Crashed
acraNotificationText = Please Send Crash Report to App Developers, So this unfortunate event may not happen again.
albumArt = Album Art albumArt = Album Art
tracks = Tracks tracks = Tracks
coverImage = Cover Image
reSearch = Re-Search reSearch = Re-Search
loading = Loading
downloadAll = Download All
button = Button
errorOccurred = An Error Occurred, Check your Link / Connection
downloadDone = Download Done
downloadError = Error! Cant Download this track
downloadStart = Start Download
supportUs = We Need Your Support!
donation = Donation
worldWideDonations = World Wide Donations
indianDonations = Indian Donations Only
dismiss = Dismiss
remindLater = Remind Later
# Exceptions
mp3ConverterBusy = MP3 Converter unreachable, probably BUSY !
unknownError = Unknown Error
noMatchFound = NO Match Found!
noLinkFound = No Downloadable link found
linkNotValid = Entered Link is NOT Valid!
checkInternetConnection = Check Your Internet Connection
featureUnImplemented = Feature not yet implemented.
minute = min
second = sec
spotiflyerLogo = SpotiFlyer Logo spotiflyerLogo = SpotiFlyer Logo
backButton = Back Button backButton = Back Button
infoTab = Info Tab infoTab = Info Tab
@ -31,5 +69,7 @@ linkTextBox = Link Text Box
pasteLinkHere = Paste Link Here... pasteLinkHere = Paste Link Here...
enterALink = Enter A Link! enterALink = Enter A Link!
madeWith = Made with madeWith = Made with
love = Love
inIndia = in India inIndia = in India
open = Open open = Open
byDeveloperName = by: Shabinder Singh