diff --git a/gems/canvas_i18nliner/js/scoped_hbs_pre_processor.js b/gems/canvas_i18nliner/js/scoped_hbs_pre_processor.js index 5d2124b1d19..da80bf7a537 100644 --- a/gems/canvas_i18nliner/js/scoped_hbs_pre_processor.js +++ b/gems/canvas_i18nliner/js/scoped_hbs_pre_processor.js @@ -26,11 +26,9 @@ PreProcessor.injectScope = function(node) { if (!node.hash) node.hash = node.sexpr.hash = new HashNode([]); pairs = node.hash.pairs; - // to match our .rb scoping behavior, don't scope inferred keys - if (pairs.length && pairs[pairs.length - 1][0] === "i18n_inferred_key") { - node.hash.pairs = pairs.slice(0, pairs.length - 1); - } - else { + // to match our .rb scoping behavior, don't scope inferred keys... + // if inferred, it's always the last option + if (!pairs.length || pairs[pairs.length - 1][0] !== "i18n_inferred_key") { node.hash.pairs = pairs.concat([["scope", new StringNode(this.scope)]]); } return node; diff --git a/gems/canvas_i18nliner/js/scoped_translate_call.js b/gems/canvas_i18nliner/js/scoped_translate_call.js index 6bd616a429a..94f48d329a2 100644 --- a/gems/canvas_i18nliner/js/scoped_translate_call.js +++ b/gems/canvas_i18nliner/js/scoped_translate_call.js @@ -17,7 +17,10 @@ module.exports = function(TranslateCall) { }; ScopedTranslateCall.prototype.normalize = function() { - if (!this.inferredKey) this.key = this.normalizeKey(this.key); + // TODO: make i18nliner-js use the latter, just like i18nliner(.rb) ... + // i18nliner-handlebars can't use the former + if (!this.inferredKey && !this.options.i18n_inferred_key) + this.key = this.normalizeKey(this.key); TranslateCall.prototype.normalize.call(this); }; diff --git a/gems/canvas_i18nliner/package.json b/gems/canvas_i18nliner/package.json index 11ce27b2862..59947bf3432 100644 --- a/gems/canvas_i18nliner/package.json +++ b/gems/canvas_i18nliner/package.json @@ -10,5 +10,11 @@ "i18nliner": "0.0.15", "i18nliner-handlebars": "0.0.11", "minimist": "^1.1.0" + }, + "devDependencies": { + "jasmine-node": "^1.14.5" + }, + "scripts": { + "test": "./node_modules/.bin/jasmine-node ./test" } } diff --git a/gems/canvas_i18nliner/test.sh b/gems/canvas_i18nliner/test.sh new file mode 100755 index 00000000000..71722f52600 --- /dev/null +++ b/gems/canvas_i18nliner/test.sh @@ -0,0 +1,15 @@ +#!/bin/bash +result=0 + +echo "################ canvas_i18nliner ################" +npm install +npm test +let result=$result+$? + +if [ $result -eq 0 ]; then + echo "SUCCESS" +else + echo "FAILURE" +fi + +exit $result diff --git a/gems/canvas_i18nliner/test/fixtures/hbs/app/coffeescripts/ember/.keep b/gems/canvas_i18nliner/test/fixtures/hbs/app/coffeescripts/ember/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gems/canvas_i18nliner/test/fixtures/hbs/app/views/jst/foo/_barBaz.hbs b/gems/canvas_i18nliner/test/fixtures/hbs/app/views/jst/foo/_barBaz.hbs new file mode 100644 index 00000000000..4a2f741c762 --- /dev/null +++ b/gems/canvas_i18nliner/test/fixtures/hbs/app/views/jst/foo/_barBaz.hbs @@ -0,0 +1,7 @@ +

{{#t "#absolute_key"}}Absolute key{{/t}}

+

{{#t "relative_key"}}Relative key{{/t}}

+

{{#t}}Inferred key{{/t}}

+ +

{{t "#inline_with_absolute_key" "Inline with absolute key"}}

+

{{t "inline_with_relative_key" "Inline with relative key"}}

+

{{t "Inline with inferred key"}}

diff --git a/gems/canvas_i18nliner/test/fixtures/hbs/public/javascripts/.keep b/gems/canvas_i18nliner/test/fixtures/hbs/public/javascripts/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gems/canvas_i18nliner/test/fixtures/js/app/coffeescripts/ember/.keep b/gems/canvas_i18nliner/test/fixtures/js/app/coffeescripts/ember/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gems/canvas_i18nliner/test/fixtures/js/app/views/jst/.keep b/gems/canvas_i18nliner/test/fixtures/js/app/views/jst/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gems/canvas_i18nliner/test/fixtures/js/public/javascripts/foo.js b/gems/canvas_i18nliner/test/fixtures/js/public/javascripts/foo.js new file mode 100644 index 00000000000..5234edd0b16 --- /dev/null +++ b/gems/canvas_i18nliner/test/fixtures/js/public/javascripts/foo.js @@ -0,0 +1,12 @@ +define(["i18n!foo"], function(I18n) { + I18n.t("#absolute_key", "Absolute key"); + I18n.t("Inferred key"); + define(["i18n!nested"], function(I18n) { + I18n.t("relative_key", "Relative key in nested scope"); + }); + I18n.t("relative_key", "Relative key"); +}); + +define(["i18n!bar"], function(I18n) { + I18n.t("relative_key", "Another relative key"); +}); diff --git a/gems/canvas_i18nliner/test/i18nliner_spec.js b/gems/canvas_i18nliner/test/i18nliner_spec.js new file mode 100644 index 00000000000..897633ad7df --- /dev/null +++ b/gems/canvas_i18nliner/test/i18nliner_spec.js @@ -0,0 +1,51 @@ +var I18nliner = require("../js/main").I18nliner; + +var subject = function(path) { + var command = new I18nliner.Commands.Check({}); + var origDir = process.cwd(); + try { + process.chdir(path); + command.run(); + } + finally { + process.chdir(origDir); + } + return command.translations.masterHash.translations; +} + +describe("I18nliner", function() { + describe("handlebars", function() { + it("extracts default translations", function() { + expect(subject("test/fixtures/hbs")).toEqual({ + absolute_key: "Absolute key", + inferred_key_c49e3743: "Inferred key", + inline_with_absolute_key: "Inline with absolute key", + inline_with_inferred_key_88e68761: "Inline with inferred key", + foo: { + bar_baz: { + inline_with_relative_key: "Inline with relative key", + relative_key: "Relative key" + } + } + }); + }); + }); + + describe("javascript", function() { + it("extracts default translations", function() { + expect(subject("test/fixtures/js")).toEqual({ + absolute_key: "Absolute key", + inferred_key_c49e3743: "Inferred key", + foo: { + relative_key: "Relative key" + }, + bar: { + relative_key: "Another relative key" + }, + nested: { + relative_key: "Relative key in nested scope" + } + }); + }); + }); +}); diff --git a/public/javascripts/i18nObj.js b/public/javascripts/i18nObj.js index f733e37af6f..1c59a8b5809 100644 --- a/public/javascripts/i18nObj.js +++ b/public/javascripts/i18nObj.js @@ -174,13 +174,23 @@ I18n.strftime = function(date, format) { I18n.Utils.HtmlSafeString = htmlEscape.SafeString; // this is what we use elsewhere in canvas, so make i18nliner use it too I18n.CallHelpers.keyPattern = /^\#?\w+(\.\w+)+$/ // handle our absolute keys + +// when inferring the key at runtime (i.e. js/coffee or inline hbs `t` +// call), signal to normalizeKey that it shouldn't be scoped. +// TODO: make i18nliner-js set i18n_inferred_key, which will DRY things up +// slightly +var origInferKey = I18n.CallHelpers.inferKey; +I18n.CallHelpers.inferKey = function() { + return "#" + origInferKey.apply(this, arguments); +}; + I18n.CallHelpers.normalizeKey = function(key, options) { if (key[0] === '#') { key = key.slice(1); delete options.scope; } return key; -} +}; if (window.ENV && window.ENV.lolcalize) { I18n.CallHelpers.normalizeDefault = i18nLolcalize; diff --git a/spec/selenium/common.rb b/spec/selenium/common.rb index d06764faa18..e235cfea72b 100644 --- a/spec/selenium/common.rb +++ b/spec/selenium/common.rb @@ -427,6 +427,22 @@ module SeleniumTestsHelperMethods driver.execute_async_script(js) end + # add some JS translations to the current page; they'll be merged in at + # the root level, so the top-most key should be the locale, e.g. + # + # set_translations fr: {key: "Bonjour"} + def set_translations(translations) + add_translations = "$.extend(true, I18n, {translations: #{translations.to_json}});" + if ENV['USE_OPTIMIZED_JS'] + driver.execute_script <<-JS + define('translations/test', ['i18nObj', 'jquery'], function(I18n, $) { + #{add_translations} + }); + JS + else + driver.execute_script add_translations + end + end end shared_examples_for "all selenium tests" do diff --git a/spec/selenium/handlebars_spec.rb b/spec/selenium/handlebars_spec.rb index d371411a5df..e5ae01b5528 100644 --- a/spec/selenium/handlebars_spec.rb +++ b/spec/selenium/handlebars_spec.rb @@ -8,14 +8,6 @@ describe "handlebars" do get "/" end - def set_translations(translations) - driver.execute_script <<-JS - define('translations/test', ['i18nObj', 'jquery'], function(I18n, $) { - $.extend(true, I18n, {translations: #{translations.to_json}}); - }); - JS - end - def run_template(template, context, locale = 'en') compiled = HandlebarsTasks::Handlebars.compile_template(template, 'test') driver.execute_script compiled @@ -82,25 +74,41 @@ describe "handlebars" do it "should translate the content" do translations = { - :pigLatin => { - :sup => 'upsay', - :test => { - :it_should_work => 'isthay ouldshay ebay anslatedtray frday' + pigLatin: { + absolute_key: "Absoluteay eykay", + inferred_key_c49e3743: "Inferreday eykay", + inline_with_absolute_key: "Inlineay ithway absoluteay eykay", + inline_with_inferred_key_88e68761: "Inlineay ithway inferreday eykay", + test: { + inline_with_relative_key: "Inlineay ithway elativeray eykay", + relative_key: "Elativeray eykay" } } } set_translations(translations) template = <<-HTML -

{{#t "#sup"}}sup{{/t}}

-

{{#t 'it_should_work'}}this should be translated frd{{/t}}

-

{{#t "not_yet_translated"}}but this shouldn't be{{/t}}

+

{{#t "#absolute_key"}}Absolute key{{/t}}

+

{{#t "relative_key"}}Relative key{{/t}}

+

{{#t}}Inferred key{{/t}}

+ +

{{t "#inline_with_absolute_key" "Inline with absolute key"}}

+

{{t "inline_with_relative_key" "Inline with relative key"}}

+

{{t "Inline with inferred key"}}

+ +

{{#t "not_yet_translated"}}No translation yet{{/t}}

HTML expect(run_template(template, {}, 'pigLatin')).to eq <<-HTML -

#{translations[:pigLatin][:sup]}

-

#{translations[:pigLatin][:test][:it_should_work]}

-

but this shouldn't be

+

Absoluteay eykay

+

Elativeray eykay

+

Inferreday eykay

+ +

Inlineay ithway absoluteay eykay

+

Inlineay ithway elativeray eykay

+

Inlineay ithway inferreday eykay

+ +

No translation yet

HTML end diff --git a/spec/selenium/i18n_js_spec.rb b/spec/selenium/i18n_js_spec.rb index ac7d7c9bc5a..e6e62b63db4 100644 --- a/spec/selenium/i18n_js_spec.rb +++ b/spec/selenium/i18n_js_spec.rb @@ -50,5 +50,16 @@ describe "i18n js" do ) end end + + it "should not scope inferred keys" do + set_translations({ + pigLatin: { + inferred_key_c49e3743: "Inferreday eykay", + test: {inferred_key_c49e3743: "Otnay isthay!"} + } + }) + expect(require_exec('i18n!test', "I18n.locale = 'pigLatin'; i18n.t('Inferred key')")) + .to eq("Inferreday eykay") + end end end