killerducky / killer_mortal_gui

11 stars 7 forks source link

Method to deal with Korean particles? #22

Closed killerducky closed 18 hours ago

killerducky commented 3 months ago

@cjeon Previous discussion at: https://github.com/killerducky/killer_mortal_gui/pull/15

Maybe for sentences that require it we could encode what part of speech is required for each keyword? See the example I made for the new dealin-pov sentence:

                "dealin-pov": {
                    "position": {
                        "pov": "position-rel-possessive",
                        "tenpai": "position-rel-object",
                    },
                    "full": "{{thisPosition}} dealin rate while {{tenpaiPosition}} is tenpai",
                },

I couldn't find anything standard for these problems when I searched. Mostly the advice is to translate full sentences together, but that's hard when there are 4*4 = 16 combinations of sentences.

What do you think about this approach?

BTW to test this you need to add &alphaTestMode=1 to the URL, go to a game where someone called Riichi and someone is about to discard into the Riichi. Then hit z.

Will be adding the z shortcut and translation stuff to about section later when I'm happy with the implementation.

killerducky commented 3 months ago

I have some other ideas, so fair warning I might change this again. :)

cjeon commented 3 months ago

Hmm I think this would work, but I have some thoughts (not necessarily opposing just other thoughts)

  1. Other languages got much more diverse weird form changes (less weird e.g. is French's gender change I guess) if you continue in this direction I am afraid in future you might have to have something like {position-rel-possessive-male} or even like {position-rel-possessive-male-singular}
  2. However, realistically, it's less likely that Mahjong's gonna get world famous and, like, 10+ languages are going to be introduced into this project. so maybe it's okay.
  3. If I did this at my work I would have done something like below msg.
cjeon commented 3 months ago

(my most comfy lang is Kotlin so it's written in Kotlin but please just see the basic idea)


enum class Languages { EN, JP, KR, CN, }

object TranslationManager {
    val currentLanguage: Languages = Languages.EN
}

object KoreanTranslationUtils {
    fun CharSequence.종성이_없음(): Boolean = last().code % 28 == 16
    fun CharSequence.이가(): String = if (종성이_없음()) "${this}가" else "${this}이"
    fun CharSequence.을를(): String = if (종성이_없음()) "${this}를" else "${this}을"
}

sealed interface TranslationToken<SELF : TranslationToken<SELF>> {
    fun translate(data: TranslationData<SELF>): String
}
sealed interface TranslationData<T: TranslationToken<T>>

// e.g. for translating "RON/TSUMO by hero/shimocha/toimen/kami"

class WinByWhomToken : TranslationToken<WinByWhomToken> {
    override fun translate(data: TranslationData<WinByWhomToken>): String {
        val data = data as WinByWhomData

        return when (TranslationManager.currentLanguage) {
            Languages.KR -> {
                when (data.winType) {
                    WinType.RON -> "${PlayerToken.translate(PlayerData(data.winner)).이가()} ${PlayerToken.translate(PlayerData(data.loser)).을를()} 쏘아서 론"
                    WinType.TSUMO -> "${PlayerToken.translate(PlayerData(data.winner))}의 쯔모"
                }
            }
            else -> {
                when (data.winType) {
                    WinType.RON -> "${PlayerToken.translate(PlayerData(data.winner))} rons ${PlayerToken.translate(PlayerData(data.loser))}"
                    WinType.TSUMO -> "${PlayerToken.translate(PlayerData(data.winner))}'s tsumo."
                }
            }
        }
    }
}

enum class Player { HERO, SHIMOCHA, TOIMEN, KAMI }

enum class WinType { RON, TSUMO }

data class WinByWhomData(
    val winner: Player,
    val loser: Player,
    val winType: WinType,
) : TranslationData<WinByWhomToken>

data object PlayerToken : TranslationToken<PlayerToken> {
    override fun translate(data: TranslationData<PlayerToken>): String {
        when (TranslationManager.currentLanguage) {
            Languages.KR -> {
                return when ((data as PlayerData).player) {
                    Player.HERO -> "나"
                    Player.SHIMOCHA -> "하가"
                    Player.TOIMEN -> "대면"
                    Player.KAMI -> "상가"
                }
            }
            else -> {
                return when ((data as PlayerData).player) {
                    Player.HERO -> "Hero"
                    Player.SHIMOCHA -> "Shimocha"
                    Player.TOIMEN -> "Toimen"
                    Player.KAMI -> "Kami"
                }
            }
        }
    }
}

data class PlayerData(
    val player: Player,
) : TranslationData<PlayerToken>
killerducky commented 3 months ago

Thanks for your feedback. I'm thinking to try to simplify things some by moving away from full sentences and doing something more like:

English Old: {{thisPosition}}'s dealin rate while {{tenpaiPosition}} is tenpai

English New: Pusher: {{thisPosition}} Tenpai: {{tenpaiPosition}}

Maybe that would reduce the amount of particles and/or verb conjugations needed in other languages.

I'm close to finishing up this set of new features for showing dealin rates. After I get it done and before I make a release I'll try to also refactor the i18n stuff related to it.

killerducky commented 3 months ago

Ok I got rid of the dealin-pov idea, and changed the full sentence to the method in the previous post. I hope this will let us keep things simple.

So this is ready for translation now.

cjeon commented 2 months ago

I'll translate them soon and let you know. Thank you for your effort !