diff --git a/multisrc/overrides/bilibili/bilibilicomics/src/BilibiliComicsFactory.kt b/multisrc/overrides/bilibili/bilibilicomics/src/BilibiliComicsFactory.kt
index d3f680679..2347c68de 100644
--- a/multisrc/overrides/bilibili/bilibilicomics/src/BilibiliComicsFactory.kt
+++ b/multisrc/overrides/bilibili/bilibilicomics/src/BilibiliComicsFactory.kt
@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliAccessTokenCookie
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliComicDto
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliCredential
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliGetCredential
+import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliIntl
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliTag
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliUnlockedEpisode
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliUserEpisodes
@@ -147,7 +148,7 @@ abstract class BilibiliComics(lang: String) : Bilibili(
         }
 
         if (!response.isSuccessful) {
-            throw Exception(FAILED_TO_GET_CREDENTIAL)
+            throw Exception(intl.failedToGetCredential)
         }
 
         val result = response.parseAs<BilibiliCredential>()
@@ -230,13 +231,13 @@ abstract class BilibiliComics(lang: String) : Bilibili(
 
     private fun refreshTokenParse(response: Response): BilibiliAccessTokenCookie {
         if (!response.isSuccessful) {
-            throw IOException(FAILED_TO_REFRESH_TOKEN)
+            throw IOException(intl.failedToRefreshToken)
         }
 
         val result = response.parseAs<BilibiliAccessToken>()
 
         if (result.code != 0) {
-            throw IOException(FAILED_TO_REFRESH_TOKEN)
+            throw IOException(intl.failedToRefreshToken)
         }
 
         val accessToken = result.data!!
@@ -263,15 +264,10 @@ abstract class BilibiliComics(lang: String) : Bilibili(
         private val GLOBAL_API_SUBDOMAINS = arrayOf("us-user", "sg-user")
         private const val GLOBAL_BASE_API_USER_ENDPOINT = "twirp/global.v1.User"
         private const val GLOBAL_BASE_API_COMIC_ENDPOINT = "twirp/comic.v1.User"
-
-        private const val FAILED_TO_REFRESH_TOKEN =
-            "Failed to refresh the token. Open the WebView to fix this error."
-        private const val FAILED_TO_GET_CREDENTIAL =
-            "Failed to get the credential to read the chapter."
     }
 }
 
-class BilibiliComicsEn : BilibiliComics("en") {
+class BilibiliComicsEn : BilibiliComics(BilibiliIntl.ENGLISH) {
 
     override fun getAllGenres(): Array<BilibiliTag> = arrayOf(
         BilibiliTag("All", -1),
@@ -293,13 +289,7 @@ class BilibiliComicsEn : BilibiliComics("en") {
     )
 }
 
-class BilibiliComicsCn : BilibiliComics("zh-Hans") {
-
-    override fun getAllSortOptions(): Array<String> = arrayOf("为你推荐", "人气推荐", "更新时间")
-
-    override fun getAllStatus(): Array<String> = arrayOf("全部", "连载中", "已完结")
-
-    override fun getAllPrices(): Array<String> = arrayOf("全部", "免费", "付费")
+class BilibiliComicsCn : BilibiliComics(BilibiliIntl.SIMPLIFIED_CHINESE) {
 
     override fun getAllGenres(): Array<BilibiliTag> = arrayOf(
         BilibiliTag("全部", -1),
@@ -319,13 +309,7 @@ class BilibiliComicsCn : BilibiliComics("zh-Hans") {
     )
 }
 
-class BilibiliComicsId : BilibiliComics("id") {
-
-    override fun getAllSortOptions(): Array<String> = arrayOf("Kamu Mungkin Suka", "Populer", "Terbaru")
-
-    override fun getAllStatus(): Array<String> = arrayOf("Semua", "Berlangsung", "Tamat")
-
-    override fun getAllPrices(): Array<String> = arrayOf("Semua", "Bebas", "Dibayar")
+class BilibiliComicsId : BilibiliComics(BilibiliIntl.INDONESIAN) {
 
     override fun getAllGenres(): Array<BilibiliTag> = arrayOf(
         BilibiliTag("Semua", -1),
diff --git a/multisrc/overrides/bilibili/bilibilimanga/src/BilibiliManga.kt b/multisrc/overrides/bilibili/bilibilimanga/src/BilibiliManga.kt
index c2767cb59..ee89c96aa 100644
--- a/multisrc/overrides/bilibili/bilibilimanga/src/BilibiliManga.kt
+++ b/multisrc/overrides/bilibili/bilibilimanga/src/BilibiliManga.kt
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.zh.bilibilimanga
 
 import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
 import eu.kanade.tachiyomi.multisrc.bilibili.Bilibili
+import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliIntl
 import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliTag
 import okhttp3.HttpUrl.Companion.toHttpUrl
 import okhttp3.OkHttpClient
@@ -9,7 +10,7 @@ import okhttp3.OkHttpClient
 class BilibiliManga : Bilibili(
     "哔哩哔哩漫画",
     "https://manga.bilibili.com",
-    "zh-Hans"
+    BilibiliIntl.SIMPLIFIED_CHINESE
 ) {
 
     override val id: Long = 3561131545129718586
@@ -25,11 +26,11 @@ class BilibiliManga : Bilibili(
 
     override val defaultLatestSort: Int = 1
 
-    override fun getAllStatus(): Array<String> = arrayOf("全部", "连载", "完结")
+    override fun getAllSortOptions(): Array<String> =
+        arrayOf(intl.sortPopular, intl.sortUpdated, intl.sortFollowers, intl.sortAdded)
 
-    override fun getAllSortOptions(): Array<String> = arrayOf("人气推荐", "更新时间", "追漫人数", "上架时间")
-
-    override fun getAllPrices(): Array<String> = arrayOf("全部", "免费", "付费", "等就免费")
+    override fun getAllPrices(): Array<String> =
+        arrayOf(intl.priceAll, intl.priceFree, intl.pricePaid, intl.priceWaitForFree)
 
     override fun getAllGenres(): Array<BilibiliTag> = arrayOf(
         BilibiliTag("全部", -1),
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/Bilibili.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/Bilibili.kt
index 5dd90d6b5..9d636590e 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/Bilibili.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/Bilibili.kt
@@ -50,77 +50,17 @@ abstract class Bilibili(
         .add("Origin", baseUrl)
         .add("Referer", "$baseUrl/")
 
+    protected val intl by lazy { BilibiliIntl(lang) }
+
     private val apiLang: String = when (lang) {
-        "zh-Hans" -> "cn"
+        BilibiliIntl.SIMPLIFIED_CHINESE -> "cn"
         else -> lang
     }
 
-    protected open val statusLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "进度"
-        else -> "Status"
-    }
-
-    protected open val sortLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "排序"
-        "id" -> "Urutkan dengan"
-        else -> "Sort by"
-    }
-
-    protected open val genreLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "题材"
-        else -> "Genre"
-    }
-
-    protected open val areaLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "地区"
-        else -> "Area"
-    }
-
-    protected open val priceLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "收费"
-        "id" -> "Harga"
-        else -> "Price"
-    }
-
-    protected open val episodePrefix: String = when (lang) {
-        "zh", "zh-Hans" -> ""
-        else -> "Ep. "
-    }
-
     protected open val defaultPopularSort: Int = 1
 
     protected open val defaultLatestSort: Int = 2
 
-    protected open val hasPaidChaptersWarning: String = when (lang) {
-        "zh", "zh-Hans" -> "$EMOJI_WARNING 此漫画的付费章节已从章节列表中过滤,暂时请用网页端或官方app阅读。"
-        else ->
-            "$EMOJI_WARNING WARNING: This series has paid chapters that were filtered out from " +
-                "the chapter list. If you have already bought and have any in your account, sign " +
-                "in through WebView and refresh the chapter list to read them."
-    }
-
-    protected open val paidLabel: String = when (lang) {
-        "zh", "zh-Hans" -> "付费"
-        else -> "Paid"
-    }
-
-    protected open val imageQualityPrefTitle: String = when (lang) {
-        "zh", "zh-Hans" -> "章节图片质量"
-        "id" -> "Kualitas gambar"
-        else -> "Chapter image quality"
-    }
-
-    protected open val imageQualityPrefEntries: Array<String> = when (lang) {
-        "zh", "zh-Hans" -> arrayOf("原图", "高", "低")
-        else -> arrayOf("Raw", "HD", "SD")
-    }
-
-    protected open val imageFormatPrefTitle: String = when (lang) {
-        "zh", "zh-Hans" -> "章节图片格式"
-        "id" -> "Format gambar"
-        else -> "Chapter image format"
-    }
-
     private val preferences: SharedPreferences by lazy {
         Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
     }
@@ -347,13 +287,13 @@ abstract class Bilibili(
         title = comic.title
         author = comic.authorName.joinToString()
         status = if (comic.isFinish == 1) SManga.COMPLETED else SManga.ONGOING
-        genre = comic.genres(paidLabel, EMOJI_LOCKED).joinToString()
+        genre = comic.genres(intl.pricePaid, EMOJI_LOCKED).joinToString()
         description = comic.classicLines
         thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION
         url = "/detail/mc" + comic.id
 
         if (comic.hasPaidChapters && !signedIn) {
-            description = "$hasPaidChaptersWarning\n\n$description"
+            description = "${intl.hasPaidChaptersWarning}\n\n$description"
         }
     }
 
@@ -373,7 +313,7 @@ abstract class Bilibili(
     }
 
     protected fun chapterFromObject(episode: BilibiliEpisodeDto, comicId: Int): SChapter = SChapter.create().apply {
-        name = episodePrefix + episode.shortTitle +
+        name = intl.episodePrefix + episode.shortTitle +
             (if (episode.title.isNotBlank()) " - " + episode.title else "")
         date_upload = episode.publicationTime.substringBefore("T").toDate()
         url = "/mc$comicId/${episode.id}"
@@ -443,8 +383,8 @@ abstract class Bilibili(
     override fun setupPreferenceScreen(screen: PreferenceScreen) {
         val imageQualityPref = ListPreference(screen.context).apply {
             key = "${IMAGE_QUALITY_PREF_KEY}_$lang"
-            title = imageQualityPrefTitle
-            entries = imageQualityPrefEntries
+            title = intl.imageQualityPrefTitle
+            entries = intl.imageQualityPrefEntries
             entryValues = IMAGE_QUALITY_PREF_ENTRY_VALUES
             setDefaultValue(IMAGE_QUALITY_PREF_DEFAULT_VALUE)
             summary = "%s"
@@ -462,7 +402,7 @@ abstract class Bilibili(
 
         val imageFormatPref = ListPreference(screen.context).apply {
             key = "${IMAGE_FORMAT_PREF_KEY}_$lang"
-            title = imageFormatPrefTitle
+            title = intl.imageFormatPrefTitle
             entries = IMAGE_FORMAT_PREF_ENTRIES
             entryValues = IMAGE_FORMAT_PREF_ENTRY_VALUES
             setDefaultValue(IMAGE_FORMAT_PREF_DEFAULT_VALUE)
@@ -487,24 +427,27 @@ abstract class Bilibili(
 
     protected open fun getAllAreas(): Array<BilibiliTag> = emptyArray()
 
-    protected open fun getAllSortOptions(): Array<String> = arrayOf("Interest", "Popular", "Updated")
+    protected open fun getAllSortOptions(): Array<String> =
+        arrayOf(intl.sortInterest, intl.sortPopular, intl.sortUpdated)
 
-    protected open fun getAllStatus(): Array<String> = arrayOf("All", "Ongoing", "Completed")
+    protected open fun getAllStatus(): Array<String> =
+        arrayOf(intl.statusAll, intl.statusOngoing, intl.statusComplete)
 
-    protected open fun getAllPrices(): Array<String> = arrayOf("All", "Free", "Paid")
+    protected open fun getAllPrices(): Array<String> =
+        arrayOf(intl.priceAll, intl.priceFree, intl.pricePaid)
 
     override fun getFilterList(): FilterList {
         val filters = mutableListOf(
-            StatusFilter(statusLabel, getAllStatus()),
-            SortFilter(sortLabel, getAllSortOptions(), defaultPopularSort),
-            PriceFilter(priceLabel, getAllPrices()),
-            GenreFilter(genreLabel, getAllGenres())
+            StatusFilter(intl.statusLabel, getAllStatus()),
+            SortFilter(intl.sortLabel, getAllSortOptions(), defaultPopularSort),
+            PriceFilter(intl.priceLabel, getAllPrices()),
+            GenreFilter(intl.genreLabel, getAllGenres())
         )
 
         val allAreas = getAllAreas()
 
         if (allAreas.isNotEmpty()) {
-            filters.add(AreaFilter(areaLabel, allAreas))
+            filters += AreaFilter(intl.areaLabel, allAreas)
         }
 
         return FilterList(filters)
@@ -588,6 +531,6 @@ abstract class Bilibili(
         }
 
         private const val EMOJI_LOCKED = "\uD83D\uDD12"
-        private const val EMOJI_WARNING = "\u26A0\uFE0F"
+        const val EMOJI_WARNING = "\u26A0\uFE0F"
     }
 }
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliGenerator.kt
index d8dcdac27..0f07e5112 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliGenerator.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliGenerator.kt
@@ -10,11 +10,11 @@ class BilibiliGenerator : ThemeSourceGenerator {
 
     override val themeClass = "Bilibili"
 
-    override val baseVersionCode: Int = 1
+    override val baseVersionCode: Int = 2
 
     override val sources = listOf(
         MultiLang("BILIBILI COMICS", "https://www.bilibilicomics.com", listOf("en", "zh-Hans", "id"), className = "BilibiliComicsFactory"),
-        SingleLang("BILIBILI MANGA", "https://manga.bilibili.com", "zh-Hans", className = "BilibiliManga", overrideVersionCode = 1)
+        SingleLang("BILIBILI MANGA", "https://manga.bilibili.com", "zh-Hans", className = "BilibiliManga", sourceName = "哔哩哔哩漫画", overrideVersionCode = 1)
     )
 
     companion object {
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliIntl.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliIntl.kt
new file mode 100644
index 000000000..9b119f374
--- /dev/null
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bilibili/BilibiliIntl.kt
@@ -0,0 +1,144 @@
+package eu.kanade.tachiyomi.multisrc.bilibili
+
+class BilibiliIntl(lang: String) {
+
+    val statusLabel: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "进度"
+        else -> "Status"
+    }
+
+    val sortLabel: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "排序"
+        INDONESIAN -> "Urutkan dengan"
+        else -> "Sort by"
+    }
+
+    val genreLabel: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "题材"
+        else -> "Genre"
+    }
+
+    val areaLabel: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "地区"
+        else -> "Area"
+    }
+
+    val priceLabel: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "收费"
+        INDONESIAN -> "Harga"
+        else -> "Price"
+    }
+
+    val episodePrefix: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> ""
+        else -> "Ep. "
+    }
+
+    val hasPaidChaptersWarning: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE ->
+            "${Bilibili.EMOJI_WARNING} 此漫画的付费章节已从章节列表中过滤,暂时请用网页端或官方app阅读。"
+        else ->
+            "${Bilibili.EMOJI_WARNING} WARNING: This series has paid chapters that were filtered " +
+                "out from the chapter list. If you have already bought and have any in your " +
+                "account, sign in through WebView and refresh the chapter list to read them."
+    }
+
+    val imageQualityPrefTitle: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "章节图片质量"
+        INDONESIAN -> "Kualitas gambar"
+        else -> "Chapter image quality"
+    }
+
+    val imageQualityPrefEntries: Array<String> = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> arrayOf("原图", "高", "低")
+        else -> arrayOf("Raw", "HD", "SD")
+    }
+
+    val imageFormatPrefTitle: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "章节图片格式"
+        INDONESIAN -> "Format gambar"
+        else -> "Chapter image format"
+    }
+
+    val sortInterest: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "为你推荐"
+        INDONESIAN -> "Kamu Mungkin Suka"
+        else -> "Interest"
+    }
+
+    val sortPopular: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "人气推荐"
+        INDONESIAN -> "Populer"
+        else -> "Popular"
+    }
+
+    val sortUpdated: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "更新时间"
+        INDONESIAN -> "Terbaru"
+        else -> "Updated"
+    }
+
+    val sortAdded: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "上架时间"
+        else -> "Added"
+    }
+
+    val sortFollowers: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "追漫人数"
+        else -> "Followers count"
+    }
+
+    val statusAll: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "全部"
+        INDONESIAN -> "Semua"
+        else -> "All"
+    }
+
+    val statusOngoing: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "连载中"
+        INDONESIAN -> "Berlangsung"
+        else -> "Ongoing"
+    }
+
+    val statusComplete: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "已完结"
+        INDONESIAN -> "Tamat"
+        else -> "Completed"
+    }
+
+    val priceAll: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "全部"
+        INDONESIAN -> "Semua"
+        else -> "All"
+    }
+
+    val priceFree: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "免费"
+        INDONESIAN -> "Bebas"
+        else -> "Free"
+    }
+
+    val pricePaid: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "付费"
+        INDONESIAN -> "Dibayar"
+        else -> "Paid"
+    }
+
+    val priceWaitForFree: String = when (lang) {
+        CHINESE, SIMPLIFIED_CHINESE -> "等就免费"
+        else -> "Wait for free"
+    }
+
+    // TODO: Add Chinese translation.
+    val failedToRefreshToken: String = "Failed to refresh the token. Open the WebView to fix this error."
+
+    // TODO: Add Chinese translation.
+    val failedToGetCredential: String = "Failed to get the credential to read the chapter."
+
+    companion object {
+        const val CHINESE = "zh"
+        const val ENGLISH = "en"
+        const val INDONESIAN = "id"
+        const val SIMPLIFIED_CHINESE = "zh-Hans"
+    }
+}