danger-localizationlinter 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +12 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +167 -0
- data/Guardfile +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +25 -0
- data/danger-localizationlinter.gemspec +60 -0
- data/ext/localizationlinter/helper/validate_wording_cli.rb +21 -0
- data/ext/localizationlinter/localizationlinter.rb +331 -0
- data/ext/localizationlinter/swiftgen_localizables_check.stencil +36 -0
- data/lib/danger_localizationlinter.rb +3 -0
- data/lib/danger_plugin.rb +3 -0
- data/lib/localizationlinter/gem_version.rb +5 -0
- data/lib/localizationlinter/plugin.rb +96 -0
- data/spec/Test/Podfile +6 -0
- data/spec/Test/Podfile.lock +16 -0
- data/spec/Test/Pods/SwiftGen/CHANGELOG.md +1357 -0
- data/spec/Test/Pods/SwiftGen/LICENCE +21 -0
- data/spec/Test/Pods/SwiftGen/README.md +892 -0
- data/spec/Test/Pods/SwiftGen/bin/swiftgen +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Commander +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/Commander +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/Commander +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Kanna +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/Kanna +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/Kanna +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/PathKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/PathKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/PathKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Stencil +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/Stencil +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/Stencil +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/StencilSwiftKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/StencilSwiftKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/StencilSwiftKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/SwiftGenKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/SwiftGenKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/SwiftGenKit +0 -0
- data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/Yams +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/Resources/Info.plist +48 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/Yams +0 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
- data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Yams +0 -0
- data/spec/Test/Pods/SwiftGen/templates/colors/literals-swift4.stencil +43 -0
- data/spec/Test/Pods/SwiftGen/templates/colors/literals-swift5.stencil +43 -0
- data/spec/Test/Pods/SwiftGen/templates/colors/swift4.stencil +84 -0
- data/spec/Test/Pods/SwiftGen/templates/colors/swift5.stencil +84 -0
- data/spec/Test/Pods/SwiftGen/templates/coredata/swift4.stencil +211 -0
- data/spec/Test/Pods/SwiftGen/templates/coredata/swift5.stencil +211 -0
- data/spec/Test/Pods/SwiftGen/templates/fonts/swift4.stencil +110 -0
- data/spec/Test/Pods/SwiftGen/templates/fonts/swift5.stencil +113 -0
- data/spec/Test/Pods/SwiftGen/templates/ib/scenes-swift4.stencil +157 -0
- data/spec/Test/Pods/SwiftGen/templates/ib/scenes-swift5.stencil +159 -0
- data/spec/Test/Pods/SwiftGen/templates/ib/segues-swift4.stencil +60 -0
- data/spec/Test/Pods/SwiftGen/templates/ib/segues-swift5.stencil +60 -0
- data/spec/Test/Pods/SwiftGen/templates/json/inline-swift4.stencil +82 -0
- data/spec/Test/Pods/SwiftGen/templates/json/inline-swift5.stencil +82 -0
- data/spec/Test/Pods/SwiftGen/templates/json/runtime-swift4.stencil +112 -0
- data/spec/Test/Pods/SwiftGen/templates/json/runtime-swift5.stencil +112 -0
- data/spec/Test/Pods/SwiftGen/templates/plist/inline-swift4.stencil +82 -0
- data/spec/Test/Pods/SwiftGen/templates/plist/inline-swift5.stencil +82 -0
- data/spec/Test/Pods/SwiftGen/templates/plist/runtime-swift4.stencil +117 -0
- data/spec/Test/Pods/SwiftGen/templates/plist/runtime-swift5.stencil +117 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/flat-swift4.stencil +97 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/flat-swift5.stencil +97 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/objc-h.stencil +66 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/objc-m.stencil +90 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/structured-swift4.stencil +102 -0
- data/spec/Test/Pods/SwiftGen/templates/strings/structured-swift5.stencil +102 -0
- data/spec/Test/Pods/SwiftGen/templates/xcassets/swift4.stencil +266 -0
- data/spec/Test/Pods/SwiftGen/templates/xcassets/swift5.stencil +274 -0
- data/spec/Test/Pods/SwiftGen/templates/yaml/inline-swift4.stencil +92 -0
- data/spec/Test/Pods/SwiftGen/templates/yaml/inline-swift5.stencil +92 -0
- data/spec/Test/Test.xcodeproj/project.pbxproj +406 -0
- data/spec/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/spec/Test/Test.xcworkspace/contents.xcworkspacedata +10 -0
- data/spec/Test/Test.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/spec/Test/Test/AppDelegate.swift +36 -0
- data/spec/Test/Test/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- data/spec/Test/Test/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
- data/spec/Test/Test/Assets.xcassets/Contents.json +6 -0
- data/spec/Test/Test/ContentView.swift +21 -0
- data/spec/Test/Test/Info.plist +62 -0
- data/spec/Test/Test/SceneDelegate.swift +63 -0
- data/spec/Test/Test/all_target_main_language.yml +1 -0
- data/spec/Test/Test/en.lproj/LaunchScreen.storyboard +25 -0
- data/spec/Test/Test/en.lproj/localizable.strings +3 -0
- data/spec/Test/Test/fr.lproj/LaunchScreen.storyboard +25 -0
- data/spec/Test/Test/fr.lproj/localizable.strings +3 -0
- data/spec/localizationofficer_spec.rb +116 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/fixtures/all_target_main_language.yml +1 -0
- data/spec/support/fixtures/resources/TEST/en.lproj/Localizable.strings +8 -0
- data/spec/support/fixtures/resources/TEST/en.lproj/Localizable.stringsdict +30 -0
- data/spec/support/fixtures/resources/TEST_KO/en.lproj/Localizable.strings +11 -0
- data/spec/support/fixtures/resources/TEST_KO/en.lproj/Localizable.stringsdict +30 -0
- data/spec/support/fixtures/resources/TEST_KO/fr.lproj/Localizable.strings +11 -0
- data/spec/support/fixtures/resources/TEST_KO/fr.lproj/Localizable.stringsdict +30 -0
- metadata +491 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0a4afdaf597ba934bea40d09e3b0fd3648a224466512c2c24b676093cce3ee40
|
4
|
+
data.tar.gz: 4c69e69f4e56d1eaf50933469c97c18522b5d4db9347a1a3551144b75eeb4fe1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2a9728aa8b54a0120d00986eaa34321beb6109228f948cdff0c0c558465c7a7e0263811293c35a35cac3b302d727362887370dea1c0ec1ee5e055d17d0da48b0
|
7
|
+
data.tar.gz: ba9a05927c1ef36c54386dae856b16099cd202b9052c4319d075fb2744ff1a5f563f4f12f9216c098a253e2bf8764128e17f579bb7e3911ddca66d383c56af5b
|
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
.DS_Store
|
2
|
+
pkg
|
3
|
+
.idea/
|
4
|
+
.yardoc
|
5
|
+
|
6
|
+
## Various iOS settings
|
7
|
+
*.pbxuser
|
8
|
+
!default.pbxuser
|
9
|
+
*.mode1v3
|
10
|
+
!default.mode1v3
|
11
|
+
*.mode2v3
|
12
|
+
!default.mode2v3
|
13
|
+
*.perspectivev3
|
14
|
+
!default.perspectivev3
|
15
|
+
xcuserdata
|
16
|
+
spec/Test/Pods/*
|
17
|
+
!spec/Test/Pods/SwiftGen/
|
18
|
+
|
19
|
+
## Derived data
|
20
|
+
spec/support/fixtures/derived_data
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
danger-localizationlinter (0.0.1)
|
5
|
+
danger-plugin-api (~> 1.0)
|
6
|
+
json-diff (~> 0.4)
|
7
|
+
xcodeproj (~> 1.19)
|
8
|
+
yaml (~> 0.1)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
CFPropertyList (3.0.3)
|
14
|
+
addressable (2.7.0)
|
15
|
+
public_suffix (>= 2.0.2, < 5.0)
|
16
|
+
ast (2.4.2)
|
17
|
+
atomos (0.1.3)
|
18
|
+
claide (1.0.3)
|
19
|
+
claide-plugins (0.9.2)
|
20
|
+
cork
|
21
|
+
nap
|
22
|
+
open4 (~> 1.3)
|
23
|
+
coderay (1.1.3)
|
24
|
+
colored2 (3.1.2)
|
25
|
+
cork (0.3.0)
|
26
|
+
colored2 (~> 3.1)
|
27
|
+
danger (8.2.3)
|
28
|
+
claide (~> 1.0)
|
29
|
+
claide-plugins (>= 0.9.2)
|
30
|
+
colored2 (~> 3.1)
|
31
|
+
cork (~> 0.1)
|
32
|
+
faraday (>= 0.9.0, < 2.0)
|
33
|
+
faraday-http-cache (~> 2.0)
|
34
|
+
git (~> 1.7)
|
35
|
+
kramdown (~> 2.3)
|
36
|
+
kramdown-parser-gfm (~> 1.0)
|
37
|
+
no_proxy_fix
|
38
|
+
octokit (~> 4.7)
|
39
|
+
terminal-table (>= 1, < 4)
|
40
|
+
danger-plugin-api (1.0.0)
|
41
|
+
danger (> 2.0)
|
42
|
+
diff-lcs (1.4.4)
|
43
|
+
faraday (1.4.1)
|
44
|
+
faraday-excon (~> 1.1)
|
45
|
+
faraday-net_http (~> 1.0)
|
46
|
+
faraday-net_http_persistent (~> 1.1)
|
47
|
+
multipart-post (>= 1.2, < 3)
|
48
|
+
ruby2_keywords (>= 0.0.4)
|
49
|
+
faraday-excon (1.1.0)
|
50
|
+
faraday-http-cache (2.2.0)
|
51
|
+
faraday (>= 0.8)
|
52
|
+
faraday-net_http (1.0.1)
|
53
|
+
faraday-net_http_persistent (1.1.0)
|
54
|
+
ffi (1.15.0)
|
55
|
+
formatador (0.2.5)
|
56
|
+
git (1.8.1)
|
57
|
+
rchardet (~> 1.8)
|
58
|
+
guard (2.16.2)
|
59
|
+
formatador (>= 0.2.4)
|
60
|
+
listen (>= 2.7, < 4.0)
|
61
|
+
lumberjack (>= 1.0.12, < 2.0)
|
62
|
+
nenv (~> 0.1)
|
63
|
+
notiffany (~> 0.0)
|
64
|
+
pry (>= 0.9.12)
|
65
|
+
shellany (~> 0.0)
|
66
|
+
thor (>= 0.18.1)
|
67
|
+
guard-compat (1.2.1)
|
68
|
+
guard-rspec (4.7.3)
|
69
|
+
guard (~> 2.1)
|
70
|
+
guard-compat (~> 1.1)
|
71
|
+
rspec (>= 2.99.0, < 4.0)
|
72
|
+
json-diff (0.4.1)
|
73
|
+
kramdown (2.3.1)
|
74
|
+
rexml
|
75
|
+
kramdown-parser-gfm (1.1.0)
|
76
|
+
kramdown (~> 2.0)
|
77
|
+
listen (3.0.7)
|
78
|
+
rb-fsevent (>= 0.9.3)
|
79
|
+
rb-inotify (>= 0.9.7)
|
80
|
+
lumberjack (1.2.8)
|
81
|
+
method_source (1.0.0)
|
82
|
+
multipart-post (2.1.1)
|
83
|
+
nanaimo (0.3.0)
|
84
|
+
nap (1.1.0)
|
85
|
+
nenv (0.3.0)
|
86
|
+
no_proxy_fix (0.1.2)
|
87
|
+
notiffany (0.1.3)
|
88
|
+
nenv (~> 0.1)
|
89
|
+
shellany (~> 0.0)
|
90
|
+
octokit (4.21.0)
|
91
|
+
faraday (>= 0.9)
|
92
|
+
sawyer (~> 0.8.0, >= 0.5.3)
|
93
|
+
open4 (1.3.4)
|
94
|
+
parallel (1.20.1)
|
95
|
+
parser (3.0.0.0)
|
96
|
+
ast (~> 2.4.1)
|
97
|
+
pry (0.14.0)
|
98
|
+
coderay (~> 1.1)
|
99
|
+
method_source (~> 1.0)
|
100
|
+
public_suffix (4.0.6)
|
101
|
+
rainbow (3.0.0)
|
102
|
+
rake (10.5.0)
|
103
|
+
rb-fsevent (0.10.4)
|
104
|
+
rb-inotify (0.10.1)
|
105
|
+
ffi (~> 1.0)
|
106
|
+
rchardet (1.8.0)
|
107
|
+
regexp_parser (2.1.1)
|
108
|
+
rexml (3.2.4)
|
109
|
+
rspec (3.10.0)
|
110
|
+
rspec-core (~> 3.10.0)
|
111
|
+
rspec-expectations (~> 3.10.0)
|
112
|
+
rspec-mocks (~> 3.10.0)
|
113
|
+
rspec-core (3.10.1)
|
114
|
+
rspec-support (~> 3.10.0)
|
115
|
+
rspec-expectations (3.10.1)
|
116
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
117
|
+
rspec-support (~> 3.10.0)
|
118
|
+
rspec-mocks (3.10.2)
|
119
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
120
|
+
rspec-support (~> 3.10.0)
|
121
|
+
rspec-support (3.10.2)
|
122
|
+
rubocop (1.12.0)
|
123
|
+
parallel (~> 1.10)
|
124
|
+
parser (>= 3.0.0.0)
|
125
|
+
rainbow (>= 2.2.2, < 4.0)
|
126
|
+
regexp_parser (>= 1.8, < 3.0)
|
127
|
+
rexml
|
128
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
129
|
+
ruby-progressbar (~> 1.7)
|
130
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
131
|
+
rubocop-ast (1.4.1)
|
132
|
+
parser (>= 2.7.1.5)
|
133
|
+
ruby-progressbar (1.11.0)
|
134
|
+
ruby2_keywords (0.0.4)
|
135
|
+
sawyer (0.8.2)
|
136
|
+
addressable (>= 2.3.5)
|
137
|
+
faraday (> 0.8, < 2.0)
|
138
|
+
shellany (0.0.1)
|
139
|
+
terminal-table (1.6.0)
|
140
|
+
thor (1.1.0)
|
141
|
+
unicode-display_width (2.0.0)
|
142
|
+
xcodeproj (1.19.0)
|
143
|
+
CFPropertyList (>= 2.3.3, < 4.0)
|
144
|
+
atomos (~> 0.1.3)
|
145
|
+
claide (>= 1.0.2, < 2.0)
|
146
|
+
colored2 (~> 3.1)
|
147
|
+
nanaimo (~> 0.3.0)
|
148
|
+
yaml (0.1.1)
|
149
|
+
yard (0.9.26)
|
150
|
+
|
151
|
+
PLATFORMS
|
152
|
+
ruby
|
153
|
+
|
154
|
+
DEPENDENCIES
|
155
|
+
bundler (~> 2.0)
|
156
|
+
danger-localizationlinter!
|
157
|
+
guard (~> 2.14)
|
158
|
+
guard-rspec (~> 4.7)
|
159
|
+
listen (= 3.0.7)
|
160
|
+
pry
|
161
|
+
rake (~> 10.0)
|
162
|
+
rspec (~> 3.4)
|
163
|
+
rubocop
|
164
|
+
yard
|
165
|
+
|
166
|
+
BUNDLED WITH
|
167
|
+
2.1.4
|
data/Guardfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A guardfile for making Danger Plugins
|
4
|
+
# For more info see https://github.com/guard/guard#readme
|
5
|
+
|
6
|
+
# To run, use `bundle exec guard`.
|
7
|
+
|
8
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
9
|
+
require 'guard/rspec/dsl'
|
10
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
11
|
+
|
12
|
+
# RSpec files
|
13
|
+
rspec = dsl.rspec
|
14
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
15
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
16
|
+
watch(rspec.spec_files)
|
17
|
+
|
18
|
+
# Ruby files
|
19
|
+
ruby = dsl.ruby
|
20
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
21
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2021 Benjamin Lavialle <benjamin.lavialle@fabernovel.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# danger-localizationlinter
|
2
|
+
|
3
|
+
Verify consistency over your project localizable files (localizable.strings and Localizable.stringdict)
|
4
|
+
It uses Swiftgen to generate a localizables output per target and language and compare the output with
|
5
|
+
a reference language one.
|
6
|
+
The comparison ensure:
|
7
|
+
- missing keys
|
8
|
+
- additional keys
|
9
|
+
- wrong parameters in string format
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
$ gem install danger-localizationlinter
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Methods and attributes from this plugin are available in your `Dangerfile` under the `localizationlinter` namespace.
|
18
|
+
|
19
|
+
localizationlinter.lint
|
20
|
+
|
21
|
+
#### Attributes
|
22
|
+
|
23
|
+
`clean_after_execution` - Keep or clean derived data after execution
|
24
|
+
|
25
|
+
`inline_mode` - Print inline or as markdown
|
26
|
+
|
27
|
+
`verbose` - Print execution logs
|
28
|
+
|
29
|
+
`language_configuration_path` - Path to language configuration yml, defining main language per target
|
30
|
+
example:
|
31
|
+
My_target: en
|
32
|
+
My_other_target: fr
|
33
|
+
|
34
|
+
default value is Configuration/Defaults/all_target_main_language.yml
|
35
|
+
|
36
|
+
`swift_gen_path` - Path to swift gen, default value is Pods/SwiftGen/bin/swiftgen
|
37
|
+
|
38
|
+
`derived_data_path` - Path to derived data, default value is localization_linter_derived_data
|
39
|
+
|
40
|
+
`resource_path` - Path to derived data, default value is Resources
|
41
|
+
|
42
|
+
`project_path` - Path to xcode project, default is taking the first project in root folder
|
43
|
+
|
44
|
+
#### Methods
|
45
|
+
|
46
|
+
`lint` - Verify the localizable files integrity over the project
|
47
|
+
rubocop:disable Metrics/MethodLength
|
48
|
+
|
49
|
+
`linter` - Returns the object in charge of verification
|
50
|
+
|
51
|
+
## Development
|
52
|
+
|
53
|
+
1. Clone this repo
|
54
|
+
2. Run `bundle install` to setup dependencies.
|
55
|
+
3. Run `bundle exec rake spec` to run the tests.
|
56
|
+
4. Use `bundle exec guard` to automatically have tests run as you make changes.
|
57
|
+
5. Make your changes.
|
58
|
+
|
59
|
+
To update swiftgen bin, use Test project in `spec`:
|
60
|
+
1. `cd spec/Test`
|
61
|
+
2. Open Podfile and update SwiftGen version
|
62
|
+
3. `pod update SwiftGen`
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:specs)
|
8
|
+
|
9
|
+
task default: :specs
|
10
|
+
|
11
|
+
task :spec do
|
12
|
+
Rake::Task['specs'].invoke
|
13
|
+
Rake::Task['rubocop'].invoke
|
14
|
+
Rake::Task['spec_docs'].invoke
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run RuboCop on the lib/specs directory'
|
18
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
19
|
+
task.patterns = ['lib/**/*.rb', 'spec/**/*.rb']
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Ensure that the plugin passes `danger plugins lint`'
|
23
|
+
task :spec_docs do
|
24
|
+
sh 'bundle exec danger plugins lint'
|
25
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'localizationlinter/gem_version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'danger-localizationlinter'
|
9
|
+
spec.version = Localizationlinter::VERSION
|
10
|
+
spec.authors = ['Fabernovel']
|
11
|
+
spec.email = ['benjamin.lavialle@fabernovel.com', 'claire.peyron@fabernovel.com']
|
12
|
+
spec.description = 'This is a danger plugin checking the consistency of localizable folders in a xcode project'
|
13
|
+
spec.summary = 'Verify consistency over your project localizable files (localizable.strings and Localizable.stringdict).
|
14
|
+
It uses Swiftgen to generate a localizables output per target and language and compare the output with a reference language one.
|
15
|
+
The comparison ensure:
|
16
|
+
- missing keys
|
17
|
+
- additional keys
|
18
|
+
- wrong parameters in string format
|
19
|
+
'
|
20
|
+
spec.homepage = 'https://github.com/fabernovel/danger-localizationlinter'
|
21
|
+
spec.license = 'MIT'
|
22
|
+
|
23
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
24
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
25
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'danger-plugin-api', '~> 1.0'
|
29
|
+
|
30
|
+
spec.add_dependency 'yaml', '~> 0.1'
|
31
|
+
spec.add_dependency 'json-diff', '~> 0.4'
|
32
|
+
spec.add_dependency 'xcodeproj', '~> 1.19'
|
33
|
+
|
34
|
+
# General ruby development
|
35
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
36
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
37
|
+
|
38
|
+
# Testing support
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
40
|
+
|
41
|
+
# Linting code and docs
|
42
|
+
spec.add_development_dependency 'rubocop'
|
43
|
+
spec.add_development_dependency 'yard'
|
44
|
+
|
45
|
+
# Makes testing easy via `bundle exec guard`
|
46
|
+
spec.add_development_dependency 'guard', '~> 2.14'
|
47
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
48
|
+
|
49
|
+
# If you want to work on older builds of ruby
|
50
|
+
spec.add_development_dependency 'listen', '3.0.7'
|
51
|
+
|
52
|
+
# This gives you the chance to run a REPL inside your tests
|
53
|
+
# via:
|
54
|
+
#
|
55
|
+
# require 'pry'
|
56
|
+
# binding.pry
|
57
|
+
#
|
58
|
+
# This will stop test execution and let you inspect the results
|
59
|
+
spec.add_development_dependency 'pry'
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../localizationlinter'
|
4
|
+
|
5
|
+
linter = LocalizationLinter.new(
|
6
|
+
ARGV[0],
|
7
|
+
ARGV[1],
|
8
|
+
ARGV[2],
|
9
|
+
ARGV[3],
|
10
|
+
ARGV[4],
|
11
|
+
ARGV[5],
|
12
|
+
ARGV[6]
|
13
|
+
)
|
14
|
+
message = linter.find_differences.map do |difference|
|
15
|
+
"#{difference[:filename]}:#{difference[:line]} #{difference[:message]}"
|
16
|
+
end
|
17
|
+
if message.empty?
|
18
|
+
puts 'Localization Linter ran with success'
|
19
|
+
else
|
20
|
+
puts "Localization Linter errors:\n#{message.join("\n")}"
|
21
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json-diff'
|
4
|
+
require 'yaml'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'xcodeproj'
|
7
|
+
|
8
|
+
class LocalizationLinter
|
9
|
+
def initialize(
|
10
|
+
verbose = nil,
|
11
|
+
clean_after_execution = nil,
|
12
|
+
language_configuration_path = nil,
|
13
|
+
swift_gen_path = nil,
|
14
|
+
derived_data_path = nil,
|
15
|
+
resource_path = nil,
|
16
|
+
project_path = nil
|
17
|
+
)
|
18
|
+
@verbose = !verbose.nil? || verbose == 'true' || verbose == true
|
19
|
+
@clean_after_execution = !clean_after_execution.nil? || clean_after_execution == 'true' || clean_after_execution == true
|
20
|
+
@language_configuration_path = language_configuration_path
|
21
|
+
@swift_gen_path = swift_gen_path
|
22
|
+
@derived_data_path = derived_data_path
|
23
|
+
@resource_path = resource_path
|
24
|
+
@project_path = project_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_differences
|
28
|
+
clean_derived_data
|
29
|
+
create_derived_data_folder
|
30
|
+
log "Validating wording for targets: #{all_targets.join ', '}"
|
31
|
+
differences = all_targets.map { |target| check_missing_keys_in_target(target) }.compact.flatten
|
32
|
+
clean_derived_data if @clean_after_execution
|
33
|
+
differences
|
34
|
+
end
|
35
|
+
|
36
|
+
def log(text)
|
37
|
+
puts(text) if @verbose
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_missing_keys_in_target(target)
|
41
|
+
log "Starting wording validation for #{target}"
|
42
|
+
main_region = main_region_for_target(target)
|
43
|
+
if main_region.nil?
|
44
|
+
return {
|
45
|
+
filename: 'General',
|
46
|
+
message: "Missing main region for target #{target}"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
log "Found main region #{main_region} for #{target}"
|
51
|
+
unless known_regions.include? main_region
|
52
|
+
return {
|
53
|
+
filename: 'General',
|
54
|
+
message: "Missing main region #{main_region} in Project"
|
55
|
+
}
|
56
|
+
end
|
57
|
+
known_regions.each { |region| write_l10n_check_file(target, region) }
|
58
|
+
main_file_name = temporary_localizable_check_file_path(target, main_region)
|
59
|
+
log "Taking #{main_file_name} as reference for #{target}"
|
60
|
+
unless File.exist?(main_file_name)
|
61
|
+
return {
|
62
|
+
filename: 'General',
|
63
|
+
message: "Target #{target} doesn't localize for main region #{main_region}"
|
64
|
+
}
|
65
|
+
end
|
66
|
+
log "Found file for main region #{main_region} for #{target}"
|
67
|
+
main_file_hash = get_hash(main_file_name)
|
68
|
+
errors = known_regions.map do |region|
|
69
|
+
begin
|
70
|
+
check_missing_key(target, region, main_region, main_file_hash)
|
71
|
+
rescue CheckMissingKeyNotNeeded
|
72
|
+
next
|
73
|
+
end
|
74
|
+
end.compact
|
75
|
+
errors.flatten.compact unless errors.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
## Tools
|
79
|
+
|
80
|
+
class CheckMissingKeyNotNeeded < StandardError
|
81
|
+
end
|
82
|
+
|
83
|
+
class IsMainRegion < CheckMissingKeyNotNeeded
|
84
|
+
end
|
85
|
+
|
86
|
+
class MissingFileForRegion < CheckMissingKeyNotNeeded
|
87
|
+
def initialize(msg="")
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class RegionHashIdenticalAsMainOne < CheckMissingKeyNotNeeded
|
93
|
+
def initialize(msg="")
|
94
|
+
super
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class RegionHasNoDiffError < CheckMissingKeyNotNeeded
|
99
|
+
def initialize(msg="")
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_missing_key(target, region, main_region, main_file_hash)
|
105
|
+
raise IsMainRegion if region == main_region
|
106
|
+
message = "#{target}_#{region}"
|
107
|
+
|
108
|
+
file_name = temporary_localizable_check_file_path(target, region)
|
109
|
+
raise MissingFileForRegion, message unless File.exist?(file_name)
|
110
|
+
file_hash = get_hash(file_name)
|
111
|
+
raise RegionHashIdenticalAsMainOne, message unless file_hash != main_file_hash
|
112
|
+
|
113
|
+
log "Computing diff for #{region} with file: #{file_name}"
|
114
|
+
previous_diff = {}
|
115
|
+
previous_previous_diff = {}
|
116
|
+
diffs = JsonDiff.diff(file_hash, main_file_hash)
|
117
|
+
last_diff = diffs.last
|
118
|
+
current_errors = []
|
119
|
+
diffs.each do |diff|
|
120
|
+
current_errors << handle_previous_diff(diff, previous_diff, previous_previous_diff)
|
121
|
+
current_errors << handle_last_diff(diff, previous_diff) if diff == last_diff
|
122
|
+
previous_previous_diff = previous_diff
|
123
|
+
previous_diff = diff
|
124
|
+
end
|
125
|
+
if current_errors.empty?
|
126
|
+
log "Did not found any diff for #{region}"
|
127
|
+
else
|
128
|
+
log "Found #{current_errors.size} diffs:#{current_errors.join "\n"}"
|
129
|
+
end
|
130
|
+
raise RegionHasNoDiffError, message if current_errors.compact.empty?
|
131
|
+
|
132
|
+
current_errors.compact.map do |error|
|
133
|
+
parse_error_with_file_and_line(error, localizable_directory(target, region))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def parse_error_with_file_and_line(error, directory)
|
138
|
+
final_key = error[:key].gsub('/L10n/', '').split('/').first
|
139
|
+
line_vs_file = find_line(final_key, directory)
|
140
|
+
{
|
141
|
+
filename: line_vs_file[1],
|
142
|
+
key: final_key,
|
143
|
+
line: line_vs_file[0],
|
144
|
+
message: error[:message]
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def find_line(key, directory)
|
149
|
+
result = [0, '']
|
150
|
+
Dir.foreach(directory) do |filename|
|
151
|
+
next if (filename == '.') || (filename == '..') || (result[0] != 0)
|
152
|
+
|
153
|
+
global = "#{directory}/#{filename}"
|
154
|
+
result = [0, global] unless result != [0, '']
|
155
|
+
File.foreach(global).with_index do |line, index|
|
156
|
+
next if result[0] != 0
|
157
|
+
|
158
|
+
result = [index + 1, global] if line.include? key
|
159
|
+
end
|
160
|
+
end
|
161
|
+
result
|
162
|
+
end
|
163
|
+
|
164
|
+
def write_l10n_check_file(target, language)
|
165
|
+
unless File.directory?(localizable_directory(target, language))
|
166
|
+
log "Target #{target} doesn't localize for region #{language}"
|
167
|
+
return
|
168
|
+
end
|
169
|
+
File.open(swiftgen_check_config_path, 'w') { |file| file.write(swiftgen_check_config(target, language).to_yaml) }
|
170
|
+
system("#{swift_gen_path} config run --config #{swiftgen_check_config_path}")
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_hash(name)
|
174
|
+
trim = File.read(name).gsub(/[[:space:]]/, '').gsub(',}', '}')
|
175
|
+
JSON.parse(trim)
|
176
|
+
end
|
177
|
+
|
178
|
+
def main_region_for_target(target)
|
179
|
+
path = language_configuration_path
|
180
|
+
return "File #{path} does not exist." unless File.exist?(path)
|
181
|
+
|
182
|
+
languages = YAML.safe_load(File.read(path)) || {}
|
183
|
+
unless languages[target]
|
184
|
+
log "Missing main region for #{target} in file #{path}, put the same one as in Swiftgen Localizables build phase"
|
185
|
+
return nil
|
186
|
+
end
|
187
|
+
|
188
|
+
languages[target]
|
189
|
+
end
|
190
|
+
|
191
|
+
# Errors
|
192
|
+
|
193
|
+
def handle_previous_diff(diff, previous_diff, previous_previous_diff)
|
194
|
+
case previous_diff['op']
|
195
|
+
when 'remove'
|
196
|
+
useless_key(previous_diff) if previous_diff['path'] != diff['path']
|
197
|
+
when 'add'
|
198
|
+
if previous_diff['path'] != diff['path']
|
199
|
+
if (previous_previous_diff != {}) && (previous_previous_diff['path'] != previous_diff['path'])
|
200
|
+
missing_key(previous_diff)
|
201
|
+
else
|
202
|
+
bad_parameter(previous_diff)
|
203
|
+
end
|
204
|
+
else
|
205
|
+
bad_parameter(previous_diff)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def handle_last_diff(diff, previous_diff)
|
211
|
+
if previous_diff['path'] != diff['path']
|
212
|
+
if diff['op'] == 'remove'
|
213
|
+
useless_key(diff)
|
214
|
+
else
|
215
|
+
missing_key(diff)
|
216
|
+
end
|
217
|
+
else
|
218
|
+
bad_parameter(diff)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def useless_key(diff)
|
223
|
+
{
|
224
|
+
key: diff['path'],
|
225
|
+
message: "useless key: #{diff['path']}"
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
229
|
+
def missing_key(diff)
|
230
|
+
{
|
231
|
+
key: diff['path'],
|
232
|
+
message: "missing key: #{diff['path']}"
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
def bad_parameter(diff)
|
237
|
+
{
|
238
|
+
key: diff['path'],
|
239
|
+
message: "wrong parameters in key: #{diff['path']}/#{diff['value']}"
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
243
|
+
## Paths
|
244
|
+
|
245
|
+
def localizable_directory(target, language)
|
246
|
+
"#{resource_path}/#{target}/#{language}.lproj"
|
247
|
+
end
|
248
|
+
|
249
|
+
def swiftgen_check_config_path
|
250
|
+
"#{derived_data_path}/swiftgen_check_config.yml"
|
251
|
+
end
|
252
|
+
|
253
|
+
def temporary_localizable_check_file_path(target, region)
|
254
|
+
"#{derived_data_path}/#{target}_#{region}"
|
255
|
+
end
|
256
|
+
|
257
|
+
def derived_data_path
|
258
|
+
@derived_data_path || 'localization_linter_derived_data'
|
259
|
+
end
|
260
|
+
|
261
|
+
def resource_path
|
262
|
+
@resource_path || 'Resources'
|
263
|
+
end
|
264
|
+
|
265
|
+
def swift_gen_path
|
266
|
+
@swift_gen_path || 'Pods/SwiftGen/bin/swiftgen'
|
267
|
+
end
|
268
|
+
|
269
|
+
def language_configuration_path
|
270
|
+
@language_configuration_path || 'Configuration/Defaults/all_target_main_language.yml'
|
271
|
+
end
|
272
|
+
|
273
|
+
def stencil_path
|
274
|
+
"#{File.expand_path(File.dirname(__FILE__))}/swiftgen_localizables_check.stencil"
|
275
|
+
end
|
276
|
+
|
277
|
+
def upper_path(path)
|
278
|
+
return "../#{path}" unless path.start_with?('/')
|
279
|
+
return path
|
280
|
+
end
|
281
|
+
|
282
|
+
## Derived data
|
283
|
+
|
284
|
+
def create_derived_data_folder
|
285
|
+
Dir.mkdir derived_data_path
|
286
|
+
end
|
287
|
+
|
288
|
+
def clean_derived_data
|
289
|
+
FileUtils.rm_rf(derived_data_path)
|
290
|
+
end
|
291
|
+
|
292
|
+
## config
|
293
|
+
|
294
|
+
def swiftgen_check_config(target, language)
|
295
|
+
{
|
296
|
+
'strings' => {
|
297
|
+
'inputs' => [
|
298
|
+
"#{upper_path(localizable_directory(target, language))}"
|
299
|
+
],
|
300
|
+
'outputs' => [{
|
301
|
+
'templatePath' => stencil_path,
|
302
|
+
'output' => "#{upper_path(temporary_localizable_check_file_path(target, language))}",
|
303
|
+
'params' => {
|
304
|
+
'publicAccess' => true
|
305
|
+
}
|
306
|
+
}]
|
307
|
+
}
|
308
|
+
}
|
309
|
+
end
|
310
|
+
|
311
|
+
## project
|
312
|
+
|
313
|
+
def project_path
|
314
|
+
@project_path || Dir.glob('*.xcodeproj').first
|
315
|
+
end
|
316
|
+
|
317
|
+
def project
|
318
|
+
Xcodeproj::Project.open(project_path)
|
319
|
+
end
|
320
|
+
|
321
|
+
def all_targets
|
322
|
+
project
|
323
|
+
.targets
|
324
|
+
.filter { |t| t.product_type == 'com.apple.product-type.application' }
|
325
|
+
.map(&:name)
|
326
|
+
end
|
327
|
+
|
328
|
+
def known_regions
|
329
|
+
project.root_object.known_regions
|
330
|
+
end
|
331
|
+
end
|