Add American British Translator
This commit is contained in:
parent
f1ce58405c
commit
0097d202b8
23 changed files with 13354 additions and 0 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"presets": ["@babel/preset-env"]
|
||||||
|
}
|
2
7-quality-assurance/5-american-british-translator/.gitattributes
vendored
Normal file
2
7-quality-assurance/5-american-british-translator/.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Tell Linguist to exclude HTML files to help Replit language detection.
|
||||||
|
*.html linguist-vendored
|
4
7-quality-assurance/5-american-british-translator/.gitignore
vendored
Normal file
4
7-quality-assurance/5-american-british-translator/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.vscode/*
|
||||||
|
.env
|
||||||
|
.glitch-assets
|
||||||
|
node_modules/
|
|
@ -0,0 +1 @@
|
||||||
|
.replit
|
10
7-quality-assurance/5-american-british-translator/.replit
Normal file
10
7-quality-assurance/5-american-british-translator/.replit
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
run = "npm start"
|
||||||
|
entrypoint = "server.js"
|
||||||
|
|
||||||
|
[packager]
|
||||||
|
language = "nodejs"
|
||||||
|
|
||||||
|
[packager.features]
|
||||||
|
packageSearch = true
|
||||||
|
guessImports = true
|
||||||
|
enabledForHosting = false
|
|
@ -0,0 +1,3 @@
|
||||||
|
# American British Translator
|
||||||
|
|
||||||
|
This is the boilerplate for the American British Translator project. Instructions for building your project can be found at https://www.freecodecamp.org/learn/quality-assurance/quality-assurance-projects/american-british-translator
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function objParser(str, init) {
|
||||||
|
// finds objects, arrays, strings, and function arguments
|
||||||
|
// between parens, because they may contain ','
|
||||||
|
let openSym = ['[', '{', '"', "'", '('];
|
||||||
|
let closeSym = [']', '}', '"', "'", ')'];
|
||||||
|
let type;
|
||||||
|
let i;
|
||||||
|
for(i = (init || 0); i < str.length; i++ ) {
|
||||||
|
type = openSym.indexOf(str[i]);
|
||||||
|
if( type !== -1) break;
|
||||||
|
}
|
||||||
|
if (type === -1) return null;
|
||||||
|
let open = openSym[type];
|
||||||
|
let close = closeSym[type];
|
||||||
|
let count = 1;
|
||||||
|
let k;
|
||||||
|
for(k = i+1; k < str.length; k++) {
|
||||||
|
if(open === '"' || open === "'") {
|
||||||
|
if(str[k] === close) count--;
|
||||||
|
if(str[k] === '\\') k++;
|
||||||
|
} else {
|
||||||
|
if(str[k] === open) count++;
|
||||||
|
if(str[k] === close) count--;
|
||||||
|
}
|
||||||
|
if(count === 0) break;
|
||||||
|
}
|
||||||
|
if(count !== 0) return null;
|
||||||
|
let obj = str.slice(i, k+1);
|
||||||
|
return {
|
||||||
|
start : i,
|
||||||
|
end: k,
|
||||||
|
obj: obj
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function replacer(str) {
|
||||||
|
// replace objects with a symbol ( __#n)
|
||||||
|
let obj;
|
||||||
|
let cnt = 0;
|
||||||
|
let data = [];
|
||||||
|
while(obj = objParser(str)) {
|
||||||
|
data[cnt] = obj.obj;
|
||||||
|
str = str.substring(0, obj.start) + '__#' + cnt++ + str.substring(obj.end+1)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
str : str,
|
||||||
|
dictionary : data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitter(str) {
|
||||||
|
// split on commas, then restore the objects
|
||||||
|
let strObj = replacer(str);
|
||||||
|
let args = strObj.str.split(',');
|
||||||
|
args = args.map(function(a){
|
||||||
|
let m = a.match(/__#(\d+)/);
|
||||||
|
while (m) {
|
||||||
|
a = a.replace(/__#(\d+)/, strObj.dictionary[m[1]]);
|
||||||
|
m = a.match(/__#(\d+)/);
|
||||||
|
}
|
||||||
|
return a.trim();
|
||||||
|
})
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertionAnalyser(body) {
|
||||||
|
|
||||||
|
// already filtered in the test runner
|
||||||
|
// // remove comments
|
||||||
|
// body = body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||||
|
// // get test function body
|
||||||
|
// body = body.match(/\{\s*([\s\S]*)\}\s*$/)[1];
|
||||||
|
|
||||||
|
if(!body) return "invalid assertion";
|
||||||
|
// replace assertions bodies, so that they cannot
|
||||||
|
// contain the word 'assertion'
|
||||||
|
|
||||||
|
let cleanedBody = body.match(/(?:browser\s*\.\s*)?assert\s*\.\s*\w*\([\s\S]*\)/)
|
||||||
|
if(cleanedBody && Array.isArray(cleanedBody)) {
|
||||||
|
body = cleanedBody[0];
|
||||||
|
} else {
|
||||||
|
// No assertions present
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let s = replacer(body);
|
||||||
|
// split on 'assertion'
|
||||||
|
let splittedAssertions = s.str.split('assert');
|
||||||
|
let assertions = splittedAssertions.slice(1);
|
||||||
|
// match the METHODS
|
||||||
|
|
||||||
|
let assertionBodies = [];
|
||||||
|
let methods = assertions.map(function(a, i){
|
||||||
|
let m = a.match(/^\s*\.\s*(\w+)__#(\d+)/);
|
||||||
|
assertionBodies.push(parseInt(m[2]));
|
||||||
|
let pre = splittedAssertions[i].match(/browser\s*\.\s*/) ? 'browser.' : '';
|
||||||
|
return pre + m[1];
|
||||||
|
});
|
||||||
|
if(methods.some(function(m){ return !m })) return "invalid assertion";
|
||||||
|
// remove parens from the assertions bodies
|
||||||
|
let bodies = assertionBodies.map(function(b){
|
||||||
|
return s.dictionary[b].slice(1,-1).trim();
|
||||||
|
});
|
||||||
|
assertions = methods.map(function(m, i) {
|
||||||
|
return {
|
||||||
|
method: m,
|
||||||
|
args: splitter(bodies[i]) //replace objects, split on ',' ,then restore objects
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return assertions;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = assertionAnalyser;
|
|
@ -0,0 +1,185 @@
|
||||||
|
module.exports = {
|
||||||
|
"acclimate": "acclimatise",
|
||||||
|
"acetaminophen": "paracetamol",
|
||||||
|
"baby carriage": "pram",
|
||||||
|
"backhoe": "digger",
|
||||||
|
"band-aid": "Elastoplast",
|
||||||
|
"bangs": "fringe",
|
||||||
|
"barrette": "hair slide",
|
||||||
|
"baseboard": "skirting board",
|
||||||
|
"bedroom community": "dormitory town",
|
||||||
|
"blacktop": "tarmac",
|
||||||
|
"bleachers": "stands",
|
||||||
|
"blinders": "blinkers",
|
||||||
|
"blood sausage": "black pudding",
|
||||||
|
"boardwalk": "promenade",
|
||||||
|
"bobby pin": "Kirby grip",
|
||||||
|
"booger": "bogey",
|
||||||
|
"bookmobile": "mobile library",
|
||||||
|
"breadbox": "bread bin",
|
||||||
|
"bullhorn": "loudhailer",
|
||||||
|
"burglarize": "burgle",
|
||||||
|
"burlap": "hessian",
|
||||||
|
"canadian bacon": "back bacon",
|
||||||
|
"candy apple": "toffee apple",
|
||||||
|
"candied apple": "toffee apple",
|
||||||
|
"careen": "career",
|
||||||
|
"catsup": "ketchup",
|
||||||
|
"cell phone": "mobile",
|
||||||
|
"cellphone": "mobile",
|
||||||
|
"certified mail": "recorded delivery",
|
||||||
|
"chapstick": "lip balm",
|
||||||
|
"charge account": "credit account",
|
||||||
|
"checkers": "draughts",
|
||||||
|
"checking account": "current account",
|
||||||
|
"cilantro": "coriander",
|
||||||
|
"cleats": "football boots",
|
||||||
|
"condo": "flat",
|
||||||
|
"costume party": "fancy-dress party",
|
||||||
|
"cotton candy": "candy floss",
|
||||||
|
"counterclockwise": "anti-clockwise",
|
||||||
|
"coveralls": "overalls",
|
||||||
|
"diaper": "nappy",
|
||||||
|
"discombobulated": "discomposed",
|
||||||
|
"dish towel": "tea towel",
|
||||||
|
"dishrag": "dishcloth",
|
||||||
|
"dish soap": "washing-up liquid",
|
||||||
|
"dishwashing liquid": "washing-up liquid",
|
||||||
|
"district attorney": "Crown Prosecutor",
|
||||||
|
"divided highway": "dual carriageway",
|
||||||
|
"doohickey": "wotsit",
|
||||||
|
"downspout": "drainpipe",
|
||||||
|
"drape": "curtain",
|
||||||
|
"drapes": "curtain",
|
||||||
|
"driver license": "driving licence",
|
||||||
|
"driver's license": "driving licence",
|
||||||
|
"drugstore": "chemist",
|
||||||
|
"drywall": "plasterboard",
|
||||||
|
"dumpster": "skip",
|
||||||
|
"eggplant": "aubergine",
|
||||||
|
"emergency brake": "handbrake",
|
||||||
|
"eminent domain": "compulsory purchase",
|
||||||
|
"envision": "to envisage",
|
||||||
|
"eraser": "rubber",
|
||||||
|
"expressway": "motorway",
|
||||||
|
"fanny pack": "bum bag",
|
||||||
|
"faucet": "tap",
|
||||||
|
"flashlight": "torch",
|
||||||
|
"flatware": "cutlery",
|
||||||
|
"freeway": "motorway",
|
||||||
|
"fries": "chips",
|
||||||
|
"french fries": "chips",
|
||||||
|
"french press": "cafetière",
|
||||||
|
"freshman": "fresher",
|
||||||
|
"front desk": "reception",
|
||||||
|
"frosting": "icing",
|
||||||
|
"garbage can": "dustbin",
|
||||||
|
"gasoline": "petrol",
|
||||||
|
"general delivery": "poste restante",
|
||||||
|
"grifter": "con man",
|
||||||
|
"ground beef": "mince",
|
||||||
|
"grunt": "squaddie",
|
||||||
|
"hard candy": "boiled sweets",
|
||||||
|
"heavy cream": "double cream",
|
||||||
|
"jackhammer": "pneumatic drill",
|
||||||
|
"jell-o": "jelly",
|
||||||
|
"ladybug": "ladybird",
|
||||||
|
"laundromat": "laundrette",
|
||||||
|
"learner's permit": "provisional driving licence",
|
||||||
|
"license plate": "number plate",
|
||||||
|
"license tag": "number plate",
|
||||||
|
"mail carrier": "postal worker",
|
||||||
|
"mailman": "postman",
|
||||||
|
"main street": "high street",
|
||||||
|
"mama": "mam",
|
||||||
|
"mamma": "mam",
|
||||||
|
"momma": "mam",
|
||||||
|
"mom": "mum",
|
||||||
|
"mass transit": "public transport",
|
||||||
|
"math": "maths",
|
||||||
|
"mohawk": "mohican",
|
||||||
|
"mortician": "undertaker",
|
||||||
|
"narc": "grass",
|
||||||
|
"nightcrawler": "earthworm",
|
||||||
|
"nightstick": "truncheon",
|
||||||
|
"nix": "cancel",
|
||||||
|
"obligated": "obliged",
|
||||||
|
"off-the-rack": "off-the-peg",
|
||||||
|
"oftentimes": "often",
|
||||||
|
"overpass": "flyover",
|
||||||
|
"pantyhose": "tights",
|
||||||
|
"paper route": "paper round",
|
||||||
|
"parking garage": "car park",
|
||||||
|
"parking lot": "car park",
|
||||||
|
"penitentiary": "prison",
|
||||||
|
"plastic wrap": "cling-film",
|
||||||
|
"play hooky": "bunk off",
|
||||||
|
"plexiglas": "Perspex",
|
||||||
|
"popsicle": "ice lolly",
|
||||||
|
"powdered sugar": "icing sugar",
|
||||||
|
"pre-authorized payment": "direct debit",
|
||||||
|
"pre-authorized withdrawal": "direct debit",
|
||||||
|
"public holiday": "bank holiday",
|
||||||
|
"rappel": "abseil",
|
||||||
|
"realtor": "estate agent",
|
||||||
|
"rif": "redundancy",
|
||||||
|
"rif'd": "made redundant",
|
||||||
|
"rowhouse": "terraced house",
|
||||||
|
"rube goldberg device": "Heath Robinson device",
|
||||||
|
"rube goldberg machine": "Heath Robinson device",
|
||||||
|
"rugola": "rocket",
|
||||||
|
"rutabaga": "swede",
|
||||||
|
"rv": "caravan",
|
||||||
|
"rv park": "caravan site",
|
||||||
|
"saran wrap": "cling film",
|
||||||
|
"scads": "great amounts",
|
||||||
|
"scallion": "spring onion",
|
||||||
|
"scalper": "ticket tout",
|
||||||
|
"scotch tape": "Sellotape",
|
||||||
|
"scuttlebutt": "rumour",
|
||||||
|
"sedan automobile": "saloon",
|
||||||
|
"self-rising flour": "self-raising flour",
|
||||||
|
"shredded cheese": "grated cheese",
|
||||||
|
"sidewalk": "pavement",
|
||||||
|
"skim milk": "skimmed milk",
|
||||||
|
"sneaker": "trainer",
|
||||||
|
"sneakers": "trainers",
|
||||||
|
"snuck": "sneaked",
|
||||||
|
"soccer": "football",
|
||||||
|
"soda pop": "soft drink",
|
||||||
|
"specialty": "speciality",
|
||||||
|
"spelunking": "caving",
|
||||||
|
"spring break": "Easter holiday",
|
||||||
|
"station wagon": "estate car",
|
||||||
|
"steam shovel": "digger",
|
||||||
|
"stickshift": "gear stick",
|
||||||
|
"stool pigeon": "grass",
|
||||||
|
"stoolie": "grass",
|
||||||
|
"stop light": "traffic light",
|
||||||
|
"streetcar": "tram",
|
||||||
|
"stroller": "pram",
|
||||||
|
"swap meet": "car boot sale",
|
||||||
|
"sweatpants": "track bottoms",
|
||||||
|
"tailpipe": "exhaust pipe",
|
||||||
|
"takeout": "takeaway",
|
||||||
|
"teleprompter": "compare autocue",
|
||||||
|
"thumbtack": "drawing pin",
|
||||||
|
"track meet": "athletics meeting",
|
||||||
|
"trash": "rubbish",
|
||||||
|
"trashcan": "bin",
|
||||||
|
"travel trailer": "caravan",
|
||||||
|
"turn signal": "turn-indicators",
|
||||||
|
"tylenol": "paracetamol",
|
||||||
|
"upscale": "upmarket",
|
||||||
|
"vacationer": "holidaymaker",
|
||||||
|
"vacay": "hols",
|
||||||
|
"variety meats": "offal",
|
||||||
|
"varmint": "vermin",
|
||||||
|
"varmit": "vermin",
|
||||||
|
"wastebasket": "wastepaper basket",
|
||||||
|
"windshield": "windscreen",
|
||||||
|
"yellow light": "amber",
|
||||||
|
"zip code": "postcode",
|
||||||
|
"zipper": "zip",
|
||||||
|
"zucchini": "courgette"
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = {
|
||||||
|
'mr.': 'mr',
|
||||||
|
'mrs.': 'mrs',
|
||||||
|
'ms.': 'ms',
|
||||||
|
'mx.': 'mx',
|
||||||
|
'dr.': 'dr',
|
||||||
|
'prof.': 'prof'
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
module.exports = {
|
||||||
|
abseil: "rappel",
|
||||||
|
accountancy: "accounting",
|
||||||
|
advert: "advertisement",
|
||||||
|
"agony column": "advice column",
|
||||||
|
answerphone: "answering machine",
|
||||||
|
"anti-clockwise": "counterclockwise",
|
||||||
|
"approved school": "juvie",
|
||||||
|
artic: "semi",
|
||||||
|
"athletics meeting": "track meet",
|
||||||
|
aubergine: "eggplant",
|
||||||
|
autocue: "teleprompter",
|
||||||
|
"bank holiday": "public holiday",
|
||||||
|
barmy: "balmy",
|
||||||
|
biccie: "cookie",
|
||||||
|
bicky: "cookie",
|
||||||
|
bikky: "cookie",
|
||||||
|
biro: "ballpoint pen",
|
||||||
|
"bits and bobs": "odds and ends",
|
||||||
|
"black pudding": "blood sausage",
|
||||||
|
bloke: "guy",
|
||||||
|
blower: "telephone",
|
||||||
|
boffin: "an expert",
|
||||||
|
"bog roll": "roll of toilet paper",
|
||||||
|
"bog-standard": "garden-variety",
|
||||||
|
"boiled sweet": "hard candy",
|
||||||
|
"bone-idle": "lazy",
|
||||||
|
brekkie: "breakfast",
|
||||||
|
brekky: "breakfast",
|
||||||
|
breve: "double whole note",
|
||||||
|
brolly: "umbrella",
|
||||||
|
"building society": "savings and loan association",
|
||||||
|
"bum bag": "fanny pack",
|
||||||
|
bunce: "a windfall",
|
||||||
|
"bureau de change": "currency exchange",
|
||||||
|
burgle: "burglarize",
|
||||||
|
"by-election": "special election",
|
||||||
|
cafetière: "French press",
|
||||||
|
cafetiere: "French press",
|
||||||
|
caff: "café",
|
||||||
|
cagoule: "windbreaker",
|
||||||
|
candidature: "candidacy",
|
||||||
|
"candy floss": "cotton candy",
|
||||||
|
"car boot sale": "swap meet",
|
||||||
|
"car boot": "trunk",
|
||||||
|
"car hire": "car rental",
|
||||||
|
"car park": "parking lot",
|
||||||
|
carer: "caregiver",
|
||||||
|
carriageway: "lane",
|
||||||
|
"cash machine": "ATM",
|
||||||
|
cashpoint: "ATM",
|
||||||
|
"central reservation": "median strip",
|
||||||
|
chancer: "opportunist",
|
||||||
|
"chat up": "flirt",
|
||||||
|
"chatted up": "flirted",
|
||||||
|
cheeky: "impertinent",
|
||||||
|
"child-minder": "babysitter",
|
||||||
|
chinwag: "chat",
|
||||||
|
chippy: "fish-and-chip shop",
|
||||||
|
"chip shop": "fish-and-chip shop",
|
||||||
|
chuffed: "pleased",
|
||||||
|
chunder: "vomit",
|
||||||
|
"clapped out": "clapped out",
|
||||||
|
cleg: "horse fly",
|
||||||
|
clingfilm: "plastic wrap",
|
||||||
|
"cling-film": "plastic wrap",
|
||||||
|
"cling film": "plastic wrap",
|
||||||
|
cobblers: "shoe repairers",
|
||||||
|
conservatoire: "conservatory",
|
||||||
|
"cotton bud": "cotton swab",
|
||||||
|
"cotton wool": "cotton ball",
|
||||||
|
counterfoil: "stub",
|
||||||
|
counterpane: "bedspread",
|
||||||
|
courgette: "zucchini",
|
||||||
|
crisps: "potato chips",
|
||||||
|
cuppa: "cup of tea",
|
||||||
|
"current account": "checking account",
|
||||||
|
daft: "silly",
|
||||||
|
dogsbody: "grunt",
|
||||||
|
dosh: "dough",
|
||||||
|
"double first": "undergraduate degree",
|
||||||
|
draper: "dry goods",
|
||||||
|
draughts: "checkers",
|
||||||
|
"drawing pin": "thumbtack",
|
||||||
|
"drink-driving": "drunk driving",
|
||||||
|
"driving licence": "driver's license",
|
||||||
|
"dual carriageway": "divided highway",
|
||||||
|
dustbin: "trash can",
|
||||||
|
dustman: "garbage man",
|
||||||
|
"dustbin man": "garbage man",
|
||||||
|
dustcart: "garbage truck",
|
||||||
|
earthed: "grounded",
|
||||||
|
elastoplast: "bandage",
|
||||||
|
"electric fire": "space heater",
|
||||||
|
"engaged tone": "busy signal",
|
||||||
|
"estate agent": "real estate agent",
|
||||||
|
"estate car": "station wagon",
|
||||||
|
"extension lead": "extension cord",
|
||||||
|
"fancy a": "would you like a",
|
||||||
|
"fairy cake": "cupcake",
|
||||||
|
"fairy lights": "Christmas lights",
|
||||||
|
"fire brigade": "fire department",
|
||||||
|
"flight lieutenant": "captain",
|
||||||
|
flypast: "flyby",
|
||||||
|
footie: "soccer",
|
||||||
|
freephone: "toll-free number",
|
||||||
|
funfair: "carnival",
|
||||||
|
gaol: "jail",
|
||||||
|
gherkin: "pickle",
|
||||||
|
"group captain": "colonel",
|
||||||
|
"guard's van": "caboose",
|
||||||
|
guv: "governor",
|
||||||
|
"heath robinson device": "rube goldberg device",
|
||||||
|
"high street": "main street",
|
||||||
|
"hire purchase": "installment plan",
|
||||||
|
"hold-all": "duffel bag",
|
||||||
|
holidaymaker: "vacationer",
|
||||||
|
hols: "holidays",
|
||||||
|
"hot up": "heating up",
|
||||||
|
"ice lolly": "popsicle",
|
||||||
|
"identity parade": "police lineup",
|
||||||
|
"inverted commas": "quotation marks",
|
||||||
|
invigilator: "proctor",
|
||||||
|
ironmongery: "hardware store",
|
||||||
|
"jacket potato": "baked potato",
|
||||||
|
jemmy: "jimmy",
|
||||||
|
jerrybuilt: "jerry-rigged",
|
||||||
|
"jerry-built": "jerry-rigged",
|
||||||
|
"jumble sale": "rummage sale",
|
||||||
|
"jump leads": "jumper cables",
|
||||||
|
"kirby grip": "bobby pin",
|
||||||
|
"kitchen roll": "paper towels",
|
||||||
|
"knacker's yard": "junkyard",
|
||||||
|
ladybird: "ladybug",
|
||||||
|
launderette: "laundromat",
|
||||||
|
lav: "toilet",
|
||||||
|
learnt: "learned",
|
||||||
|
loo: "bathroom",
|
||||||
|
lorry: "truck",
|
||||||
|
loudhailer: "megaphone",
|
||||||
|
maths: "math",
|
||||||
|
"mole grips": "vise-grips",
|
||||||
|
motorway: "freeway",
|
||||||
|
muppet: "an incompetent or foolish person",
|
||||||
|
nark: "narc",
|
||||||
|
nappy: "daiper",
|
||||||
|
"nosy parker": "nosy",
|
||||||
|
"nosey parker": "nosy",
|
||||||
|
"number plate": "license plate",
|
||||||
|
oap: "senior citizen",
|
||||||
|
"off-licence": "liquor store",
|
||||||
|
offie: "liquor store",
|
||||||
|
"off-the-peg": "off-the-rack",
|
||||||
|
"oughtn't": "shouldn't",
|
||||||
|
overleaf: "reverse",
|
||||||
|
owt: "anything",
|
||||||
|
pants: "underwear",
|
||||||
|
"panda car": "police car",
|
||||||
|
"paper round": "paper route",
|
||||||
|
paracetamol: "Tylenol",
|
||||||
|
pernickety: "persnickety",
|
||||||
|
petrol: "gasoline",
|
||||||
|
petrolhead: "gearhead",
|
||||||
|
"phone box": "payphone",
|
||||||
|
"pillar box": "mailbox",
|
||||||
|
"pillar-box red": "fire engine red",
|
||||||
|
plasterboard: "drywall",
|
||||||
|
plectrum: "guitar pick",
|
||||||
|
"postal order": "money order",
|
||||||
|
"poste restante": "general delivery",
|
||||||
|
postie: "postman",
|
||||||
|
"pound shop": "dollar store",
|
||||||
|
pram: "stroller",
|
||||||
|
perambulator: "stroller",
|
||||||
|
prang: "fender bender",
|
||||||
|
prat: "idiot",
|
||||||
|
"press-up": "push-up",
|
||||||
|
"press-ups": "push-ups",
|
||||||
|
"pritt-stick": "glue stick",
|
||||||
|
"provisional licence": "learner's permit",
|
||||||
|
"provisional driving licence": "learner's permit",
|
||||||
|
pub: "bar",
|
||||||
|
publican: "landlord",
|
||||||
|
"punch-up": "a fistfight",
|
||||||
|
pushchair: "stroller",
|
||||||
|
"quieten down": "quiet down",
|
||||||
|
rashers: "bacon",
|
||||||
|
recce: "recon",
|
||||||
|
"reel of cotton": "spool of thread",
|
||||||
|
sarky: "snarky",
|
||||||
|
sarnie: "sandwich",
|
||||||
|
sarny: "sandwich",
|
||||||
|
sannie: "sandwich",
|
||||||
|
"sat nav": "GPS",
|
||||||
|
"self-raising flour": "self-rising flour",
|
||||||
|
"selling-out shop": "liquor store",
|
||||||
|
sellotape: "Scotch tape",
|
||||||
|
"shan't": "won't",
|
||||||
|
"shopping trolley": "shopping cart",
|
||||||
|
skint: "broke",
|
||||||
|
"skirting board": "baseboard",
|
||||||
|
slaphead: "bald man",
|
||||||
|
"sleeping partner": "silent partner",
|
||||||
|
"sleeping policeman": "speed bump",
|
||||||
|
slippy: "slippery",
|
||||||
|
slowcoach: "slowpoke",
|
||||||
|
"smart dress": "formal attire",
|
||||||
|
snog: "kiss",
|
||||||
|
spawny: "lucky",
|
||||||
|
spiffing: "spiffy",
|
||||||
|
"spot of tea": "cup of tea",
|
||||||
|
squaddie: "grunt",
|
||||||
|
squidgy: "squishy",
|
||||||
|
stockist: "dealer",
|
||||||
|
"sun cream": "sunscreen",
|
||||||
|
"suspender belt": "garter belt",
|
||||||
|
"swimming costume": "swimsuit",
|
||||||
|
ta: "thank you",
|
||||||
|
takeaway: "takeout",
|
||||||
|
tannoy: "public address system",
|
||||||
|
"tea towel": "dish towel",
|
||||||
|
"telephone kiosk": "phone booth",
|
||||||
|
telly: "television",
|
||||||
|
"ticket tout": "scalper",
|
||||||
|
"tipp-ex": "Wite-Out",
|
||||||
|
"tipping down": "raining hard",
|
||||||
|
trainers: "sneakers",
|
||||||
|
"transport cafe": "truckstop",
|
||||||
|
trousers: "pants",
|
||||||
|
truncheon: "nightstick",
|
||||||
|
"turf accountant": "bookie",
|
||||||
|
"turn-indicator": "turn signal",
|
||||||
|
"turn-ups": "cuffs",
|
||||||
|
twee: "cutesy",
|
||||||
|
uni: "college",
|
||||||
|
upmarket: "upscale",
|
||||||
|
veg: "vegetables",
|
||||||
|
"wage packet": "paycheck",
|
||||||
|
"washing-up liquid": "dish soap",
|
||||||
|
wc: "bathroom",
|
||||||
|
windscreen: "windshield",
|
||||||
|
"wing mirrors": "side mirrors",
|
||||||
|
"y-fronts": "briefs",
|
||||||
|
"zebra crossing": "crosswalk",
|
||||||
|
};
|
|
@ -0,0 +1,107 @@
|
||||||
|
const americanOnly = require("./american-only.js");
|
||||||
|
const americanToBritishSpelling = require("./american-to-british-spelling.js");
|
||||||
|
const americanToBritishTitles = require("./american-to-british-titles.js");
|
||||||
|
const britishOnly = require("./british-only.js");
|
||||||
|
|
||||||
|
class Translator {
|
||||||
|
translate(text, locale, highlight) {
|
||||||
|
let translation = text;
|
||||||
|
if (locale === "british-to-american") {
|
||||||
|
translation = this.translateOneWay(britishOnly, translation, highlight);
|
||||||
|
translation = this.translateTitles("british", translation, highlight);
|
||||||
|
translation = this.translateSpelling("british", translation, highlight);
|
||||||
|
translation = this.translateTime("british", translation, highlight);
|
||||||
|
} else {
|
||||||
|
translation = this.translateOneWay(americanOnly, translation, highlight);
|
||||||
|
translation = this.translateTitles("american", translation, highlight);
|
||||||
|
translation = this.translateSpelling("american", translation, highlight);
|
||||||
|
translation = this.translateTime("american", translation, highlight);
|
||||||
|
}
|
||||||
|
if (translation === text) {
|
||||||
|
return "Everything looks good to me!";
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
translateOneWay(locale, translation, highlight) {
|
||||||
|
for (let i in locale) {
|
||||||
|
let replacement = locale[i];
|
||||||
|
if (highlight === true) {
|
||||||
|
replacement = '<span class="highlight">' + replacement + "</span>";
|
||||||
|
}
|
||||||
|
let regex = new RegExp(`(?<=[^a-zA-Z-]|^)${i}(?=[^a-zA-Z])`, "ig");
|
||||||
|
translation = translation.replace(regex, replacement);
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
translateTitles(from, translation, highlight) {
|
||||||
|
for (let i in americanToBritishTitles) {
|
||||||
|
let replacement, word;
|
||||||
|
if (from === "american") {
|
||||||
|
word = i;
|
||||||
|
replacement = americanToBritishTitles[i];
|
||||||
|
} else {
|
||||||
|
word = americanToBritishTitles[i];
|
||||||
|
replacement = i;
|
||||||
|
}
|
||||||
|
if (highlight === true) {
|
||||||
|
replacement =
|
||||||
|
'<span class="highlight">' +
|
||||||
|
replacement.charAt(0).toUpperCase() +
|
||||||
|
replacement.slice(1) +
|
||||||
|
"</span>";
|
||||||
|
} else {
|
||||||
|
replacement =
|
||||||
|
replacement.charAt(0).toUpperCase() + replacement.slice(1);
|
||||||
|
}
|
||||||
|
let regex = new RegExp(`(?<=[^a-zA-Z]|^)${word}(?=[^a-zA-Z])`, "ig");
|
||||||
|
translation = translation.replace(regex, replacement);
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
translateSpelling(from, translation, highlight) {
|
||||||
|
for (let i in americanToBritishSpelling) {
|
||||||
|
let replacement, word;
|
||||||
|
if (from === "american") {
|
||||||
|
word = i;
|
||||||
|
replacement = americanToBritishSpelling[i];
|
||||||
|
} else {
|
||||||
|
word = americanToBritishSpelling[i];
|
||||||
|
replacement = i;
|
||||||
|
}
|
||||||
|
if (highlight === true) {
|
||||||
|
replacement = '<span class="highlight">' + replacement + "</span>";
|
||||||
|
}
|
||||||
|
let regex = new RegExp(`(?<=[^a-zA-Z]|^)${word}(?=[^a-zA-Z])`, "ig");
|
||||||
|
translation = translation.replace(regex, replacement);
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
translateTime(from, translation, highlight) {
|
||||||
|
let char;
|
||||||
|
let replacement;
|
||||||
|
if (from === "british") {
|
||||||
|
char = ".";
|
||||||
|
replacement = ":";
|
||||||
|
} else {
|
||||||
|
char = ":";
|
||||||
|
replacement = ".";
|
||||||
|
}
|
||||||
|
let regex = new RegExp(`\\d\\d?[${char}]\\d{2}`, "gi");
|
||||||
|
let matches = translation.match(regex);
|
||||||
|
for (let i in matches) {
|
||||||
|
let tempRegex = new RegExp(`(?<=\\d\\d?)[${char}](?=\\d{2})`, "gi");
|
||||||
|
let temp = matches[i].replace(tempRegex, replacement);
|
||||||
|
if (highlight === true) {
|
||||||
|
temp = '<span class="highlight">' + temp + "</span>";
|
||||||
|
}
|
||||||
|
translation = translation.replace(matches[i], temp);
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Translator;
|
10142
7-quality-assurance/5-american-british-translator/package-lock.json
generated
Normal file
10142
7-quality-assurance/5-american-british-translator/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "american-british-english-translator",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"description": "Quality Assurance 5: American / British English Translator",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "nodemon server.js",
|
||||||
|
"test": "mocha --timeout 5000 --require @babel/register --recursive --exit --ui tdd tests/"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.11.6",
|
||||||
|
"@babel/preset-env": "^7.11.5",
|
||||||
|
"@babel/register": "^7.11.5",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"chai-http": "^4.3.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"jsdom": "^16.4.0",
|
||||||
|
"mocha": "^8.1.3",
|
||||||
|
"nodemon": "^2.0.4"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
const translateHandler = async () => {
|
||||||
|
const textArea = document.getElementById("text-input");
|
||||||
|
const localeArea = document.getElementById("locale-select");
|
||||||
|
const errorArea = document.getElementById("error-msg");
|
||||||
|
const translatedArea = document.getElementById("translated-sentence");
|
||||||
|
|
||||||
|
const stuff = {"text": textArea.value, "locale": localeArea.value};
|
||||||
|
errorArea.innerText = "";
|
||||||
|
translatedArea.innerText = "";
|
||||||
|
|
||||||
|
const data = await fetch("/api/translate", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(stuff)
|
||||||
|
});
|
||||||
|
|
||||||
|
const parsed = await data.json();
|
||||||
|
if (parsed.error) {
|
||||||
|
errorArea.innerText = JSON.stringify(parsed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
translatedArea.innerHTML = parsed.translation;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById("translate-btn").addEventListener("click", translateHandler)
|
|
@ -0,0 +1,81 @@
|
||||||
|
code {
|
||||||
|
background: #d0d0d5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
max-width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user-stories {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output-container,
|
||||||
|
#solution-container,
|
||||||
|
#text-input,
|
||||||
|
#locale-select,
|
||||||
|
input[type="button"] {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output-container {
|
||||||
|
width: 80%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#solution-container {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#solution-container {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#translated-sentence {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-msg {
|
||||||
|
font-weight: normal;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
#text-input {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 800px) {
|
||||||
|
.container {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output-container {
|
||||||
|
flex-direction: row;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#solution-container {
|
||||||
|
width: 75%;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Translator = require("../components/translator.js");
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
const translator = new Translator();
|
||||||
|
|
||||||
|
app.route("/api/translate").post((req, res) => {
|
||||||
|
if (req.body.locale === undefined || req.body.text === undefined) {
|
||||||
|
return res.json({ error: "Required field(s) missing" });
|
||||||
|
}
|
||||||
|
if (!req.body.text) {
|
||||||
|
return res.json({ error: "No text to translate" });
|
||||||
|
}
|
||||||
|
const locale = req.body.locale;
|
||||||
|
if (locale === "american-to-british" || locale === "british-to-american") {
|
||||||
|
return res.json({
|
||||||
|
translation: translator.translate(req.body.text, locale, true),
|
||||||
|
text: req.body.text,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return res.json({ error: "Invalid value for locale field" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const cors = require('cors');
|
||||||
|
const fs = require('fs');
|
||||||
|
const runner = require('../test-runner');
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
|
||||||
|
app.route('/_api/server.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/server.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.route('/_api/routes/api.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/routes/api.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.type('txt').send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.route('/_api/controllers/convertHandler.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/controllers/convertHandler.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.type('txt').send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/_api/get-tests', cors(), function(req, res, next){
|
||||||
|
console.log('requested');
|
||||||
|
if(process.env.NODE_ENV === 'test') return next();
|
||||||
|
res.json({status: 'unavailable'});
|
||||||
|
},
|
||||||
|
function(req, res, next){
|
||||||
|
if(!runner.report) return next();
|
||||||
|
res.json(testFilter(runner.report, req.query.type, req.query.n));
|
||||||
|
},
|
||||||
|
function(req, res){
|
||||||
|
runner.on('done', function(report){
|
||||||
|
process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.get('/_api/app-info', function(req, res) {
|
||||||
|
let hs = Object.keys(res._headers)
|
||||||
|
.filter(h => !h.match(/^access-control-\w+/));
|
||||||
|
let hObj = {};
|
||||||
|
hs.forEach(h => {hObj[h] = res._headers[h]});
|
||||||
|
delete res._headers['strict-transport-security'];
|
||||||
|
res.json({headers: hObj});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function testFilter(tests, type, n) {
|
||||||
|
let out;
|
||||||
|
switch (type) {
|
||||||
|
case 'unit' :
|
||||||
|
out = tests.filter(t => t.context.match('Unit Tests'));
|
||||||
|
break;
|
||||||
|
case 'functional':
|
||||||
|
out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out = tests;
|
||||||
|
}
|
||||||
|
if(n !== undefined) {
|
||||||
|
return out[n] || out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
56
7-quality-assurance/5-american-british-translator/server.js
Normal file
56
7-quality-assurance/5-american-british-translator/server.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
require('dotenv').config();
|
||||||
|
const express = require('express');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const expect = require('chai').expect;
|
||||||
|
const cors = require('cors');
|
||||||
|
|
||||||
|
const fccTestingRoutes = require('./routes/fcctesting.js');
|
||||||
|
const runner = require('./test-runner');
|
||||||
|
const userRoutes = require('./routes/api.js');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use('/public', express.static(process.cwd() + '/public'));
|
||||||
|
app.use(cors({origin: '*'})); //For FCC testing purposes only
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// Index page (static HTML)
|
||||||
|
app.route('/')
|
||||||
|
.get(function (req, res) {
|
||||||
|
res.sendFile(process.cwd() + '/views/index.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
//For FCC testing purposes
|
||||||
|
fccTestingRoutes(app);
|
||||||
|
|
||||||
|
// User routes
|
||||||
|
userRoutes(app);
|
||||||
|
|
||||||
|
// 404 Not Found Middleware
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
res.status(404)
|
||||||
|
.type('text')
|
||||||
|
.send('Not Found');
|
||||||
|
});
|
||||||
|
|
||||||
|
const portNum = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
// Start our server and tests!
|
||||||
|
app.listen(portNum, () => {
|
||||||
|
console.log(`Listening on port ${portNum}`);
|
||||||
|
if (process.env.NODE_ENV==='test') {
|
||||||
|
console.log('Running Tests...');
|
||||||
|
setTimeout(function () {
|
||||||
|
try {
|
||||||
|
runner.run();
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Tests are not valid:');
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = app; // For testing
|
107
7-quality-assurance/5-american-british-translator/test-runner.js
Normal file
107
7-quality-assurance/5-american-british-translator/test-runner.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const analyser = require('./assertion-analyser');
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
const Mocha = require('mocha'),
|
||||||
|
fs = require('fs'),
|
||||||
|
path = require('path');
|
||||||
|
require("@babel/register");
|
||||||
|
|
||||||
|
const mocha = new Mocha({ timeout: 5000 });
|
||||||
|
const testDir = './tests'
|
||||||
|
|
||||||
|
|
||||||
|
// Add each .js file to the mocha instance
|
||||||
|
fs.readdirSync(testDir).filter(function(file){
|
||||||
|
// Only keep the .js files
|
||||||
|
return file.substr(-3) === '.js';
|
||||||
|
|
||||||
|
}).forEach(function(file){
|
||||||
|
mocha.addFile(
|
||||||
|
path.join(testDir, file)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let emitter = new EventEmitter();
|
||||||
|
emitter.run = function() {
|
||||||
|
|
||||||
|
let tests = [];
|
||||||
|
let context = "";
|
||||||
|
let separator = ' -> ';
|
||||||
|
// Run the tests.
|
||||||
|
try {
|
||||||
|
let runner = mocha.ui('tdd').run()
|
||||||
|
.on('test end', function(test) {
|
||||||
|
// remove comments
|
||||||
|
let body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||||
|
// collapse spaces
|
||||||
|
body = body.replace(/\s+/g,' ');
|
||||||
|
let obj = {
|
||||||
|
title: test.title,
|
||||||
|
context: context.slice(0, -separator.length),
|
||||||
|
state: test.state,
|
||||||
|
// body: body,
|
||||||
|
assertions: analyser(body)
|
||||||
|
};
|
||||||
|
tests.push(obj);
|
||||||
|
})
|
||||||
|
.on('end', function() {
|
||||||
|
emitter.report = tests;
|
||||||
|
emitter.emit('done', tests)
|
||||||
|
})
|
||||||
|
.on('suite', function(s) {
|
||||||
|
context += (s.title + separator);
|
||||||
|
|
||||||
|
})
|
||||||
|
.on('suite end', function(s) {
|
||||||
|
context = context.slice(0, -(s.title.length + separator.length))
|
||||||
|
})
|
||||||
|
} catch(e) {
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = emitter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mocha.runner Events:
|
||||||
|
* can be used to build a better custom report
|
||||||
|
*
|
||||||
|
* - `start` execution started
|
||||||
|
* - `end` execution complete
|
||||||
|
* - `suite` (suite) test suite execution started
|
||||||
|
* - `suite end` (suite) all tests (and sub-suites) have finished
|
||||||
|
* - `test` (test) test execution started
|
||||||
|
* - `test end` (test) test completed
|
||||||
|
* - `hook` (hook) hook execution started
|
||||||
|
* - `hook end` (hook) hook complete
|
||||||
|
* - `pass` (test) test passed
|
||||||
|
* - `fail` (test, err) test failed
|
||||||
|
* - `pending` (test) test pending
|
||||||
|
*/
|
|
@ -0,0 +1,237 @@
|
||||||
|
const chai = require("chai");
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
const Translator = require("../components/translator.js");
|
||||||
|
|
||||||
|
const translator = new Translator();
|
||||||
|
|
||||||
|
suite("Unit Tests", () => {
|
||||||
|
suite("Translation tests", () => {
|
||||||
|
suite("American to british", () => {
|
||||||
|
test("Mangoes are my favorite fruit.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Mangoes are my favorite fruit.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"Mangoes are my favourite fruit."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("I ate yogurt for breakfast.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"I ate yogurt for breakfast.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"I ate yoghurt for breakfast."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("We had a party at my friend's condo.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"We had a party at my friend's condo.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"We had a party at my friend's flat."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Can you toss this in the trashcan for me?", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Can you toss this in the trashcan for me?",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"Can you toss this in the bin for me?"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("The parking lot was full.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"The parking lot was full.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"The car park was full."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Like a high tech Rube Goldberg machine.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Like a high tech Rube Goldberg machine.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"Like a high tech Heath Robinson device."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("To play hooky means to skip class or work.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"To play hooky means to skip class or work.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"To bunk off means to skip class or work."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("No Mr. Bond, I expect you to die.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"No Mr. Bond, I expect you to die.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"No Mr Bond, I expect you to die."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Dr. Grosh will see you now.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Dr. Grosh will see you now.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"Dr Grosh will see you now."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Lunch is at 12:15 today.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Lunch is at 12:15 today.",
|
||||||
|
"american-to-british"
|
||||||
|
),
|
||||||
|
"Lunch is at 12.15 today."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
suite("British to american", () => {
|
||||||
|
test("We watched the footie match for a while.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"We watched the footie match for a while.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"We watched the soccer match for a while."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Paracetamol takes up to an hour to work.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Paracetamol takes up to an hour to work.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"Tylenol takes up to an hour to work."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("First, caramelise the onions.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"First, caramelise the onions.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"First, caramelize the onions."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("I spent the bank holiday at the funfair.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"I spent the bank holiday at the funfair.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"I spent the public holiday at the carnival."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("I had a bicky then went to the chippy.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"I had a bicky then went to the chippy.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"I had a cookie then went to the fish-and-chip shop."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("I've just got bits and bobs in my bum bag.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"I've just got bits and bobs in my bum bag.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"I've just got odds and ends in my fanny pack."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("The car boot sale at Boxted Airfield was called off.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"The car boot sale at Boxted Airfield was called off.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"The swap meet at Boxted Airfield was called off."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Have you met Mrs Kalyani?", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Have you met Mrs Kalyani?",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"Have you met Mrs. Kalyani?"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Prof Joyner of King's College, London.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Prof Joyner of King's College, London.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"Prof. Joyner of King's College, London."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Tea time is usually around 4 or 4.30.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Tea time is usually around 4 or 4.30.",
|
||||||
|
"british-to-american"
|
||||||
|
),
|
||||||
|
"Tea time is usually around 4 or 4:30."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
suite("Highlighting tests", () => {
|
||||||
|
test("Mangoes are my favorite fruit.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Mangoes are my favorite fruit.",
|
||||||
|
"american-to-british",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'Mangoes are my <span class="highlight">favourite</span> fruit.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("I ate yogurt for breakfast.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"I ate yogurt for breakfast.",
|
||||||
|
"american-to-british",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'I ate <span class="highlight">yoghurt</span> for breakfast.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("We watched the footie match for a while.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"We watched the footie match for a while.",
|
||||||
|
"british-to-american",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'We watched the <span class="highlight">soccer</span> match for a while.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Paracetamol takes up to an hour to work.", () => {
|
||||||
|
assert.equal(
|
||||||
|
translator.translate(
|
||||||
|
"Paracetamol takes up to an hour to work.",
|
||||||
|
"british-to-american",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'<span class="highlight">Tylenol</span> takes up to an hour to work.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,95 @@
|
||||||
|
const chai = require("chai");
|
||||||
|
const chaiHttp = require("chai-http");
|
||||||
|
const assert = chai.assert;
|
||||||
|
const server = require("../server.js");
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
|
||||||
|
suite("Functional Tests", () => {
|
||||||
|
test("Translation with text and locale fields: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
locale: "american-to-british",
|
||||||
|
text: "Mangoes are my favorite fruit.",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.text, "Mangoes are my favorite fruit.");
|
||||||
|
assert.equal(
|
||||||
|
res.body.translation,
|
||||||
|
'Mangoes are my <span class="highlight">favourite</span> fruit.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test("Translation with text and invalid locale field: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
locale: "american-to-nyanya",
|
||||||
|
text: "Mangoes are my favorite fruit.",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.error, "Invalid value for locale field");
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test("Translation with missing text field: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
locale: "american-to-british",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.error, "Required field(s) missing");
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test("Translation with missing locale field: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
text: "Mangoes are my favorite fruit.",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.error, "Required field(s) missing");
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test("Translation with empty text: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
locale: "american-to-british",
|
||||||
|
text: "",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.error, "No text to translate");
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test("Translation with text that needs no translation: POST request to /api/translate", (done) => {
|
||||||
|
chai
|
||||||
|
.request(server)
|
||||||
|
.post("/api/translate")
|
||||||
|
.send({
|
||||||
|
locale: "british-to-american",
|
||||||
|
text: "Mangoes are my favorite fruit.",
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.equal(res.body.translation, "Everything looks good to me!");
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
45
7-quality-assurance/5-american-british-translator/views/index.html
vendored
Normal file
45
7-quality-assurance/5-american-british-translator/views/index.html
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>American/British English Translator</title>
|
||||||
|
<meta name="description" content="An example for the fCC QA American/British English Translator project" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link id="favicon" rel="icon" href="https://cdn.freecodecamp.org/universal/favicons/favicon-32x32.png" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="../public/style.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>
|
||||||
|
American / British English Translator
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<hr style="margin: 25px" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="form-container">
|
||||||
|
<textarea
|
||||||
|
rows="10"
|
||||||
|
cols="60"
|
||||||
|
id="text-input"
|
||||||
|
></textarea>
|
||||||
|
<br />
|
||||||
|
<select id="locale-select">
|
||||||
|
<option value="american-to-british">American to British</option>
|
||||||
|
<option value="british-to-american">British to American</option>
|
||||||
|
</select>
|
||||||
|
<input type="button" value="Translate" id="translate-btn"/>
|
||||||
|
</div>
|
||||||
|
<div id="output-container">
|
||||||
|
<div id="solution-container">
|
||||||
|
Translated Sentence:
|
||||||
|
<div id="translated-sentence"></div>
|
||||||
|
<div id="error-msg"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script src="../public/index.js"></script>
|
||||||
|
</html>
|
Reference in a new issue