Skip to content

Commit

Permalink
Add pontoon strings & build step to transform into webextension strings
Browse files Browse the repository at this point in the history
- Add pontoon-to-webext.js script from bwinton/SnoozeTabs repo and
  related npm dependencies (to be removed when/if that script is
  published on npm as a standalone module).

- Add extracted strings to a properties file at the location expected by
  Pontoon. Remove the webextension-formatted strings from git.

- Add a pontoon-to-webextension build step to the Makefile.

This commit, together with the fix for mozilla-services#2344, closes mozilla-services#2294.
  • Loading branch information
jaredhirsch committed Mar 14, 2017
1 parent 67d336b commit f9e24d7
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ cookie-jar.txt
/addon/webextension/build
/addon/webextension/.web-extension-id
/addon/webextension/manifest.json
/addon/webextension/_locales
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ imgs_server_dest := $(imgs_source:%=build/server/%)

raven_source := $(shell node -e 'console.log(require.resolve("raven-js/dist/raven.js"))')

l10n_source := $(wildcard locales/*)
l10n_dest := $(l10n_source:%/webextension.properties=addon/webextension/_locales/%/messages.json)

## General transforms:
# These cover standard ways of building files given a source

Expand Down Expand Up @@ -87,7 +90,7 @@ build/%.html: %.html
cp $< $@

.PHONY: addon
addon: npm set_backend set_sentry addon/webextension/manifest.json addon/webextension/build/shot.js addon/webextension/build/inlineSelectionCss.js addon/webextension/build/raven.js addon/webextension/build/defaultSentryDsn.js
addon: npm set_backend set_sentry addon/webextension/manifest.json addon_locales addon/webextension/build/shot.js addon/webextension/build/inlineSelectionCss.js addon/webextension/build/raven.js addon/webextension/build/defaultSentryDsn.js

.PHONY: zip
zip: addon
Expand All @@ -103,6 +106,10 @@ signed_xpi: addon
./node_modules/.bin/web-ext sign --api-key=${AMO_USER} --api-secret=${AMO_SECRET} --source-dir addon/webextension/
mv web-ext-artifacts/*.xpi build/pageshot.xpi

.PHONY: addon_locales
addon_locales: $(l10n_dest)
./bin/build-scripts/pontoon-to-webext.js --dest addon/webextension/_locales

addon/webextension/manifest.json: addon/webextension/manifest.json.template build/.backend.txt package.json
./bin/build-scripts/update_manifest $< $@

Expand Down
33 changes: 0 additions & 33 deletions addon/webextension/_locales/en_US/messages.json

This file was deleted.

168 changes: 168 additions & 0 deletions bin/build-scripts/pontoon-to-webext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#! /usr/bin/env node

/* eslint-disable promise/avoid-new */

const propertiesParser = require('properties-parser');
const path = require('path');
const FS = require('q-io/fs');
const argv = require('minimist')(process.argv.slice(2));

const Habitat = require('habitat');
Habitat.load();

const regexPlaceholders = /\{([A-Za-z0-9_@]*)\}/g;
let supportedLocales = process.env.SUPPORTED_LOCALES || '*';

const config = {
'dest': argv.dest || 'dist/_locales',
'src': argv.src || 'locales',
'default_locale': argv.locale || 'en-US'
};

function log(...args) {
console.log(...args); // eslint-disable-line no-console
}

function error(...args) {
console.error(...args); // eslint-disable-line no-console
}

function fatal(...args) {
error(...args);
process.exit(1);
}

function getListLocales() {
return new Promise((resolve, reject) => {
if (supportedLocales === '*') {
FS.listDirectoryTree(path.join(process.cwd(), config.src)).then((dirTree) => {
const localeList = [];

// Get rid of the top level, we're only interested with what's inside it
dirTree.splice(0,1);
dirTree.forEach((localeLocation) => {
// Get the locale code from the end of the path. We're expecting the structure of Pontoon's output here
const langcode = localeLocation.split(path.sep).slice(-1)[0];

if (langcode) {
localeList.push(langcode);
}
});
return resolve(localeList);
}).catch((e) => {
reject(e);
});
} else {
supportedLocales = supportedLocales.split(',').map(item => item.trim());
resolve(supportedLocales);
}
});
}

function writeFiles(entries) {
for (const entry of entries) {
const publicPath = path.join(process.cwd(), config.dest, entry.locale.replace('-', '_'));
const localesPath = path.join(publicPath, 'messages.json');

FS.makeTree(publicPath).then(() => {
return FS.write(localesPath, JSON.stringify(entry.content, null, 2));
}).then(() => {
log(`Done compiling locales at: ${localesPath}`);
}).catch((e) => {
fatal(e);
});
}
}

function readPropertiesFile(filePath) {
return new Promise((resolve, reject) => {
propertiesParser.read(filePath, (messageError, messageProperties) => {
if (messageError && messageError.code !== 'ENOENT') {
return reject(messageError);
}
resolve(messageProperties);
});
});
}

function getContentPlaceholders() {
return new Promise((resolve, reject) => {
FS.listTree(path.join(process.cwd(), config.src, config.default_locale), (filePath) => {
return path.extname(filePath) === '.properties';
}).then((files) => {
return Promise.all(files.map(readPropertiesFile)).then((properties) => {
const mergedPlaceholders = {};

properties.forEach(messages => {
const placeholders = {};
Object.keys(messages).forEach(key => {
const message = messages[key];
if (message.indexOf('{') !== -1) {
const placeholder = {};
let index = 1;
message.replace(regexPlaceholders, (item, key) => {
placeholder[key.toLowerCase()] = { content: `$${index}` };
index++;
});
placeholders[key] = placeholder;
}
});
Object.assign(mergedPlaceholders, placeholders);
});

resolve(mergedPlaceholders);
});
}).catch((e) => {
reject(e);
});
});
}

function getContentMessages(locale, placeholders) {
return new Promise((resolve, reject) => {
FS.listTree(path.join(process.cwd(), config.src, locale), (filePath) => {
return path.extname(filePath) === '.properties';
}).then((files) => {
return Promise.all(files.map(readPropertiesFile)).then((properties) => {
const mergedProperties = {};

properties.forEach(messages => {
Object.keys(messages).forEach(key => {
let message = messages[key];
messages[key] = { 'message': message };
if (placeholders[key]) {
message = message.replace(regexPlaceholders, (item, key) => `\$${key.toUpperCase()}\$`);
messages[key] = {
'message': message,
'placeholders': placeholders[key]
};
}
});
Object.assign(mergedProperties, messages);
});

resolve({content: mergedProperties, locale: locale});
});
}).catch((e) => {
reject(e);
});
});
}

function processMessageFiles(locales) {
if (!locales) {
fatal('List of locales was undefined. Cannot run pontoon-to-webext.');
}
if (locales.length === 0) {
fatal('Locale list is empty. Cannot run pontoon-to-webext.');
}
log(`processing the following locales: ${locales.toString()}`);
return getContentPlaceholders().then(placeholders => {
return Promise.all(locales.map(locale => getContentMessages(locale, placeholders)));
});
}

getListLocales().then(processMessageFiles)
.then(writeFiles).catch((err)=> {
error(err);
});
28 changes: 28 additions & 0 deletions locales/en-US/webextension.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
addonDescription = Page Shot takes clips and screenshots from pages, and can save a permanent copy of a page.
addonAuthorsList = Ian Bicking, Donovan Preston, and Bram Pitoyo
toolbarButtonLabel = Take a shot
contextMenuLabel = Create Page Shot
myShotsLink = My Shots
screenshotInstructions = Drag or click on the page to select a region. Press ESC to cancel.
saveScreenshotSelectedArea = Save
saveScreenshotVisibleArea = Save visible
saveScreenshotFullPage = Save full page
cancelScreenshot = Cancel
downloadScreenshot = Download
notificationLinkCopiedTitle = Link Copied
# The string "{meta_key}-V" should be translated to the region-specific
# shorthand for the Paste keyboard shortcut. {meta_key} is a placeholder for the
# modifier key used in the shortcut (do not translate it): for example, Ctrl-V
# on Windows systems.
notificationLinkCopiedDetails = The link to your shot has been copied to the clipboard. Press {meta_key}-V to paste.
requestErrorTitle = Page Shot is out of order.
requestErrorDetails = Your shot was not saved. We apologize for the inconvenience. Try again soon.
connectionErrorTitle = Cannot connect to the Page Shot server.
connectionErrorDetails = There may be a problem with the service or with your network connection.
loginErrorDetails = Your shot was not saved. There was an error authenticating with the server.
loginConnectionErrorDetails = There may be a problem with the service or your network connection.
unshootablePageErrorTitle = Page cannot be screenshotted.
unshootablePageErrorDetails = This is not a normal web page, and Page Shot cannot capture screenshots from it.
selfScreenshotErrorTitle = You can’t take a shot of a Page Shot page!
genericErrorTitle = Page Shot went haywire.
genericErrorDetails = Try again or take a shot on another page?
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@
"eslint-plugin-react": "6.10.0",
"fx-runner": "1.0.6",
"geckodriver": "1.4.0",
"habitat": "3.1.2",
"minimist": "1.2.0",
"mocha": "3.2.0",
"node-sass": "4.5.0",
"npm-run-all": "4.0.2",
"nsp": "2.6.3",
"properties-parser": "0.3.1",
"q-io": "1.13.2",
"sass-lint": "1.10.2",
"selenium-webdriver": "3.3.0",
"svgo": "0.7.2",
Expand Down

0 comments on commit f9e24d7

Please sign in to comment.