Mobrovac has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/355097 )

Change subject: Use marcXML translator in addition to dc for ISBN
......................................................................


Use marcXML translator in addition to dc for ISBN

Request both dublin core and marcXML data from
WorldCat, as marcXML lacks an itemType field,
and dublinCore lacks edition and publisher
fields.

Also fixes some bugs in dublin core translator
which were missing some author fields.

Add "overwriteAuthors" parameter to Translator;
this allows multiple translators to be used on a
creators field. Must be used with caution as it
make cause duplicate authors.

Fix extendGeneral method in translators/util/
which used the same key (contributors) in the
translator.

Bug: T155161
Change-Id: I58489d2959306b620f9bfa4a5bfb2a81ea7cb4a4
---
M lib/CitoidService.js
M lib/Translator.js
M lib/XMLReader.js
M lib/translators/README.md
M lib/translators/bePress.js
M lib/translators/coins.js
M lib/translators/dublinCore.js
M lib/translators/general.js
A lib/translators/marcXML.js
D lib/translators/template.js.txt
M lib/translators/util/index.js
M test/features/scraping/isbn.js
R test/features/unit/translator.js
M test/features/unit/translators/coins.js
M test/features/unit/translators/general.js
M test/features/unit/translators/util.js
16 files changed, 771 insertions(+), 183 deletions(-)

Approvals:
  Mobrovac: Verified; Looks good to me, approved
  jenkins-bot: Verified



diff --git a/lib/CitoidService.js b/lib/CitoidService.js
index 3e234c7..b41f68e 100644
--- a/lib/CitoidService.js
+++ b/lib/CitoidService.js
@@ -517,8 +517,13 @@
     citation.format = cr.format;
     citation.doi = cr.doi;
 
-    var wskeyFormat = 'dc';
     var self = this;
+
+    var dcXML;
+    var scrapeDC;
+
+    var marcXML;
+    var scrapeMARC;
 
     // Set responses if below is rejected
     function reject(){
@@ -532,16 +537,38 @@
         return cr;
     }
 
-    // Make request to WorldCat srn index service
-    return this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', 
wskeyFormat).then(
-        function(body){
-            return self.scrapeXML(citation, cr, body, wskeyFormat);
+    dcXML = this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', 
'dc');
+    marcXML = this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', 
'marc');
+
+    // Make concurrent requests for the data in both Dublin Core and MarcXML
+    return BBPromise.all([dcXML, marcXML]).then(function(results){
+
+        // Promises for scraping results from each of dc and marc
+        scrapeDC =  self.scrapeXML(citation, cr, results[0], 'dc', true); // 
Boolean at end allows multiple creators translators to be used within the dc 
translator
+        scrapeMARC =  self.scrapeXML(citation, cr, results[1], 'marc');
+
+        // Scrape dc first because it can determine type
+        return scrapeDC.then(function(){
+            return scrapeMARC.then(function(){
+                citation.responseCode = 200;
+                citation.source.push('WorldCat');
+                return cr;
+            },
+            // If rejected by scrapeMARC, still send 200 because DC was 
successfully added
+            function(){
+                citation.responseCode = 200;
+                citation.source.push('WorldCat');
+                return cr;
+            });
         },
-        // Rejection handler
+        // If unable to scrape DC, reject.
         function(){
-            return reject();
-        }
-    );
+            reject();
+        });
+    },
+    function(){
+        reject();
+    });
 
 
 };
@@ -622,8 +649,8 @@
  * @param  {String}   wskeyFormat      Format the XML citation will come back 
in. Can be 'dc', 'marcXML', or WorldCat's native 'openSearch' format
  * @return {Object}                    BBPromise for CitoidRequest object
  */
-CitoidService.prototype.scrapeXML = function(citation, cr, xml, wskeyFormat){
-    return this.xml.translate(citation, cr, xml, wskeyFormat);
+CitoidService.prototype.scrapeXML = function(citation, cr, xml, wskeyFormat, 
creatorOverwrite){
+    return this.xml.translate(citation, cr, xml, wskeyFormat, 
creatorOverwrite);
 };
 
 module.exports = CitoidService;
diff --git a/lib/Translator.js b/lib/Translator.js
index 8a9b562..f2dd75c 100644
--- a/lib/Translator.js
+++ b/lib/Translator.js
@@ -18,21 +18,37 @@
  * specific type, and a translator specific to that metadata type
  * @param  {Object} metadata   flat metadata object (i.e. metadata.openGraph)
  * @param  {Object} translator
+ * @param  {Boolean} creatorOverwrite whether or not unique creator 
translators can be run multiply
  */
-Translator.prototype.translate = function(citation, metadata, translator){
+Translator.prototype.translate = function(citation, metadata, translator, 
creatorOverwrite){
        var logger = this.logger;
     if (!translator || !metadata){return citation;}
     var property;
-    Object.keys(metadata).forEach(function(key){ // Loop through results
-        property = translator[key]; // Look up property in translator
-        if (property && !citation[property.name]){ // If it has a 
corresponding translation and won't overwrite properties already set
-            try {
-                citation = property.translate(citation, metadata, key);
-            } catch (e) {
-                logger.log('debug/scraper', "Failed to translate property " + 
property.name);
+    var creatorSubnames = []; // Store types of creators already added
+    var useCreatorTranslator = false; // Bool for whether a creator translator 
should be used.
+
+    for (var key in metadata) {
+        if (metadata.hasOwnProperty(key)) { // Loop through properties of 
metadata Obj
+            property = translator[key]; // Look up property in the translator 
to find the translator function specific to the field
+            if (!property){continue;} // Skip rest of loop if undefined
+            // Set bool to determine if current translator is a non-duplicate 
creators translator subname
+            if (creatorOverwrite && property.name && property.name === 
'creators' && property.subname){
+                if (creatorSubnames.indexOf(property.subname)=== -1){ // Run 
translator if not already in array
+                    useCreatorTranslator = true;
+                    creatorSubnames.push(property.subname); // i.e. 'author' 
or 'contributor'
+                }
+            }
+            // Don't overwrite properties already set; only allows translator 
to be run only if it's a non-duplicate creator subtype
+            if (!citation[property.name] || useCreatorTranslator){
+                try {
+                    citation = property.translate(citation, metadata, key);
+                    useCreatorTranslator = false; // Set to false for next 
iteration
+                } catch (e) {
+                    logger.log('debug/translator', "Failed to translate 
property " + property.name);
+                }
             }
         }
-    });
+    }
     return citation;
 };
 
diff --git a/lib/XMLReader.js b/lib/XMLReader.js
index 7812099..40c003b 100644
--- a/lib/XMLReader.js
+++ b/lib/XMLReader.js
@@ -8,6 +8,7 @@
  */
 var dc = require('./translators/dublinCore.js');
 var BBPromise = require('bluebird');
+var marc = require('./translators/marcXML.js');
 var xml2js = BBPromise.promisifyAll(require('xml2js'));
 
 /**
@@ -19,8 +20,8 @@
     this.translator = translator;
 };
 
-// Process XML which has been converted to a JS obj
-function process(jsobj){
+// Process XML which has been converted to a JS obj from DC metadata
+function processDC(jsobj){
     var record = {};
     var recordIDS;
     var newKey;
@@ -56,7 +57,7 @@
     return record;
 }
 
-// Return an itemType given a record jsobj
+// Return an itemType given a record jsobj from DC metadata
 function getItemType(record){
     var itemType;
     // Types for worldcat search API dublincore records
@@ -83,49 +84,110 @@
     return itemType;
 }
 
-XMLReader.prototype.translate = function(citationObj, cr, xml, wskeyFormat){
+// Process MarcXML which has been converted to a JS obj
+function processMARCXML(jsobj){
+    var key;
+    var value;
+    var code;
+    var record = {};
+    var i;
+    var j;
+    var item;
+    var subitem;
+    var trailing = /\s*[\/:;.]*\s*$/; // Regex for trailing punct and white 
space
+    for (i = 0; i < jsobj.length; i++){
+        item = jsobj[i];
+        var tag = item.$.tag;
+        if (item.subfield){
+            for (j = 0; j < item.subfield.length; j++){
+                subitem = item.subfield[j];
+                code = subitem.$.code;
+                value = subitem._.replace(trailing, ''); //Remove trailing 
punctuation and white space
+
+                key = code + tag; // Create key out of tag and subfield code
+                if (!record[key]){ // If undef, def new key
+                    record[key] = [value]; // Put in Array since same tag/code 
entry is allowed
+                } else {
+                    record[key].push(value); // If key already exists, add new 
value
+                }
+            }
+        } else {
+            key = tag;
+            value = item._;
+            if (!record[key]){ // If undef, def new key
+                record[key] = [value]; // Put in Array since same tag/code 
entry is allowed
+            } else {
+                record[key].push(value); // If key already exists, add new 
value
+            }
+        }
+
+    }
+    return record;
+}
+
+// Return an itemType given a MarcXML record JS obj
+function getMARCItemType(record){
+    var itemType = 'book'; // MarcXML unfortnately does not report the item 
type, default to book
+    return itemType;
+}
+
+XMLReader.prototype.translate = function(citationObj, cr, xml, wskeyFormat, 
creatorOverwrite){
 
     var content = citationObj.content;
     var translate = this.translator.translate;
-    var itemType;
+    var message = 'Unable to retrieve data from ISBN ' + citationObj.isbn;
     var xmlreader = this;
-    var record;
-    var message;
-    var error;
 
-    function reject(){
-        error = {Error: message};
-        citationObj.responseCode = 404;
-        citationObj.error = error;
-        return cr;
-    }
+    var itemType;
+    var record;
+    var controlfields;
 
     return xml2js.parseStringAsync(xml).then(function(result) {
-        if (result && result.oclcdcs) {
-            record = process(result.oclcdcs);
-            content.itemType = getItemType(record);
-            // dublinCore.js translator properties
-            content = translate(content, record, dc[content.itemType]);
-            // Add OCLC number to response, url, and oclc fields
-            if (record.oclc){
-                citationObj.oclc = record.oclc;
-                content.oclc = record.oclc;
-                content.url = 'https://www.worldcat.org/oclc/' + record.oclc;
+        if (wskeyFormat === 'dc'){
+            if (result && result.oclcdcs) {
+                record = processDC(result.oclcdcs);
+                if (!content.itemType) {
+                    content.itemType = getItemType(record);
+                }
+
+                // dublinCore.js translator properties; won't overwrite 
previous values
+                content = translate(content, record, dc[content.itemType], 
creatorOverwrite);
+
+                // Add OCLC number to response, url, and oclc fields; may 
overwrite previous values
+                if (record.oclc){
+                    citationObj.oclc = record.oclc;
+                    content.oclc = record.oclc;
+                    content.url = 'https://www.worldcat.org/oclc/' + 
record.oclc;
+                }
+
+                return cr;
+            } else {
+                return BBPromise.reject(message);
             }
+        } else if (wskeyFormat === 'marc'){
+             if (result && result.record && result.record.datafield) {
+                record = processMARCXML(result.record.datafield, record);
+                if (!content.itemType){
+                    content.itemType = getMARCItemType(record);
+                }
+                controlfields = processMARCXML(result.record.controlfield);
+                content = translate(content, record, marc[content.itemType], 
creatorOverwrite);
 
-            citationObj.responseCode = 200;
-            citationObj.source.push('WorldCat');
+                // Add OCLC number to response, url, and oclc fields
+                content.oclc = controlfields['001'][0];
+                content.url = 'https://www.worldcat.org/oclc/' + content.oclc;
 
-            return cr;
-        } else {
-            message = 'Unable to retrieve data from ISBN ' + citationObj.isbn;
-            return reject();
+                citationObj.oclc = content.oclc;
+
+                return cr;
+            } else {
+                return BBPromise.reject(message);
+            }
         }
-
     })
     .catch(function (err) {
         xmlreader.logger.log('debug/ISBN', err);
-        return reject();
+        return BBPromise.reject(message);
     });
 };
 
diff --git a/lib/translators/README.md b/lib/translators/README.md
index ea123e2..10bada0 100644
--- a/lib/translators/README.md
+++ b/lib/translators/README.md
@@ -9,6 +9,4 @@
 
 Each translator here corresponds to a type of metadata found in [html-metadata 
node library](https://github.com/wikimedia/html-metadata). The name of the file 
matches the keys found in the Object 
[metadataFunctions](https://github.com/wikimedia/html-metadata/blob/master/lib/index.js)
 in the library.
 
-A template for writing new translators is found in template.js.txt.
-
 Utility functions that are used across translators are found in ./util.
\ No newline at end of file
diff --git a/lib/translators/bePress.js b/lib/translators/bePress.js
index 18072b3..388d6db 100644
--- a/lib/translators/bePress.js
+++ b/lib/translators/bePress.js
@@ -33,7 +33,7 @@
 
 // Shortcut for extendWithCreators utility
 function extendWithCreators(creatorName){
-    return extendGeneral(exports.general, creatorName);
+    return extendGeneral(exports.general, creatorName, 'author');
 }
 
 // Create a general type with the author in the creator field once since it is 
used many times.
diff --git a/lib/translators/coins.js b/lib/translators/coins.js
index 5c178b0..f97db93 100644
--- a/lib/translators/coins.js
+++ b/lib/translators/coins.js
@@ -3,7 +3,6 @@
 var ex = require('../Exporter.js');
 var ut = require('./util/index.js');
 
-var eg = ut.extendGeneral;
 var generateCreatorObj = ut.generateCreatorObj;
 var makeTranslator = ut.makeTranslator;
 var makeListTranslator = ut.makeListTranslator;
@@ -38,11 +37,6 @@
     title: makeTranslator('title'),
     date: makeTranslator('date', fixDate)
 };
-
-// Shortcut for extendGeneral utility
-function extendGeneral(creatorName){
-    return eg(exports.general, creatorName);
-}
 
 /**
  * Methods that are used by multiple types
diff --git a/lib/translators/dublinCore.js b/lib/translators/dublinCore.js
index c2e1c7c..95c4134 100644
--- a/lib/translators/dublinCore.js
+++ b/lib/translators/dublinCore.js
@@ -8,8 +8,6 @@
 
 var makeTranslator = ut.makeTranslator;
 var makeCreatorsTranslator = ut.makeCreatorsTranslator;
-var eg = ut.extendGeneral;
-
 
 /**
  * Dublin core type values : Zotero type field values
@@ -35,40 +33,54 @@
  * Object with fields common to all but a few types
  * @type {Object}
  */
-exports.general = {
+exports.generalWithAuthor = {
     title: makeTranslator('title'),
     date: makeTranslator('date', fixDate),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('author'),
     contributor: makeCreatorsTranslator('contributor')
 };
-
-/* Function to add arbitrary creator function to the exports.general obj*/
-function extendGeneral(creatorName){
-    return eg(exports.general, creatorName);
-}
-
-// Create frequently used general types once.
-exports.generalWithAuthor = extendGeneral('author');
 
 exports.generalWithAuthorAndPublisher = Object.assign({}, 
exports.generalWithAuthor, {
     publisher: makeTranslator('publisher')
 });
 
 /* Complete list of Zotero types with field translators in the Object */
-exports.artwork = extendGeneral('artist');
+exports.artwork = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('artist'),
+    contributor: makeCreatorsTranslator('contributor')
+};
 exports.attachment = {
     title: makeTranslator('title')
 };
-exports.audioRecording = Object.assign({}, extendGeneral('performer'), {
+exports.audioRecording = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('performer'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('label')
-});
-exports.bill = extendGeneral('sponsor');
+};
+exports.bill = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('sponsor'),
+    contributor: makeCreatorsTranslator('contributor')
+};
 exports.blogPost = exports.generalWithAuthor;
 exports.book = exports.generalWithAuthorAndPublisher;
 exports.bookSection = exports.generalWithAuthorAndPublisher;
 exports['case'] = {
-    author: makeCreatorsTranslator('author'),
+    creator: makeCreatorsTranslator('author'),
+    contributor: makeCreatorsTranslator('contributor'),
     title: makeTranslator('caseName'),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote')
@@ -78,6 +90,7 @@
     title: makeTranslator('title'),
     date: makeTranslator('date', fixDate),
     creator: makeCreatorsTranslator('programmer'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('company')
 };
 exports.conferencePaper = exports.generalWithAuthorAndPublisher;
@@ -85,51 +98,93 @@
 exports.document = exports.generalWithAuthorAndPublisher;
 exports.email = {
     author: makeCreatorsTranslator('author'),
+    contributor: makeCreatorsTranslator('contributor'),
     title: makeTranslator('subject'),
     date: makeTranslator('date', fixDate),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote')
 };
 exports.encyclopediaArticle = exports.generalWithAuthorAndPublisher;
-exports.film = Object.assign({}, extendGeneral('director'), {
+exports.film = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('director'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('distributor')
-});
+};
 exports.forumPost = exports.generalWithAuthor;
-exports.hearing = Object.assign({}, extendGeneral('contributor'), {
+exports.hearing =  {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('contributor'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('publisher')
-});
+};
 exports.instantMessage = exports.generalWithAuthor;
-exports.interview = extendGeneral('interviewee');
+exports.interview =  {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('interviewee'),
+    contributor: makeCreatorsTranslator('contributor'),
+    publisher: makeTranslator('publisher')
+};
 exports.journalArticle = exports.generalWithAuthor;
 exports.letter = exports.generalWithAuthor;
 exports.magazineArticle = exports.generalWithAuthor;
 exports.manuscript = exports.generalWithAuthor;
-exports.map = Object.assign({}, extendGeneral('cartographer'),{
+exports.map = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('cartographer'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('publisher')
-});
+};
 exports.newspaperArticle = exports.generalWithAuthor;
 exports.note = {}; // Has no fields
 exports.patent = {
-    author: makeCreatorsTranslator('inventor'),
+    creator: makeCreatorsTranslator('inventor'),
+    contributor: makeCreatorsTranslator('contributor'),
     title: makeTranslator('title'),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote')
 };
 exports.podcast =  {
-    author: makeCreatorsTranslator('podcaster'),
+    creator: makeCreatorsTranslator('podcaster'),
+    contributor: makeCreatorsTranslator('contributor'),
     title: makeTranslator('title'),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote')
 };
-exports.presentation = extendGeneral('presenter');
-exports.radioBroadcast = Object.assign({}, extendGeneral('director'),{
+exports.presentation = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('presenter'),
+    contributor: makeCreatorsTranslator('contributor')
+};
+exports.radioBroadcast = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('director'),
     publisher: makeTranslator('network')
-});
+};
 exports.report = Object.assign({}, exports.generalWithAuthor, {
     publisher: makeTranslator('institution')
 });
 exports.statute = {
-    author: makeCreatorsTranslator('author'),
+    creator: makeCreatorsTranslator('author'),
+    contributor: makeCreatorsTranslator('contributor'),
     title: makeTranslator('nameOfAct'),
     language: makeTranslator('language', fixLang),
     abstract: makeTranslator('abstractNote')
@@ -137,10 +192,22 @@
 exports.thesis = Object.assign({}, exports.generalWithAuthor, {
     publisher: makeTranslator('university')
 });
-exports.tvBroadcast = Object.assign({}, extendGeneral('director'), {
+exports.tvBroadcast = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('director'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('network')
-});
-exports.videoRecording = Object.assign({}, extendGeneral('director'), {
+};
+exports.videoRecording = {
+    title: makeTranslator('title'),
+    date: makeTranslator('date', fixDate),
+    language: makeTranslator('language', fixLang),
+    abstract: makeTranslator('abstractNote'),
+    creator: makeCreatorsTranslator('director'),
+    contributor: makeCreatorsTranslator('contributor'),
     publisher: makeTranslator('studio')
-});
+};
 exports.webpage = exports.generalWithAuthor;
\ No newline at end of file
diff --git a/lib/translators/general.js b/lib/translators/general.js
index f7e1cc7..fc80ea2 100644
--- a/lib/translators/general.js
+++ b/lib/translators/general.js
@@ -22,7 +22,7 @@
 
 // Shortcut for extendGeneral utility
 function extendGeneral(creatorName){
-    return eg(exports.general, creatorName);
+    return eg(exports.general, creatorName, 'author');
 }
 
 // Create a general type with the author in the creator field once since it is 
used many times.
diff --git a/lib/translators/marcXML.js b/lib/translators/marcXML.js
new file mode 100644
index 0000000..2e94407
--- /dev/null
+++ b/lib/translators/marcXML.js
@@ -0,0 +1,390 @@
+'use strict';
+
+var ex = require('../Exporter.js');
+var ut = require('./util/index.js');
+
+var fixDate = ex.fixDate;
+var fixLang = ex.fixLang;
+var vISBN = ex.validateISBN;
+var vISSN = ex.validateISSN;
+
+var makeTranslator = ut.makeTranslator;
+var makeCreatorsTranslator = ut.makeCreatorsTranslator;
+var makeListTranslator = ut.makeListTranslator;
+var makePagesTranslator = ut.makePagesTranslator;
+
+/**
+ * Translator for MARCXML
+ */
+
+exports.artwork = { // No publisher
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    b260: makeTranslator('publisher'), // Name of publisher, distributor, etc
+    t100: makeTranslator('title'),
+    a245: makeTranslator('title'),
+    c245: makeCreatorsTranslator('artist'), // Personal name
+    a100: makeCreatorsTranslator('artist'), // Personal name
+    a700: makeCreatorsTranslator('contributor'),
+    l100: makeTranslator('language', fixLang)
+};
+exports.attachment = {
+    t100: makeTranslator('title'),
+    a245: makeTranslator('title')
+};
+exports.audioRecording = {
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    b260: makeTranslator('label'), // Name of publisher, distributor, etc
+    t100: makeTranslator('title'),
+    a245: makeTranslator('title'),
+    c245: makeCreatorsTranslator('performer'), // Personal name
+    a100: makeCreatorsTranslator('performer'), // Personal name
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'), // Place of publication, distribution, etc.,
+    a264: makeTranslator('place'), // Place of publication, distribution, etc.,
+    a700: makeCreatorsTranslator('contributor'),
+    l100: makeTranslator('language', fixLang),
+    g773: makeTranslator('volume'),
+    a020: makeListTranslator('ISBN', vISBN) // International Standard Book 
Number
+};
+exports.bill = {
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    b260: makeTranslator('label'), // Name of publisher, distributor, etc
+    t100: makeTranslator('title'),
+    a245: makeTranslator('title'),
+    c245: makeCreatorsTranslator('sponsor'), // Personal name
+    a100: makeCreatorsTranslator('sponsor'), // Personal name
+    a700: makeCreatorsTranslator('contributor'),
+    l100: makeTranslator('language', fixLang),
+    a020: makeListTranslator('ISBN', vISBN) // International Standard Book 
Number
+};
+exports.blogPost = {
+    t100: makeTranslator('title'), // Title of work
+    a245: makeTranslator('title'), // Title
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    l100: makeTranslator('language', fixLang), // Language of a work
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    c245: makeCreatorsTranslator('author'), // Personal name
+    a100: makeCreatorsTranslator('author'), // Personal name
+    t773: makeTranslator('blogTitle'),
+    a700: makeCreatorsTranslator('contributor')
+};
+exports.book = {
+    t100: makeTranslator('title'), // Title of work
+    a245: makeTranslator('title'), // Title
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    l100: makeTranslator('language', fixLang), // Language of a work
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    a250: makeTranslator('edition'), // Edition statement
+    b773: makeTranslator('edition'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'), // Place of publication, distribution, etc.,
+    a020: makeListTranslator('ISBN', vISBN), // International Standard Book 
Number
+    b260: makeTranslator('publisher'), // Name of publisher, distributor, etc.
+    c245: makeCreatorsTranslator('author'), // Personal name
+    //a100: makeCreatorsTranslator('author'), // Personal name
+    a700: makeCreatorsTranslator('contributor'),
+    g773: makeTranslator('volume'),
+    a300: makeTranslator('numPages')
+};
+exports.bookSection = {
+    t100: makeTranslator('title'), // Title of work
+    a245: makeTranslator('title'), // Title
+    c260: makeTranslator('date', fixDate), // Date of publication, 
distribution, etc.
+    f100: makeTranslator('date', fixDate), // Date of a work
+    l100: makeTranslator('language', fixLang), // Language of a work
+    a520: makeTranslator('abstractNote'), // Summary, etc.
+    a250: makeTranslator('edition'), // Edition statement
+    b773: makeTranslator('edition'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'), // Place of publication, distribution, etc.,
+    a020: makeListTranslator('ISBN', vISBN), // International Standard Book 
Number
+    b260: makeTranslator('publisher'), // Name of publisher, distributor, etc.
+    c245: makeCreatorsTranslator('author'), // Personal name
+    a100: makeCreatorsTranslator('author'), // Personal name
+    a700: makeCreatorsTranslator('contributor'),
+    t773: makeTranslator('bookTitle'),
+    g773: makeTranslator('volume')
+};
+exports['case'] =  { // No publisher
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('caseName'),
+    f100: makeTranslator('dateDecided'),
+    c260: makeTranslator('dateDecided'),
+    a100: makeCreatorsTranslator('author'),
+    l100: makeTranslator('language', fixLang),
+    q773: makeTranslator('firstPage')
+};
+exports.computerProgram = { // No language field
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('programmer'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.conferencePaper = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    g773: makeTranslator('volume'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    t773: makeTranslator('proceedingsTitle'),
+    b260: makeTranslator('publisher'),
+    l100: makeTranslator('language', fixLang),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.dictionaryEntry = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date',fixDate),
+    c260: makeTranslator('date', fixDate),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    t773: makeTranslator('dictionaryTitle'),
+    b260: makeTranslator('publisher'),
+    l100: makeTranslator('language', fixLang),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.document = exports.generalWithAuthor;
+exports.email = {
+    a520: makeTranslator('abstractNote'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    t100: makeTranslator('subject'),
+    l100: makeTranslator('language', fixLang),
+    a100: makeCreatorsTranslator('author')
+};
+exports.encyclopediaArticle = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    t773: makeTranslator('encyclopediaTitle'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    b260: makeTranslator('publisher'),
+    l100: makeTranslator('language', fixLang),
+    q773: makeTranslator('pages'),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.film =  {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('director'),
+    c260: makeTranslator('date', fixDate),
+    f100: makeTranslator('date', fixDate)
+};
+exports.forumPost = exports.blogPost;
+exports.hearing = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('contributor'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    c260: makeTranslator('date', fixDate),
+    f100: makeTranslator('date', fixDate),
+    q773: makeTranslator('pages')
+};
+exports.instantMessage = exports.blogPost;
+exports.interview = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('interviewee'),
+    c260: makeTranslator('date', fixDate),
+    f100: makeTranslator('date', fixDate),
+    l100: makeTranslator('language', fixLang)
+};
+exports.journalArticle = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    r773: makeTranslator('issue'),
+    g773: makeTranslator('volume'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    a490: makeTranslator('seriesTitle'),
+    t773: makeTranslator('publicationTitle'),
+    x773: makeListTranslator('ISSN', vISSN),
+    l100: makeTranslator('language', fixLang)
+};
+exports.letter = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    l100: makeTranslator('language', fixLang)
+};
+exports.magazineArticle = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    t773: makeTranslator('publicationTitle'),
+    l100: makeTranslator('language', fixLang),
+    x773: makeListTranslator('ISSN', vISSN)
+};
+exports.manuscript = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    l100: makeTranslator('language', fixLang)
+};
+exports.map =  {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('cartographer'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    t773: makeTranslator('seriesTitle'),
+    a490: makeTranslator('seriesTitle'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    b260: makeTranslator('publisher'),
+    l100: makeTranslator('language', fixLang),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.newspaperArticle =  {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    t773: makeTranslator('publicationTitle'),
+    l100: makeTranslator('language', fixLang),
+    x773: makeListTranslator('ISSN', vISSN)
+};
+exports.note = {}; // Has no fields
+exports.patent =  {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    l100: makeTranslator('language', fixLang),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    a100: makeCreatorsTranslator('inventor'),
+    f100: makeTranslator('issueDate'),
+    c260: makeTranslator('issueDate')
+};
+exports.podcast = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('podcaster'),
+    t773: makeTranslator('seriesTitle'),
+    a490: makeTranslator('seriesTitle'),
+    l100: makeTranslator('language', fixLang)
+};
+exports.presentation =  {
+    a520: makeTranslator('abstractNote'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    t100: makeTranslator('title'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    l100: makeTranslator('language', fixLang),
+    a100: makeCreatorsTranslator('presenter')
+};
+exports.radioBroadcast = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('director'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    l100: makeTranslator('language', fixLang)
+};
+exports.report = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    t773: makeTranslator('seriesTitle'),
+    a490: makeTranslator('seriesTitle'),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    r773: makeTranslator('number'),
+    u773: makeTranslator('number'),
+    l100: makeTranslator('language', fixLang)
+};
+exports.statute = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('nameOfAct'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('dateEnacted'),
+    c260: makeTranslator('dateEnacted', fixDate),
+    l100: makeTranslator('language', fixLang)
+};
+exports.thesis = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    a264: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    l100: makeTranslator('language', fixLang),
+    b260: makeTranslator('university')
+};
+exports.tvBroadcast = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('director'),
+    f100: makeTranslator('date', fixDate),
+    c260: makeTranslator('date', fixDate),
+    a264: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    l100: makeTranslator('language', fixLang)
+};
+exports.videoRecording = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('director'),
+    f100: makeTranslator('date',fixDate),
+    c260: makeTranslator('date', fixDate),
+    t773: makeTranslator('seriesTitle'),
+    a490: makeTranslator('seriesTitle'),
+    a264: makeTranslator('place'),
+    a260: makeTranslator('place'),
+    d773: makeTranslator('place'),
+    l100: makeTranslator('language', fixLang),
+    a020: makeListTranslator('ISBN', vISBN)
+};
+exports.webpage = {
+    a520: makeTranslator('abstractNote'),
+    t100: makeTranslator('title'),
+    a100: makeCreatorsTranslator('author'),
+    f100: makeTranslator('date',fixDate),
+    l100: makeTranslator('language', fixLang)
+};
\ No newline at end of file
diff --git a/lib/translators/template.js.txt b/lib/translators/template.js.txt
deleted file mode 100644
index 02f2429..0000000
--- a/lib/translators/template.js.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-'use strict';
-
-var makeTranslator = require('./util/index.js').makeTranslator;
-var addCreators = require('./util/index.js').addCreators;
-var eg = require('./util/index.js').extendGeneral;
-var makeCreatorsTranslator = require('./util/index.js').makeCreatorsTranslator;
-
-/**
- * Template field values : translators made with Zotero type field values
- * @type {Object}
- */
-
-exports.general = {
-    urlTemplateField: makeTranslator('url'),
-    abstractTemplateField: makeTranslator('abstractNote'),
-    publisherTemplateField: makeTranslator('publisher'),
-    titleTemplateField: makeTranslator('title')
-};
-
-// Shortcut for extendGeneral utility
-function extendGeneral(creatorName){
-    return eg(exports.general, creatorName);
-}
-
-// Create a general type with the author in the creator field once since it is 
used many times.
-exports.generalWithAuthor = extendGeneral('author');
-
-/* Complete list of Zotero types with field translators in the Object */
-exports.artwork = extendGeneral('artist');
-exports.attachment = {
-    title: makeTranslator('title')
-};
-exports.audioRecording = extendGeneral('performer');
-exports.bill = extendGeneral('sponsor');
-exports.blogPost = exports.generalWithAuthor;
-exports.book = exports.generalWithAuthor;
-exports.bookSection = exports.generalWithAuthor;
-exports['case'] = exports.generalWithAuthor;
-exports.computerProgram = { // No language field
-    title: makeTranslator('title'),
-    creator: makeCreatorsTranslator('programmer')
-};
-exports.conferencePaper = exports.generalWithAuthor;
-exports.dictionaryEntry = exports.generalWithAuthor;
-exports.document = exports.generalWithAuthor;
-exports.email = exports.generalWithAuthor;
-exports.encyclopediaArticle = exports.generalWithAuthor;
-exports.film = extendGeneral('director');
-exports.forumPost = exports.generalWithAuthor;
-exports.hearing = extendGeneral('contributor');
-exports.instantMessage = exports.generalWithAuthor;
-exports.interview = extendGeneral('interviewee');
-exports.journalArticle = exports.generalWithAuthor;
-exports.letter = exports.generalWithAuthor;
-exports.magazineArticle = exports.generalWithAuthor;
-exports.manuscript = exports.generalWithAuthor;
-exports.map = extendGeneral('cartographer');
-exports.newspaperArticle = exports.generalWithAuthor;
-exports.note = {}; // Has no fields
-exports.patent = extendGeneral('inventor');
-exports.podcast = extendGeneral('podcaster');
-exports.presentation = extendGeneral('presenter');
-exports.radioBroadcast = extendGeneral('director');
-exports.report = exports.generalWithAuthor;
-exports.statute = exports.generalWithAuthor;
-exports.thesis = exports.generalWithAuthor;
-exports.tvBroadcast = extendGeneral('director');
-exports.videoRecording = extendGeneral('director');
-exports.webpage = exports.generalWithAuthor;
\ No newline at end of file
diff --git a/lib/translators/util/index.js b/lib/translators/util/index.js
index a4dd747..6e66edf 100644
--- a/lib/translators/util/index.js
+++ b/lib/translators/util/index.js
@@ -95,14 +95,19 @@
     }
     return {
         name: 'creators',
+        subname: creatorType,
         translate: translateProp
     };
 };
 
 /* Function to add arbitrary creator function to the exports.general obj*/
-exports.extendGeneral = function(generalObj, creatorType){
+exports.extendGeneral = function(generalObj, creatorType, key){
+    if (!key){
+        throw new Error('a key is required');
+    }
     var extendedType = {};
-    Object.assign(extendedType, generalObj, {creator: 
exports.makeCreatorsTranslator(creatorType)});
+    Object.assign(extendedType, generalObj);
+    extendedType[key] = exports.makeCreatorsTranslator(creatorType);
     return extendedType;
 };
 
diff --git a/test/features/scraping/isbn.js b/test/features/scraping/isbn.js
index 037c778..e070782 100644
--- a/test/features/scraping/isbn.js
+++ b/test/features/scraping/isbn.js
@@ -92,8 +92,8 @@
                 assert.isInArray(res.body[0].source, 'WorldCat');
                 assert.deepEqual(res.body[0].author, [['Barrett, Daniel', 
'J.']], 'Unexpected value:' + res.body[0].author);
                 assert.deepEqual(res.body[0].publisher, 'O\'Reilly', 
'Unexpected value; expected O\'Reilly, got ' + res.body[0].publisher);
-                //assert.deepEqual(res.body[0].place, 'Sebastapool, Calif.', 
'Unexpected value; expected Sebastapool, Calif., got ' + res.body[0].place); // 
Not currently working with Worldcat Search API - not present in results
-                //assert.deepEqual(res.body[0].edition, '1st ed.', 'Unexpected 
value; expected 1st ed., got ' + res.body[0].edition); // Not currently working 
with Worldcat Search API - present in description tag
+                assert.deepEqual(res.body[0].place, 'Sebastapool, Calif.', 
'Unexpected value; expected Sebastapool, Calif., got ' + res.body[0].place); // 
Not currently working with Worldcat Search API - not present in results
+                assert.deepEqual(res.body[0].edition, '1st ed', 'Unexpected 
value; expected 1st ed, got ' + res.body[0].edition); // Not currently working 
with Worldcat Search API - present in description tag
                 assert.deepEqual(res.body[0].date, '2009', 'Unexpected value; 
expected 2009, got ' + res.body[0].date);
                 assert.isInArray(res.body[0].ISBN, '9780596519797');
                 assert.deepEqual(res.body[0].itemType, 'book', 'Wrong 
itemType; expected book, got ' + res.body[0].itemType);
@@ -108,7 +108,7 @@
                 assert.isInArray(res.body[0].source, 'WorldCat');
                 assert.deepEqual(res.body[0].contributor, 
[['Sheen,','Martin.'],['Cohen,','Bonni.'],['Thomson,','Richard.'],['DK 
Publishing,','Inc.']], 'Unexpected value:' + res.body[0].author); // only get 
this sometimes
                 assert.deepEqual(res.body[0].studio, 'DK Pub', 'Unexpected 
value; expected DK Pub, got ' + res.body[0].studio);
-                //assert.deepEqual(res.body[0].place, 'New York', 'Unexpected 
value; expected New York, got ' + res.body[0].place);
+                assert.deepEqual(res.body[0].place, 'New York', 'Unexpected 
value; expected New York, got ' + res.body[0].place);
                 assert.deepEqual(res.body[0].date, '2010, ©1996', 'Unexpected 
value; expected 2010, ©1996, got ' + res.body[0].date); // Not currently 
working with worldcat; date is returned to us as '2010, ©1996'
                 assert.isInArray(res.body[0].ISBN, '9780756662967');
                 assert.deepEqual(res.body[0].itemType, 'videoRecording', 
'Wrong itemType; expected videoRecording, got ' + res.body[0].itemType);
@@ -129,15 +129,16 @@
             });
         });
 
-        it('valid ISBN with funky author field', function() {
+        it('valid ISBN with author and contributor', function() {
             return server.query('9780439784542').then(function(res) {
                 assert.status(res, 200);
                 assert.checkCitation(res, 'Harry Potter and the Half-Blood 
Prince');
                 assert.deepEqual(!!res.body[0].oclc, true, 'Missing OCLC');
                 assert.isInArray(res.body[0].source, 'WorldCat');
-                assert.deepEqual(!!res.body[0].contributor, true, 'Missing 
contributor');
-                //assert.deepEqual(res.body[0].place, 'New York, NY', 
'Unexpected value; expected New York, NY, got ' + res.body[0].place);
-                //assert.deepEqual(res.body[0].edition, '1st American ed.', 
'Unexpected value; expected 1st ed., got ' + res.body[0].edition);
+                
assert.deepEqual(res.body[0].contributor,[['GrandPré,','Mary,']], 'Missing 
contributor');
+                assert.deepEqual(res.body[0].author, [['Rowling, J.', 'K.,']], 
'Missing author');
+                assert.deepEqual(res.body[0].place, 'New York, NY', 
'Unexpected value; expected New York, NY, got ' + res.body[0].place);
+                assert.deepEqual(res.body[0].edition, 'First American 
edition', 'Unexpected value; expected First American edition, got ' + 
res.body[0].edition);
                 assert.isInArray(res.body[0].ISBN, '9780439784542');
                 assert.deepEqual(res.body[0].itemType, 'book', 'Wrong 
itemType; expected book, got ' + res.body[0].itemType);
             });
diff --git a/test/features/unit/scraper.js b/test/features/unit/translator.js
similarity index 74%
rename from test/features/unit/scraper.js
rename to test/features/unit/translator.js
index 47796ec..6db3a78 100644
--- a/test/features/unit/scraper.js
+++ b/test/features/unit/translator.js
@@ -29,11 +29,13 @@
     {value:article, name:'article'}
 ];
 
+var app = {
+    logger: function(){}
+};
+var translator = new Translator(app);
+
 describe('translate function: ', function() {
-    var app = {
-        logger: function(){}
-    };
-    var translator = new Translator(app);
+
     var types = new CachedTypes();
     var citation;
     var result;
@@ -98,3 +100,44 @@
 
     });
 });
+
+describe('check specific results', function() {
+    it('sets right info from webpage for general metadata', function() {
+        return meta.parseAll(article).then(function(metadata){
+            var citation = translator.translate({itemType:'webpage'}, 
metadata.general, gen.webpage);
+            var expected = {
+              itemType: "webpage",
+              creators: [
+                {
+                  creatorType: "author",
+                  lastName: "Lvr",
+                  firstName: "Turtle"
+                }
+              ],
+              url: "http://example.com/turtles";,
+              abstractNote: "Exposition on the awesomeness of turtles",
+              title: "Turtles are AWESOME!!1 | Awesome Turtles Website",
+              language: "en"
+            }
+            assert.deepEqual(citation, expected);
+        });
+    });
+    it('sets right info from webpage for bepress metadata', function() {
+        return meta.parseAll(article).then(function(metadata){
+            var citation = translator.translate({itemType:'webpage'}, 
metadata.bePress, bp.webpage);
+            var expected = {
+              itemType: "webpage",
+              creators: [
+                {
+                  creatorType: "author",
+                  lastName: "Lvr",
+                  firstName: "Turtle"
+                }
+              ],
+              date: "2012",
+              title: "Turtles are AWESOME!!1"
+            }
+            assert.deepEqual(citation, expected);
+        });
+    });
+});
diff --git a/test/features/unit/translators/coins.js 
b/test/features/unit/translators/coins.js
index 280ff44..a5b112b 100644
--- a/test/features/unit/translators/coins.js
+++ b/test/features/unit/translators/coins.js
@@ -4,7 +4,7 @@
 var coins = require('../../../../lib/translators/coins.js');
 
 
-describe('coins unit', function() {
+describe('coins metadata', function() {
 
     var result;
     var expected;
diff --git a/test/features/unit/translators/general.js 
b/test/features/unit/translators/general.js
index 433d229..c0d8517 100644
--- a/test/features/unit/translators/general.js
+++ b/test/features/unit/translators/general.js
@@ -17,7 +17,7 @@
                 lastName: 'One'
             }]
         };
-        result = gen.generalWithAuthor.creator.translate({}, {author:['One']}, 
'author');
+        result = gen.generalWithAuthor.author.translate({}, {author:['One']}, 
'author');
         assert.deepEqual(result, expected);
     });
 
@@ -29,7 +29,7 @@
                 lastName: 'One'
             }]
         };
-        result = gen.generalWithAuthor.creator.translate({}, {author:'One'}, 
'author');
+        result = gen.generalWithAuthor.author.translate({}, {author:'One'}, 
'author');
         assert.deepEqual(result, expected);
     });
 
@@ -41,7 +41,7 @@
                 lastName: 'Two'
             }]
         };
-        result = gen.generalWithAuthor.creator.translate({}, {author:'One 
Two'}, 'author');
+        result = gen.generalWithAuthor.author.translate({}, {author:'One 
Two'}, 'author');
         assert.deepEqual(result, expected);
     });
 
@@ -53,7 +53,7 @@
                 lastName: 'Three'
             }]
         };
-        result = gen.generalWithAuthor.creator.translate({}, {author:'One Two 
Three'}, 'author');
+        result = gen.generalWithAuthor.author.translate({}, {author:'One Two 
Three'}, 'author');
         assert.deepEqual(result, expected);
     });
 
@@ -65,7 +65,7 @@
                 lastName: 'GrandPré.'
             }]
         };
-        result = gen.generalWithAuthor.creator.translate({}, {author:'J.K. 
Rowling ; illustrations by Mary GrandPré.'}, 'author');
+        result = gen.generalWithAuthor.author.translate({}, {author:'J.K. 
Rowling ; illustrations by Mary GrandPré.'}, 'author');
         assert.deepEqual(result, expected);
     });
 });
diff --git a/test/features/unit/translators/util.js 
b/test/features/unit/translators/util.js
index aab04ab..a9c0106 100644
--- a/test/features/unit/translators/util.js
+++ b/test/features/unit/translators/util.js
@@ -19,6 +19,8 @@
     var result;
     var expected;
     var input;
+    var author;
+    var contributor;
 
     describe('makeTranslator function: ', function() {
 
@@ -105,4 +107,56 @@
             assert.deepEqual(result, expected);
         });
     });
+
+    describe('makeCreatorsTranslator function: ', function() {
+
+        it('Correctly adds author', function() {
+            input = ['Daniel J. Barrett'];
+            expected = {
+                creators: [{
+                    'creatorType':'author',
+                    'firstName': 'Daniel J.',
+                    'lastName': 'Barrett'
+                }]
+            };
+            result = ut.makeCreatorsTranslator('author').translate({}, 
{author:input}, 'author');
+            assert.deepEqual(result, expected);
+        });
+
+        it('Doesn not like format Last name, first name', function() {
+            input = ['Barrett, Daniel J.'];
+            expected = {
+                creators: [{
+                    'creatorType':'author',
+                    'firstName': 'Barrett, Daniel',
+                    'lastName': 'J.'
+                }]
+            };
+            result = ut.makeCreatorsTranslator('author').translate({}, 
{author:input}, 'author');
+            assert.deepEqual(result, expected);
+        });
+
+        it('Correctly adds two different contributor types', function() {
+            author = 'J.K. Rowling';
+            contributor = 'Mary GrandPré'
+            expected = {
+                creators: [{
+                    'creatorType':'author',
+                    'firstName': 'J.K.',
+                    'lastName': 'Rowling'
+                },
+                {
+                    'creatorType':'contributor',
+                    'firstName': 'Mary',
+                    'lastName': 'GrandPré'
+                }]
+            };
+            result = ut.makeCreatorsTranslator('author').translate({}, 
{author:author}, 'author');
+            result = 
ut.makeCreatorsTranslator('contributor').translate(result, 
{contributor:contributor}, 'contributor');
+            assert.deepEqual(result, expected);
+        });
+
+
+
+    });
 });

-- 
To view, visit https://gerrit.wikimedia.org/r/355097
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I58489d2959306b620f9bfa4a5bfb2a81ea7cb4a4
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/services/citoid
Gerrit-Branch: master
Gerrit-Owner: Mvolz <mv...@wikimedia.org>
Gerrit-Reviewer: Mobrovac <mobro...@wikimedia.org>
Gerrit-Reviewer: Mvolz <mv...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to