Sorry, we don't support your browser.  Install a modern browser

Ability to concatenate Translation strings in Lua#1029

As an example, this is basically how I’m working with translations:-
“{en}Congratulation “..playerName..”, you have won{es}Enhorabuena “..playerName..”, usted ha ganado”

It’s probably far too complicated to do in the back end, but I’d rather do:-
“{en}Congratulation {es}Enhorabuena “..playerName..”{en}, you have won{es}, usted ha ganado”
(this short example seems trivial, but I have much longer sentances)
This would require LUA to recognise two matching translation tags on the one line and know to ditch any other language found in between. Hmmm, in my example it’s going to assume the playerName is Spanish. then we’ll need {/es} to mark the end of translation. OK this got more complicated than I thought. Maybe I just need to write a function to do this for me.

5 years ago

Use gsub:

playerName = "Bob"
str = "{en}Congratulation PLAYERNAME, you have won{es}Enhorabuena PLAYERNAME, usted ha ganado"
str = str:gsub('PLAYERNAME', playerName)
print(str)
5 years ago

You might have the key to achieving this, but I need to thiink more about how to implement it.

My example might have been a little too simple, I’m trying to concatenate a few variable togeather and the translation bracket can only apear once in the string.

playerName = "Bob"

salutation="{en}Congratulation {es}Enhorabuena "
If lost then salutation="{en}Sorry {es}Lo siento "

reason="{en},  you have won{es}, usted ha ganado"
If lost then reason="{en}, you have lost{es}, Usted ha perdido"

str = salutation..playerName..reason
print(str)

So at the moment you will only get the reason variable displayed.

5 years ago

Implementation :)

do --Some functions for localizations
    local DEFAULT_ORDER = {"en", "es"}
    local meta

    local function ExtractLocalizationFromString(str)
        local loc = {}
        setmetatable(loc,meta)
        local found = nil
        for lang, s in str:gmatch("{([a-z][a-z])}([^{}]*)") do
            loc[lang] = s
            found = true
        end
        if not found then
            for _,lang in pairs(DEFAULT_ORDER) do
                loc[lang] = str
            end
        end
        return loc
    end

    local function ShallowCopy(t)
        if not t then
            return
        end
        local new = {}
        for k,v in pairs(t) do
            new[k] = t[k]
        end
        return new
    end

    --Can be used with strings
    function ConcatLocalizations(loc1, loc2)
        if type(loc1) ~= "table" then
            loc1 = ExtractLocalizationFromString(tostring(loc1))
        end
        if type(loc2) ~= "table" then
            loc2 = ExtractLocalizationFromString(tostring(loc2))
        end
        local res = ShallowCopy(loc1)
        setmetatable(res, getmetatable(loc1))
        for lang,str in pairs(res) do
            res[lang] = str .. (loc2[lang] or "???")
        end
        for lang,str in pairs(loc2) do
            if not res[lang] then
                res[lang] = "???" .. str
            end
        end
        return res
    end

    meta = {
        __add = ConcatLocalizations,
        __concat = ConcatLocalizations,
        __tostring = function(t1)
            local t = {}
            for _,lang in ipairs(DEFAULT_ORDER) do
                if t1[lang] then
                    table.insert(t, "{" .. lang .. "}" .. t1[lang])
                end
            end
            return table.concat(t)
        end,
    }

    --Creates special localization object.
    function MakeLocalizationString(en, es)
        local loc = {
            en = en,
            es = es,
        }
        setmetatable(loc,meta)
        return loc
    end
end

--- Test1 ---
print("Test 1:")
str1 = "{en}AAA{es}BBB"
str2 = "{en}CCC{es}DDD"
print(ConcatLocalizations(str1,str2))

--- Test2 ---
print("Test 2:")
loc1 = MakeLocalizationString("AAAAA", "BBBBB")
print(loc1)
loc2 = MakeLocalizationString("CCCCC", "DDDDD")
print(loc2)
print(loc1 .. loc2)

--- Test3 ---
print("Test 3:")
print(loc1 .. "ZZZZZ")
print("ZZZZZ" .. loc2)

--- Test4 ---
print("Test 4:")
print(loc1 .. "{en}XXXXX{es}YYYYY")
print("{en}XXXXX{es}YYYYY" .. loc2)

I tested it on https://rextester.com/l/lua_online_compiler

5 years ago

Wow, you got inspired, I’ll pick it apart and see how you got it to work.

Only done a quick glance, but looks like you didn’t use gsub in the end

Many thanks for this.

PS My mod has six languages but I suspect your code can handle it.

5 years ago

Sadly, you have to use tostring() with this tiny lib :(

obj.setName(tostring(loc1))

Or you may improve it somehow idk)

5 years ago

I didn’t use gsub but I used gmatch, it’s almost the same.

5 years ago

my brain melted a little bit, but I think I have a handle on your code. The thing I havent got staright is your gmatch search string
“{([a-z][a-z])}([^{}]*)”
I get that it pulls out all the text between two sets of curly brackets (and uses what’s in the curly brackets as the key), but I can’t figure out how. I’m wondering if there are any characters I might use that would confise it? I’ll be testing tonight, but i use “\n” alot to cariage return.

5 years ago

Damn, my six languages are {en}, {es}, {fr}, {ko}, {pt-br}, and {zh-cn}.
That gmatch search finds the first 4, but doesn’t find the last two. I can see why, “([a-z][a-z])”, but can’t think how to modify that to include all six posibilities. Adding more [a-z] seemed to not find the first four. I know enough to read it, but not enough to speak it :-(

5 years ago

In case others need this, I found the following tweaks helped:-

local DEFAULT_ORDER={"en", "zh-cn", "ko", "es", "pt-br")
gmatch("{([^{}]*)}([^{}]*)")
5 years ago

Make sure any languages you are using are in the DEFAULT_ORDER, and the updated gmatch will find any language between the curly brackets..

5 years ago

Hmmm, then replace gmatch with this:

str:gmatch("{([a-z-]+)}([^{}]*)")

For more info see:
https://en.wikipedia.org/wiki/Regular_expression

But note that Lua uses % as an escape symbol.
http://lua-users.org/wiki/PatternsTutorial

5 years ago