Skip to content

Commit 6a7bc51

Browse files
authored
Merge pull request #126 from pylonmc/add-language-file-warnings
Add language file warnings
2 parents b7ac14b + 1070aeb commit 6a7bc51

6 files changed

Lines changed: 115 additions & 16 deletions

File tree

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/PylonBlock.kt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import io.github.pylonmc.pylon.core.block.waila.WailaConfig
77
import io.github.pylonmc.pylon.core.config.Config
88
import io.github.pylonmc.pylon.core.config.Settings
99
import io.github.pylonmc.pylon.core.datatypes.PylonSerializers
10+
import io.github.pylonmc.pylon.core.i18n.AddonTranslator
11+
import io.github.pylonmc.pylon.core.item.PylonItemSchema
1012
import io.github.pylonmc.pylon.core.registry.PylonRegistry
1113
import io.github.pylonmc.pylon.core.util.position.BlockPosition
1214
import io.github.pylonmc.pylon.core.util.position.position
@@ -63,9 +65,30 @@ open class PylonBlock protected constructor(val block: Block) {
6365
private val pylonBlockPositionKey = pylonKey("position")
6466
private val pylonBlockErrorKey = pylonKey("error")
6567

68+
private val wailaWarningsSupressed: MutableSet<NamespacedKey> = mutableSetOf()
69+
70+
fun checkWaila(schema: PylonBlockSchema) {
71+
val translator = AddonTranslator.translators[schema.addon]
72+
check(translator != null) {
73+
"Addon does not have a translator; did you forget to call registerWithPylon()?"
74+
}
75+
76+
77+
for (locale in schema.addon.languages) {
78+
val translationKey = "pylon.${schema.key.namespace}.block.${schema.key.key}"
79+
if (!translator.translationKeyExists(translationKey, locale)) {
80+
PylonCore.logger.warning("${schema.key.namespace} is missing a WAILA translation key for block ${schema.key} (locale: ${locale.displayName} | expected translation key: $translationKey")
81+
}
82+
}
83+
}
84+
6685
@JvmStatic
6786
fun register(key: NamespacedKey, material: Material, blockClass: Class<out PylonBlock>) {
68-
PylonRegistry.BLOCKS.register(PylonBlockSchema(key, material, blockClass))
87+
val schema = PylonBlockSchema(key, material, blockClass)
88+
if (key !in wailaWarningsSupressed) {
89+
checkWaila(schema)
90+
}
91+
PylonRegistry.BLOCKS.register(schema)
6992
}
7093

7194
@JvmSynthetic
@@ -135,5 +158,10 @@ open class PylonBlock protected constructor(val block: Block) {
135158
}
136159
}
137160
}
161+
162+
@JvmStatic
163+
fun supressWailaWarnings(key: NamespacedKey) {
164+
wailaWarningsSupressed.add(key)
165+
}
138166
}
139167
}

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/i18n/AddonTranslator.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,10 @@ class AddonTranslator(private val addon: PylonAddon) : Translator {
5252
return translated
5353
}
5454

55-
private fun getTranslation(component: TranslatableComponent, locale: Locale): Component? {
56-
val key = component.key()
57-
val translation = translationCache.getOrPut(locale to key) {
58-
if (!key.startsWith("pylon.")) return null
59-
val (_, addon, key) = key.split('.', limit = 3)
55+
private fun getTranslation(translationKey: String, locale: Locale): Component? {
56+
return translationCache.getOrPut(locale to translationKey) {
57+
if (!translationKey.startsWith("pylon.")) return null
58+
val (_, addon, key) = translationKey.split('.', limit = 3)
6059
if (addon != addonNamespace) return null
6160
val languageRange = languageRanges.getOrPut(locale) {
6261
val lookupList = LocaleUtils.localeLookupList(locale).reversed()
@@ -68,12 +67,19 @@ class AddonTranslator(private val addon: PylonAddon) : Translator {
6867
val translation = translations[matchedLocale]?.get<String>(key) ?: return null
6968
customMiniMessage.deserialize(translation)
7069
}
71-
return Component.text().style(component.style()).append(translation).build()
7270
}
7371

72+
private fun getTranslation(component: TranslatableComponent, locale: Locale): Component? {
73+
val translated = getTranslation(component.key(), locale) ?: return null
74+
return Component.text().style(component.style()).append(translated).build()
75+
}
76+
77+
fun translationKeyExists(key: String, locale: Locale): Boolean
78+
= getTranslation(key, locale) != null
79+
7480
companion object : Listener {
7581

76-
private val translators = mutableMapOf<PylonAddon, AddonTranslator>()
82+
val translators = mutableMapOf<PylonAddon, AddonTranslator>()
7783

7884
@JvmSynthetic
7985
internal fun register(addon: PylonAddon) {

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/item/PylonItem.kt

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package io.github.pylonmc.pylon.core.item
22

3+
import io.github.pylonmc.pylon.core.PylonCore
34
import io.github.pylonmc.pylon.core.config.Settings
45
import io.github.pylonmc.pylon.core.datatypes.PylonSerializers
6+
import io.github.pylonmc.pylon.core.i18n.AddonTranslator
7+
import io.github.pylonmc.pylon.core.item.builder.ItemStackBuilder
58
import io.github.pylonmc.pylon.core.registry.PylonRegistry
9+
import io.papermc.paper.datacomponent.DataComponentTypes
610
import net.kyori.adventure.text.ComponentLike
11+
import net.kyori.adventure.text.TranslatableComponent
712
import org.bukkit.Keyed
813
import org.bukkit.NamespacedKey
914
import org.bukkit.inventory.ItemStack
@@ -34,16 +39,56 @@ open class PylonItem(val stack: ItemStack) : Keyed {
3439

3540
companion object {
3641

37-
@JvmStatic
38-
fun register(itemClass: Class<out PylonItem>, template: ItemStack) {
39-
PylonRegistry.ITEMS.register(PylonItemSchema(itemClass, template))
42+
private val nameAndLoreWarningsSupressed: MutableSet<NamespacedKey> = mutableSetOf()
43+
44+
private fun checkNameAndLore(schema: PylonItemSchema) {
45+
val translator = AddonTranslator.translators[schema.addon]
46+
check(translator != null) {
47+
"Addon does not have a translator; did you forget to call registerWithPylon()?"
48+
}
49+
50+
// Adventure is a perfect API with absolutely no problems whatsoever.
51+
val name = schema.itemStack.getData(DataComponentTypes.ITEM_NAME) as? TranslatableComponent
52+
val lore = schema.itemStack.getData(DataComponentTypes.LORE)?.lines()?.get(0) as? TranslatableComponent
53+
54+
var isNameAndLoreValid = true
55+
if (name == null || name.key() != ItemStackBuilder.nameKey(schema.key)) {
56+
PylonCore.logger.warning("Item ${schema.key}'s name is not a translation key; check your item uses ItemStackBuilder.pylonItem(...)")
57+
isNameAndLoreValid = false
58+
}
59+
60+
if (lore == null || lore.key() != ItemStackBuilder.loreKey(schema.key)) {
61+
PylonCore.logger.warning("Item ${schema.key}'s lore is not a translation key; check your item uses ItemStackBuilder.pylonItem(...)")
62+
isNameAndLoreValid = false
63+
}
64+
65+
if (isNameAndLoreValid) {
66+
for (locale in schema.addon.languages) {
67+
if (!translator.translationKeyExists(name!!.key(), locale)) {
68+
PylonCore.logger.warning("${schema.key.namespace} is missing a name translation key for item ${schema.key} (locale: ${locale.displayName} | expected translation key: ${ItemStackBuilder.nameKey(schema.key)}")
69+
}
70+
if (!translator.translationKeyExists(lore!!.key(), locale)) {
71+
PylonCore.logger.warning("${schema.key.namespace} is missing a lore translation key for item ${schema.key} (locale: ${locale.displayName} | expected translation key: ${ItemStackBuilder.loreKey(schema.key)}")
72+
}
73+
}
74+
}
4075
}
4176

42-
@JvmStatic
43-
fun register(itemClass: Class<out PylonItem>, template: ItemStack, pylonBlockKey: NamespacedKey) {
44-
PylonRegistry.ITEMS.register(PylonItemSchema(itemClass, template, pylonBlockKey))
77+
private fun register(schema: PylonItemSchema) {
78+
if (schema.key !in nameAndLoreWarningsSupressed) {
79+
checkNameAndLore(schema)
80+
}
81+
PylonRegistry.ITEMS.register(schema)
4582
}
4683

84+
@JvmStatic
85+
fun register(itemClass: Class<out PylonItem>, template: ItemStack)
86+
= register(PylonItemSchema(itemClass, template))
87+
88+
@JvmStatic
89+
fun register(itemClass: Class<out PylonItem>, template: ItemStack, pylonBlockKey: NamespacedKey)
90+
= register(PylonItemSchema(itemClass, template, pylonBlockKey))
91+
4792
/**
4893
* Converts a regular ItemStack to a PylonItemStack
4994
* Returns null if the ItemStack is not a Pylon item
@@ -58,5 +103,10 @@ open class PylonItem(val stack: ItemStack) : Keyed {
58103
?: return null
59104
return schema.itemClass.cast(schema.loadConstructor.invoke(stack))
60105
}
106+
107+
@JvmStatic
108+
fun supressNameAndLoreWarnings(key: NamespacedKey) {
109+
nameAndLoreWarningsSupressed.add(key)
110+
}
61111
}
62112
}

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/item/builder/ItemStackBuilder.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ open class ItemStackBuilder private constructor(private val stack: ItemStack) :
6363
fun name(name: String) = name(fromMiniMessage(name))
6464

6565
fun defaultTranslatableName(key: NamespacedKey) =
66-
name(Component.translatable("pylon.${key.namespace}.item.${key.key}.name"))
66+
name(Component.translatable(nameKey(key)))
6767

6868
fun lore(vararg loreToAdd: ComponentLike) = apply {
6969
val lore = ItemLore.lore()
@@ -75,7 +75,7 @@ open class ItemStackBuilder private constructor(private val stack: ItemStack) :
7575
fun lore(vararg lore: String) = lore(*lore.map(::fromMiniMessage).toTypedArray())
7676

7777
fun defaultTranslatableLore(key: NamespacedKey) =
78-
lore(Component.translatable("pylon.${key.namespace}.item.${key.key}.lore"))
78+
lore(Component.translatable(loreKey(key)))
7979

8080
fun build(): ItemStack = stack.clone()
8181

@@ -103,6 +103,13 @@ open class ItemStackBuilder private constructor(private val stack: ItemStack) :
103103
}
104104

105105
companion object {
106+
107+
fun nameKey(key: NamespacedKey)
108+
= "pylon.${key.namespace}.item.${key.key}.name"
109+
110+
fun loreKey(key: NamespacedKey)
111+
= "pylon.${key.namespace}.item.${key.key}.lore"
112+
106113
@JvmStatic
107114
fun of(stack: ItemStack): ItemStackBuilder {
108115
return ItemStackBuilder(stack)

pylon-core/src/main/resources/lang/en.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ item:
44
lore: |-
55
<red>This item dropped from a block that, for some reason, failed to load
66
<red>Errored block:</red> <yellow>%block%
7+
8+
phantom_block:
9+
name: "<red>Phantom Block (%block%)"
10+
lore: ""
711

812
debug_waxed_weathered_cut_copper_stairs:
913
name: "<red>Debug Waxed Weathered Cut Copper Stairs"

pylon-core/src/main/resources/lang/enws.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ item:
55
<red>Lo, this item was cast forth from a block that, by misfortune or devilry, could not take form
66
<red>The block in error:</red> <yellow>%block%
77
8+
phantom_block:
9+
name: "<red>Phantom Block (%block%)"
10+
lore: ""
11+
812
debug_waxed_weathered_cut_copper_stairs:
913
name: "<red>Wax'd Weather'd Cutteth Copp'r Stairs of Unriddling"
1014
lore: "<insn>Strike with thy right hand</insn> yon block, and its Pylon lore shall be revealed"

0 commit comments

Comments
 (0)