Titlecasing english texts because Polyglot ain't doing it

This commit is contained in:
minjaesong
2024-02-17 19:17:22 +09:00
parent 84222f0d98
commit c9f6246cd3
12 changed files with 153 additions and 57 deletions

View File

@@ -1,6 +1,7 @@
{
"APP_WARNING_HEALTH_AND_SAFETY": "WARNING-HEALTH AND SAFETY",
"CONTEXT_CHARACTER": "Character",
"CONTEXT_ESTIMATED_MINUTES": "Estimated: about {0} minute",
"CONTEXT_ESTIMATED_MINUTES_PLURAL": "Estimated: about {0} minutes",
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
@@ -42,7 +43,7 @@
"MENU_OPTIONS_LIGHT_UPDATE_PASSES": "Light Calculation Depth",
"MENU_OPTIONS_MASTER_VOLUME": "Master Volume",
"MENU_OPTIONS_NONE" : "None",
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show Notification for",
"MENU_OPTIONS_PARTICLES": "Particles",
"MENU_OPTIONS_PERFORMANCE": "Performance",
"MENU_OPTIONS_SAVEFORMAT": "Savegame Format",

View File

@@ -9,7 +9,7 @@
"APP_NOMODULE_1": "No Module is currently loaded.",
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
"MENU_LABEL_AUDIO_BUFFER_INSTRUCTION": "Set it to the minimum value in which you do not hear a stuttering.\nIf your audio is stuttering, increase the value until the stuttering is gone.\nLarger value will increase the processing stability but also the delay.",
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
"MENU_LABEL_KEYCONFIG_HELP1": "Click on the Keycap to Assign Actions",
"MENU_LABEL_WARN_ACE": "Script mods may damage your game or result in other unexpected behaviour.\nOnly use the mods you know they can be trusted."
}

View File

@@ -1,6 +1,7 @@
{
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
"CONTEXT_CHARACTER": "캐릭터",
"CONTEXT_ESTIMATED_MINUTES": "예상 시간: 약 {0}분",
"CONTEXT_ESTIMATED_MINUTES_PLURAL": "예상 시간: 약 {0}분",
"CONTEXT_TIME_MINUTE_PLURAL": "분",
"CONTEXT_TIME_SECOND_PLURAL": "초",

View File

@@ -73,7 +73,7 @@ class ModOptionsHost(val remoCon: UIRemoCon) : UICanvas() {
val modOptions: ControlPanelOptions = mod.configPlan.map {
val options = it.split("->")
val labelfun = if (options[1].startsWith("Lang:")) {
{ Lang[options[1].substringAfter(":")] }
{ Lang[options[1].substringAfter(":"), true] }
}
else {
{ options[1] }

View File

@@ -134,7 +134,7 @@ object Lang {
* - `BLOCK_AIR` Prints out `Lang.get("BLOCK_AIR")`
* - `BLOCK_AIR>>=BLOCK_WALL_NAME_TEMPLATE` Prints out `Formatter().format(Lang.get("BLOCK_WALL_NAME_TEMPLATE"), Lang.get("BLOCK_AIR")).toString()`
*/
operator fun get(key: String, capitalise: Boolean = true): String {
operator fun get(key: String, capitalise: Boolean = false): String {
fun getstr(s: String) = getByLocale(s, App.GAME_LOCALE, capitalise) ?: getByLocale(s, FALLBACK_LANG_CODE, capitalise) ?: "$$s"
@@ -164,19 +164,45 @@ object Lang {
}
/**
* Does NOT parse the operators
* @param localecode int the form of "en", "de" or "daDK" or something
*/
fun getByLocale(key: String, locale: String, capitalise: Boolean): String? {
private fun getJavaLocaleFromTerrarumLocaleCode(localecode: String): Locale {
val localecode = localecode.substring(0 until minOf(4, localecode.length))
val lang = localecode.substring(0..1)
val country = if (localecode.length == 4) localecode.substring(2..3) else null
return if (country == null) Locale(lang) else Locale(lang, country)
}
private val capCache = HashMap<String/*Locale*/, HashMap<String/*Key*/, String/*Text*/>>()
private fun CAP(key: String, locale: String): String? {
val ret = langpack["${key}_$locale"] ?: return null
fun String.CAP() = if (capitalise) this.capitalize() else this
if (!capCache.containsKey(locale))
capCache[locale] = HashMap<String, String>()
if (!capCache[locale]!!.containsKey(key)) {
capCache[locale]!![key] = TitlecaseConverter(ret, locale)
}
return capCache[locale]!![key]!!
}
private fun NOCAP(key: String, locale: String): String? {
return langpack["${key}_$locale"] ?: return null
}
/**
* Does NOT parse the operators
*/
fun getByLocale(key: String, locale: String, capitalise: Boolean = false): String? {
val s = if (capitalise) CAP(key, locale) else NOCAP(key, locale)
return if (locale.startsWith("bg"))
"${App.fontGame.charsetOverrideBulgarian}${ret.CAP()}${App.fontGame.charsetOverrideDefault}"
"${App.fontGame.charsetOverrideBulgarian}$s${App.fontGame.charsetOverrideDefault}"
else if (locale.startsWith("sr"))
"${App.fontGame.charsetOverrideSerbian}${ret.CAP()}${App.fontGame.charsetOverrideDefault}"
"${App.fontGame.charsetOverrideSerbian}$s${App.fontGame.charsetOverrideDefault}"
else
ret.CAP()
s
}
private fun String.getEndTag() = this.split("_").last()

View File

@@ -0,0 +1,65 @@
package net.torvald.terrarum.langpack
import java.util.*
/**
* Created by minjaesong on 2024-02-17.
*/
object TitlecaseConverter {
/**
* @param localecode int the form of "en", "de" or "daDK" or something
*/
private fun getJavaLocaleFromTerrarumLocaleCode(localecode: String): Locale {
val localecode = localecode.substring(0 until minOf(4, localecode.length))
val lang = localecode.substring(0..1)
val country = if (localecode.length == 4) localecode.substring(2..3) else null
return if (country == null) Locale(lang) else Locale(lang, country)
}
private val locEN = getJavaLocaleFromTerrarumLocaleCode("en")
operator fun invoke(s: String, localeCode: String): String {
return if (localeCode.startsWith("en")) titlecaseEn(s)
else if (
localeCode.startsWith("ja") ||
localeCode.startsWith("ko") ||
localeCode.startsWith("th") ||
localeCode.startsWith("zh")
) passThru(s)
else titlecaseGeneric(s, getJavaLocaleFromTerrarumLocaleCode(localeCode))
}
private fun passThru(s: String) = s
private fun titlecaseGeneric(s: String, loc: Locale) = s.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(loc)
else it.toString()
}
private val englishWordsNoCapital = hashSetOf(
"a", "an",
"the", "to", "but", "for", "or", "and", "nor", "as",
"amid", "mid", "anti", "at", "atop", "by", "but", "come", "in", "including", "into", "less", "like", "near",
"next", "of", "off", "on", "onto", "out", "over", "past", "per", "plus", "post", "pre", "pro",
"re", "sans", "sub", "than", "till", "until", "under", "up", "upon", "via", "with", "within", "without",
"except"
)
private fun titlecaseEn(s: String): String {
val ssplit = s.split(' ')
return ssplit.mapIndexed { index, it ->
if (index == 0 || index == ssplit.lastIndex) it.capitalise(locEN)
else if (it[0].isUpperCase()) it
else {
if (englishWordsNoCapital.contains(it)) it else it.capitalise(locEN)
}
}.joinToString(" ")
}
private fun String.capitalise(loc: Locale) = this.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(loc)
else it.toString()
}
}

View File

@@ -26,21 +26,21 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
handler.allowESCtoClose = false
ControlPanelCommon.register(this, width, "basegame.graphicscontrolpanel", arrayOf(
arrayOf("", { Lang["CREDITS_VFX"] }, "h1"),
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER"] }, "toggle"),
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR"] }, "toggle"),
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES"] }, "spinner,256,1024,256"),
arrayOf("lightpasses", { Lang["MENU_OPTIONS_LIGHT_UPDATE_PASSES"] }, "spinner,2,4,1"),
arrayOf("", { Lang["MENU_OPTIONS_DISPLAY"] }, "h1"),
arrayOf("screenwidth,screenheight", { Lang["MENU_OPTIONS_RESOLUTION"] }, "typeinres"),
arrayOf("fullscreen", { Lang["MENU_OPTIONS_FULLSCREEN"] }, "toggle"),
arrayOf("screenmagnifying", { Lang["GAME_ACTION_ZOOM"] }, "spinnerd,1.0,2.0,0.05"),
arrayOf("screenmagnifyingfilter", { Lang["MENU_OPTIONS_FILTERING_MODE"] }, "textsel,none=MENU_OPTIONS_NONE,bilinear=MENU_OPTIONS_FILTERING_BILINEAR,hq2x=MENU_OPTIONS_FILTERING_HQ2X_DNT"),
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC"] }, "spinner,0,300,2"),
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC"] }, "toggle"),
arrayOf("", { Lang["CREDITS_VFX", true] }, "h1"),
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER", true] }, "toggle"),
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR", true] }, "toggle"),
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES", true] }, "spinner,256,1024,256"),
arrayOf("lightpasses", { Lang["MENU_OPTIONS_LIGHT_UPDATE_PASSES", true] }, "spinner,2,4,1"),
arrayOf("", { Lang["MENU_OPTIONS_DISPLAY", true] }, "h1"),
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
arrayOf("", { Lang["MENU_LABEL_STREAMING"] }, "h1"),
arrayOf("fx_streamerslayout", { Lang["MENU_OPTIONS_STREAMERS_LAYOUT"] }, "toggle"),
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC", true] }, "spinner,0,300,2"),
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC", true] }, "toggle"),
arrayOf("screenwidth,screenheight", { Lang["MENU_OPTIONS_RESOLUTION", true] }, "typeinres"),
arrayOf("fullscreen", { Lang["MENU_OPTIONS_FULLSCREEN", true] }, "toggle"),
arrayOf("screenmagnifying", { Lang["GAME_ACTION_ZOOM", true] }, "spinnerd,1.0,2.0,0.05"),
arrayOf("screenmagnifyingfilter", { Lang["MENU_OPTIONS_FILTERING_MODE", true] }, "textsel,none=MENU_OPTIONS_NONE,bilinear=MENU_OPTIONS_FILTERING_BILINEAR,hq2x=MENU_OPTIONS_FILTERING_HQ2X_DNT"),
arrayOf("", { Lang["MENU_LABEL_STREAMING", true] }, "h1"),
arrayOf("fx_streamerslayout", { Lang["MENU_OPTIONS_STREAMERS_LAYOUT", true] }, "toggle"),
))
}

View File

@@ -176,15 +176,15 @@ class UIIMEConfig(remoCon: UIRemoCon?) : UICanvas() {
override fun renderImpl(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
batch.color = Color.WHITE
val txt1 = Lang["MENU_LABEL_KEYBOARD_LAYOUT"]; val tw1 = App.fontGame.getWidth(txt1)
val txt1 = Lang["MENU_LABEL_KEYBOARD_LAYOUT", true]; val tw1 = App.fontGame.getWidth(txt1)
App.fontGame.draw(batch, txt1, selDrawX + (halfselw - tw1) / 2, keyboardLayoutSelection.posY - 40)
val txt2 = Lang["MENU_LABEL_IME"]; val tw2 = App.fontGame.getWidth(txt2)
val txt2 = Lang["MENU_LABEL_IME", true]; val tw2 = App.fontGame.getWidth(txt2)
App.fontGame.draw(batch, txt2, selDrawX + halfselw + (halfselw - tw2) / 2, keyboardLayoutSelection.posY - 40)
// title
// todo show "Keyboard"/"Gamepad" accordingly
val title = Lang["MENU_CONTROLS_KEYBOARD"]
val title = Lang["MENU_CONTROLS_KEYBOARD", true]
batch.color = Color.WHITE
App.fontUITitle.draw(batch, title, drawX.toFloat() + (width - App.fontUITitle.getWidth(title)) / 2, drawY.toFloat())

View File

@@ -217,7 +217,7 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
// title
// todo show "Keyboard"/"Gamepad" accordingly
batch.color = Color.WHITE
val title = Lang["MENU_CONTROLS_KEYBOARD"]
val title = Lang["MENU_CONTROLS_KEYBOARD", true]
App.fontUITitle.draw(batch, title, drawX.toFloat() + (width - App.fontUITitle.getWidth(title)) / 2, drawY.toFloat())
@@ -473,18 +473,18 @@ class UIItemControlPaletteBaloon(val parent: UIKeyboardControlPanel, initialX: I
// texts. Sorted in the same way as UIItemControlPaletteBaloon.iconButtons
batch.color = Color.WHITE
App.fontGame.draw(batch, Lang["GAME_ACTION_MOVE_VERB"], col0 + 72, posY + 41)
App.fontGame.draw(batch, Lang["GAME_ACTION_JUMP"], col1 + 40, posY + 41)
App.fontGame.draw(batch, Lang["GAME_ACTION_MOVE_VERB", true], col0 + 72, posY + 41)
App.fontGame.draw(batch, Lang["GAME_ACTION_JUMP", true], col1 + 40, posY + 41)
App.fontGame.draw(batch, Lang["GAME_INVENTORY"], col0 + 40, row1 - 2)
App.fontGame.draw(batch, Lang["GAME_CRAFTING"], col0 + 40, row2 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_GRAPPLE"], col0 + 40, row3 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_QUICKSEL"], col0 + 40, row4 - 2)
App.fontGame.draw(batch, Lang["GAME_INVENTORY", true], col0 + 40, row1 - 2)
App.fontGame.draw(batch, Lang["GAME_CRAFTING", true], col0 + 40, row2 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_GRAPPLE", true], col0 + 40, row3 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_QUICKSEL", true], col0 + 40, row4 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_ZOOM"], col1 + 40, row1 - 2)
App.fontGame.draw(batch, Lang["MENU_LABEL_IME_TOGGLE"], col1 + 40, row2 - 2)
App.fontGame.draw(batch, Lang["MENU_LABEL_MENU"], col1 + 40, row3 - 2)
App.fontGame.draw(batch, Lang["GAME_INVENTORY_DROP"], col1 + 40, row4 - 2)
App.fontGame.draw(batch, Lang["GAME_ACTION_ZOOM", true], col1 + 40, row1 - 2)
App.fontGame.draw(batch, Lang["MENU_LABEL_IME_TOGGLE", true], col1 + 40, row2 - 2)
App.fontGame.draw(batch, Lang["MENU_LABEL_MENU", true], col1 + 40, row3 - 2)
App.fontGame.draw(batch, Lang["GAME_INVENTORY_DROP", true], col1 + 40, row4 - 2)
}

View File

@@ -296,7 +296,10 @@ class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
val (wx, wy) = TerrarumIngame.NEW_WORLD_SIZE[sizeSelector.selection]
val etaSec = Worldgen.getEstimationSec(wx, wy)
val etaMin = etaSec.div(60f).roundToInt().coerceAtLeast(1)
val etaText = Lang.getAndUseTemplate("CONTEXT_ESTIMATED_MINUTES_PLURAL", true, etaMin)
val etaText = if (etaMin == 1)
Lang.getAndUseTemplate("CONTEXT_ESTIMATED_MINUTES", true, etaMin)
else
Lang.getAndUseTemplate("CONTEXT_ESTIMATED_MINUTES_PLURAL", true, etaMin)
val etaTextPrint = etaText + (if (App.IS_DEVELOPMENT_BUILD) " ($etaSec s)" else "")
Toolkit.drawTextCentered(batch, App.fontGame, etaTextPrint, width, drawX, drawY + sizeSelY + inputLineY3)

View File

@@ -16,18 +16,18 @@ class UIPerformanceControlPanel(remoCon: UIRemoCon?) : UICanvas() {
handler.allowESCtoClose = false
ControlPanelCommon.register(this, width, "basegame.performancecontrolpanel", arrayOf(
arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY"] }, "h1"),
arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,5,120,5,60000"),
arrayOf("notificationshowuptime", { Lang["MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION"] + " (${Lang["CONTEXT_TIME_SECOND_PLURAL"]})" }, "spinnerimul,2,10,1,1000"),
arrayOf("savegamecomp", { Lang["MENU_OPTIONS_SAVEFORMAT"] }, "textsel,zstd=MENU_OPTIONS_SAVEFORMAT_SMALL,snappy=MENU_OPTIONS_SAVEFORMAT_FAST"),
arrayOf("", { Lang["MENU_MODULES"] }, "h1"),
arrayOf("enablescriptmods", { Lang["MENU_OPTIONS_ENABLE_SCRIPT_MODS"] }, "toggle"),
arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY", true] }, "h1"),
arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE", true] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"].lowercase()})" }, "spinnerimul,5,120,5,60000"),
arrayOf("notificationshowuptime", { Lang["MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION"] + " (${Lang["CONTEXT_TIME_SECOND_PLURAL"].lowercase()})" }, "spinnerimul,2,10,1,1000"),
arrayOf("savegamecomp", { Lang["MENU_OPTIONS_SAVEFORMAT", true] }, "textsel,zstd=MENU_OPTIONS_SAVEFORMAT_SMALL,snappy=MENU_OPTIONS_SAVEFORMAT_FAST"),
arrayOf("", { Lang["MENU_MODULES", true] }, "h1"),
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
arrayOf("enablescriptmods", { Lang["MENU_OPTIONS_ENABLE_SCRIPT_MODS", true] }, "toggle"),
arrayOf("", { "${Lang["MENU_LABEL_WARN_ACE"]}" }, "emph"),
arrayOf("", { Lang["MENU_LABEL_JVM_DNT"] }, "h1"),
arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX"] + " (GB)" }, "spinner,2,32,1"),
arrayOf("jvm_extra_cmd", { Lang["MENU_LABEL_EXTRA_JVM_ARGUMENTS"] }, "typein"),
arrayOf("", { Lang["MENU_LABEL_JVM_DNT", true] }, "h1"),
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX", true] + " (GB)" }, "spinner,2,32,1"),
arrayOf("jvm_extra_cmd", { Lang["MENU_LABEL_EXTRA_JVM_ARGUMENTS", true] }, "typein"),
)
)
}

View File

@@ -20,20 +20,20 @@ class UISoundControlPanel(remoCon: UIRemoCon?) : UICanvas() {
handler.allowESCtoClose = false
ControlPanelCommon.register(this, width, "basegame.soundcontrolpanel", arrayOf(
arrayOf("", { Lang["MENU_OPTIONS_SOUND_VOLUME"] }, "h1"),
arrayOf("mastervolume", { Lang["MENU_OPTIONS_MASTER_VOLUME"] }, "sliderd,0,1"),
arrayOf("", { Lang["MENU_OPTIONS_SOUND_VOLUME", true] }, "h1"),
arrayOf("mastervolume", { Lang["MENU_OPTIONS_MASTER_VOLUME", true] }, "sliderd,0,1"),
arrayOf("", { "" }, "pp"),
arrayOf("bgmvolume", { Lang["MENU_LABEL_MUSIC"] }, "sliderd,0,1"),
arrayOf("bgmvolume", { Lang["MENU_LABEL_MUSIC", true] }, "sliderd,0,1"),
arrayOf("", { "" }, "pp"),
arrayOf("ambientvolume", { Lang["MENU_LABEL_AMBIENT_SOUNDS"] }, "sliderd,0,1"),
arrayOf("ambientvolume", { Lang["MENU_LABEL_AMBIENT_SOUNDS", true] }, "sliderd,0,1"),
arrayOf("", { "" }, "pp"),
arrayOf("sfxvolume", { Lang["CREDITS_SFX"] }, "sliderd,0,1"),
arrayOf("sfxvolume", { Lang["CREDITS_SFX", true] }, "sliderd,0,1"),
arrayOf("", { "" }, "pp"),
arrayOf("guivolume", { Lang["MENU_LABEL_INTERFACE"] }, "sliderd,0,1"),
arrayOf("guivolume", { Lang["MENU_LABEL_INTERFACE", true] }, "sliderd,0,1"),
arrayOf("", { "" }, "pp"),
arrayOf("", { Lang["MENU_LABEL_AUDIO_ENGINE"] }, "h1"),
arrayOf("audio_speaker_setup", { Lang["MENU_OPTIONS_SPEAKER_SETUP"] }, "textsel,headphone=MENU_OPTIONS_SPEAKER_HEADPHONE,stereo=MENU_OPTIONS_SPEAKER_STEREO"),
arrayOf("audio_buffer_size", { Lang["MENU_OPTIONS_AUDIO_BUFFER_SIZE"] }, "spinnersel,128,256,512,1024,2048"),
arrayOf("", { Lang["MENU_LABEL_AUDIO_ENGINE", true] }, "h1"),
arrayOf("audio_speaker_setup", { Lang["MENU_OPTIONS_SPEAKER_SETUP", true] }, "textsel,headphone=MENU_OPTIONS_SPEAKER_HEADPHONE,stereo=MENU_OPTIONS_SPEAKER_STEREO"),
arrayOf("audio_buffer_size", { Lang["MENU_OPTIONS_AUDIO_BUFFER_SIZE", true] }, "spinnersel,128,256,512,1024,2048"),
arrayOf("", { "${Lang["MENU_LABEL_AUDIO_BUFFER_INSTRUCTION"]}" }, "p"),
))