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.
- data/config/locales/en.yml +1 -0
- data/config/locales/translations/zendesk_apps_support.yml +4 -0
- data/lib/zendesk_apps_support/build_translation.rb +8 -13
- data/lib/zendesk_apps_support/validations/translations.rb +30 -3
- data/spec/build_translation_spec.rb +61 -75
- data/spec/i18n_spec.rb +1 -1
- data/spec/validations/fixture/invalid_en.json +20 -0
- data/spec/validations/fixture/valid_en.json +21 -0
- data/spec/validations/translations_spec.rb +32 -5
- metadata +10 -6
data/config/locales/en.yml
CHANGED
@@ -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
|
5
|
-
I18N_VALUE_KEY
|
6
|
-
I18N_KEYS
|
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 = [
|
12
|
-
|
10
|
+
key = [prefix, key].compact.join('.')
|
13
11
|
if value.kind_of?(Hash)
|
14
|
-
|
15
|
-
|
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(
|
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
|
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
|
-
|
29
|
-
|
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
|
-
"
|
10
|
-
|
11
|
-
|
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
|
-
"
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
"
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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 '#
|
49
|
-
|
50
|
-
context "
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
89
|
-
|
55
|
+
to_flattened_namespaced_hash(en_json, I18N_VALUE_KEY).should == expected
|
56
|
+
end
|
90
57
|
end
|
91
58
|
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
97
|
-
|
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
|
-
[
|
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
|
-
[
|
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
|
-
[
|
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
|
-
[
|
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
|
-
|
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.
|
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-
|
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:
|
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:
|
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
|