LSL languageAPI

From Second Life Wiki
Revision as of 02:21, 8 October 2013 by Kireji Haiku (talk | contribs) (-1 >> ERR_GENERIC and 0 >> PUBLIC_CHANNEL)
Jump to navigation Jump to search

This is an API that will handle chat messages and HUD menus in multiple languages based on language files in notecards. Included are two LSL files, the API itself, a simple example usage script and two language files ( English and French )

todo: floating text support is not yet included in this script.


<lsl> // LSL_languageAPI // License: LGPL // Version: 0.20 // Author: Gypsy Paz


//============== // CONFIG //============== integer autoLoad = FALSE; // load the first notecard on CHANGED_INVENTORY float menuTimeout = 10; // Set the blue menu time out ( in seconds )


//================================================================================================ // LINK CODES: //================================================================================================ list langLinkCodes = [

   "INIT",     0x88000,     //Initialize
   "INIT_R",   0x88001,     //Confirm Initialized
   "LOAD",     0x88002,     //Load Language            lang file name (blank loads first one)
   "LOAD_R",   0x88003,     //Confirm Lanugage Loaded
   "MENU",     0x88004,     //langMenu                  caption|button1|button2|etc...    avkey
   "MENU_R",   0x88005,     //langMenu Response         button    uuid
   "MENU_C",   0x88006,     //Close the menu (turn off the listener)
   "WHISPER",  0x88007,     //langWhisper               message    uuid
   "SAY",      0x88008,     //langSay                   message uuid
   "SHOUT",    0x88009,     //langShout                 message uuid
   "OSAY",     0x8800A,     //langOwnerSay              message uuid
   "IM",       0x8800B,     //langIM                    message|avkey    uuid
   "FTEXT",    0x8800C,     //floating text             message color alpha
   "DUMP",     0x8800D,     //dump lang from memory to chat (for debugging)
   "ERROR",    0x8800E      // return an error message ( not sure how I'll handle this yet

];


//================================================================================================ // LANGUAGE FUNCTIONS: //================================================================================================ integer langGetCode(string langCode){

   integer i = llListFindList(langLinkCodes, [langCode]);
   return llList2Integer(langLinkCodes, i+1);

}


// Language Vars string Language; list langData; list langIndex; string curLangFile;

// llDialog Vars string menuCaption; list menuButtons; key menuUser; integer menuChannel; integer menuListener;

// Data Server Vars integer lines; integer line; key request = NULL_KEY;

string translate(string index, string id){

   string val;
   integer i = llListFindList(langIndex,[index]);
   if ( i != ERR_GENERIC ){
       return parse(llList2String(langData,i),id);
   }
   else{
       return ">>>error<<<";
   }

}


string parse(string val, string id){

   // Memory
   integer i;
   i = llSubStringIndex(val,"<<memory>>");
   if ( i != ERR_GENERIC ){
       val = llDeleteSubString(val,i,llStringLength("<<memory>>")-1);
       val = llInsertString(val,i,(string)llGetFreeMemory());
   }
   i = llSubStringIndex(val,"<<key2name>>");
   if ( i != ERR_GENERIC ){
       val = llDeleteSubString(val,i,i+llStringLength("<<key2name>>"));
       val = llInsertString(val,i,llKey2Name((key)id));
   }
   return val;

}


integer processing = FALSE; processData(string data){

   if ( processing ){
       if ( data == ">>>STOP<<<" ){
           processing = FALSE;
           return;
       }
       string prefix = llGetSubString(data,0,1);
       if ( ( prefix == "//" ) || ( llStringLength(data) == 0 ) ){
           return;
       }
       list s = llParseString2List(data,["|"],[]);
       string cmd = llStringTrim(llList2String(s,0),STRING_TRIM);
       string val = llStringTrim(llList2String(s,1),STRING_TRIM);
       if ( cmd == "!PRINT" ){
           llSay(PUBLIC_CHANNEL,parse(val,""));
       }
       else if ( cmd == "!SET_LANG" ){
           Language = val;
       }
       else{
           integer i = llListFindList(langIndex,[cmd]);
           if ( i == ERR_GENERIC ) return;          //<<<<<<<<<<<<<< this will silently fail missing indexes
           langData = llListReplaceList(langData,[val],i,i);
       }



   }
   else if ( data == ">>>START<<<" ){
       processing = TRUE;
   }

}


dumpData(){

   integer i;
   for ( i=0; i<llGetListLength(langIndex); i++ ){
       llSay(PUBLIC_CHANNEL,llList2String(langIndex,i)+" | "+llList2String(langData,i));
   }

}


default{

   link_message(integer sender, integer num, string msg, key id){
       list s;
       integer i;
       if ( num == langGetCode("INIT") ){        //Initialize
           curLangFile = "";
           Language = "";
           langIndex = llParseString2List(msg,["|"],[]);
           langData = [];
           for ( i = 0; i < llGetListLength(langIndex); i++ ){
               langData += ["..."];
           }
           llMessageLinked(LINK_THIS,langGetCode("INIT_R"),"ok"," ");
       }
       else if ( num == langGetCode("LOAD") ){    // Load Language
           if ( llStringLength(msg) == 0 ){
               curLangFile = llGetInventoryName(INVENTORY_NOTECARD,0);
           }
           else{
               curLangFile = msg;
           }
           if ( llGetInventoryType(curLangFile) != INVENTORY_NOTECARD ){
               llSay(PUBLIC_CHANNEL,"Error, Language File Doesn't Exist");
               return;
           }
           state prep;
       }
       else if ( num == langGetCode("MENU") ){    // llDialog
           s = llParseString2List(msg,["|"],[]);
           menuCaption = translate(llList2String(s,0),"");
           menuButtons = [];
           for ( i=1; i<llGetListLength(s); i++ ){
               menuButtons += translate(llList2String(s,i),"");
           }
           menuUser    = id;
           state menu;
       }
       else if ( num == langGetCode("WHISPER") ){    // Whisper
           llWhisper(PUBLIC_CHANNEL,translate(msg,id));
       }
       else if ( num == langGetCode("SAY") ){    // Say
           llSay(PUBLIC_CHANNEL,translate(msg,id));
       }
       else if ( num == langGetCode("SHOUT") ){    // Shout
           llShout(PUBLIC_CHANNEL,translate(msg,id));
       }
       else if ( num == langGetCode("OSAY") ){    // OwnerSay
           llOwnerSay(translate(msg,id));
       }
       else if ( num == langGetCode("IM") ){    // Instant Message
           s = llParseString2List(msg,["|"],[]);
           llInstantMessage(llList2Key(s,1),translate(llList2String(s,0),id));        
       }
       else if ( num == langGetCode("DUMP") ){
           dumpData();
       }
   }
   
   changed(integer change){
       if ( change & CHANGED_INVENTORY ){
           
       }
   }
                   

}


state menu{

   state_entry(){
       menuChannel = PUBLIC_CHANNEL;
       while(menuChannel == PUBLIC_CHANNEL ){
           menuChannel = (integer)llRound(llFrand(5)*10000000);
       }
       llDialog(menuUser,menuCaption,menuButtons,menuChannel);
       llSetTimerEvent(menuTimeout);
       menuListener = llListen(menuChannel, "", menuUser, "");       
   }
   
   listen(integer channel, string name, key id, string msg){
       llSetTimerEvent(0.0);
       integer i = llListFindList(langData,[msg]);
       if ( i != ERR_GENERIC ){
           llMessageLinked(LINK_THIS,langGetCode("MENU_R"),llList2String(langIndex,i),id);
       }
       else{
           llMessageLinked(LINK_THIS,langGetCode("MENU_R"),">>>error<<<",id);
       }
       state default;
   }



   timer(){
       llSetTimerEvent(0.0);
       llMessageLinked(LINK_THIS,langGetCode("MENU_R"),">>>timeout<<<", menuUser);
       state default;
   }
   
   link_message(integer sender, integer num, string str, key id){
       if ( num == langGetCode("MENU_C") ){
           llSetTimerEvent(0.0);
           state default;
       }
   }
   
   state_exit(){
       llSetTimerEvent(0.0);
   }

}

state prep{

   state_entry(){
       if ( llGetInventoryType(curLangFile) == INVENTORY_NOTECARD ){
           request = llGetNumberOfNotecardLines(curLangFile);
           llSetTimerEvent(5.0);
       }
       else{
           llOwnerSay("Error, Language File Does Not Exist");
       }
   }
   
   dataserver(key query_id, string data){
       if (query_id == request){
           llSetTimerEvent(0.0);
           lines = (integer)data;
           state read;
       }
   }
   
   timer(){
       state timeout;
   }

}


state read{

   state_entry(){
       line = 0;
       request = llGetNotecardLine(curLangFile, line);
       llSetTimerEvent(5.0);
   }
   
   dataserver(key query_id, string data){
       if (query_id == request){
           llSetTimerEvent(0.0);
           processData(data);
           line++;
           if ( line <= lines ){
               request = llGetNotecardLine(curLangFile, line);
               llSetTimerEvent(5);
           }
           else{
               state default;
           }
       }
   }
   
   timer(){
       state timeout;
   }

}


state timeout{

   state_entry(){
       llSetTimerEvent(0.0);
       llSay(PUBLIC_CHANNEL,"Error, reading the language file timed out");
       llMessageLinked(LINK_THIS,51,"error","timeout");
       state default;
   }

} </lsl>


<lsl>


//================================================================================================ // LANGUAGE API: //------------------------------------------------------------------------------------------------

//================================================================================================ string langName; list langIndex = [

   "HELLO_WORLD",
   "HELLO_AVATAR",
   "OBJECT_NAME",
   "OWNED_BY",
   "CAPTION",
   "BUTTON_1",
   "BUTTON_2",
   "BUTTON_3",
   "BUTTON_4",
   "BUTTON_5",
   "BUTTON_6"

];

//================================================================================================ // LINK CODES: //================================================================================================ list langLinkCodes = [

   "INIT",     0x88000,     //Initialize
   "INIT_R",   0x88001,     //Confirm Initialized
   "LOAD",     0x88002,     //Load Language            lang file name (blank loads first one)
   "LOAD_R",   0x88003,     //Confirm Lanugage Loaded
   "MENU",     0x88004,     //langMenu                  caption|button1|button2|etc...    avkey
   "MENU_R",   0x88005,     //langMenu Response         button    uuid
   "MENU_C",   0x88006,     //Close the menu (turn off the listener)
   "WHISPER",  0x88007,     //langWhisper               message    uuid
   "SAY",      0x88008,     //langSay                   message uuid
   "SHOUT",    0x88009,     //langShout                 message uuid
   "OSAY",     0x8800A,     //langOwnerSay              message uuid
   "IM",       0x8800B,     //langIM                    message|avkey    uuid
   "FTEXT",    0x8800C,     //floating text             message color alpha
   "DUMP",     0x8800D,     //dump lang from memory to chat (for debugging)
   "ERROR",    0x8800E      // return an error message ( not sure how I'll handle this yet

];


//================================================================================================ // LANGUAGE FUNCTIONS: //================================================================================================ integer langGetCode(string langCode){

   integer i = llListFindList(langLinkCodes, [langCode]);
   return llList2Integer(langLinkCodes, i+1);

}

langInit(){

   llMessageLinked(LINK_THIS,langGetCode("INIT"),llDumpList2String(langIndex,"|")," ");

}

langLoad(string notecard){

   langName = "";
   llMessageLinked(LINK_THIS,langGetCode("LOAD"),notecard, " ");

}

langWhisper(string msg, key id){

   llMessageLinked(LINK_THIS,langGetCode("WHISPER"),msg,id);

}

langSay(string msg, key id){

   llMessageLinked(LINK_THIS,langGetCode("SAY"),msg,id);

}

langShout(string msg, key id){

   llMessageLinked(LINK_THIS,langGetCode("SHOUT"),msg,id);

}

langMenu(string caption, list buttons, key id){

   llMessageLinked(LINK_THIS,langGetCode("MENU"),caption+"|"+llDumpList2String(buttons,"|"),id);

}




default{

   state_entry(){
       langInit();
   }
   
   link_message(integer sender, integer num, string msg, key id){
       // Language is initialized
       if ( num == langGetCode("INIT_R") ){
           if ( msg == "ok" ){
               // load the default language (first notecard)
               langLoad("");
           }
           else if ( msg == "error" ){
               // something went wrong
               llOwnerSay((string)id);
           }
       }
       
       // Language is loaded
       else if ( num == langGetCode("LOAD_R") ){
           if ( msg == "ok" ){
               // load the default language (first notecard)
               langName = (string)id;
           }
           else if ( msg == "error" ){
               // something went wrong
               llOwnerSay((string)id);
           }

llMessageLinked(LINK_THIS,langGetCode("DUMP"),"dump data"," ");

       }
       
       // Blue Menu Response
       else if ( num == langGetCode("MENU_R") ){
           if ( msg == "BUTTON_1" ){
               langSay("HELLO_AVATAR", id);
           }
           else if ( msg == "BUTTON_2" ){
               langSay("OBJECT_NAME", llGetKey());            
           }
           else if ( msg == "BUTTON_3" ){
               langSay("OWNED_BY", llGetOwner());            
           }
           else if ( msg == "BUTTON_4" ){
               llMessageLinked(LINK_THIS,langGetCode("DUMP"),"dump"," ");
           }
           else if ( msg == "BUTTON_5" ){
               langLoad("language - ENGLISH");
           }
           else if ( msg == "BUTTON_6" ){
               langLoad("language - FRENCH");
           }
       }
   }
   
   touch_start(integer n){
       langMenu("CAPTION", ["BUTTON_1", "BUTTON_2", "BUTTON_3", "BUTTON_4", "BUTTON_5", "BUTTON_6"], llDetectedKey(0)); 
   }
   

} </lsl>



<lsl> Instructions go up here


>>>START<<< // start processing the notecard !SET_LANG | Engilish !PRINT | Loading Language File...

HELLO_WORLD | Hello, I'm a multi-lingual api HELLO_AVATAR | Hello <<key2name>> OBJECT_NAME | I am a <<key2name>> OWNED_BY | I belong to <<key2name>> CAPTION | Language API Sample, choose your option BUTTON_1 | Avatar BUTTON_2 | Object BUTTON_3 | Owner BUTTON_4 | Dump BUTTON_5 | ENGLISH BUTTON_6 | FRENCH


!PRINT | Language file loaded. !PRINT | <<memory>> bytes free

>>>STOP<<< </lsl>


<lsl> Mettez vos instructions ici


>>>START<<< // commencez à traiter le notecard !SET_LANG | Francais !PRINT | Chargement du Dossier de Langue...

HELLO_WORLD | Bonjour, je suis api multilingue HELLO_AVATAR | Bonjour <<key2name>> OBJECT_NAME | Je suis <<key2name>> OWNED_BY | J'appartiens à <<key2name>> CAPTION | L'Échantillon d'API de langue, choisissez votre option BUTTON_1 | Avatar BUTTON_2 | Objet BUTTON_3 | Propriétaire BUTTON_4 | Décharge publique


!PRINT | Le dossier de langue a chargé. !PRINT | octets de <<memory>> libres

>>>STOP<< </lsl>