System Language

Azlier

Old World Ghost
Reaction score
461
Have you ever wanted an RPG map where NPC's that spoke different languages exist? Well, if you define the words, this script can translate English into your language for you.

These languages must follow English grammar rules.

First, here's the script for translating English -> Language. This includes the Language API.
JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Language ~~ By Azlier ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Language?
//         - Language translates phrases from English to defined languages.
//
//    Methods:
//         - Language.create() creates a new language that words can be added to.
//              Up to 8191 languages can exist.
//
//         - languageInstance.translateWord(string word) returns translation
//              Translates the given word into its counterpart in the language.
//
//         - languageInstance.translate(string phrase) returns translation
//              Translates an entire phrase into the language. Can support any string length.
//
//         - languageInstance.define(string word, string translation)
//              This is used to define the translations for different English words.
//              word is case insensitive. translation is CaSe SeNsItIvE.
//
//
//  How to import:
//         - Create a trigger named Language.
//         - Convert it to custom text and replace the whole trigger text with this.
//         - Define languages in a separate trigger.
//
//  Thanks:
//         - quraji for fixing the string parser.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

library Language initializer Init

globals
    private hashtable ht = InitHashtable()
endglobals

private function AddSeparator takes string s returns nothing
    call SaveBoolean(ht, 0, StringHash(s), true)
endfunction

struct Language
    
    method define takes string word, string trans returns nothing
        call SaveStr(ht, this, StringHash(word), trans)
    endmethod
    
    method translateWord takes string word returns string
        //It's important to know if you forgot to define a word.
        local string s = LoadStr(ht, this, StringHash(word))
        if s == null then
            debug if StringLength(word) > 0 then
                debug call BJDebugMsg("Language ERROR: Undefined word \"" + word + "\".")
            debug endif
            return word
        endif
        return s
    endmethod
    
    method translate takes string source returns string
        local integer i = 0
        local string result = " "
        local string s
        local integer end = StringLength(source)
        local string s2 = source
        loop
            exitwhen (i==end)
            set s = SubString(source, i, i+1)
            if LoadBoolean(ht, 0, StringHash(s)) then // separator found
                set result = result + .translateWord(SubString(source, 0, i)) // translate the word and add it to the result
                set result = result + s                                       // add the separator
                set source = SubString(source, i+1, end)     // set source to itself minus what has been parsed
                set i = -1 // reset i (-1 so it is incremented to 0 after the endif)
            endif
            set i = i + 1
        endloop
        
        if (i>0) then // there's some unparsed string left (with no separators, so should be a word)
            set result = result + .translateWord(source)
        endif
        
        set s = SubString(s2, 0, 1)
        set s2 = StringCase(s, true)
        if s == s2 then
            set result = StringCase(SubString(result, 0, 2), true) + SubString(result, 2, StringLength(result))
        endif
        
        return result
    endmethod
    
endstruct

function CreateLanguage takes nothing returns Language
    return Language.create()
endfunction

function DefineWord takes Language l, string w, string t returns nothing
    call l.define(w, t)
endfunction

function TranslateWord takes Language l, string s returns string
    return l.translateWord(s)
endfunction

function Translate takes Language l, string s returns string
    return l.translate(s)
endfunction

private function Init takes nothing returns nothing
    //Define separators (spaces, punctuation marks)
    call AddSeparator(" ")
    call AddSeparator("\"")
    call AddSeparator(".")
    call AddSeparator("'")
    call AddSeparator(":")
    call AddSeparator(";")
    call AddSeparator(",")
    call AddSeparator("(")
    call AddSeparator(")")
    call AddSeparator("-")
    call AddSeparator("!")
    call AddSeparator("?")
    call AddSeparator("\\")
    call AddSeparator("/")
endfunction

endlibrary


This is a sample script for language definition. Very incomplete.
JASS:
library LanguagePreDef initializer Init requires Language
//This small library is an example of how languages are defined.
//It's tedious work, and you must define every word you want to translate correctly.
globals
    Language LANGUAGE_ELVEN
    //Just a tiny, tiny predefined language. To show you how it's done.
endglobals
    
private function Init takes nothing returns nothing
    //Init languages:
    set LANGUAGE_ELVEN = CreateLanguage()
    
    //Define Elven:
    call DefineWord(LANGUAGE_ELVEN, "the", &quoti")
    call DefineWord(LANGUAGE_ELVEN, "a", "ai")
    call DefineWord(LANGUAGE_ELVEN, "I", &quoti")
    call DefineWord(LANGUAGE_ELVEN, "fight", "purya")
    call DefineWord(LANGUAGE_ELVEN, "death", "moor")
    call DefineWord(LANGUAGE_ELVEN, "prepared", "yawhæt")
    call DefineWord(LANGUAGE_ELVEN, "you", &quotiu")
    call DefineWord(LANGUAGE_ELVEN, "are", "aiur")
    call DefineWord(LANGUAGE_ELVEN, "to", "ag")
    call DefineWord(LANGUAGE_ELVEN, "am", "at")
    call DefineWord(LANGUAGE_ELVEN, "hill", "hëihl")
    call DefineWord(LANGUAGE_ELVEN, "hills", "hëihli")
    call DefineWord(LANGUAGE_ELVEN, "at", "yr")
    call DefineWord(LANGUAGE_ELVEN, "it", &quotth")
    call DefineWord(LANGUAGE_ELVEN, "on", "eun")
    call DefineWord(LANGUAGE_ELVEN, "will", "yeihll")
    call DefineWord(LANGUAGE_ELVEN, "for", "tor")
    call DefineWord(LANGUAGE_ELVEN, "die", "mor")
    call DefineWord(LANGUAGE_ELVEN, "fights", "puryæ")
    
endfunction

endlibrary


And last, but not least, a script showcasing how easy it is to translate stuff.
JASS:
scope LanguageTest initializer Init
//This is a test script for Language.
//Type something like "death to the hill" ingame to see the result.
private function Actions takes nothing returns boolean
    call DisplayTextToPlayer(Player(0), 0, 0, "Translated to Elven: " + Translate(LANGUAGE_ELVEN, GetEventPlayerChatString()))
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(t, Player(0), "", false)
    call TriggerAddCondition(t, Condition(function Actions))
endfunction

endscope
 

Attachments

  • Language.w3m
    16 KB · Views: 215

Romek

Super Moderator
Reaction score
963
> Have you ever wanted an RPG map where NPC's that spoke different languages exist?
Nope. :p

And if I did, I'd simply change [ljass]call Message("Hello, what do you want?")[/ljass] to [ljass]call Message("Juba, poby che klop rekkum?")[/ljass]; instead of using some translator.
 

Azlier

Old World Ghost
Reaction score
461
Well that's because you haven't thought of that!

And it's much easier to define a few words than to manually translate with every sentence. You risk making a stupid mistake and making it untranslatable as well.
 

Azlier

Old World Ghost
Reaction score
461
Would you, as a user, have fun designing the grammar rules of each separate language?

That's what you would have to do if this supported grammar rules. :p

EDIT:

You know what I realized? You can add words as you need them, without any sort of bugs.

You can also change words' translations during gameplay, but I can't guarantee that'll work buglessly.
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
And it's much easier to define a few words than to manually translate with every sentence. You risk making a stupid mistake and making it untranslatable as well.
And it's much easier to write coherently by having a human translate it than just using word-for-word swapping. I mean heck, just try to imagine english-to-spanish verb swapping.
 

Azlier

Old World Ghost
Reaction score
461
Who needs to write coherently when you can have some insane system write a mess for you?
 

Nestharus

o-o
Reaction score
84
Why not just follow the normal method and just scramble up the characters in the alphabet? lol ;p

Then based on how well you know the language, do some letters normal and some letters not normal ^_^.

That's how I usually seen it done anyways ; P.
 

Azlier

Old World Ghost
Reaction score
461
Ahsdjkfhjc, eowuic fkchiwn?

Doesn't look much like a language to me.
 

quraji

zap
Reaction score
144
To the naysayers: I agree that this wouldn't really be needed to translate into a totally new language, but it doesn't have to. While NPC's could adopt a new language, I think the coolest part would be using a custom chat system and allowing changes to be made to their chats automatically. Think swear filter (they're stupid, but...), or a pirate speech thing. Get creative :p

(I'm a bit partial to this because I made a similar one for my Talkative! chat system that died...)

Ahsdjkfhjc, eowuic fkchiwn?

Doesn't look much like a language to me.

I think he means this:

1. The English sentence could be "Glory to the Horde!".
2. In Orcish, to someone who didn't understand it, it would be "Ljitx zi zko Kituo!" (the language is just random letter replacements).
3. Now, if a hypothetical character has a proficiency in Orcish (but not yet mastered), it would show up as "Glirx ti the Hirue!". Some of the characters are recognizable. You might be able to read this if it had some context.
4. If the character was fluent in Orcish it would show up as "Glory to the Horde!".

While that is cool it would be very specific and would be hard to implement in a general way. It would probably be better in a system of it's own.
 

Tru_Power22

You can change this now in User CP.
Reaction score
144
I was talking about this on the IRC with you last night. Cool to see that it was finally released.
 

Azlier

Old World Ghost
Reaction score
461
Slowly learning the language. Doesn't work too well with this implementation because the translation can be of any word length.

Learning one word at a time would most certainly work. Romek's ExplodeString mixed with this can make that a reality rather quickly. :p

Then again, I would probably need another text parser to do it. ExplodeString doesn't have the features required for saving punctuation.

>Think swear filter

Yes, this can work as a limited filter.

Potentially, one could create a language during gameplay via some chat commands. Lots of possibilities (RP wise, most likely) but annoying to make the user do.
 

quraji

zap
Reaction score
144
There's another little bug. If I start an input with a separator, my sentence will not be capitalized. This is because when you check for the case if the first character of the source string, you're assuming it will be a letter.

There's another thing that's not much of a bug really, but still; it doesn't recognize ending punctuation like periods, question marks etc. This means if I type something like "Are you prepared to fight for the hill? Do you have the will?", the second sentence won't be capitalized.

It's also worth noting that when you define a word like so: [ljass]MyLanguage.define(x, y)[/ljass]
x is case insensitive while y is case sensitive. This is because StringHash is case insensitive.
 

Azlier

Old World Ghost
Reaction score
461
Yes, I know. I'll need to make some changes to capitalize the first letter of every sentence to handle that. I hate string parsing, and I'll most likely break something. :(

Oh, and quraji, one nice thing about your fix is that it doesn't translate what it can't find a translation for. So if you give it a name, the name remains constant between languages. Yay!
 

quraji

zap
Reaction score
144
>I hate string parsing, and I'll most likely break something. :(

I hate it too, but I love it. :nuts:

>Oh, and quraji, one nice thing about your fix is that it doesn't translate what it can't find a translation for. So if you give it a name, the name remains constant between languages. Yay!

Much better than having gaps in your translation, eh? Yay!
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
Some languages have 100 000 words.

I doubt warcraft can handle well 100 000 words.

And also, registring words would be long.
 

Azlier

Old World Ghost
Reaction score
461
The amount of words that a language can handle depends on how much a hashtable can store.

And I seriously doubt that you'll be able to use more than a few thousand different words in another language in your map.
 

Executor

I see you
Reaction score
57
What about this debug mode:
You play your Map for Bug-finding purposes, 'Language' stores all non-translated words in an array or sth., before you end the game you type "-debugLanguage" and all words are displayed. Then you can add these words, you forgot.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top