Skip to content

Commit

Permalink
Even stricter language file linting
Browse files Browse the repository at this point in the history
  • Loading branch information
Earthcomputer committed Dec 18, 2024
1 parent 6879f63 commit 84855a5
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,58 @@ abstract class CheckLanguageFilesTask : DefaultTask() {
private fun validateValue(filename: String, lineNumber: Int, key: String, value: String, enUs: JsonObject?): Boolean {
var errored = false

val englishValue = enUs?.get(key)?.takeIf { it is JsonPrimitive && it.isString }?.let(JsonElement::getAsString)

if (!checkFormattingCodes(filename, lineNumber, key, value)) {
errored = true
}

if (!checkZeroWidthSpace(filename, lineNumber, key, value)) {
errored = true
}

if (!checkNotEndWithPeriod(filename, lineNumber, key, value)) {
errored = true
}

if (!checkFormatSpecifiers(filename, lineNumber, key, value, englishValue)) {
errored = true
}

return !errored
}

private fun checkFormattingCodes(filename: String, lineNumber: Int, key: String, value: String): Boolean {
if (value.contains('§')) {
logger.error("$filename:$lineNumber: translation '$key' contains legacy formatting code ('§'). Use formatting in code instead")
errored = true
return false
}

return true
}

private fun checkZeroWidthSpace(filename: String, lineNumber: Int, key: String, value: String): Boolean {
if (value.contains('\u200b')) {
logger.error("$filename:$lineNumber: translation '$key' contains zero width space")
return false
}

return true
}

private fun checkNotEndWithPeriod(filename: String, lineNumber: Int, key: String, value: String): Boolean {
// only check English, it's a mess otherwise with other languages' weird rules
if (filename == "en_us.json" && value.endsWith('.') && !value.endsWith("...")) {
logger.error("$filename:$lineNumber: translation '$key' ends with a period")
return false
}

return true
}

private fun checkFormatSpecifiers(filename: String, lineNumber: Int, key: String, value: String, englishValue: String?): Boolean {
var errored = false

val formatSpecifiers = formatSpecifierRegex.findAll(value)
val (legalFormatSpecifiers, illegalFormatSpecifiers) = formatSpecifiers.partition { allowedFormatSpecifierRegex.matches(it.value) }

Expand Down Expand Up @@ -326,31 +373,29 @@ abstract class CheckLanguageFilesTask : DefaultTask() {
}
}

if (!mixedIndexed) {
enUs?.get(key)?.takeIf { it is JsonPrimitive && it.isString }?.let(JsonElement::getAsString)?.let { englishValue ->
val (englishLegalFormatSpecifiers, englishIllegalFormatSpecifiers) = formatSpecifierRegex.findAll(englishValue).partition { allowedFormatSpecifierRegex.matches(it.value) }
if (englishIllegalFormatSpecifiers.isEmpty() && englishLegalFormatSpecifiers.all { it.groups["argIndex"] == null }) {
val numSpecifiers = englishLegalFormatSpecifiers.count { it.value.endsWith('s') }
if (allowNonIndexed) {
if (usedIndexes.size < numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' does not have enough format specifiers. It only has ${usedIndexes.size} while the English has $numSpecifiers")
errored = true
} else if (usedIndexes.size > numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' has extra format specifiers. It has ${usedIndexes.size} while the English only ha $numSpecifiers")
if (!mixedIndexed && englishValue != null) {
val (englishLegalFormatSpecifiers, englishIllegalFormatSpecifiers) = formatSpecifierRegex.findAll(englishValue).partition { allowedFormatSpecifierRegex.matches(it.value) }
if (englishIllegalFormatSpecifiers.isEmpty() && englishLegalFormatSpecifiers.all { it.groups["argIndex"] == null }) {
val numSpecifiers = englishLegalFormatSpecifiers.count { it.value.endsWith('s') }
if (allowNonIndexed) {
if (usedIndexes.size < numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' does not have enough format specifiers. It only has ${usedIndexes.size} while the English has $numSpecifiers")
errored = true
} else if (usedIndexes.size > numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' has extra format specifiers. It has ${usedIndexes.size} while the English only ha $numSpecifiers")
errored = true
}
} else {
for (i in 0 until numSpecifiers) {
if (i !in usedIndexes) {
logger.error("$filename:$lineNumber: translation key '$key' does not specify '%${i + 1}\$s' which is required because the English has $numSpecifiers format specifiers")
errored = true
}
} else {
for (i in 0 until numSpecifiers) {
if (i !in usedIndexes) {
logger.error("$filename:$lineNumber: translation key '$key' does not specify '%${i + 1}\$s' which is required because the English has $numSpecifiers format specifiers")
errored = true
}
}
for (i in usedIndexes) {
if (i >= numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' specifies '%${i + 1}\$s' which is out of bounds for $numSpecifiers format specifiers existing in the English")
errored = true
}
}
for (i in usedIndexes) {
if (i >= numSpecifiers) {
logger.error("$filename:$lineNumber: translation key '$key' specifies '%${i + 1}\$s' which is out of bounds for $numSpecifiers format specifiers existing in the English")
errored = true
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/main/resources/assets/clientcommands/lang/de_de.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"c2cpacket.messageC2CPacket.outgoing": "du -> %s: %s",
"c2cpacket.messageTooLong": "Nachricht zu lange (max. 255 Zeichen) %s Zeichen gefunden",
"c2cpacket.publicKeyNotFound": "Öffentlicher Schlüssel nicht gefunden",
"c2cpacket.receivedC2CPacket": "Du hast ein C2C-Paket erhalten, aber du akzeptierst keine eingehenden C2C-Pakete! Hover um das rohe Paket zu sehen.",
"c2cpacket.receivedC2CPacket": "Du hast ein C2C-Paket erhalten, aber du akzeptierst keine eingehenden C2C-Pakete! Hover um das rohe Paket zu sehen",
"c2cpacket.sentC2CPacket": "Du hast ein C2C-Paket gesendet, aber du akzeptierst keine eingehenden C2C-Pakete!",

"chorusManip.goalTooFar": "Ziel ist zu weit entfernt!",
"chorusManip.landing.failed": "Landungsmanipulation nicht möglich",
"chorusManip.landing.success": "Landung auf: %s, %s, %s",
"chorusManip.needChorusManipulation": "Chorusfruchtmanipulation muss aktiviert sein, um diesen Befehl auszuführen.",
"chorusManip.needChorusManipulation": "Chorusfruchtmanipulation muss aktiviert sein, um diesen Befehl auszuführen",
"chorusManip.setGoal": "%s-Zielbereich von %s bis %s festgelegt",

"commands.calias.addAlias.aliasAlreadyExists": "Alias \"%s\" existiert bereits",
Expand Down Expand Up @@ -54,7 +54,7 @@
"commands.ccalcstack.success.exact": "%s %s sind genau %s Stapel",

"commands.ccrackrng.failed": "Knacken des Spielerseeds gescheitert",
"commands.ccrackrng.failed.help": "Hilfe: RNG-Manipulation funktioniert nicht auf manchen modifizierten Servern, im Besonderen nicht auf Paper.",
"commands.ccrackrng.failed.help": "Hilfe: RNG-Manipulation funktioniert nicht auf manchen modifizierten Servern, im Besonderen nicht auf Paper",
"commands.ccrackrng.retries": "Knacke Spielerseed, Versuch %s/%s",
"commands.ccrackrng.starting": "Knacke Spielerseed",
"commands.ccrackrng.success": "Spieler-RNG geknackt: %s",
Expand All @@ -75,9 +75,9 @@
"commands.cenchant.failed": "Es ist unmöglich oder würde zu lange brauchen, diese Verzauberungen zu bekommen",
"commands.cenchant.help.uncrackedPlayerSeed": "Hilfe: du hast den Spielerseed nicht vollständig geknackt",
"commands.cenchant.incompatible": "Unvereinbare Verzauberungen",
"commands.cenchant.needEnchantingPrediction": "Verzauberungsprognose muss aktiviert sein, um diesen Befehl auszuführen.",
"commands.cenchant.needEnchantingPrediction": "Verzauberungsprognose muss aktiviert sein, um diesen Befehl auszuführen",
"commands.cenchant.success": "Verzauberungsmanipulation beginnt",
"commands.cenchant.uncracked": "Seed muss geknackt sein.",
"commands.cenchant.uncracked": "Seed muss geknackt sein",

"commands.cfind.found": "Fand %s an %s, %s Blöcke entfernt",
"commands.cfind.keepSearching.success": "Finde Objekte",
Expand All @@ -90,7 +90,7 @@

"commands.cfinditem.match": "%sx %s wurden an %s gefunden",
"commands.cfinditem.starting": "Suche nach %s",
"commands.cfinditem.starting.keepSearching": "Suche unendlich lange nach %s.",
"commands.cfinditem.starting.keepSearching": "Suche unendlich lange nach %s",
"commands.cfinditem.total": "Fand insgesamt %sx %s",

"commands.cfish.addGoal.success": "Ziel %s erfolgreich hinzugefügt",
Expand Down Expand Up @@ -323,7 +323,7 @@
"playerManip.state.waiting_dummy_enchant": "Warte auf eine Dummy-Verzauberung",
"playerManip.throwError": "Bedingung nicht möglich oder würde mehr als %s Würfe von Gegenstände erfordern",
"playerManip.toolBreakWarning": "Warnung: Werkzeug hat nur mehr %s Haltbarkeit übrig",
"playerManip.uncracked": "Spieler-Seed muss geknackt sein.",
"playerManip.uncracked": "Spieler-Seed muss geknackt sein",

"snakeGame.score": "Punkte: %s",
"snakeGame.title": "Snake"
Expand Down
8 changes: 4 additions & 4 deletions src/main/resources/assets/clientcommands/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"c2cpacket.encryptionFailed": "Something failed while encrypting your message",
"c2cpacket.malformedPacket": "You have received a malformed C2C packet:",
"c2cpacket.messageC2CPacket.incoming": "%s -> you: %s",
"c2cpacket.messageC2CPacket.outgoing": "you -> %s: %s",
"c2cpacket.messageC2CPacket.outgoing": "You -> %s: %s",
"c2cpacket.messageTooLong": "Message too long (max. 255 characters) got %s characters",
"c2cpacket.publicKeyNotFound": "Public key not found",
"c2cpacket.receivedC2CPacket": "You have received a C2C packet, but you aren't accepting incoming C2C packets! Hover to view the raw packet.",
"c2cpacket.receivedC2CPacket": "You have received a C2C packet, but you aren't accepting incoming C2C packets! Hover to view the raw packet",
"c2cpacket.sentC2CPacket": "You have sent a C2C packet, but you aren't accepting incoming C2C packets!",
"c2cpacket.startTwoPlayerGameC2CPacket.incoming": "%s invited you to a game of %s",
"c2cpacket.startTwoPlayerGameC2CPacket.incoming.accept": "Accept",
Expand Down Expand Up @@ -63,7 +63,7 @@
"commands.cconnectfour.name": "Connect Four",

"commands.ccrackrng.failed": "Failed to crack player seed",
"commands.ccrackrng.failed.help": "Help: RNG manipulation doesn't work on some modded servers, in particular Paper.",
"commands.ccrackrng.failed.help": "Help: RNG manipulation doesn't work on some modded servers, in particular Paper",
"commands.ccrackrng.retries": "Cracking player seed, attempt %s/%s",
"commands.ccrackrng.starting": "Cracking player seed",
"commands.ccrackrng.success": "Player RNG cracked: %s",
Expand All @@ -85,7 +85,7 @@
"commands.cenchant.help.uncrackedPlayerSeed": "Help: you have not fully cracked the player seed",
"commands.cenchant.incompatible": "Incompatible enchantments",
"commands.cenchant.needEnchantingPrediction": "This command requires enchanting prediction to be enabled",
"commands.cenchant.success": "Starting enchantment manipulation.",
"commands.cenchant.success": "Starting enchantment manipulation...",
"commands.cenchant.uncracked": "Seed needs to be cracked",

"commands.cfind.found": "Found %s at %s, %s blocks away",
Expand Down
20 changes: 10 additions & 10 deletions src/main/resources/assets/clientcommands/lang/id_id.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"c2cpacket.messageC2CPacket.outgoing": "Anda -> %s: %s",
"c2cpacket.messageTooLong": "Pesan terlalu panjang (max. 255 karakter) saat ini %s karakter",
"c2cpacket.publicKeyNotFound": "Kunci publik tidak ditemukan",
"c2cpacket.receivedC2CPacket": "Anda telah menerima paket C2C, tetapi Anda tidak menerima paket C2C yang masuk! Sorot untuk melihat paket mentah.",
"c2cpacket.receivedC2CPacket": "Anda telah menerima paket C2C, tetapi Anda tidak menerima paket C2C yang masuk! Sorot untuk melihat paket mentah",
"c2cpacket.sentC2CPacket": "Anda telah mengirimkan paket C2C, tetapi Anda tidak menerima paket C2C yang masuk!",

"chorusManip.goalTooFar": "Tujuan mendarat terlalu jauh!",
"chorusManip.landing.failed": "Manipulasi mendarat tidak mungkin",
"chorusManip.landing.success": "Mendarat di: %s, %s, %s",
"chorusManip.needChorusManipulation": "Manipulasi Buah Korus tidak di aktifkan.",
"chorusManip.needChorusManipulation": "Manipulasi Buah Korus tidak di aktifkan",
"chorusManip.setGoal": "Set %s area tujuan dari %s menjadi %s",

"commands.calias.addAlias.aliasAlreadyExists": "Alias \"%s\" sudah ada",
Expand Down Expand Up @@ -54,7 +54,7 @@
"commands.ccalcstack.success.exact": "%s %s adalah %s tumpukan persis",

"commands.ccrackrng.failed": "Gagal untuk memecahkan benih pemain",
"commands.ccrackrng.failed.help": "Banutan: Manipulasi RNG tidak bekerja di beberapa server yang dimodifikasi, terutapa Paper.",
"commands.ccrackrng.failed.help": "Banutan: Manipulasi RNG tidak bekerja di beberapa server yang dimodifikasi, terutapa Paper",
"commands.ccrackrng.retries": "Memecahkan benih pemain, attempt %s/%s",
"commands.ccrackrng.starting": "Memecahkan benih pemain",
"commands.ccrackrng.success": "RNG Pemain telah di pecahkan: %s",
Expand All @@ -74,12 +74,12 @@
"commands.cenchant.failed": "Tidak mungkin atau akan memakan waktu yang lama untuk mendapatkan pesona tersebut",
"commands.cenchant.help.uncrackedPlayerSeed": "Bantuan: anda belum sepenuhnya memecahkan benih pemain",
"commands.cenchant.incompatible": "Pesona tidak kompatibel",
"commands.cenchant.needEnchantingPrediction": "Perintah ini memerlukan prediksi pesona aktif.",
"commands.cenchant.needEnchantingPrediction": "Perintah ini memerlukan prediksi pesona aktif",
"commands.cenchant.success": "Memulai memanipulasi pesona",
"commands.cenchant.uncracked": "Seed butuh diketahui.",
"commands.cenchant.uncracked": "Seed butuh diketahui",

"commands.cfind.found": "Menemukan %s di %s, %s block jaraknya",
"commands.cfind.keepSearching.success": "Mencari entitas.",
"commands.cfind.keepSearching.success": "Mencari entitas",
"commands.cfind.noMatch": "Tidak ada entitas yang cocok di kuery anda",
"commands.cfind.success": "%s entitas yang cocok di kuery anda",

Expand All @@ -89,7 +89,7 @@

"commands.cfinditem.match": "%sx %s ketemu di %s",
"commands.cfinditem.starting": "Mencari benda %s",
"commands.cfinditem.starting.keepSearching": "Mencari benda %s selamanya.",
"commands.cfinditem.starting.keepSearching": "Mencari benda %s selamanya",
"commands.cfinditem.total": "Menemukan %sx %s",

"commands.cfish.addGoal.success": "Berhasil menambahkan tujuan %s",
Expand All @@ -108,7 +108,7 @@
"commands.cfish.help.tooManyEnchants": "Bantuan: beberapa pesona sekaligus tidak mungkin dan mungkin butuh waktu lama untuk mendapatkannya",
"commands.cfish.listGoals.noGoals": "Tidak ada tujuan memancing",
"commands.cfish.listGoals.success": "Ada %s tujuan memancing:",
"commands.cfish.needFishingManipulation": "Manipulasi fishing tidak dinyalakan.",
"commands.cfish.needFishingManipulation": "Manipulasi fishing tidak dinyalakan",
"commands.cfish.removeGoal.success": "Berhasil menghapus tujuan %s",
"commands.cfish.wrongLoot": "Tidak dapat mendapatkan loot yang benar dengan koreksi %sms, seharusnya %s ticks didepan",

Expand All @@ -132,7 +132,7 @@

"commands.cglow.area.success": "Berhasil membuat %s area menjadi bersinar",
"commands.cglow.entity.failed": "Tidak ada entitas untuk menjadi bersinar",
"commands.cglow.entity.keepSearching.success": "Entitas bersinar.",
"commands.cglow.entity.keepSearching.success": "Entitas bersinar",
"commands.cglow.entity.success": "Berhasil membuat %s entitas menjadi bersinar",

"commands.chat.success": "Berhasil membuka c🎩",
Expand Down Expand Up @@ -307,7 +307,7 @@
"playerManip.state.waiting_dummy_enchant": "Sedang menunggu pesona asal",
"playerManip.throwError": "Kondisi tidak bisa atau akan membutuhkan lebih dari %s benda yang dilempar",
"playerManip.toolBreakWarning": "Peringatan: Alat mempunyai sisa %s ketahanan",
"playerManip.uncracked": "Benih Pemain butuh dipecahkan.",
"playerManip.uncracked": "Benih Pemain butuh dipecahkan",

"snakeGame.score": "Skor: %s",
"snakeGame.title": "Game Ular"
Expand Down
8 changes: 4 additions & 4 deletions src/main/resources/assets/clientcommands/lang/ja_jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"commands.calias.addAlias.success": "次のエイリアスの追加に成功しました: \"%s\"",
"commands.calias.file.readError": "エイリアスファイルの読み込みに失敗しました",
"commands.calias.file.writeError": "エイリアスファイルへの書き込みに失敗しました",
"commands.calias.illegalFormatException": "文字のフォーマットが不正であるか引数が多すぎる・もしくは少なすぎます",
"commands.calias.illegalFormatException": "文字のフォーマットが不正であるか引数が多すぎる・もしくは少なすぎます",
"commands.calias.listAliases.noAliasesRegistered": "エイリアスが登録されていません",
"commands.calias.listAliases.success": "%s 個のエイリアスが登録されています: ",
"commands.calias.notFound": "エイリアス \"%s\" が見つかりません",
Expand Down Expand Up @@ -54,7 +54,7 @@
"commands.ccalcstack.success.exact": "%s %s はちょうど %s スタックです",

"commands.ccrackrng.failed": "プレイヤーのシードをクラックするのに失敗しました",
"commands.ccrackrng.failed.help": "ヘルプ: RNG操作は一部のサーバーでは動作不可能です。特にPaperベースのサーバーでは動きません",
"commands.ccrackrng.failed.help": "ヘルプ: RNG操作は一部のサーバーでは動作不可能です。特にPaperベースのサーバーでは動きません",
"commands.ccrackrng.retries": "プレイヤーシードをクラックしています: 試行回数 %s/%s",
"commands.ccrackrng.starting": "プレイヤーシードをクラックしています",
"commands.ccrackrng.success": "プレイヤーシードのクラックに成功しました: %s",
Expand All @@ -73,11 +73,11 @@
"commands.ccreativetab.setStack.success": "\"%s\"からのスタックを索引%sに%sを保存するのに成功しました",

"commands.cenchant.failed": "それらのエンチャントを取得するのは不可能であるか、時間がかかりすぎます",
"commands.cenchant.help.uncrackedPlayerSeed": "ヘルプ: プレイヤーのシードは完全にクラックされていません",
"commands.cenchant.help.uncrackedPlayerSeed": "ヘルプ: プレイヤーのシードは完全にクラックされていません",
"commands.cenchant.incompatible": "競合するエンチャント",
"commands.cenchant.needEnchantingPrediction": "このコマンドはenchant predictionが有効化されている必要があります",
"commands.cenchant.success": "エンチャント操作を開始しています",
"commands.cenchant.uncracked": "シードがクラックされる必要があります",
"commands.cenchant.uncracked": "シードがクラックされる必要があります",

"commands.cfind.found": " %s を次の場所で発見しました: %s, %s ブロック分離れています",
"commands.cfind.keepSearching.success": "エンティティを検索しています",
Expand Down
Loading

0 comments on commit 84855a5

Please sign in to comment.