diff --git a/README.md b/README.md index c0c8c12..b0b6bf4 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,29 @@ be called when it's time to load the image, and should pass an error, or `null` and a buffer to its callback. +Additionally localizations can be added if needed: +```js +pass.addLocalization("en", { + "GATE": "GATE", + "DEPART": "DEPART", + "ARRIVE": "ARRIVE", + "SEAT": "SEAT", + "PASSENGER": "PASSENGER", + "FLIGHT": "FLIGHT" +}); + +pass.addLocalization("ru", { + "GATE": "ВЫХОД", + "DEPART": "ВЫЛЕТ", + "ARRIVE": "ПРИЛЁТ", + "SEAT": "МЕСТО", + "PASSENGER": "ПАССАЖИР", + "FLIGHT": "РЕЙС" +}); +``` + +Localization applies for all fields' `label` and `value`. There is a note about that in [documentation](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html). + # Generate the file To generate a file: diff --git a/lib/pass.js b/lib/pass.js index 3fefcfd..5a95e89 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -17,8 +17,8 @@ var zlib = require("zlib"); // Top-level pass fields. var TOP_LEVEL = [ "authenticationToken", "backgroundColor", "barcode", "description", "foregroundColor", "labelColor", "locations", "logoText", - "organizationName", "relevantDate", "serialNumber", - "suppressStripShine", "webServiceURL"]; + "organizationName", "relevantDate", "serialNumber", + "suppressStripShine", "webServiceURL", "expirationDate"]; // These top level fields are required for a valid pass. var REQUIRED_TOP_LEVEL = [ "description", "organizationName", "passTypeIdentifier", "serialNumber", "teamIdentifier" ]; @@ -46,6 +46,9 @@ function Pass(template, fields, images) { if (!this.structure) this.structure = this.fields[style] = {}; this.images = cloneObject(images); + + // For localizations support + this.localizations = {}; } inherits(Pass, EventEmitter); @@ -139,7 +142,7 @@ Fields.prototype.add = function(key, label, value, options) { // key - Field key // label - Field label (optional) // value - Field value -// Other field options (e.g. dateStyle) +// Other field options (e.g. dateStyle) Fields.prototype.get = function(key) { var fields = this.pass.structure[this.key]; if (fields) { @@ -180,6 +183,15 @@ Fields.prototype.clear = function() { return this; }; +// Localization +Pass.prototype.addLocalization = function (lang, values) { + var keys = Object.keys(values); + // .string files formatting + var strings = keys.map(function(key) { + return "\"" + key + "\" = \"" + values[key].replace(/"/g, "\\\"") + "\";"; + }); + this.localizations[lang] = strings.join("\n"); +}; // Validate pass, throws error if missing a mandatory top-level field or image. Pass.prototype.validate = function() { @@ -238,6 +250,13 @@ Pass.prototype.pipe = function(output) { var passJson = new Buffer(JSON.stringify(this.getPassJSON()), "utf-8"); addFile("pass.json").end(passJson, "utf8"); + // Localization + var langs = Object.keys(this.localizations); + for (var i = 0; i < langs.length; i++) { + var lang = langs[i]; + addFile(lang + ".lproj/pass.strings").end(new Buffer(this.localizations[lang]), 'utf-16'); + } + var expecting = 0; for (var key in this.images) { var filename = key.replace(/2x$/, "@2x") + ".png"; @@ -360,7 +379,7 @@ function signManifest(template, manifest, callback) { "-passin", "pass:" + template.password ]; var sign = execFile("openssl", args, { stdio: "pipe" }, function(error, stdout, stderr) { - var trimmedStderr = stderr.trim(); + var trimmedStderr = stderr.trim(); // Windows outputs some unhelpful error messages, but still produces a valid signature if (error || (trimmedStderr && trimmedStderr.indexOf('- done') < 0)) { callback(new Error(stderr)); diff --git a/package.json b/package.json index ba5cfd0..ff09fc0 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,17 @@ { "name": "passbook", "description": "iOS Passbook for the Node hacker", "homepage": "https://github.com/assaf/node-passbook", - "version": "2.1.1", + "version": "2.1.2", "author": { "name": "Assaf Arkin", "email": "assaf@labnotes.org" }, + "contributors": [ + { + "name": "Sergey Pronin", + "email" : "sergey@pronin.me" + } + ], "main": "./lib/index.js", "bin": { "node-passbook": "./bin/node-passbook"