zendesk_apps_support 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,7 @@ en:
36
36
  duplicate_parameters: ! 'Duplicate app parameters defined: %{duplicate_parameters}'
37
37
  translation:
38
38
  invalid_locale: ! '%{file} is not a valid locale.'
39
+ invalid_format: ! '%{field} is invalid for translation.'
39
40
  not_json: ! '%{file} is not valid JSON. %{errors}'
40
41
  not_json_object: ! '%{file} is not a JSON object.'
41
42
  stylesheet_error: ! 'Sass error: %{sass_error}'
@@ -91,6 +91,10 @@ parts:
91
91
  key: "txt.apps.admin.error.app_build.translation.invalid_locale"
92
92
  title: "App builder job: invalid locale file name"
93
93
  value: "%{file} is not a valid locale."
94
+ - translation:
95
+ key: "txt.apps.admin.error.app_build.translation.invalid_format"
96
+ title: "App builder job: file format is invalid for translation"
97
+ value: "%{field} is invalid for translation."
94
98
  - translation:
95
99
  key: "txt.apps.admin.error.app_build.translation.not_json"
96
100
  title: "App builder job: translation file is invalid json"
@@ -1,29 +1,24 @@
1
1
  module ZendeskAppsSupport
2
2
  module BuildTranslation
3
3
 
4
- I18N_TITLE_KEY = 'title'
5
- I18N_VALUE_KEY = 'value'
6
- I18N_KEYS = [ I18N_TITLE_KEY, I18N_VALUE_KEY ]
7
-
8
- def to_flattened_namespaced_hash(hash, prefix = nil)
4
+ I18N_TITLE_KEY = 'title'
5
+ I18N_VALUE_KEY = 'value'
6
+ I18N_KEYS = [I18N_TITLE_KEY, I18N_VALUE_KEY]
9
7
 
8
+ def to_flattened_namespaced_hash(hash, target_key = nil, prefix = nil)
10
9
  hash.inject({}) do |result, (key, value)|
11
- key = [ prefix, key ].compact.join('.')
12
-
10
+ key = [prefix, key].compact.join('.')
13
11
  if value.kind_of?(Hash)
14
-
15
- if is_translation_hash?(value)
16
- result[key] = value[I18N_VALUE_KEY]
12
+ if target_key && is_translation_hash?(value)
13
+ result[key] = value[target_key]
17
14
  else
18
- result.update( to_flattened_namespaced_hash(value, key) )
15
+ result.update(to_flattened_namespaced_hash(value, target_key, key))
19
16
  end
20
-
21
17
  else
22
18
  result[key] = value
23
19
  end
24
20
  result
25
21
  end
26
-
27
22
  end
28
23
 
29
24
  def remove_zendesk_keys(scope, translations = {})
@@ -4,7 +4,10 @@ module ZendeskAppsSupport
4
4
  module Validations
5
5
  module Translations
6
6
  TRANSLATIONS_PATH = %r{^translations/(.*)\.json$}
7
- VALID_LOCALE = /^[a-z]{2}(-\w{2,3})?$/
7
+ VALID_LOCALE = /^[a-z]{2}(-\w{2,3})?$/
8
+
9
+ class TranslationFormatError < StandardError
10
+ end
8
11
 
9
12
  class << self
10
13
  def call(package)
@@ -25,12 +28,36 @@ module ZendeskAppsSupport
25
28
 
26
29
  def json_error(file)
27
30
  json = MultiJson.load(file.read)
28
- return nil if json.kind_of?(Hash)
29
- ValidationError.new('translation.not_json_object', :file => file.relative_path)
31
+ if json.kind_of?(Hash)
32
+ if json["app"] && json["app"]["package"]
33
+ json["app"].delete("package")
34
+ begin
35
+ validate_translation_format(json)
36
+ return
37
+ rescue TranslationFormatError => e
38
+ ValidationError.new('translation.invalid_format', :field => e.message)
39
+ end
40
+ end
41
+ else
42
+ ValidationError.new('translation.not_json_object', :file => file.relative_path)
43
+ end
30
44
  rescue MultiJson::DecodeError => e
31
45
  ValidationError.new('translation.not_json', :file => file.relative_path, :errors => e)
32
46
  end
33
47
 
48
+ def validate_translation_format(json)
49
+ json.keys.each do |key|
50
+ raise TranslationFormatError.new("'#{key}': '#{json[key]}'") unless json[key].kind_of? Hash
51
+
52
+ if json[key].keys.sort == BuildTranslation::I18N_KEYS &&
53
+ json[key][BuildTranslation::I18N_TITLE_KEY].class == String &&
54
+ json[key][BuildTranslation::I18N_VALUE_KEY].class == String
55
+ next
56
+ else
57
+ validate_translation_format(json[key])
58
+ end
59
+ end
60
+ end
34
61
  end
35
62
  end
36
63
  end
@@ -6,99 +6,85 @@ describe ZendeskAppsSupport::BuildTranslation do
6
6
  let(:en_json) {
7
7
  {
8
8
  "app" => {
9
- "description" => "Shows related tickets",
10
- "title" => "Related tickets",
11
- "parameters" => {
12
- "disable_tooltip" => {
13
- "label" => "Disable tooltip"
14
- }
9
+ "abc" => {
10
+ "title" => "description for abc field",
11
+ "value" => "value of abc"
15
12
  }
16
13
  },
17
- "parent_without_child" => "Foo",
18
- "parent_with_child" => {
19
- "child" => "Foo"
20
- },
21
- "parent_with_child_title" => {
22
- "title" => "Foo"
23
- },
24
- "parent_with_zendesk_tranlation" => {
25
- "title" => "Bar",
26
- "value" => "Foo"
27
- },
28
- "parent_with_child_title_nested" => {
29
- "title" => {
30
- "value" => "Foo"
31
- }
32
- },
33
- "parent_with_nested_invalid_zendesk_translation" => {
34
- "title" => {
35
- "title" => "Bar",
36
- "desc" => "Foo"
37
- }
38
- },
39
- "parent_with_nested_zendesk_translation" => {
40
- "title" => {
41
- "title" => "Bar",
42
- "value" => "Foo"
14
+ "a" => {
15
+ "a1" => {
16
+ "title" => "description for a1 field",
17
+ "value" => "value of a1"
18
+ },
19
+ "b" => {
20
+ "b1" => {
21
+ "title" => "description for b1 field",
22
+ "value" => "value of b1"
23
+ }
43
24
  }
44
25
  }
45
26
  }
46
27
  }
47
28
 
48
- describe '#market_translations' do
49
-
50
- context "flatten translations" do
51
-
52
- before do
53
- @market_translations = to_flattened_namespaced_hash(en_json)
54
- end
55
-
56
- it "value is correct parent with a child that has an valid nested zendesk translation" do
57
- @market_translations['parent_with_nested_zendesk_translation.title'].should eq 'Foo'
58
- end
29
+ describe '#to_flattened_namespaced_hash' do
30
+
31
+ context "not zendesk i18n format" do
32
+ it "should flatten hash without removing zendesk keys" do
33
+ expected = {
34
+ "app.abc.title" => "description for abc field",
35
+ "app.abc.value" => "value of abc",
36
+ "a.a1.title" => "description for a1 field",
37
+ "a.a1.value" => "value of a1",
38
+ "a.b.b1.title" => "description for b1 field",
39
+ "a.b.b1.value" => "value of b1"
40
+ }
59
41
 
60
- it "value is correct parent with a child that has an invalid nested zendesk translation" do
61
- @market_translations['parent_with_nested_invalid_zendesk_translation.title.title'].should eq 'Bar'
42
+ to_flattened_namespaced_hash(en_json).should == expected
62
43
  end
63
-
64
44
  end
65
45
 
66
- end
67
-
68
- describe '#app_translations' do
69
-
70
- context "reformat translations" do
71
-
72
- before do
73
- @app_translations = remove_zendesk_keys(en_json)
74
- end
75
-
76
- it "value is correct parent without a child" do
77
- @app_translations['parent_without_child'].should eq 'Foo'
78
- end
79
-
80
- it "value is correct parent with a child" do
81
- @app_translations['parent_with_child']['child'].should eq 'Foo'
82
- end
83
-
84
- it "value is correct parent with a child with a title" do
85
- @app_translations['parent_with_child_title']['title'].should eq 'Foo'
86
- end
46
+ context 'zendesk i18n format' do
47
+ context 'flatten value keys' do
48
+ it "should flatten hash by removing zendesk title keys" do
49
+ expected = {
50
+ "app.abc" => "value of abc",
51
+ "a.a1" => "value of a1",
52
+ "a.b.b1" => "value of b1"
53
+ }
87
54
 
88
- it "value is correct parent with a zendesk translation" do
89
- @app_translations['parent_with_child_title_nested']['title']['value'].should eq 'Foo'
55
+ to_flattened_namespaced_hash(en_json, I18N_VALUE_KEY).should == expected
56
+ end
90
57
  end
91
58
 
92
- it "value is correct parent with a child that has a nested zendesk translation" do
93
- @app_translations['parent_with_nested_zendesk_translation']['title'].should eq 'Foo'
94
- end
59
+ context 'flatten title keys' do
60
+ it "should flatten hash by removing zendesk value keys" do
61
+ expected = {
62
+ "app.abc" => "description for abc field",
63
+ "a.a1" => "description for a1 field",
64
+ "a.b.b1" => "description for b1 field"
65
+ }
95
66
 
96
- it "value is correct parent with a child that has an invalid nested zendesk translation" do
97
- @app_translations['parent_with_nested_invalid_zendesk_translation']['title'].should eq({ "title" => "Bar", "desc" => "Foo" })
67
+ to_flattened_namespaced_hash(en_json, I18N_TITLE_KEY).should == expected
68
+ end
98
69
  end
99
-
100
70
  end
101
71
 
102
72
  end
103
73
 
74
+ describe '#remove_zendesk_keys' do
75
+ it "should remove zendesk translation keys" do
76
+ expected = {
77
+ "app" => {
78
+ "abc" => "value of abc"
79
+ },
80
+ "a" => {
81
+ "a1" => "value of a1",
82
+ "b" => {
83
+ "b1" => "value of b1"
84
+ }
85
+ }
86
+ }
87
+ remove_zendesk_keys(en_json).should == expected
88
+ end
89
+ end
104
90
  end
data/spec/i18n_spec.rb CHANGED
@@ -16,7 +16,7 @@ describe 'translations' do
16
16
  project_root = Pathname.new(File.expand_path('../../', __FILE__))
17
17
  zendesk_version = project_root.join('config/locales/translations/zendesk_apps_support.yml')
18
18
  standard_version = project_root.join('config/locales/en.yml')
19
- File.mtime(zendesk_version).should be <= File.mtime(standard_version)
19
+ File.mtime(zendesk_version).to_i.should be <= File.mtime(standard_version).to_i
20
20
  end
21
21
 
22
22
  end
@@ -0,0 +1,20 @@
1
+ {
2
+ "app": {
3
+ "package" : "my_app",
4
+ "abc" : {
5
+ "title" : "description for abc field",
6
+ "value" : "value of abc"
7
+ }
8
+ },
9
+ "a": {
10
+ "a1": {
11
+ "title": "description for a1 field",
12
+ "value": "value of a1"
13
+ },
14
+ "b": {
15
+ "b1": {
16
+ "value": "value of b1"
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "app": {
3
+ "package" : "my_app",
4
+ "abc" : {
5
+ "title" : "description for abc field",
6
+ "value" : "value of abc"
7
+ }
8
+ },
9
+ "a": {
10
+ "a1": {
11
+ "title": "description for a1 field",
12
+ "value": "value of a1"
13
+ },
14
+ "b": {
15
+ "b1": {
16
+ "title": "description for b1 field",
17
+ "value": "value of b1"
18
+ }
19
+ }
20
+ }
21
+ }
@@ -1,6 +1,10 @@
1
1
  require 'zendesk_apps_support'
2
2
  require 'json'
3
3
 
4
+ def read_fixture_file(file)
5
+ File.read("#{File.dirname(__FILE__)}/fixture/#{file}")
6
+ end
7
+
4
8
  describe ZendeskAppsSupport::Validations::Translations do
5
9
 
6
10
  let(:package) { mock('Package', :files => translation_files) }
@@ -15,7 +19,7 @@ describe ZendeskAppsSupport::Validations::Translations do
15
19
 
16
20
  context 'when there is file with invalid JSON' do
17
21
  let(:translation_files) do
18
- [ mock('AppFile', :relative_path => 'translations/en.json', :read => '}') ]
22
+ [mock('AppFile', :relative_path => 'translations/en.json', :read => '}')]
19
23
  end
20
24
 
21
25
  it 'should report the error' do
@@ -26,7 +30,7 @@ describe ZendeskAppsSupport::Validations::Translations do
26
30
 
27
31
  context 'when there is file with JSON representing a non-Object' do
28
32
  let(:translation_files) do
29
- [ mock('AppFile', :relative_path => 'translations/en.json', :read => '"foo bar"') ]
33
+ [mock('AppFile', :relative_path => 'translations/en.json', :read => '"foo bar"')]
30
34
  end
31
35
 
32
36
  it 'should report the error' do
@@ -37,7 +41,7 @@ describe ZendeskAppsSupport::Validations::Translations do
37
41
 
38
42
  context 'when there is a file with an invalid locale for a name' do
39
43
  let(:translation_files) do
40
- [ mock('AppFile', :relative_path => 'translations/en-US-1.json', :read => '{}') ]
44
+ [mock('AppFile', :relative_path => 'translations/en-US-1.json', :read => '{}')]
41
45
  end
42
46
 
43
47
  it 'should report the error' do
@@ -48,11 +52,34 @@ describe ZendeskAppsSupport::Validations::Translations do
48
52
 
49
53
  context 'when there is a file with a valid locale containing valid JSON' do
50
54
  let(:translation_files) do
51
- [ mock('AppFile', :relative_path => 'translations/en-US.json', :read => '{}') ]
55
+ [mock('AppFile', :relative_path => 'translations/en-US.json', :read => '{}')]
52
56
  end
53
57
 
54
58
  it 'should be valid' do
55
59
  subject.length.should == 0
56
60
  end
57
61
  end
58
- end
62
+
63
+ context 'validate translation format when "package" is defined inside "app"' do
64
+ context 'all the leaf nodes have defined "title" and "value"' do
65
+ let(:translation_files) do
66
+ [mock('AppFile', :relative_path => 'translations/en-US.json', :read => read_fixture_file("valid_en.json"))]
67
+ end
68
+
69
+ it 'should be valid' do
70
+ subject.length.should == 0
71
+ end
72
+ end
73
+
74
+ context 'when the "title" field is not defined on one leaf node' do
75
+ let(:translation_files) do
76
+ [mock('AppFile', :relative_path => 'translations/en-US.json', :read => read_fixture_file("invalid_en.json"))]
77
+ end
78
+
79
+ it 'should be invalid' do
80
+ subject.length.should == 1
81
+ subject[0].to_s.should =~ /is invalid for translation/
82
+ end
83
+ end
84
+ end
85
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zendesk_apps_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-10-28 00:00:00.000000000 Z
15
+ date: 2013-11-04 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: i18n
@@ -67,17 +67,17 @@ dependencies:
67
67
  requirement: !ruby/object:Gem::Requirement
68
68
  none: false
69
69
  requirements:
70
- - - ~>
70
+ - - ! '>='
71
71
  - !ruby/object:Gem::Version
72
- version: 1.7.7
72
+ version: '0'
73
73
  type: :runtime
74
74
  prerelease: false
75
75
  version_requirements: !ruby/object:Gem::Requirement
76
76
  none: false
77
77
  requirements:
78
- - - ~>
78
+ - - ! '>='
79
79
  - !ruby/object:Gem::Version
80
- version: 1.7.7
80
+ version: '0'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: erubis
83
83
  requirement: !ruby/object:Gem::Requirement
@@ -183,6 +183,8 @@ files:
183
183
  - spec/build_translation_spec.rb
184
184
  - spec/i18n_spec.rb
185
185
  - spec/package_spec.rb
186
+ - spec/validations/fixture/invalid_en.json
187
+ - spec/validations/fixture/valid_en.json
186
188
  - spec/validations/jshint_error_spec.rb
187
189
  - spec/validations/manifest_spec.rb
188
190
  - spec/validations/source_spec.rb
@@ -228,6 +230,8 @@ test_files:
228
230
  - spec/build_translation_spec.rb
229
231
  - spec/i18n_spec.rb
230
232
  - spec/package_spec.rb
233
+ - spec/validations/fixture/invalid_en.json
234
+ - spec/validations/fixture/valid_en.json
231
235
  - spec/validations/jshint_error_spec.rb
232
236
  - spec/validations/manifest_spec.rb
233
237
  - spec/validations/source_spec.rb