Skip to content

Commit

Permalink
feat: Localization, English + French (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielweck authored May 5, 2019
1 parent 5d78397 commit bf8b374
Show file tree
Hide file tree
Showing 43 changed files with 963 additions and 228 deletions.
2 changes: 1 addition & 1 deletion packages/ace-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@daisy/ace-cli",
"version": "1.0.3",
"version": "1.0.4",
"description": "Ace by DAISY, an Accessibility Checker for EPUB",
"author": {
"name": "DAISY developers",
Expand Down
5 changes: 4 additions & 1 deletion packages/ace-cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const cli = meow({
-V, --verbose display verbose output
-s, --silent do not display any output
-l, --lang <language> language code for localized messages (e.g. "fr"), default is "en"
Examples
$ ace -o out ~/Documents/book.epub
`,
Expand All @@ -46,9 +47,10 @@ version: pkg.version
t: 'tempdir',
v: 'version',
V: 'verbose',
l: 'lang',
},
boolean: ['force', 'verbose', 'silent', 'subdir'],
string: ['outdir', 'tempdir'],
string: ['outdir', 'tempdir', 'lang'],
});

function sleep(ms) {
Expand Down Expand Up @@ -102,6 +104,7 @@ ${overrides.map(file => ` - ${file}`).join('\n')}
verbose: cli.flags.verbose,
silent: cli.flags.silent,
jobId: '',
lang: cli.flags.lang,
})
.then((jobData) => {
var reportJson = jobData[1];
Expand Down
4 changes: 3 additions & 1 deletion packages/ace-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@daisy/ace-core",
"version": "1.0.3",
"version": "1.0.4",
"description": "Core library for Ace",
"author": {
"name": "DAISY developers",
Expand All @@ -18,6 +18,8 @@
"license": "MIT",
"main": "lib/index.js",
"dependencies": {
"@daisy/ace-localize": "^1.0.0",
"@daisy/ace-logger": "^1.0.1",
"@daisy/ace-meta": "^1.0.3",
"@daisy/ace-report": "^1.0.1",
"@daisy/ace-report-axe": "^1.0.1",
Expand Down
50 changes: 46 additions & 4 deletions packages/ace-core/src/checker/checker-chromium.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const winston = require('winston');
const axe2ace = require('@daisy/ace-report-axe');
const utils = require('@daisy/puppeteer-utils');

const { getRawResourcesForCurrentLanguage } = require('../l10n/localize').localizer;

tmp.setGracefulCleanup();

const scripts = [
Expand All @@ -23,7 +25,7 @@ const scripts = [
require.resolve('../scripts/ace-extraction.js'),
];

async function checkSingle(spineItem, epub, browser) {
async function checkSingle(spineItem, epub, browser, lang) {
winston.verbose(`- Processing ${spineItem.relpath}`);
try {
let url = spineItem.url;
Expand All @@ -42,6 +44,46 @@ async function checkSingle(spineItem, epub, browser) {

const page = await browser.newPage();
await page.goto(url);

let localePath = "";
try {
winston.info(`- Axe locale: [${lang}]`);

// https://github.com/dequelabs/axe-core#localization
// https://github.com/dequelabs/axe-core/tree/develop/locales

if (lang && lang !== "en" && lang.indexOf("en-") !== 0) { // default English built into Axe source code
localePath = path.resolve(require.resolve('axe-core'), `../locales/${lang}.json`);
if (fs.existsSync(localePath)) {
const localeStr = fs.readFileSync(localePath, { encoding: "utf8" });
const localeScript = `window.__axeLocale__=${localeStr};`;
await utils.addScriptContents([localeScript], page);
} else {
winston.info(`- Axe locale missing? [${lang}] => ${localePath}`);
}
}

let localizedScript = "";
const rawJson = getRawResourcesForCurrentLanguage();

["axecheck", "axerule"].forEach((checkOrRule) => {
const checkOrRuleKeys = Object.keys(rawJson[checkOrRule]);
for (const checkOrRuleKey of checkOrRuleKeys) {
const msgs = Object.keys(rawJson[checkOrRule][checkOrRuleKey]);
for (const msg of msgs) {
const k = `__aceLocalize__${checkOrRule}_${checkOrRuleKey}_${msg}`;
localizedScript += `window['${k}']="${rawJson[checkOrRule][checkOrRuleKey][msg]}";\n`;
}
}
});
await utils.addScriptContents([localizedScript], page);

} catch (err) {
console.log(err);
winston.verbose(err);
winston.info(`- Axe locale problem? [${lang}] => ${localePath}`);
}

await utils.addScripts(scripts, page);

const results = await page.evaluate(() => new Promise((resolve, reject) => {
Expand All @@ -57,7 +99,7 @@ async function checkSingle(spineItem, epub, browser) {
await page.close();

// Post-process results
results.assertions = (results.axe != null) ? axe2ace.axe2ace(spineItem, results.axe) : [];
results.assertions = (results.axe != null) ? axe2ace.axe2ace(spineItem, results.axe, lang) : [];
delete results.axe;
winston.info(`- ${spineItem.relpath}: ${
(results.assertions && results.assertions.assertions.length > 0)
Expand Down Expand Up @@ -97,14 +139,14 @@ async function checkSingle(spineItem, epub, browser) {
}
}

module.exports.check = async (epub) => {
module.exports.check = async (epub, lang) => {
const args = [];
if (os.platform() !== 'win32' && os.platform() !== 'darwin') {
args.push('--no-sandbox')
}
const browser = await puppeteer.launch({ args });
winston.info('Checking documents...');
return pMap(epub.contentDocs, doc => checkSingle(doc, epub, browser), { concurrency: 4 })
return pMap(epub.contentDocs, doc => checkSingle(doc, epub, browser, lang), { concurrency: 4 })
.then(async (results) => {
await browser.close();
return results;
Expand Down
28 changes: 15 additions & 13 deletions packages/ace-core/src/checker/checker-epub.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const builders = require('@daisy/ace-report').builders;
const winston = require('winston');

const { localize } = require('../l10n/localize').localizer;

const ASSERTED_BY = 'Ace';
const MODE = 'automatic';
const KB_BASE = 'http://kb.daisy.org/publishing/';
Expand Down Expand Up @@ -42,11 +44,11 @@ function newMetadataAssertion(name, impact = 'serious') {
return newViolation({
impact,
title: `metadata-${name.toLowerCase().replace(':', '-')}`,
testDesc: `Ensures a '${name}' metadata is present`,
resDesc: `Add a '${name}' metadata property to the Package Document`,
testDesc: localize("checkepub.metadataviolation.testdesc", { name, interpolation: { escapeValue: false } }),
resDesc: localize("checkepub.metadataviolation.resdesc", { name, interpolation: { escapeValue: false } }),
kbPath: 'docs/metadata/schema-org.html',
kbTitle: 'Schema.org Accessibility Metadata',
ruleDesc: `Publications must declare the '${name}' metadata`
kbTitle: localize("checkepub.metadataviolation.kbtitle"),
ruleDesc: localize("checkepub.metadataviolation.ruledesc", { name, interpolation: { escapeValue: false } })
});
}

Expand All @@ -70,11 +72,11 @@ function checkTitle(assertions, epub) {
if (title === '') {
assertions.withAssertions(newViolation({
title: 'epub-title',
testDesc: 'Ensures the EPUB has a title',
resDesc: 'Add a \'dc:title\' metadata property to the Package Document',
testDesc: localize("checkepub.titleviolation.testdesc"),
resDesc: localize("checkepub.titleviolation.resdesc"),
kbPath: '',
kbTitle: 'EPUB Title',
ruleDesc: 'Publications must have a title',
kbTitle: localize("checkepub.titleviolation.kbtitle"),
ruleDesc: localize("checkepub.titleviolation.ruledesc")
}));
}
}
Expand All @@ -85,11 +87,11 @@ function checkPageSource(assertion, epub) {
|| epub.metadata['dc:source'].toString() === '')) {
assertion.withAssertions(newViolation({
title: 'epub-pagesource',
testDesc: 'Ensures the source of page breaks is identified',
resDesc: 'Add a \'dc:source\' metadata property to the Package Document',
testDesc: localize("checkepub.pagesourceviolation.testdesc"),
resDesc: localize("checkepub.pagesourceviolation.resdesc"),
kbPath: 'docs/navigation/pagelist.html',
kbTitle: 'Page Navigation',
ruleDesc: 'Publications with page breaks must declare the \'dc:source\' metadata',
kbTitle: localize("checkepub.pagesourceviolation.kbtitle"),
ruleDesc: localize("checkepub.pagesourceviolation.ruledesc")
}));
}
}
Expand Down Expand Up @@ -121,7 +123,7 @@ function check(epub, report) {
hasBindings: epub.hasBindings,
hasSVGContentDocuments: epub.hasSVGContentDocuments,
});

winston.info(`- ${epub.packageDoc.src}: ${
(builtAssertions.assertions && builtAssertions.assertions.length > 0)
? builtAssertions.assertions.length
Expand Down
4 changes: 2 additions & 2 deletions packages/ace-core/src/checker/checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ function consolidate(results, report) {
return report;
}

module.exports.check = function check(epub, report) {
module.exports.check = function check(epub, report,lang) {
return epubChecker.check(epub, report)
.then(() => htmlChecker.check(epub))
.then(() => htmlChecker.check(epub, lang))
.then(results => consolidate(results, report));
};
15 changes: 13 additions & 2 deletions packages/ace-core/src/core/ace.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,21 @@ const pkg = require('@daisy/ace-meta/package');
const EPUB = require('@daisy/epub-utils').EPUB;
const Report = require('@daisy/ace-report').Report;
const checker = require('../checker/checker.js');
const { setCurrentLanguage } = require('../l10n/localize').localizer;

const logger = require('@daisy/ace-logger');

tmp.setGracefulCleanup();

module.exports = function ace(epubPath, options) {
if (options.lang) {
setCurrentLanguage(options.lang);
}

if (options.initLogger) {
logger.initLogger({ verbose: options.verbose, silent: options.silent });
}

return new Promise((resolve, reject) => {
// the jobid option just gets returned in the resolve/reject
// so the calling function can track which job finished
Expand Down Expand Up @@ -56,9 +67,9 @@ module.exports = function ace(epubPath, options) {
epub.extract()
.then(() => epub.parse())
// initialize the report
.then(() => new Report(epub, options.outdir))
.then(() => new Report(epub, options.outdir, options.lang))
// Check each Content Doc
.then(report => checker.check(epub, report))
.then(report => checker.check(epub, report, options.lang))
// Process the Results
.then((report) => {
if (options.outdir === undefined) {
Expand Down
37 changes: 37 additions & 0 deletions packages/ace-core/src/l10n/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"checkepub": {
"metadataviolation": {
"testdesc": "Ensures a '{{name}}' metadata is present",
"resdesc": "Add a '{{name}}' metadata property to the Package Document",
"ruledesc": "Publications must declare the '{{name}}' metadata",
"kbtitle": "Schema.org Accessibility Metadata"
},
"titleviolation": {
"testdesc": "Ensures the EPUB has a title",
"resdesc": "Add a 'dc:title' metadata property to the Package Document",
"ruledesc": "Publications must have a title",
"kbtitle": "EPUB Title"
},
"pagesourceviolation": {
"testdesc": "Ensures the source of page breaks is identified",
"resdesc": "Add a 'dc:source' metadata property to the Package Document",
"ruledesc": "Publications with page breaks must declare the 'dc:source' metadata",
"kbtitle": "Page Navigation"
}
},
"axecheck": {
"matching-aria-role": {
"pass": "Element has an ARIA role matching its epub:type",
"fail": "Element has no ARIA role matching its epub:type"
}
},
"axerule": {
"pagebreak-label": {
"desc": "Ensure page markers have an accessible label"
},
"epub-type-has-matching-role": {
"help": "ARIA role should be used in addition to epub:type",
"desc": "Ensure the element has an ARIA role matching its epub:type"
}
}
}
37 changes: 37 additions & 0 deletions packages/ace-core/src/l10n/locales/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"checkepub": {
"metadataviolation": {
"testdesc": "Vérifie que la métadonnée '{{name}}' est présente",
"resdesc": "Ajouter la métadonnée '{{name}}' au Document de Package",
"ruledesc": "Toute publication doit déclarer la métadonnée '{{name}}'",
"kbtitle": "Métadonnées d'accessibilité Schema.org"
},
"titleviolation": {
"testdesc": "Vérifie que le EPUB a un titre",
"resdesc": "Ajouter la métadonnée 'dc:title' au Document de Package",
"ruledesc": "Une publication doit avoir un titre",
"kbtitle": "Titre de l’EPUB"
},
"pagesourceviolation": {
"testdesc": "Vérifie que la source des sauts de page est identifiée",
"resdesc": "Ajouter la métadonnée 'dc:source' au Document de Package",
"ruledesc": "Une publication avec des sauts de page doit déclarer la métadonnée 'dc:source'",
"kbtitle": "Navigation par page"
}
},
"axecheck": {
"matching-aria-role": {
"pass": "L’élément a un rôle ARIA correspondant à son epub:type",
"fail": "L’élément n’a pas de rôle ARIA correspondant à son epub:type"
}
},
"axerule": {
"pagebreak-label": {
"desc": "Vérifie que les sauts de page ont un label accessible"
},
"epub-type-has-matching-role": {
"help": "Un rôle ARIA devrait être spécifié en plus de l’epub:type",
"desc": "Vérifie qu’un élément a un rôle ARIA correspondant à son epub:type"
}
}
}
16 changes: 16 additions & 0 deletions packages/ace-core/src/l10n/localize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { newLocalizer } = require('@daisy/ace-localize');

const enJson = require("./locales/en.json");
const frJson = require("./locales/fr.json");

export const localizer = newLocalizer({
en: {
name: "English",
default: true,
translation: enJson,
},
fr: {
name: "Français",
translation: frJson,
},
});
Loading

0 comments on commit bf8b374

Please sign in to comment.