From 6323c8e084c8e263953dc2d5684859ee6f01b843 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 14:39:11 -0500 Subject: [PATCH 1/6] Loading extension resources via stringbundle --- extensions/chrome/.gitignore | 1 + extensions/firefox/.gitignore | 2 + extensions/firefox/chrome.manifest | 3 + .../firefox/components/PdfStreamConverter.js | 39 +++++++++++++ make.js | 55 +++++++++++-------- web/viewer.js | 11 ++-- 6 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 extensions/chrome/.gitignore create mode 100644 extensions/firefox/chrome.manifest diff --git a/extensions/chrome/.gitignore b/extensions/chrome/.gitignore new file mode 100644 index 000000000..3eb92306c --- /dev/null +++ b/extensions/chrome/.gitignore @@ -0,0 +1 @@ +content/ diff --git a/extensions/firefox/.gitignore b/extensions/firefox/.gitignore index 08a23850c..6eec9a7f2 100644 --- a/extensions/firefox/.gitignore +++ b/extensions/firefox/.gitignore @@ -1,2 +1,4 @@ content/ metadata.inc +chrome.manifest.inc +locale/ diff --git a/extensions/firefox/chrome.manifest b/extensions/firefox/chrome.manifest new file mode 100644 index 000000000..97b76306b --- /dev/null +++ b/extensions/firefox/chrome.manifest @@ -0,0 +1,3 @@ +# Additional resources for pdf.js + +# PDFJS_SUPPORTED_LOCALES diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 49fd134ae..d84f19e58 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -4,6 +4,10 @@ 'use strict'; var EXPORTED_SYMBOLS = ['PdfStreamConverter']; +var DEFAULT_LOCALE = 'en-US'; + +var IS_MOZCENTRAL = false; // PDFJS_SUPPORTED_LOCALES +var SUPPORTED_LOCALES = [DEFAULT_LOCALE]; // PDFJS_SUPPORTED_LOCALES const Cc = Components.classes; const Ci = Components.interfaces; @@ -59,6 +63,28 @@ function getDOMWindow(aChannel) { return win; } +function getLocalizedStrings(path) { + var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService). + createBundle("chrome://pdfviewer/locale/" + path); + + var map = {}; + var enumerator = stringBundle.getSimpleEnumeration(); + while (enumerator.hasMoreElements()) { + var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); + var key = string.key, property = 'textContent'; + var i = key.lastIndexOf('.'); + if (i >= 0) { + property = key.substring(i + 1); + key = key.substring(0, i); + } + if (!(key in map)) + map[key] = {}; + map[key][property] = string.value; + } + return map; +} + // All the priviledged actions. function ChromeActions() { this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; @@ -113,6 +139,19 @@ ChromeActions.prototype = { getLocale: function() { return getStringPref('general.useragent.locale', 'en-US'); }, + getStrings: function(data) { + try { + // Lazy initialization of localizedStrings + if (!('localizedStrings' in this)) + this.localizedStrings = getLocalizedStrings('viewer.properties'); + + var result = this.localizedStrings[data]; + return JSON.stringify(result || null) + } catch (e) { + log('Unable to retrive localized strings: ' + e); + return 'null'; + } + }, pdfBugEnabled: function() { return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); } diff --git a/make.js b/make.js index 0a39e0b07..34dc27c9b 100755 --- a/make.js +++ b/make.js @@ -6,6 +6,7 @@ var ROOT_DIR = __dirname + '/', // absolute path to project's root BUILD_TARGET = BUILD_DIR + 'pdf.js', FIREFOX_BUILD_DIR = BUILD_DIR + '/firefox/', EXTENSION_SRC_DIR = 'extensions/', + LOCALE_SRC_DIR = 'l10n/', GH_PAGES_DIR = BUILD_DIR + 'gh-pages/', REPO = 'git@github.com:mozilla/pdf.js.git', PYTHON_BIN = 'python2.7'; @@ -67,8 +68,9 @@ target.web = function() { // Creates localized resources for the viewer and extension. // target.locale = function() { - var L10N_PATH = 'l10n'; var METADATA_OUTPUT = 'extensions/firefox/metadata.inc'; + var CHROME_MANIFEST_OUTPUT = 'extensions/firefox/chrome.manifest.inc'; + var EXTENSION_LOCALE_OUTPUT = 'extensions/firefox/locale'; var VIEWER_OUTPUT = 'web/locale.properties'; var DEFAULT_LOCALE = 'en-US'; @@ -76,13 +78,17 @@ target.locale = function() { echo(); echo('### Building localization files'); - var subfolders = ls(L10N_PATH); + rm('-rf', EXTENSION_LOCALE_OUTPUT); + mkdir('-p', EXTENSION_LOCALE_OUTPUT); + + var subfolders = ls(LOCALE_SRC_DIR); subfolders.sort(); var metadataContent = ''; + var chromeManifestContent = ''; var viewerOutput = ''; for (var i = 0; i < subfolders.length; i++) { var locale = subfolders[i]; - var path = L10N_PATH + '/' + locale; + var path = LOCALE_SRC_DIR + locale; if (!test('-d', path)) continue; @@ -91,12 +97,13 @@ target.locale = function() { continue; } + mkdir('-p', EXTENSION_LOCALE_OUTPUT + '/' + locale); + chromeManifestContent += 'locale pdfviewer ' + locale + ' locale/' + locale + '/\n'; + if (test('-f', path + '/viewer.properties')) { var properties = cat(path + '/viewer.properties'); - if (locale == DEFAULT_LOCALE) - viewerOutput = '[*]\n' + properties + '\n' + viewerOutput; - else - viewerOutput = viewerOutput + '[' + locale + ']\n' + properties + '\n'; + viewerOutput += '[' + locale + ']\n' + properties + '\n'; + cp(path + '/viewer.properties', EXTENSION_LOCALE_OUTPUT + '/' + locale); } if (test('-f', path + '/metadata.inc')) { @@ -106,6 +113,7 @@ target.locale = function() { } viewerOutput.to(VIEWER_OUTPUT); metadataContent.to(METADATA_OUTPUT); + chromeManifestContent.to(CHROME_MANIFEST_OUTPUT); }; // @@ -227,7 +235,7 @@ var EXTENSION_WEB_FILES = 'web/viewer.css', 'web/viewer.js', 'web/viewer.html', - 'external/webL10n/l10n.js', + 'extensions/firefox/tools/l10n.js', 'web/viewer-production.html'], EXTENSION_BASE_VERSION = 'f0f0418a9c6637981fe1182b9212c2d592774c7d', EXTENSION_VERSION_PREFIX = '0.3.', @@ -277,21 +285,23 @@ target.firefox = function() { '*.rdf', '*.svg', '*.png', + '*.manifest', 'components', + 'locale', '../../LICENSE'], FIREFOX_EXTENSION_FILES = ['bootstrap.js', 'install.rdf', + 'chrome.manifest', 'icon.png', 'icon64.png', 'components', 'content', + 'locale', 'LICENSE'], FIREFOX_EXTENSION_NAME = 'pdf.js.xpi', FIREFOX_AMO_EXTENSION_NAME = 'pdf.js.amo.xpi'; - var LOCALE_CONTENT = cat('web/locale.properties'); - target.production(); target.buildnumber(); cd(ROOT_DIR); @@ -310,7 +320,6 @@ target.firefox = function() { // Copy a standalone version of pdf.js inside the content directory cp(BUILD_TARGET, FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR); cp('-R', EXTENSION_WEB_FILES, FIREFOX_BUILD_CONTENT_DIR + '/web'); - cp('web/locale.properties', FIREFOX_BUILD_CONTENT_DIR + '/web'); rm(FIREFOX_BUILD_CONTENT_DIR + '/web/viewer-production.html'); // Copy over the firefox extension snippet so we can inline pdf.js in it @@ -319,7 +328,6 @@ target.firefox = function() { // Modify the viewer so it does all the extension-only stuff. cd(FIREFOX_BUILD_CONTENT_DIR + '/web'); sed('-i', /.*PDFJSSCRIPT_INCLUDE_BUNDLE.*\n/, cat(ROOT_DIR + BUILD_TARGET), 'viewer-snippet-firefox-extension.html'); - sed('-i', /.*PDFJSSCRIPT_LOCALE_DATA.*\n/, LOCALE_CONTENT, 'viewer-snippet-firefox-extension.html'); sed('-i', /.*PDFJSSCRIPT_REMOVE_CORE.*\n/g, '', 'viewer.html'); sed('-i', /.*PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION.*\n/g, '', 'viewer.html'); sed('-i', /.*PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION.*\n/, cat('viewer-snippet-firefox-extension.html'), 'viewer.html'); @@ -328,7 +336,6 @@ target.firefox = function() { // We don't need pdf.js anymore since its inlined rm('-Rf', FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR); rm(FIREFOX_BUILD_CONTENT_DIR + '/web/viewer-snippet-firefox-extension.html'); - rm(FIREFOX_BUILD_CONTENT_DIR + '/web/locale.properties'); // Remove '.DS_Store' and other hidden files find(FIREFOX_BUILD_DIR).forEach(function(file) { if (file.match(/^\./)) @@ -342,6 +349,8 @@ target.firefox = function() { // Update localized metadata var localizedMetadata = cat(EXTENSION_SRC_DIR + '/firefox/metadata.inc'); sed('-i', /.*PDFJS_LOCALIZED_METADATA.*\n/, localizedMetadata, FIREFOX_BUILD_DIR + '/install.rdf'); + var chromeManifest = cat(EXTENSION_SRC_DIR + '/firefox/chrome.manifest.inc'); + sed('-i', /.*PDFJS_SUPPORTED_LOCALES.*\n/, chromeManifest, FIREFOX_BUILD_DIR + '/chrome.manifest'); // Create the xpi cd(FIREFOX_BUILD_DIR); @@ -365,25 +374,27 @@ target.mozcentral = function() { echo(); echo('### Building mozilla-central extension'); - var MOZCENTRAL_DIR = BUILD_DIR + '/mozcentral', - MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_DIR + '/content/', - MOZCENTRAL_L10N_DIR = MOZCENTRAL_DIR + '/l10n/', + var MOZCENTRAL_DIR = BUILD_DIR + 'mozcentral/', + MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + 'browser/app/profile/extensions/uriloader@pdf.js/', + MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_EXTENSION_DIR + 'content/', + MOZCENTRAL_L10N_DIR = MOZCENTRAL_DIR + 'browser/locales/en-US/pdfviewer/', FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + '/firefox/content/', FIREFOX_EXTENSION_FILES_TO_COPY = ['*.js', '*.svg', '*.png', + '*.manifest', 'install.rdf.in', 'README.mozilla', 'components', '../../LICENSE'], DEFAULT_LOCALE_FILES = - ['l10n/en-US/viewer.properties', - 'l10n/en-US/metadata.inc'], + [LOCALE_SRC_DIR + 'en-US/viewer.properties'], FIREFOX_MC_EXTENSION_FILES = ['bootstrap.js', 'icon.png', 'icon64.png', + 'chrome.manifest', 'components', 'content', 'LICENSE']; @@ -401,7 +412,7 @@ target.mozcentral = function() { // Copy extension files cd('extensions/firefox'); - cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_DIR); + cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_EXTENSION_DIR); cd(ROOT_DIR); // Copy a standalone version of pdf.js inside the content directory @@ -433,11 +444,11 @@ target.mozcentral = function() { cp(DEFAULT_LOCALE_FILES, MOZCENTRAL_L10N_DIR); // Update the build version number - sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_DIR + '/install.rdf.in'); - sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_DIR + '/README.mozilla'); + sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'install.rdf.in'); + sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'README.mozilla'); // List all files for mozilla-central - cd(MOZCENTRAL_DIR); + cd(MOZCENTRAL_EXTENSION_DIR); var extensionFiles = ''; find(FIREFOX_MC_EXTENSION_FILES).forEach(function(file){ if (test('-f', file)) diff --git a/web/viewer.js b/web/viewer.js index dcbfcf14e..dd267065a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1362,11 +1362,12 @@ window.addEventListener('load', function webViewerLoad(evt) { if ('disableWorker' in hashParams) PDFJS.disableWorker = (hashParams['disableWorker'] === 'true'); - var locale = !PDFJS.isFirefoxExtension ? navigator.language : - FirefoxCom.request('getLocale', null); - if ('locale' in hashParams) - locale = hashParams['locale']; - mozL10n.language.code = locale; + if (!PDFJS.isFirefoxExtension) { + var locale = navigator.language; + if ('locale' in hashParams) + locale = hashParams['locale']; + mozL10n.language.code = locale; + } if ('disableTextLayer' in hashParams) PDFJS.disableTextLayer = (hashParams['disableTextLayer'] === 'true'); From 56b3a7086e94775ff0cd3d03135d78965e0da066 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 14:42:20 -0500 Subject: [PATCH 2/6] Remove unused code --- extensions/firefox/components/PdfStreamConverter.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index d84f19e58..898058004 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -4,10 +4,6 @@ 'use strict'; var EXPORTED_SYMBOLS = ['PdfStreamConverter']; -var DEFAULT_LOCALE = 'en-US'; - -var IS_MOZCENTRAL = false; // PDFJS_SUPPORTED_LOCALES -var SUPPORTED_LOCALES = [DEFAULT_LOCALE]; // PDFJS_SUPPORTED_LOCALES const Cc = Components.classes; const Ci = Components.interfaces; From 5ca12d549e5d9d0ea1162e33067d5da7bf2389f9 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 15:14:50 -0500 Subject: [PATCH 3/6] Missing file --- extensions/firefox/tools/l10n.js | 113 +++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 extensions/firefox/tools/l10n.js diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js new file mode 100644 index 000000000..ad3b4ab95 --- /dev/null +++ b/extensions/firefox/tools/l10n.js @@ -0,0 +1,113 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +// Small subset of the webL10n API by Fabien Cazenave for pdf.js extension. +(function(window) { + var gLanguage = ''; + + // fetch an l10n objects + function getL10nData(key) { + var response = FirefoxCom.request('getStrings', key); + var data = JSON.parse(response); + if (!data) + console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']'); + return data; + } + + // replace {{arguments}} with their values + function substArguments(text, args) { + if (!args) + return text; + + return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) { + return name in args ? args[name] : '{{' + name + '}}'; + }); + } + + // translate a string + function translateString(key, args, fallback) { + var data = getL10nData(key); + if (!data && fallback) + data = {textContent: fallback}; + if (!data) + return '{{' + key + '}}'; + return substArguments(data.textContent, args); + } + + // translate an HTML element + function translateElement(element) { + if (!element || !element.dataset) + return; + + // get the related l10n object + var data = getL10nData(element.dataset.l10nId); + if (!data) + return; + + // get arguments (if any) + // TODO: more flexible parser? + var args; + if (element.dataset.l10nArgs) try { + args = JSON.parse(element.dataset.l10nArgs); + } catch (e) { + console.warn('[l10n] could not parse arguments for #' + key + ''); + } + + // translate element + // TODO: security check? + for (var k in data) + element[k] = substArguments(data[k], args); + } + + + // translate an HTML subtree + function translateFragment(element) { + element = element || document.querySelector('html'); + + // check all translatable children (= w/ a `data-l10n-id' attribute) + var children = element.querySelectorAll('*[data-l10n-id]'); + var elementCount = children.length; + for (var i = 0; i < elementCount; i++) + translateElement(children[i]); + + // translate element itself if necessary + if (element.dataset.l10nId) + translateElement(element); + } + + window.addEventListener('DOMContentLoaded', function() { + gLanguage = FirefoxCom.request('getLocale', null); + + translateFragment(); + + // fire a 'localized' DOM event + var evtObject = document.createEvent('Event'); + evtObject.initEvent('localized', false, false); + evtObject.language = gLanguage; + window.dispatchEvent(evtObject); + }); + + // Public API + document.mozL10n = { + // get a localized string + get: translateString, + + // get|set the document language and direction + get language() { + return { + // get|set the document language (ISO-639-1) + get code() { return gLanguage; }, + + // get the direction (ltr|rtl) of the current language + get direction() { + // http://www.w3.org/International/questions/qa-scripts + // Arabic, Hebrew, Farsi, Pashto, Urdu + var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; + return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr'; + } + }; + } + }; +})(this); \ No newline at end of file From 7d648cfa130203392b34d0c93aefddde433ae855 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 15:18:46 -0500 Subject: [PATCH 4/6] Lint errors --- extensions/firefox/components/PdfStreamConverter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 898058004..6ed755554 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -60,9 +60,9 @@ function getDOMWindow(aChannel) { } function getLocalizedStrings(path) { - var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]. + var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. getService(Ci.nsIStringBundleService). - createBundle("chrome://pdfviewer/locale/" + path); + createBundle('chrome://pdfviewer/locale/' + path); var map = {}; var enumerator = stringBundle.getSimpleEnumeration(); @@ -142,7 +142,7 @@ ChromeActions.prototype = { this.localizedStrings = getLocalizedStrings('viewer.properties'); var result = this.localizedStrings[data]; - return JSON.stringify(result || null) + return JSON.stringify(result || null); } catch (e) { log('Unable to retrive localized strings: ' + e); return 'null'; From d9f995f9caa149aa3e8334092e02e3a04aad61ce Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 17:35:43 -0500 Subject: [PATCH 5/6] Change pdfviewer->pdf.js for chrome://;new line --- extensions/firefox/components/PdfStreamConverter.js | 2 +- extensions/firefox/tools/l10n.js | 3 ++- make.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 6ed755554..4a6cd9eca 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -62,7 +62,7 @@ function getDOMWindow(aChannel) { function getLocalizedStrings(path) { var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. getService(Ci.nsIStringBundleService). - createBundle('chrome://pdfviewer/locale/' + path); + createBundle('chrome://pdf.js/locale/' + path); var map = {}; var enumerator = stringBundle.getSimpleEnumeration(); diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js index ad3b4ab95..b16636e31 100644 --- a/extensions/firefox/tools/l10n.js +++ b/extensions/firefox/tools/l10n.js @@ -110,4 +110,5 @@ }; } }; -})(this); \ No newline at end of file +})(this); + diff --git a/make.js b/make.js index 34dc27c9b..90ccfb347 100755 --- a/make.js +++ b/make.js @@ -98,7 +98,7 @@ target.locale = function() { } mkdir('-p', EXTENSION_LOCALE_OUTPUT + '/' + locale); - chromeManifestContent += 'locale pdfviewer ' + locale + ' locale/' + locale + '/\n'; + chromeManifestContent += 'locale pdf.js ' + locale + ' locale/' + locale + '/\n'; if (test('-f', path + '/viewer.properties')) { var properties = cat(path + '/viewer.properties'); From 085723a7b2daf548a148d64d26a024c6b7834ef0 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 18:12:48 -0500 Subject: [PATCH 6/6] make the locale stuff a precondition for make extension --- make.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make.js b/make.js index 90ccfb347..88f7c69a0 100755 --- a/make.js +++ b/make.js @@ -250,6 +250,7 @@ target.extension = function() { echo(); echo('### Building extensions'); + target.locale(); target.production(); target.firefox(); target.chrome(); @@ -302,6 +303,7 @@ target.firefox = function() { FIREFOX_EXTENSION_NAME = 'pdf.js.xpi', FIREFOX_AMO_EXTENSION_NAME = 'pdf.js.amo.xpi'; + target.locale(); target.production(); target.buildnumber(); cd(ROOT_DIR);