aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-android/app/src/main/kotlin/org/meshbay/client/shell/NativeText.kt
blob: ae23e46404397fc094d4ef10b0ecc15c7391c67f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package org.meshbay.client.shell

/**
 * A sentence from the interface's own catalogues, for the few things the
 * application draws itself (main.js `nativeText`). The page chooses the
 * language and nothing else: a confirmation it worded would be one it could
 * answer for itself.
 *
 * The catalogues are `export default { 'key': '…', … }` with single-quoted
 * strings; a plural entry is an object, of which `other` is taken.
 */
class NativeText(private val readCatalogue: (String) -> String?) {

    fun get(key: String, locale: String, params: Map<String, String> = emptyMap()): String {
        var text = pick(readCatalogue(locale), key) ?: pick(readCatalogue("en"), key) ?: key
        // split/join, as i18n.js: a folder name may contain `$&`.
        for ((k, v) in params) text = text.split("{$k}").joinToString(v)
        return text
    }

    companion object {
        fun pick(source: String?, key: String): String? {
            source ?: return null
            val k = Regex.escape(key)
            Regex("""(?m)^\s*'$k'\s*:\s*'((?:[^'\\]|\\.)*)'""").find(source)?.let { return unescape(it.groupValues[1]) }
            Regex("""(?ms)^\s*'$k'\s*:\s*\{.*?\bother\s*:\s*'((?:[^'\\]|\\.)*)'""").find(source)?.let { return unescape(it.groupValues[1]) }
            return null
        }

        fun unescape(s: String): String {
            val out = StringBuilder()
            var i = 0
            while (i < s.length) {
                val c = s[i]
                if (c == '\\' && i + 1 < s.length) {
                    val n = s[i + 1]
                    when (n) {
                        'n' -> out.append('\n'); 't' -> out.append('\t')
                        'u' -> if (i + 5 < s.length) { out.append(s.substring(i + 2, i + 6).toInt(16).toChar()); i += 4 }
                        else -> out.append(n)
                    }
                    i += 2
                } else { out.append(c); i++ }
            }
            return out.toString()
        }
    }
}