Santhosh has submitted this change and it was merged. Change subject: Dict dictionary protocol backend ......................................................................
Dict dictionary protocol backend * Implements a dict protocol client and a dictionary registry * Exposes a REST api dictionary/:word/:from/:to Example: http://localhost:8000/dictionary/pen/en/de Result: { "definitions": [ { "def": "pen /pen/\r\n (Schreib-) Feder; Füller; Griffel <m>; Stift <m>", "db": { "name": "fd", "desc": "English-German FreeDict Dictionary ver. 0.3.5" } } ], "suggestions": [] } Change-Id: I138b5d457ce46c5bfe4e760d95f29c3adf25abfd --- M ContentTranslationService.js A dictionary/dict/Dict.js A dictionary/dict/DictClient.js A dictionary/dict/DictRegistry.json A dictionary/dict/Readme.md A public/dictionary/css/main.css A public/dictionary/index.html A public/dictionary/js/main.js 8 files changed, 958 insertions(+), 0 deletions(-) Approvals: Santhosh: Looks good to me, approved jenkins-bot: Verified diff --git a/ContentTranslationService.js b/ContentTranslationService.js index 3789500..a36d5e9 100644 --- a/ContentTranslationService.js +++ b/ContentTranslationService.js @@ -69,6 +69,17 @@ } ); } ); +app.get( '/dictionary/:word/:from/:to', function ( req, res ) { + var sourceLanguage = req.params.from, + word = req.params.word, + targetLanguage = req.params.to, + dictClient = require( __dirname + '/dictionary/dict/Dict.js' ); + + dictClient.getDefinition( word, sourceLanguage, targetLanguage ).then( function ( data ) { + res.send( data ); + } ); +} ); + app.get( '/version', function ( req, res ) { var version = { name: pkg.name, diff --git a/dictionary/dict/Dict.js b/dictionary/dict/Dict.js new file mode 100644 index 0000000..5c8aef0 --- /dev/null +++ b/dictionary/dict/Dict.js @@ -0,0 +1,29 @@ +var dictClient = require( __dirname + '/DictClient.js' ), + dictRegistry = require( __dirname + '/DictRegistry.json' ), + Q = require( 'q' ); + +function findDatabase( source, target ) { + var dictionaries = dictRegistry[ source ] && dictRegistry[ source ][ target ]; + if ( !dictionaries ) { + return null; + } + return Object.keys( dictionaries ); +} + +function getDefinition( word, from, to ) { + var deferred = Q.defer(); + dictClient.lookup( word, { + db: findDatabase( from, to ), + action: 'def', + suggestions: true, + error: function ( responseCode, message ) { + deferred.reject( responseCode + ': ' + message ); + }, + success: function ( data ) { + deferred.resolve( data ); + } + } ); + return deferred.promise; +} + +module.exports.getDefinition = getDefinition; diff --git a/dictionary/dict/DictClient.js b/dictionary/dict/DictClient.js new file mode 100644 index 0000000..5e11c77 --- /dev/null +++ b/dictionary/dict/DictClient.js @@ -0,0 +1,501 @@ +/** + * Dict dictionary protocol client as per RFC 2229 + * Credits: + * Dict client implementation borrowed from: https://github.com/ptrm/dict.json + * Copyright (c) 2010 Piotrek Marciniak <piot...@ptrm.eu>, MIT Style License + * RFC 2229: http://www.dict.org/rfc2229.txt + *@author Santhosh Thottingal <santhosh.thottin...@gmail.com> + *@license MIT + */ + +var sys = require( 'sys' ), + net = require( 'net' ), + logLevel, config; + +logLevel = { + silent: 0, + standard: 1, + diagnostic: 2, + verbose: 3 +}; +config = { + logging: logLevel.silent, + dictd: { + port: '2628', + host: '127.0.0.1', + timeout: 700 + }, + db: '!' // First match +}; + +function firstObj( list ) { + var obj = null, + idx; + + if ( typeof list !== 'object' ) { + return null; + } + for ( idx in list ) { + obj = list[ idx ]; + break; + } + + return obj; +} + +/** + * Simple logger, mainly for debugging + */ +function log( msg, level ) { + if ( !level ) { + level = logLevel.standard; + } + if ( level <= config.logging ) { + sys.log( msg ); + } +} + +/** + * Sanitize the words + * @param {Object} words + */ +function parseWords( words ) { + var i, word, db, nDb, dbIdx, + res = {}, + count = 0; + + for ( i in words ) { + if ( typeof words[ i ].word !== 'string' ) { + continue; + } + // cleanup the word by removing traling new line characters + word = words[ i ].word.replace( /["\r\n]/g, '' ).trim().toLowerCase(); + + db = []; + if ( words[ i ].db ) { + if ( typeof words[ i ].db !== 'object' ) { + words[ i ].db = new Array( words[ i ].db ); + } + for ( dbIdx in words[ i ].db ) { + nDb = words[ i ].db[ dbIdx ]; + // cleanup the db name by removing traling new line characters + db.push( nDb.replace( /["\r\n]/g, '' ).trim().toLowerCase() ); + } + } + + if ( !db.length ) { + db.push( config.db ); + } + if ( word ) { + res[ word ] = { + db: db + }; + count++; + } + } + + res.count = count; + log( sys.inspect( res ), logLevel.verbose ); + + return res; +} + +function getDefs( words, options ) { + var dict, defs = {}, + suggestions = {}, + reqQueue = [], + sentReqs = [], + reqOnDrain = false, + currentReqIdx = -1, + currentReq = {}, + textBuf = '', + textEnded = true, + word = '', + dbDesc = '', + dbName = '', + status = ''; + + // Create a connection to the dict host and port + dict = net.createConnection( config.dictd.port, config.dictd.host ); + dict.setTimeout( config.dictd.timeout ); + dict.setEncoding( 'utf8' ); + + if ( typeof options !== 'object' ) { + options = {}; + } + + dict.on( 'timeout', function () { + log( 'timeout', logLevel.diagnostic ); + options.error( 'error', 'Timeout' ); + dict.end(); + } ); + + dict.on( 'end', function () { + log( 'end', logLevel.diagnostic ); + dict.end(); + } ); + + dict.on( 'connect', function () { + var dbIdx, req, db, word; + log( 'getDefs: connected', logLevel.verbose ); + + // put requests to queue + for ( word in words ) { + if ( word === 'count' ) { + continue; + } + defs[ word ] = []; + for ( dbIdx in words[ word ].db ) { + db = words[ word ].db[ dbIdx ]; + req = 'd ' + db + ' "' + word + '"' + '\r\n'; + reqQueue.push( { + request: req, + word: word, + type: 'def', + db: db + } ); + } + + } + } ); + + function nextRequest() { + var req, i; + reqOnDrain = false; + + // check whether all responses arrived and if there are requests to be sent + if ( ( currentReqIdx + 1 < sentReqs.length ) || reqQueue.length ) { + if ( !dict.writable ) { + reqOnDrain = true; + log( 'nextRequest() postponed till drain', logLevel.diagnostic ); + return; + } + + // Send the all pending requests at once. It increases performance when + // using remote dict server, and is encouraged by the RFC. + req = ''; + for ( i in reqQueue ) { + req = req + reqQueue[ i ].request; + } + + sentReqs = sentReqs.concat( reqQueue ); + reqQueue = []; + currentReqIdx++; + currentReq = sentReqs[ currentReqIdx ]; + + if ( req.trim() ) { + dict.write( req ); + log( 'getDefs: nextRequest: sent request: "' + req + '"', logLevel.verbose ); + } + } else { // if not, send the quit message + currentReq = { + request: 'q\r\n' + }; + dict.end( currentReq.request ); + log( 'nextRequest(): Sent "q"', logLevel.diagnostic ); + } + } + + dict.on( 'drain', function () { + if ( !reqOnDrain ) { + return; + } + nextRequest(); + log( 'called nextRequestuest() on drain', logLevel.diagnostic ); + } ); + + dict.on( 'data', function ( data ) { + var idx, definition, header, nextResponsePos = -2, + sug, sugLines, lNum, + response = ''; + + if ( typeof data !== 'string' ) { + return; + } + log( 'Data: ' + JSON.stringify( data ), logLevel.verbose ); + + /* + To understand the response handling code, an example response is given below. + C: DEFINE * shortcake + ----------------- + S: 150 2 definitions found: list follows + S: 151 "shortcake" wn "WordNet 1.5" : text follows + S: shortcake + S: 1. n: very short biscuit spread with sweetened fruit and usu. + S: whipped cream + S: . + S: 151 "Shortcake" web1913 "Webster's Dictionary (1913)" : text follows + S: Shortcake + S: \Short"cake`\, n. + S: An unsweetened breakfast cake shortened with butter or lard, + S: rolled thin, and baked. + S: . + S: 250 Command complete + */ + function nextResponse() { + if ( textEnded ) { + nextResponsePos = data.search( /\r\n[0-9]{3}/ ); + } else { + nextResponsePos = data.search( /\r\n\.(\r\n|$)/ ); + } + + if ( nextResponsePos !== -1 ) { + response = data.substring( 0, nextResponsePos ); + // + 2 for \r\n + data = data.slice( nextResponsePos + 2 ); + } else { + response = data; + } + if ( textEnded ) { + status = response.substring( 0, 3 ); + } else { + textEnded = ( nextResponsePos > -1 ); + log( 'nextResponsePos: ' + nextResponsePos, logLevel.verbose ); + } + + log( 'Response: "' + response + '", next at ' + nextResponsePos, logLevel.verbose ); + log( 'Status: ' + status, logLevel.verbose ); + } + + while ( ( nextResponsePos !== -1 ) && ( nextResponsePos !== 0 ) ) { + + if ( textEnded ) { + // reset state variables + textBuf = ''; + status = ''; + response = ''; + nextResponse(); + } else { + log( 'Continuing previous data', logLevel.verbose ); + } + + switch ( status ) { + //greetings + case '220': + log( 'getDefs: dict.org said hello', logLevel.verbose ); + + //we can start the fun now + nextRequest(); + break; + + //bye + case '221': + log( 'getDefs: dict.org says bye', logLevel.verbose ); + //onEnd event should follow, so no need to do anything here + break; + + //a couple of errors on which we should close + //temorarily unavailable + case '420': + //Server temporarily unavailable + case '421': + //Server shutting down at operator request + options.error( 'error', 'Error code ' + status ); + return; + //no match + case '552': + //provide suggestions? + // checking request type, because server gives the same not found code for suggestions as for words + // also checking whether db isn't on ignore list + if ( ( currentReq.type === 'def' ) && options.suggestions ) { + reqQueue.push( { + request: 'match ' + currentReq.db + ' lev "' + currentReq.word + '"' + '\r\n', + type: 'sug', + word: currentReq.word + } ); + } + nextRequest(); + break; + + //a couple of errors on which we might try to continue + //syntax error, command not recognized + case '500': + //Syntax error, command not recognized + case '501': + //Syntax error, illegal parameters + case '502': + //Command not implemented + case '503': + // Command parameter not implemented + case '550': + //invalid strategy + case '551': + log( 'Proceeding to next request at status ' + status, logLevel.diagnostic ); + nextRequest(); + break; + + //suggestions + case '152': + word = currentReq.word; + + if ( textEnded ) { + //first line is the status message: + idx = response.indexOf( '\r\n' ); + if ( idx === -1 ) { + break; + } + header = response.substring( 0, idx ); + response = response.slice( idx + 2 ); + textBuf = response; + textEnded = response.match( /\r\n\.(\r\n|$)/ ); + if ( !textEnded ) { + log( 'Suggestions didn\'t end.', logLevel.verbose ); + } + } else { + nextResponse(); + textBuf = textBuf.concat( response ); + } + + if ( textEnded ) { + // Example suggestion response: + // 152 7 matches found: list follows + // dbname suggestion1 + // dbname suggestion2 + // Remove the "." ending the text message. + sugLines = textBuf.replace( /\r\n\.(\r\n|$)/, '' ).split( '\r\n' ); + // That removed the first line too. + if ( !suggestions[ word ] ) { + // initialize the object + suggestions[ word ] = []; + } + + for ( lNum in sugLines ) { + if ( !sugLines[ lNum ].trim() ) { + continue; + } + // remove the first word in the line because it is db name + sug = sugLines[ lNum ].replace( /^[a-zA-Z0-9]+ "([^"]+)".*/, '$1' ); + log( 'Suggestion: "' + sug + '"', logLevel.verbose ); + if ( suggestions[ word ].indexOf( sug ) === -1 ) { + suggestions[ word ].push( sug ); + } + } + + log( 'Suggestions ended.', logLevel.verbose ); + log( 'Parsed suggestions: ' + sys.inspect( suggestions[ word ] ), logLevel.verbose ); + } + break; + + //ok + case '250': + nextRequest(); + break; + + //definition + case '151': + //word database name - text follows + //textEnded, so we are free to start anew + if ( textEnded ) { + //first line is the status message: + idx = response.indexOf( '\r\n' ); + if ( idx === -1 ) { + break; + } + header = response.substring( 0, idx ); + response = response.slice( idx + 2 ); + + word = header.replace( /[0-9]{3} "([^"]*)".*/, '$1' ).toLowerCase(); + dbName = header.replace( /[0-9]{3} "[^"]*" (\w+)\b.*/, '$1' ); + dbDesc = header.replace( /[0-9]{3} "[^"]*".*"([^"]*)"/, '$1' ); + + textBuf = response; + + textEnded = response.match( /\r\n\.(\r\n|$)/ ); + if ( !textEnded ) { + log( 'Definition did not end.', logLevel.verbose ); + } + } else { + nextResponse(); + textBuf = textBuf.concat( response ); + } + + if ( textEnded ) { + // ".." On the beggining of a new line means "." + // We also remove the "." ending the text message. + definition = textBuf.replace( /^\.\./m, '.' ).replace( /\r\n\.(\r\n|$)/, '' ); + + log( 'Definition ended.', logLevel.verbose ); + log( 'Parsed defs: ' + sys.inspect( definition ), logLevel.verbose ); + + if ( typeof defs[ currentReq.word ] !== 'object' ) { + defs[ currentReq.word ] = []; + } + defs[ currentReq.word ].push( { + def: definition, + db: { + name: dbName, + desc: dbDesc + } + } ); + + log( 'Defs: ' + sys.inspect( defs ), logLevel.verbose ); + } + break; + } + log( '*** End of data event\n', logLevel.verbose ); + } + } ); + + dict.on( 'close', function () { + var data; + if ( options.action === 'def' ) { + defs = firstObj( defs ) || []; + + if ( options.suggestions ) { + suggestions = firstObj( suggestions ) || []; + } + } + + data = { + definitions: defs + }; + + if ( options.suggestions ) { + data.suggestions = suggestions; + } + options.success( data ); + log( 'Connection ended.', logLevel.verbose ); + } ); +} + +/** + * Search for the definition of a word + * @param {string|Array} word + * @param {Object} options + */ +function lookup( word, options ) { + var defs, words, wordList = [], + action = options.action || 'def'; + + switch ( action ) { + case 'def': + wordList = [ { + word: word, + //type: type, + db: options.db || config.db + } ]; + break; + + case 'multi': + wordList = word; + break; + + default: + options.error( 'error', 'Wrong action given.' ); + return; + } + + // Sanitize the wordList + words = parseWords( wordList ); + if ( words.count ) { + log( 'Words ok', logLevel.verbose ); + defs = getDefs( words, { + action: options.action, + suggestions: !!options.suggestions, + error: options.error, + success: options.success + } ); + } +} + +module.exports.lookup = lookup; diff --git a/dictionary/dict/DictRegistry.json b/dictionary/dict/DictRegistry.json new file mode 100644 index 0000000..1ac0907 --- /dev/null +++ b/dictionary/dict/DictRegistry.json @@ -0,0 +1,316 @@ +{ + "en": { + "af": { + "fd-eng-afr": "English-Afrikaans FreeDict Dictionary ver. 0.1.1" + }, + "ar": { + "fd-eng-ara": "English-Arabic FreeDict Dictionary ver. 0.6.2" + }, + "cs": { + "fd-eng-ces": "English-Czech dicts.info/FreeDict Dictionary ver. 0.1.1", + "fd-eng-cze": "English-Czech fdicts/FreeDict Dictionary" + }, + "hr": { + "fd-eng-cro": "English-Croatian Freedict Dictionary" + }, + "cy": { + "fd-eng-cym": "Eurfa Saesneg, English-Welsh Eurfa/Freedict dictionary ver. 0.2." + }, + "de": { + "fd-eng-deu": "English-German FreeDict Dictionary ver. 0.3.5" + }, + "el": { + "fd-eng-ell": "English - Modern Greek XDXF/FreeDict dictionary ver. 0.1" + }, + "en": { + "gcide": "The Collaborative International Dictionary of English v.0.48" + }, + "fr": { + "fd-eng-fra": "English-French FreeDict Dictionary ver. 0.1.4" + }, + "ga": { + "fd-eng-gle": "English-Irish FreeDict Dictionary ver. 0.3.1" + }, + "hi": { + "fd-eng-hin": "English-Hindi FreeDict Dictionary ver. 1.5.1" + }, + "hr": { + "fd-eng-hrv": "English-Croatian FreeDict Dictionary ver. 0.2.1" + }, + "hu": { + "fd-eng-hun": "English-Hungarian FreeDict Dictionary ver. 0.1" + }, + "it": { + "fd-eng-ita": "English-Italian FreeDict Dictionary ver. 0.1.1" + }, + "la": { + "fd-eng-lat": "English-Latin FreeDict Dictionary ver. 0.1.1" + }, + "lt": { + "fd-eng-lit": "English-Lithuanian FreeDict Dictionary ver. 0.7.1" + }, + "nl": { + "fd-eng-nld": "English-Dutch FreeDict Dictionary ver. 0.1.1" + }, + "pl": { + "fd-eng-pol": "English - Polish Piotrowski+Saloni/FreeDict dictionary ver. 0.1" + }, + "pt": { + "fd-eng-por": "English-Portuguese FreeDict Dictionary ver. 0.2.2" + }, + "ro": { + "fd-eng-rom": "English-Romanian FreeDict Dictionary ver. 0.6.1" + }, + "ru": { + "fd-eng-rus": "English-Russian FreeDict Dictionary ver. 0.3", + "mueller7": "Mueller English-Russian Dictionary" + }, + "sr": { + "fd-eng-scr": "English-Serbo-Croat Freedict dictionary", + "fd-eng-srp": "English-Serbian FreeDict Dictionary ver. 0.1.2" + }, + "es": { + "fd-eng-spa": "English-Spanish FreeDict Dictionary ver. 0.2.1" + }, + "sw": { + "fd-eng-swa": "English-Swahili xFried/FreeDict Dictionary" + }, + "sv": { + "fd-eng-swe": "English-Swedish FreeDict Dictionary ver. 0.1.1" + }, + "tr": { + "fd-eng-tur": "English-Turkish FreeDict Dictionary ver. 0.2.1" + }, + "cy": { + "fd-eng-wel": "English-Welsh Freedict dictionary" + } + }, + "af": { + "de": { + "fd-afr-deu": "Afrikaans-German FreeDict Dictionary ver. 0.3" + }, + "en": { + "fd-afr-eng": "Afrikaans-English FreeDict Dictionary ver. 0.2.1", + "fd-ara-eng": "Arabic-English FreeDict DictionaryByarabeyes.org ver. 0.6.2" + } + }, + "br": { + "fr": { + "fd-bre-fra": "Breton-French FreeDict Dictionary (Geriadur Tomaz) ver. 0.3.0" + }, + "en": { + "fd-ces-eng": "Czech-English FreeDict Dictionary ver. 0.2.1" + } + }, + "cr": { + "en": { + "fd-cro-eng": "Croatian-English Freedict Dictionary" + } + }, + "cy": { + "en": { + "fd-cym-eng": "Eurfa Cymraeg, Welsh-English Eurfa/Freedict dictionary ver. 0.2.2" + } + }, + "cs": { + "en": { + "fd-cze-eng": "Czech-English Freedict dictionary" + } + }, + "da": { + "en": { + "fd-dan-eng": "Danish-English FreeDict Dictionary ver. 0.2.1" + } + }, + "de": { + "en": { + "fd-deu-eng": "German-English FreeDict Dictionary ver. 0.3.3" + }, + "fr": { + "fd-deu-fra": "German-French FreeDict Dictionary ver. 0.3.1" + }, + "it": { + "fd-deu-ita": "German-Italian FreeDict Dictionary ver. 0.1.1" + }, + "nl": { + "fd-deu-nld": "German-Dutch FreeDict Dictionary ver. 0.1.1" + }, + "ku": { + "fd-deu-kur": "German-Kurdish Ferheng/FreeDict Dictionary ver. 0.2.1" + }, + "pt": { + "fd-deu-por": "German-Portuguese FreeDict Dictionary ver. 0.2.1" + }, + "tr": { + "fd-deu-tur": "German-Turkish Ferheng/FreeDict Dictionary ver. 0.2.1" + } + }, + "fr": { + "br": { + "fd-fra-bre": "French-Breton FreeDict Dictionary (Geriadur Tomaz) ver. 0.2.5" + }, + "de": { + "fd-fra-deu": "French-German FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-fra-eng": "French-English FreeDict Dictionary ver. 0.3.4" + }, + "nl": { + "fd-fra-nld": "French-Dutch FreeDict Dictionary ver. 0.1.2" + } + }, + "gd": { + "de": { + "fd-gla-deu": "Scottish Gaelic-German FreeDict Dictionary ver. 0.1.1" + } + }, + "ga": { + "en": { + "fd-gle-eng": "Irish-English FreeDict Dictionary ver. 0.1.2" + }, + "pl": { + "fd-gle-pol": "Irish-Polish FreeDict Dictionary ver. 0.1.1" + } + }, + "hi": { + "en": { + "fd-hin-eng": "English-Hindi Freedict Dictionary [reverse index]" + } + }, + "hr": { + "en": { + "fd-hrv-eng": "Croatian-English FreeDict Dictionary ver. 0.1.1" + } + }, + "hu": { + "en": { + "fd-hun-eng": "Hungarian-English FreeDict Dictionary ver. 0.3" + } + }, + "ga": { + "en": { + "fd-iri-eng": "Irish-English Freedict dictionary" + } + }, + "is": { + "en": { + "fd-isl-eng": "íslenska - English FreeDict Dictionary ver. 0.1" + } + }, + "it": { + "de": { + "fd-ita-deu": "Italian-German FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-ita-eng": "Italian-English FreeDict Dictionary ver. 0.1.1" + } + }, + "ja": { + "de": { + "fd-jpn-deu": "Japanese-German FreeDict Dictionary ver. 0.1.1" + } + }, + "ku": { + "de": { + "fd-kur-deu": "Kurdish-German Ferheng/FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-kur-eng": "Kurdish-English Ferheng/FreeDict Dictionary ver. 0.1.1" + }, + "tr": { + "fd-kur-tur": "Kurdish-Turkish Ferheng/FreeDict Dictionary ver. 0.1.1" + } + }, + "la": { + "de": { + "fd-lat-deu": "Latin - German FreeDict dictionary ver. 0.4" + }, + "en": { + "fd-lat-eng": "Latin-English FreeDict Dictionary ver. 0.1.1" + } + }, + "lt": { + "fd-lit-eng": "Lithuanian-English FreeDict Dictionary ver. 0.7.1" + }, + "mk": { + "bg": { + "fd-mkd-bul": "Macedonian - Bulgarian FreeDict Dictionary ver. 0.1" + } + }, + "nl": { + "de": { + "fd-nld-deu": "Dutch-German FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-nld-eng": "Dutch-English Freedict Dictionary ver. 0.1.3" + }, + "fr": { + "fd-nld-fra": "Nederlands-French FreeDict Dictionary ver. 0.1.1" + } + }, + "pl": { + "ga": { + "fd-pol-gle": "Polish-Irish FreeDict Dictionary ver. 0.1.1" + } + }, + "pt": { + "de": { + "fd-por-deu": "Portuguese-German FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-por-eng": "Portuguese-English FreeDict Dictionary ver. 0.1.1" + } + }, + "sa": { + "de": { + "fd-san-deu": "Sanskrit-German FreeDict Dictionary ver. 0.2.1" + } + }, + "sr": { + "en": { + "fd-scr-eng": "Serbo-Croat-English Freedict dictionary" + } + }, + "sk": { + "en": { + "fd-slk-eng": "Slovak-English FreeDict Dictionary ver. 0.1.1" + } + }, + "es": { + "en": { + "fd-spa-eng": "Spanish-English FreeDict Dictionary ver. 0.1.1" + } + }, + "sr": { + "en": { + "fd-srp-eng": "Serbian - English FreeDict Dictionary ver. 0.1.3" + } + }, + "sw": { + "en": { + "fd-swa-eng": "Swahili-English xFried/FreeDict Dictionary", + "fd-swh-eng": "Swahili-English xFried/FreeDict Dictionary ver. 0.4.3" + }, + "pl": { + "fd-swh-pol": "Swahili-Polish SSSP/FreeDict Dictionary ver. 0.2.2" + } + }, + "sv": { + "en": { + "fd-swe-eng": "Swedish-English FreeDict Dictionary ver. 0.1.1" + } + }, + "tr": { + "de": { + "fd-tur-deu": "Turkish-German FreeDict Dictionary ver. 0.1.1" + }, + "en": { + "fd-tur-eng": "Turkish-English FreeDict Dictionary ver. 0.2.1" + } + }, + "cy": { + "en": { + "fd-wel-eng": "Welsh-English Freedict dictionary" + } + } +} diff --git a/dictionary/dict/Readme.md b/dictionary/dict/Readme.md new file mode 100644 index 0000000..0445de9 --- /dev/null +++ b/dictionary/dict/Readme.md @@ -0,0 +1,16 @@ +Dict client in nodejs +===================== + +This is a Dict dictionary protocol client written in javascript. + +It exposes a simple api to check the word definitions in the available backends. + +```javascript +getDefinition( 'swim', 'en', 'de' ).then( function (data) { + console.log(data) +} ); +``` + +The backend dictionaries are listed in DictRegistry.json in the form of a json registry. +It provides a handy translation of ISO 639 two letter language codes to the available dictionary +identifiers. diff --git a/public/dictionary/css/main.css b/public/dictionary/css/main.css new file mode 100644 index 0000000..cbb9f57 --- /dev/null +++ b/public/dictionary/css/main.css @@ -0,0 +1,40 @@ + body { + width: 80%; + margin-left: 10%; + } + label { + width: 20%; + } + input { + width: 40%; + padding: 5px; + } + .lang { + width: 5%; + } + button { + width: 10%; + padding: 5px; + } + .status { + position: fixed; + bottom: 0; + left: 0; + right: 0; + height: 16px; + padding: 5px; + background: #ccc; + color: green; + font-size: 0.8em; + } + .form { + border: 1px solid #000; + padding: 10px; + } + .definition { + border: 1px solid #000; + padding: 10px; + font-size: medium; + word-wrap: break-word; + font-family: sans-serif; + } diff --git a/public/dictionary/index.html b/public/dictionary/index.html new file mode 100644 index 0000000..46f3e85 --- /dev/null +++ b/public/dictionary/index.html @@ -0,0 +1,23 @@ +<html> + +<head> + <script src="//code.jquery.com/jquery-1.10.2.min.js"></script> + <title>DictionaryContent Translation Server</title> + <link rel="stylesheet" href="css/main.css" type="text/css" /> +</head> + +<body> + <h1>Dictionary - Content Translation Server</h1> + <div class="form"> + <label for="word">Define</label> + <input name="word" value="Food" /> + <label for="sourceLanguage">from</label> + <input class="lang" name="sourceLanguage" value="en" /> + <label for="targetLanguage">to</label> + <input class="lang" name="targetLanguage" value="de" /> + <button>Go</button> + </div> + <pre class="definition"></pre> + <script src="js/main.js"></script> +</body> +</html> diff --git a/public/dictionary/js/main.js b/public/dictionary/js/main.js new file mode 100644 index 0000000..7d80ed8 --- /dev/null +++ b/public/dictionary/js/main.js @@ -0,0 +1,22 @@ +/*jshint browser:true, jquery:true */ +( function ( $ ) { + 'use strict'; + + $( document ).ready( function () { + $( 'button' ).click( function () { + $( '.definition' ).empty(); + var word = $( 'input[name=word]' ).val(), + from = $( 'input[name=sourceLanguage]' ).val(), + to = $( 'input[name=targetLanguage]' ).val(); + $.get( word + '/' + from + '/' + to, function ( response ) { + $.each( response.definitions, function ( index, definition ) { + $( '.definition' ).append( definition.def ); + $( '.definition' ).append( '\n' ); + $( '.definition' ).append( definition.db.desc ); + $( '.definition' ).append( '\n\n' ); + } ); + $( 'progress' ).hide(); + } ); + } ); + } ); +}( jQuery ) ); -- To view, visit https://gerrit.wikimedia.org/r/134074 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I138b5d457ce46c5bfe4e760d95f29c3adf25abfd Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/services/cxserver Gerrit-Branch: master Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com> Gerrit-Reviewer: Divec <da...@sheetmusic.org.uk> Gerrit-Reviewer: KartikMistry <kartik.mis...@gmail.com> Gerrit-Reviewer: Santhosh <santhosh.thottin...@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits