-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* uses (requires) the Globalization Pipeline bound service * use `npm run gen-i18n` to pickup any changes to index.html * use localized number formatting on the client side * escape HTML from `Hey <b>you!</b>` to `Hey {b}you!{/b}` for translation Fixes: #1
- Loading branch information
Showing
10 changed files
with
460 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (c) 2016 IBM Corp. All rights reserved. | ||
// Use of this source code is governed by the Apache License, | ||
// Version 2.0, a copy of which can be found in the LICENSE file. | ||
|
||
// this file extracts source-language (English) content out of the HTML doc | ||
// in order to produce public/scripts/en.json | ||
|
||
const jsdom = require('jsdom'); | ||
const jquery = require('jquery'); | ||
const fs = require('fs'); | ||
|
||
var virtualConsole = jsdom.createVirtualConsole(); | ||
virtualConsole.on("jsdomError", function (error) { | ||
console.error(error.stack, error.detail); | ||
}); | ||
|
||
const htmlFile = './public/index.html'; | ||
|
||
jsdom.env({ | ||
// url: 'file://' + process.cwd() + '/public/index.html', | ||
html: fs.readFileSync(htmlFile), | ||
scripts: [/*fs.readFileSync(*/'node_modules/jquery/dist/jquery.min.js'/*)*/, | ||
/*fs.readFileSync(*/'./node_modules/jquery-selectorator/dist/selectorator.min.js'/*)*/], | ||
virtualConsole: virtualConsole, | ||
done: function(err, window) { | ||
if(err) { | ||
console.error(err); | ||
return; | ||
} | ||
|
||
console.log('read:', htmlFile); | ||
// var $ = jquery(window); | ||
var $ = window.$; | ||
|
||
// Now, determine which objects should be extracted | ||
var m = require('./public/scripts/en-extra.json'); // output map. Start with extra list. | ||
|
||
function extract(stuff) { | ||
$(stuff).each(function() { | ||
const t = $(this); | ||
if(t.hasClass('no-t')) return; // skip | ||
|
||
if (t.text() && t.text() !== '') { | ||
m[t.getSelector()] = t.html() | ||
.replace(/</g,'{') | ||
.replace(/>/g,'}'); | ||
} | ||
if (t.attr('title') && t.attr('title') !== '') { | ||
m[ 'title::' + t.getSelector()] = t.attr('title'); | ||
} | ||
if (t.attr('placeholder') && t.attr('placeholder') !== '') { | ||
m[ 'placeholder::' + t.getSelector()] = t.attr('placeholder'); | ||
} | ||
}); | ||
} | ||
|
||
// the options | ||
extract($('option')); | ||
// the window title | ||
// extract($('title')); | ||
// buttons | ||
extract($('.t')); | ||
|
||
// log it to screen | ||
//console.dir(m); | ||
console.log('Extracted', Object.keys(m).length, 'items'); | ||
|
||
const jsonFile = 'public/scripts/en.json'; | ||
// write the .json version | ||
fs.writeFileSync(jsonFile, | ||
JSON.stringify(m)); | ||
console.log('wrote: ', [jsonFile] ); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright (c) 2016 IBM Corp. All rights reserved. | ||
// Use of this source code is governed by the Apache License, | ||
// Version 2.0, a copy of which can be found in the LICENSE file. | ||
|
||
const detectLocale = require('locale-detector'); | ||
const gp = require('g11n-pipeline'); | ||
const express = require('express'); | ||
const router = express.Router(); | ||
const Q = require('q'); | ||
const sourceLanguage = 'en'; | ||
|
||
function getBundleInfoOrCreate(bundle) { | ||
var deferred = Q.defer(); | ||
bundle.getInfo({}, function(err, data) { | ||
if(err && (err.toString().indexOf('ResourceNotFoundException') !== -1)) { | ||
// does not exist, create | ||
console.log('g11n-pipeline creating bundle',bundle.id ); | ||
return deferred.resolve(Q.ninvoke(bundle, 'create', { | ||
sourceLanguage: sourceLanguage, | ||
targetLanguages: [] // start empty | ||
}) | ||
// .then(Q.fcall(function(){ | ||
// return bundle; | ||
// }) | ||
.then(function() { | ||
var deferred2 = Q.defer(); | ||
// console.log('..getting info'); | ||
// return Q.ninvoke(bundle, 'getInfo', {}); < did not work?! | ||
// get info again on our newly created bundle | ||
bundle.getInfo({}, function(err2, data2) { | ||
if(err2) return deferred2.reject(err2); | ||
return deferred2.resolve(data2); | ||
}); | ||
return deferred2.promise; | ||
})); | ||
} | ||
if(err) return deferred.reject(err); | ||
console.log('g11n-pipeline using existing bundle',bundle.id ); | ||
return deferred.resolve(data); | ||
}); | ||
return deferred.promise; | ||
} | ||
|
||
// need appEnv to get the client. | ||
module.exports = function(appEnv) { | ||
const gpClient = gp.getClient({appEnv: appEnv}); | ||
const bundleName = appEnv.name + (appEnv.isLocal?'-local':''); | ||
const bundle = gpClient.bundle(bundleName); | ||
console.log('g11n-pipeline bundle name',bundleName); | ||
|
||
// Promise with full bundle info | ||
var bundleInfoPromise = | ||
getBundleInfoOrCreate(gpClient.bundle(bundleName)); | ||
|
||
console.dir(require('./public/scripts/en.json')); | ||
|
||
// Promise for the bundle: for reading, only after bundle is created and populated. | ||
var bundlePromise = | ||
bundleInfoPromise | ||
// upload our strings | ||
.then(function() { | ||
return Q.ninvoke(gpClient.bundle(bundleName), | ||
'uploadStrings', | ||
{languageId: sourceLanguage, strings: require('./public/scripts/en.json')}); | ||
}) | ||
.then(function() { | ||
return bundle; | ||
}); | ||
|
||
// A promise for the array of all languages: [ 'en', 'de', … ] | ||
var targetLanguagesPromise = | ||
bundleInfoPromise | ||
.then(function(bundleInfo) { | ||
// extract just the list of languages | ||
var langs = [bundleInfo.sourceLanguage] | ||
.concat(bundleInfo.targetLanguages||[]); | ||
return langs; | ||
}); | ||
|
||
// Make sure the target langs are ready. | ||
targetLanguagesPromise.then(function(langs) { | ||
if(!langs) throw new Error('No target languages!'); | ||
console.log('Bundle ready!', bundleName, 'langs:', langs); | ||
}).done(); | ||
|
||
// Make sure we can fetch English | ||
bundlePromise | ||
.then(function() {return 'en'; }) | ||
.then(fetchBundle) | ||
.done(); | ||
|
||
/** | ||
* Returns a promise to fetch the specified language bundle. | ||
*/ | ||
function fetchBundle(lang) { | ||
return bundlePromise.then(function(bundle){ | ||
bundle = gpClient.bundle(bundleName); | ||
if(!bundle) throw new Error('Hey, bundle is null!'); | ||
// need to unpack bundle into a 'get' call | ||
// return Q.ninvoke(bundle, 'getStrings', {languageId: lang}); | ||
var deferred = Q.defer(); | ||
bundle.getStrings({languageId: lang}, function(err, data) { | ||
if(err) return deferred.reject(err); | ||
return deferred.resolve(data); | ||
}); | ||
return deferred.promise; | ||
}) | ||
.then(function(result) { | ||
// Restructure data | ||
return { | ||
lang: lang, | ||
data: result.resourceStrings | ||
}; | ||
}); | ||
}; | ||
|
||
|
||
// Test route | ||
router.get('/loctest', function(req, res) { | ||
targetLanguagesPromise.then(function(langs) { | ||
console.log('Langs='+langs); | ||
res.end(detectLocale(req.headers['accept-language'], langs) | ||
|| sourceLanguage); // fallback. | ||
}, function(e) { | ||
res.writeHead(500, {'Content-Type': 'text/plain'}); | ||
res.end('Internal Error'); | ||
console.error(e); | ||
}); | ||
}); | ||
|
||
// Return the bundle as javascript | ||
router.get('/auto.js', function(req, res) { | ||
targetLanguagesPromise | ||
.then(function(langs) { | ||
var lang = detectLocale(req.headers['accept-language'], langs) | ||
|| sourceLanguage; | ||
return lang; | ||
}) | ||
.then(fetchBundle) | ||
.then(function(json) { | ||
res.end('i18n_bundle=' + JSON.stringify(json)+';\n'); // fallback. | ||
}, function(e) { | ||
res.writeHead(500, {'Content-Type': 'text/plain'}); | ||
res.end('Internal Error'); | ||
console.error(e); | ||
}) | ||
.done(); | ||
}); | ||
|
||
return { | ||
router: router | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
{ | ||
"name": "blue-messenger", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "A simple nodejs app for Bluemix", | ||
"scripts": { | ||
"start": "node app.js" | ||
"start": "node app.js", | ||
"gen-i18n": "node i18n-extract.js" | ||
}, | ||
"dependencies": { | ||
"ascoltatori": "0.21.0", | ||
|
@@ -12,9 +13,12 @@ | |
"ejs": "*", | ||
"express": "4.12.x", | ||
"fs": "*", | ||
"g11n-pipeline": "^1.1.6", | ||
"locale-detector": "^1.0.1", | ||
"morgan": "*", | ||
"mosca": "0.30.x", | ||
"optional": "^0.1.3" | ||
"optional": "^0.1.3", | ||
"q": "^1.4.1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
|
@@ -31,5 +35,10 @@ | |
"email": "[email protected]" | ||
} | ||
], | ||
"license": "Apache-2.0" | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"jquery": "^2.2.3", | ||
"jsdom": "^9.1.0", | ||
"jquery-selectorator": "^0.1.6" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"_disconnected": "Disconnected..." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"_disconnected":"Disconnected...","#rates > option:eq(0)":"Low","#rates > option:eq(1)":"Medium","#rates > option:eq(2)":"High",".nb-devopsservices-text":"IBM {b}Bluemix{/b} Architecture Center","body > div:eq(1) > div:eq(0) > label:eq(0)":"Messaging Rate:","body > div:eq(1) > div:eq(1) > label:eq(0)":"Duration in Minutes:",".container > label.t":"Message:","placeholder::#message":"Write your message here...","#send":"Send a Message","h3.t":"Generate a {span id=\"spamrate\"}high{/span} message load for {span id=\"duration\"}5{/span} minutes!","#start > .t":"Start","title::#start > .t":"Start sending automated messages!","#stop > .t":"Stop","title::#stop > .t":"Stop sending automated messages!","h4.t":"You have sent {span id=\"messageCount\"}0{/span} messages!"} |
Oops, something went wrong.