ad_localize 4.0.7 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +123 -57
- data/Gemfile.lock +46 -44
- data/README.md +26 -24
- data/ad_localize.gemspec +1 -1
- data/lib/ad_localize/entities/key.rb +6 -1
- data/lib/ad_localize/entities/translation.rb +12 -0
- data/lib/ad_localize/interactors/export_g_spreadsheet.rb +5 -1
- data/lib/ad_localize/interactors/export_wording.rb +9 -5
- data/lib/ad_localize/interactors/platforms/export_android_locale_wording.rb +4 -0
- data/lib/ad_localize/interactors/platforms/export_csv_locale_wording.rb +25 -0
- data/lib/ad_localize/interactors/platforms/export_ios_locale_wording.rb +4 -0
- data/lib/ad_localize/interactors/platforms/export_json_locale_wording.rb +4 -0
- data/lib/ad_localize/interactors/platforms/export_platform_factory.rb +6 -0
- data/lib/ad_localize/interactors/platforms/export_properties_locale_wording.rb +4 -0
- data/lib/ad_localize/interactors/platforms/export_yaml_locale_wording.rb +4 -0
- data/lib/ad_localize/mappers/csv_path_to_wording.rb +5 -8
- data/lib/ad_localize/mappers/locale_wording_to_hash.rb +8 -0
- data/lib/ad_localize/mappers/value_range_to_wording.rb +6 -8
- data/lib/ad_localize/requests/export_request.rb +15 -2
- data/lib/ad_localize/serializers/strings_serializer.rb +4 -2
- data/lib/ad_localize/validators/key_validator.rb +31 -0
- data/lib/ad_localize/version.rb +1 -1
- data/lib/ad_localize/view_models/translation_group_view_model.rb +4 -0
- data/lib/ad_localize/view_models/translation_view_model.rb +4 -0
- data/lib/ad_localize.rb +2 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1a18c57ba71812f3a373cb5b5904b784cf2855f444b1cf979a6c854db3d585b
|
4
|
+
data.tar.gz: aa1199ab974d906eb9b3bad2b319601709251632e42d13965dded74fa4a9384e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b7c19e962e871d0248443ba4a64f53a4f7a4348c63cbee07fabdeb2e020d97a8f9d6ae3beff1e46f89347c252615510c003b8cec30c96f93dde9c938e786374
|
7
|
+
data.tar.gz: 12eaeeded22193ea3c0e5e6a6fc5c4bf9faece87cb4c33811452b0bfa44bb73ca448c3665a26930d824acf724701c85e7e49a045974ca9d470c4da4c1d226051
|
data/CHANGELOG.md
CHANGED
@@ -1,143 +1,209 @@
|
|
1
1
|
# Changelog
|
2
|
+
|
2
3
|
All notable changes to this project will be documented in this file.
|
3
4
|
|
4
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
7
|
|
8
|
+
## [4.1.0] - 2022-03-02
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Do not export empty translation on Android in PR [#72](https://github.com/faberNovel/ad_localize/pull/72)
|
13
|
+
|
14
|
+
|
15
|
+
## [4.0.9] - 2021-09-05
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- Fix error warning when spreadsheet is empty. Fix [#58](https://github.com/applidium/ad_localize/issues/58) in PR [#69](https://github.com/applidium/ad_localize/pull/69)
|
20
|
+
- Add warning messages when input is corrupted. Fix [#59](https://github.com/applidium/ad_localize/issues/59) in PR [#69](https://github.com/applidium/ad_localize/pull/69)
|
21
|
+
- Fix performance issue and add warning messages. Fix [#61](https://github.com/applidium/ad_localize/issues/61) in PR [#69](https://github.com/applidium/ad_localize/pull/69)
|
22
|
+
- Update deprecated `google-api-client` gem. Fix [#63](https://github.com/applidium/ad_localize/issues/63) in PR [#70](https://github.com/applidium/ad_localize/pull/70)
|
23
|
+
|
24
|
+
## [4.0.8] - 2021-05-25
|
25
|
+
|
26
|
+
### Fixed
|
27
|
+
|
28
|
+
- Add `NFCReaderUsageDescription` to InfoPlist keys for iOS
|
29
|
+
|
7
30
|
## [4.0.7] - 2021-05-18
|
31
|
+
|
8
32
|
### Changed
|
33
|
+
|
9
34
|
- Support Ruby 3.x
|
10
35
|
|
11
36
|
## [4.0.6] - 2020-01-25
|
37
|
+
|
12
38
|
### Fixed
|
13
|
-
|
39
|
+
|
40
|
+
- Fix google spreadsheet sheet id comparison with sheet_ids option value
|
14
41
|
|
15
42
|
## [4.0.5] - 2020-11-12
|
43
|
+
|
16
44
|
### Fixed
|
17
|
-
|
18
|
-
|
45
|
+
|
46
|
+
- Fix csv file type check (also add compatibility with macOS Big Sur)
|
47
|
+
|
19
48
|
## [4.0.4] - 2020-11-09
|
49
|
+
|
20
50
|
### Fixed
|
21
|
-
|
22
|
-
|
23
|
-
|
51
|
+
|
52
|
+
- Fix android special character escaping [#56](https://github.com/applidium/ad_localize/issues/56)
|
53
|
+
- Fix platform filter on export [#55](https://github.com/applidium/ad_localize/issues/55)
|
54
|
+
|
24
55
|
### Changed
|
25
|
-
|
56
|
+
|
57
|
+
- Use default terminal color for debug log
|
26
58
|
|
27
59
|
## [4.0.3] - 2020-10-27
|
60
|
+
|
28
61
|
### Fixed
|
29
|
-
|
30
|
-
|
62
|
+
|
63
|
+
- Fix CSV detection and remove dependency to MimeType gem
|
64
|
+
- Fix drive key detection in options
|
31
65
|
|
32
66
|
## [4.0.2] - 2020-10-26
|
67
|
+
|
33
68
|
### Fixed
|
34
|
-
|
69
|
+
|
70
|
+
- Use percent HTML char for escaping '%' on android. [#49](https://github.com/applidium/ad_localize/pull/49) by [flolom](https://github.com/flolom)
|
35
71
|
|
36
72
|
## [4.0.1] - 2020-10-19
|
73
|
+
|
37
74
|
### Fixed
|
38
|
-
|
75
|
+
|
76
|
+
- delete downloaded files even when any of them is a CSV file
|
39
77
|
|
40
78
|
## [4.0.0] - 2020-10-19
|
79
|
+
|
41
80
|
### Breaking change
|
42
|
-
|
43
|
-
|
44
|
-
|
81
|
+
|
82
|
+
- Precedence to csv files. Only CSV files will be exported if both csv file and google spreadsheet are provided
|
83
|
+
- In case of multiple CSVs or sheet ids, you should be aware that all sources will be merged. By default the merge policy to keep the first wording translation for each key
|
84
|
+
- New architecture. Separate export process responsibilities in dedicated classes. Fixes [#48](https://github.com/applidium/ad_localize/issues/48), [#20](https://github.com/applidium/ad_localize/issues/20)
|
45
85
|
|
46
86
|
### Changed
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
87
|
+
|
88
|
+
- it is now possible to provide an output path path that does not exist
|
89
|
+
- if a service account configuration is provided, there won't be any files downloaded
|
90
|
+
- it is now possible to provide a sheet id list
|
91
|
+
- `ActiveSupport::TestCase` is now the base class of test classes
|
92
|
+
- Only global constants are in the constant class
|
93
|
+
- Replaced the Runner class file by a cli class
|
94
|
+
- tests for ad_localize class are restricted to the minimum
|
95
|
+
- No more file generated when there are no data to export
|
96
|
+
- Less verbose logs. Now, they only describe the different steps of the export process
|
97
|
+
- do not add `InfoPlist` translations to android `strings.xml`
|
57
98
|
|
58
99
|
### Added
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
100
|
+
|
101
|
+
- -e, -export_all_sheets option export all sheets from a spreadsheet by [@sjcqs](https://github.com/sjcqs)
|
102
|
+
- -m, --merge-option to select the merge policy (`keep` or `replace`) by [@sjcqs](https://github.com/sjcqs)
|
103
|
+
- it is now possible to select which locales you want to export
|
104
|
+
- key class is tested
|
105
|
+
- option handler is tested
|
106
|
+
- execute_export_request is tested (only csv)
|
107
|
+
- export request is tested
|
108
|
+
- dedicated folder for fixture files
|
109
|
+
- add ability to use AdLocalize in a Ruby program
|
110
|
+
- add documentation for JSON and YAML support. Fixes [#23](https://github.com/applidium/ad_localize/issues/23)
|
69
111
|
|
70
112
|
### Fixed
|
71
|
-
|
72
|
-
|
113
|
+
|
114
|
+
- comments will now be added to iOS and Android plural files
|
115
|
+
- do not remove existing files in export output folder. Fixes [#40](https://github.com/applidium/ad_localize/issues/40)
|
73
116
|
|
74
117
|
### Removed
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
118
|
+
|
119
|
+
- no more option -a option to indicate that a service account configuration will be provided. If set, the environment variable `GCLOUD_CLIENT_SECRET` content will be used
|
120
|
+
- no more substitution of empty wording with by "Missing Translation" when using the option -d
|
121
|
+
- no more Makefile, the Rakefile is sufficient. Use `bundle exec rake -T` to display the available commands
|
122
|
+
- no more check for ordered interpolation variables in translations
|
79
123
|
|
80
124
|
## [3.6.0] - 2020-06-23
|
125
|
+
|
81
126
|
### Added
|
82
|
-
|
83
|
-
|
127
|
+
|
128
|
+
- add documentation for service account usage by [@sjcqs](https://github.com/sjcqs)
|
129
|
+
- add compatibility with activesupport 6 by [@Hugo-Hache](https://github.com/Hugo-Hache)
|
84
130
|
|
85
131
|
### Changed
|
86
132
|
|
87
133
|
### Fixed
|
88
134
|
|
89
135
|
## [3.5.0] - 2020-05-12
|
136
|
+
|
90
137
|
### Added
|
91
|
-
|
92
|
-
|
138
|
+
|
139
|
+
- add support for private spreadsheet using google service acccount by [@sjcqs](https://github.com/sjcqs). Fixes [#31](https://github.com/applidium/ad_localize/issues/31)
|
140
|
+
- add makefile for easier testing by [@felginep](https://github.com/felginep)
|
93
141
|
|
94
142
|
### Changed
|
95
|
-
|
96
|
-
|
97
|
-
|
143
|
+
|
144
|
+
- improve error message to have useful information in case of google spreadsheet use by [@felginep](https://github.com/felginep). Fixes [#27](https://github.com/applidium/ad_localize/issues/27)
|
145
|
+
- platform folder is no longer generated when there is only one platform selected. The files are directly generated in the output path. By [@felginep](https://github.com/felginep). Fixes [#29](https://github.com/applidium/ad_localize/issues/29)
|
146
|
+
- raise error when google spreadsheet key is invalid by [@felginep](https://github.com/felginep)
|
98
147
|
|
99
148
|
### Fixed
|
100
|
-
|
101
|
-
|
149
|
+
|
150
|
+
- auto escape strings in Localizable.strings by [@felginep](https://github.com/felginep). Fixes [#26](https://github.com/applidium/ad_localize/issues/26)
|
151
|
+
- trim keys to prevent user error by [@felginep](https://github.com/felginep). Fixes [#16](https://github.com/applidium/ad_localize/issues/16)
|
102
152
|
|
103
153
|
## [3.4.0] - 2019-02-10
|
154
|
+
|
104
155
|
### Added
|
105
|
-
|
156
|
+
|
157
|
+
- Rails folks, [@epaillous](https://github.com/epaillous) has improved the YAML support. You can now have multi-level wording.
|
106
158
|
|
107
159
|
## [3.3.0] - 2019-02-10
|
160
|
+
|
108
161
|
### Added
|
109
|
-
|
162
|
+
|
163
|
+
- improve React support using keys with dots to generate nested JSON files by [@epaillous](https://github.com/epaillous)
|
110
164
|
|
111
165
|
## [3.2.0] - 2019-12-10
|
166
|
+
|
112
167
|
### Added
|
113
|
-
|
114
|
-
|
168
|
+
|
169
|
+
- Add tests to compare reference exports by [@felginep](https://github.com/felginep)
|
170
|
+
- [iOS only] Handle [adaptive strings](https://developer.apple.com/documentation/foundation/nsstring/1413104-variantfittingpresentationwidth) by [@felginep](https://github.com/felginep)
|
115
171
|
|
116
172
|
### Changed
|
117
|
-
|
118
|
-
|
173
|
+
|
174
|
+
- Fix issue with Info.plist format by [@felginep](https://github.com/felginep)
|
175
|
+
- Do not export plurals for android when there are no values by [@felginep](https://github.com/felginep)
|
119
176
|
|
120
177
|
## [3.1.0] - 2019-09-30
|
178
|
+
|
121
179
|
### Added
|
122
|
-
|
180
|
+
|
181
|
+
- [iOS only] Info.plist generation support by [@felginep](https://github.com/felginep)
|
123
182
|
|
124
183
|
### Changed
|
125
|
-
|
184
|
+
|
185
|
+
- No more warning log for empty lines by [@felginep](https://github.com/felginep)
|
126
186
|
|
127
187
|
## [3.0.0] - 2019-02-19
|
188
|
+
|
128
189
|
TODO
|
129
190
|
|
130
191
|
## [2.1.0] - 2016-12-22
|
192
|
+
|
131
193
|
TODO
|
132
194
|
|
133
195
|
## [2.0.0] - 2016-07-05
|
196
|
+
|
134
197
|
TODO
|
135
198
|
|
136
199
|
## [1.1.0] - 2016-04-27
|
200
|
+
|
137
201
|
TODO
|
138
202
|
|
139
203
|
## [1.0.0] - 2016-04-25
|
204
|
+
|
140
205
|
TODO
|
141
206
|
|
142
207
|
## [0.1.0] - 2016-04-25
|
208
|
+
|
143
209
|
TODO
|
data/Gemfile.lock
CHANGED
@@ -1,76 +1,79 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ad_localize (4.0
|
4
|
+
ad_localize (4.1.0)
|
5
5
|
activesupport (>= 6.1.3.2, < 7.0)
|
6
6
|
colorize (~> 0.8)
|
7
|
-
google-
|
7
|
+
google-apis-sheets_v4 (~> 0.9)
|
8
8
|
googleauth (~> 0.12)
|
9
9
|
nokogiri (~> 1.10)
|
10
10
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
activesupport (6.1.
|
14
|
+
activesupport (6.1.4.6)
|
15
15
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
16
|
i18n (>= 1.6, < 2)
|
17
17
|
minitest (>= 5.1)
|
18
18
|
tzinfo (~> 2.0)
|
19
19
|
zeitwerk (~> 2.3)
|
20
|
-
addressable (2.
|
20
|
+
addressable (2.8.0)
|
21
21
|
public_suffix (>= 2.0.2, < 5.0)
|
22
22
|
ansi (1.5.0)
|
23
23
|
builder (3.2.4)
|
24
24
|
byebug (11.1.3)
|
25
25
|
colorize (0.8.1)
|
26
|
-
concurrent-ruby (1.1.
|
26
|
+
concurrent-ruby (1.1.9)
|
27
27
|
declarative (0.0.20)
|
28
28
|
diffy (3.3.0)
|
29
|
-
faraday (1.
|
29
|
+
faraday (1.10.0)
|
30
|
+
faraday-em_http (~> 1.0)
|
31
|
+
faraday-em_synchrony (~> 1.0)
|
30
32
|
faraday-excon (~> 1.1)
|
33
|
+
faraday-httpclient (~> 1.0)
|
34
|
+
faraday-multipart (~> 1.0)
|
31
35
|
faraday-net_http (~> 1.0)
|
32
|
-
faraday-net_http_persistent (~> 1.
|
33
|
-
|
36
|
+
faraday-net_http_persistent (~> 1.0)
|
37
|
+
faraday-patron (~> 1.0)
|
38
|
+
faraday-rack (~> 1.0)
|
39
|
+
faraday-retry (~> 1.0)
|
34
40
|
ruby2_keywords (>= 0.0.4)
|
41
|
+
faraday-em_http (1.0.0)
|
42
|
+
faraday-em_synchrony (1.0.0)
|
35
43
|
faraday-excon (1.1.0)
|
44
|
+
faraday-httpclient (1.0.1)
|
45
|
+
faraday-multipart (1.0.3)
|
46
|
+
multipart-post (>= 1.2, < 3)
|
36
47
|
faraday-net_http (1.0.1)
|
37
|
-
faraday-net_http_persistent (1.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
google-apis-core (0.3.0)
|
48
|
+
faraday-net_http_persistent (1.2.0)
|
49
|
+
faraday-patron (1.0.0)
|
50
|
+
faraday-rack (1.0.0)
|
51
|
+
faraday-retry (1.0.3)
|
52
|
+
google-apis-core (0.4.2)
|
43
53
|
addressable (~> 2.5, >= 2.5.1)
|
44
|
-
googleauth (
|
45
|
-
httpclient (>= 2.8.1, < 3.
|
54
|
+
googleauth (>= 0.16.2, < 2.a)
|
55
|
+
httpclient (>= 2.8.1, < 3.a)
|
46
56
|
mini_mime (~> 1.0)
|
47
57
|
representable (~> 3.0)
|
48
|
-
retriable (>= 2.0, < 4.
|
58
|
+
retriable (>= 2.0, < 4.a)
|
49
59
|
rexml
|
50
|
-
signet (~> 0.14)
|
51
60
|
webrick
|
52
|
-
google-apis-
|
53
|
-
google-apis-core (
|
54
|
-
|
55
|
-
activesupport (>= 5.0)
|
56
|
-
gems (~> 1.2)
|
57
|
-
google-apis-core (~> 0.1)
|
58
|
-
google-apis-discovery_v1 (~> 0.0)
|
59
|
-
thor (>= 0.20, < 2.a)
|
60
|
-
googleauth (0.16.2)
|
61
|
+
google-apis-sheets_v4 (0.11.0)
|
62
|
+
google-apis-core (>= 0.4, < 2.a)
|
63
|
+
googleauth (0.17.1)
|
61
64
|
faraday (>= 0.17.3, < 2.0)
|
62
65
|
jwt (>= 1.4, < 3.0)
|
63
66
|
memoist (~> 0.16)
|
64
67
|
multi_json (~> 1.11)
|
65
68
|
os (>= 0.9, < 2.0)
|
66
|
-
signet (~> 0.
|
69
|
+
signet (~> 0.15)
|
67
70
|
httpclient (2.8.3)
|
68
|
-
i18n (1.
|
71
|
+
i18n (1.10.0)
|
69
72
|
concurrent-ruby (~> 1.0)
|
70
|
-
jwt (2.
|
73
|
+
jwt (2.3.0)
|
71
74
|
memoist (0.16.2)
|
72
|
-
mini_mime (1.1.
|
73
|
-
mini_portile2 (2.
|
75
|
+
mini_mime (1.1.2)
|
76
|
+
mini_portile2 (2.8.0)
|
74
77
|
minitest (5.14.4)
|
75
78
|
minitest-reporters (1.4.2)
|
76
79
|
ansi
|
@@ -79,12 +82,12 @@ GEM
|
|
79
82
|
ruby-progressbar
|
80
83
|
multi_json (1.15.0)
|
81
84
|
multipart-post (2.1.1)
|
82
|
-
nokogiri (1.
|
83
|
-
mini_portile2 (~> 2.
|
85
|
+
nokogiri (1.13.3)
|
86
|
+
mini_portile2 (~> 2.8.0)
|
84
87
|
racc (~> 1.4)
|
85
|
-
os (1.1.
|
88
|
+
os (1.1.4)
|
86
89
|
public_suffix (4.0.6)
|
87
|
-
racc (1.
|
90
|
+
racc (1.6.0)
|
88
91
|
rake (12.3.3)
|
89
92
|
representable (3.1.1)
|
90
93
|
declarative (< 0.1.0)
|
@@ -93,19 +96,18 @@ GEM
|
|
93
96
|
retriable (3.1.2)
|
94
97
|
rexml (3.2.5)
|
95
98
|
ruby-progressbar (1.10.1)
|
96
|
-
ruby2_keywords (0.0.
|
97
|
-
signet (0.
|
98
|
-
addressable (~> 2.
|
99
|
-
faraday (>= 0.17.
|
99
|
+
ruby2_keywords (0.0.5)
|
100
|
+
signet (0.16.1)
|
101
|
+
addressable (~> 2.8)
|
102
|
+
faraday (>= 0.17.5, < 3.0)
|
100
103
|
jwt (>= 1.5, < 3.0)
|
101
104
|
multi_json (~> 1.10)
|
102
|
-
|
103
|
-
trailblazer-option (0.1.1)
|
105
|
+
trailblazer-option (0.1.2)
|
104
106
|
tzinfo (2.0.4)
|
105
107
|
concurrent-ruby (~> 1.0)
|
106
108
|
uber (0.1.0)
|
107
109
|
webrick (1.7.0)
|
108
|
-
zeitwerk (2.4
|
110
|
+
zeitwerk (2.5.4)
|
109
111
|
|
110
112
|
PLATFORMS
|
111
113
|
ruby
|
@@ -120,4 +122,4 @@ DEPENDENCIES
|
|
120
122
|
rake (~> 12.3)
|
121
123
|
|
122
124
|
BUNDLED WITH
|
123
|
-
2.2.
|
125
|
+
2.2.26
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
The purpose of this gem is to automatically generate wording files from a CSV input (CSV file or Google Spreadsheet).
|
4
4
|
It supports iOS, Android, JSON, YAML and Java Properties.
|
5
|
-
It is a useful tool when working on a mobile application or a SPA.
|
5
|
+
It is a useful tool when working on a mobile application or a SPA.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -41,12 +41,12 @@ $ ad_localize -k <your-spreadsheet-drive-key>
|
|
41
41
|
$ ad_localize -k <your-spreadsheet-drive-key> -s <comma-separated-sheet-id-list>
|
42
42
|
```
|
43
43
|
|
44
|
-
* Export wording from a private google spreadsheet. It requires a [Google Cloud Service Account](#using-a-google-cloud-service-account).
|
44
|
+
* Export wording from a private google spreadsheet. It requires a [Google Cloud Service Account](#using-a-google-cloud-service-account).
|
45
45
|
```
|
46
46
|
$ GCLOUD_CLIENT_SECRET=$(cat <path-to-client-secret.json>) ad_localize -k <your-spreadsheet-drive-key>
|
47
47
|
```
|
48
48
|
|
49
|
-
* Export wording from all sheets in a google spreadsheet. It requires a [Google Cloud Service Account](#using-a-google-cloud-service-account).
|
49
|
+
* Export wording from all sheets in a google spreadsheet. It requires a [Google Cloud Service Account](#using-a-google-cloud-service-account).
|
50
50
|
```
|
51
51
|
$ GCLOUD_CLIENT_SECRET=$(cat <path-to-client-secret.json>) ad_localize -k <your-spreadsheet-drive-key> -e
|
52
52
|
```
|
@@ -76,7 +76,7 @@ If you want more examples, please open a documentation issue.
|
|
76
76
|
require 'ad_localize'
|
77
77
|
# create optional google spreasheet options
|
78
78
|
g_spreadsheet_options = AdLocalize::Requests::GSpreadsheetOptions.new(spreadsheet_id: 'some_id', sheet_ids: ['first', 'second'], service_account_config: ENV['GCLOUD_CLIENT_SECRET'])
|
79
|
-
# create export request
|
79
|
+
# create export request
|
80
80
|
export_request = AdLocalize::Requests::ExportRequest.new(g_spreadsheet_options: g_spreadsheet_options, verbose: true)
|
81
81
|
# execute request
|
82
82
|
AdLocalize::Interactors::ExecuteExportRequest.new.call(export_request: export_request)
|
@@ -86,20 +86,20 @@ If you want more examples, please open a documentation issue.
|
|
86
86
|
### Share to anyone with the link
|
87
87
|
|
88
88
|
If you do not have high security concerns, the simplest way to access a google spreadsheet is to allow **anyone** with the link to **view** it and enable the `Viewers and commenters can see the option to download, print, and copy` option in the spreadsheet sharing settings.
|
89
|
-
|
89
|
+
|
90
90
|
### Use a Google Cloud Service Account
|
91
91
|
|
92
|
-
To use a private google spreasheet you need to use a Google Cloud Service Account. Here are the steps to follow :
|
93
|
-
1. Create a GCloud Service Account:
|
94
|
-
- Go to [Google Cloud Console](https://console.cloud.google.com/)
|
95
|
-
- Either create a new project or use an existing one (when using Firebase, a GCloud project is created)
|
96
|
-
- Go to *IAM & Admin / Service Account* and create a new service account.
|
97
|
-
- Store the created `client-secret.json` (in a password manager for example)
|
98
|
-
2. Enable Google Spreadsheet API for the project
|
99
|
-
- Go to *API / Library* and enable the **Google Spreadsheet API** there.
|
100
|
-
3. Add the service account to a spreadsheet.
|
92
|
+
To use a private google spreasheet you need to use a Google Cloud Service Account. Here are the steps to follow :
|
93
|
+
1. Create a GCloud Service Account:
|
94
|
+
- Go to [Google Cloud Console](https://console.cloud.google.com/)
|
95
|
+
- Either create a new project or use an existing one (when using Firebase, a GCloud project is created)
|
96
|
+
- Go to *IAM & Admin / Service Account* and create a new service account.
|
97
|
+
- Store the created `client-secret.json` (in a password manager for example)
|
98
|
+
2. Enable Google Spreadsheet API for the project
|
99
|
+
- Go to *API / Library* and enable the **Google Spreadsheet API** there.
|
100
|
+
3. Add the service account to a spreadsheet.
|
101
101
|
- In *IAM & Admin / Service Account*, the service account's email is listed. Invite it to the spreadsheet to export.
|
102
|
-
|
102
|
+
|
103
103
|
```
|
104
104
|
$ GCLOUD_CLIENT_SECRET=$(cat <path-to-client-secrets>) ad_localize -k # one way
|
105
105
|
$ GCLOUD_CLIENT_SECRET=$(cat <path-to-client-secrets>) ad_localize -k <your-spreadsheet-drive-key> -s <comma-separated-sheet-id-list> # another way
|
@@ -123,12 +123,13 @@ $ ad_localize -k <your-spreadsheet-drive-key> -s <comma-separated-sheet-id-list>
|
|
123
123
|
- Any column after the `key` column will be considered as a locale column (except from the optional `comment` columns)
|
124
124
|
- Keys should contain only letter, number, underscore and dot : [a-z0-9_.]+.
|
125
125
|
- Format specifiers must be numeroted if there are more than one in a translation string (eg: `"%1$@ %2$@'s report"`).
|
126
|
+
- _Only for Android_ keys without translation won't be considered
|
126
127
|
|
127
|
-
### Comments
|
128
|
+
### Comments
|
128
129
|
|
129
130
|
_Only for Android and iOS_
|
130
131
|
|
131
|
-
To add comments for iOS or Android, simply add a comment column using the naming convention `comment <locale>`.
|
132
|
+
To add comments for iOS or Android, simply add a comment column using the naming convention `comment <locale>`.
|
132
133
|
Comments are available in `strings.xml`, `Localizable.strings`, `Localizable.stringsdict`, `InfoPlist.strings`. Here is an example for `InfoPlist.strings` :
|
133
134
|
|
134
135
|
| key | en | comment en |
|
@@ -177,21 +178,22 @@ _Only for iOS._
|
|
177
178
|
|
178
179
|
Every key that matches the following formats will be added to the `InfoPlist.strings` file instead of `Localizable.strings`:
|
179
180
|
* `NS...UsageDescription`
|
181
|
+
* `NFCReaderUsageDescription`
|
180
182
|
* `CF...Name`
|
181
183
|
|
182
184
|
### Nested wording
|
183
185
|
|
184
186
|
_Only for YAML and JSON_
|
185
187
|
|
186
|
-
For these two platforms it is common to have nested wording files, either to handle plural or to group wording by sections. To handle this behavior in a simple way you should use dots in the key to separate the different levels. For example :
|
187
|
-
|
188
|
+
For these two platforms it is common to have nested wording files, either to handle plural or to group wording by sections. To handle this behavior in a simple way you should use dots in the key to separate the different levels. For example :
|
189
|
+
|
188
190
|
| key | fr |
|
189
191
|
| --- | --- |
|
190
192
|
| login.password | mot de passe |
|
191
193
|
| login.email | email |
|
192
194
|
|
193
195
|
```json
|
194
|
-
{"login":{"password":"mot de passe","email":"email"}}
|
196
|
+
{"login":{"password":"mot de passe","email":"email"}}
|
195
197
|
```
|
196
198
|
|
197
199
|
```yaml
|
@@ -199,14 +201,14 @@ fr:
|
|
199
201
|
login:
|
200
202
|
password: "mot de passe"
|
201
203
|
email: "email"
|
202
|
-
```
|
204
|
+
```
|
203
205
|
|
204
206
|
|
205
207
|
## Output
|
206
208
|
|
207
|
-
The default output folder name is `exports`.
|
208
|
-
If your export is for multiple platforms there will be an intermediate folder for each platform, otherwise the wording files (and folders) will directly be generated in the export folder.
|
209
|
-
Any existing file will be overriden.
|
209
|
+
The default output folder name is `exports`.
|
210
|
+
If your export is for multiple platforms there will be an intermediate folder for each platform, otherwise the wording files (and folders) will directly be generated in the export folder.
|
211
|
+
Any existing file will be overriden.
|
210
212
|
You can see examples of generated files in `test/fixtures/export_references/`
|
211
213
|
|
212
214
|
Here an export tree example for all supported platforms in `fr` and `en`:
|
data/ad_localize.gemspec
CHANGED
@@ -49,8 +49,8 @@ Gem::Specification.new do |spec|
|
|
49
49
|
spec.add_dependency 'activesupport', '>= 6.1.3.2', '< 7.0'
|
50
50
|
spec.add_dependency 'nokogiri', '~> 1.10'
|
51
51
|
spec.add_dependency 'colorize', '~> 0.8'
|
52
|
-
spec.add_dependency 'google-api-client', '~> 0.34'
|
53
52
|
spec.add_dependency 'googleauth', '~> 0.12'
|
53
|
+
spec.add_dependency 'google-apis-sheets_v4', '~> 0.9'
|
54
54
|
|
55
55
|
spec.required_ruby_version = '>= 2.3'
|
56
56
|
end
|
@@ -4,7 +4,7 @@ module AdLocalize
|
|
4
4
|
PLURAL_KEY_REGEXP = /\#\#\{([A-Za-z]+)\}/.freeze
|
5
5
|
ADAPTIVE_KEY_REGEXP = /\#\#\{(\d+)\}/.freeze
|
6
6
|
# see https://developer.apple.com/documentation/bundleresources/information_property_list
|
7
|
-
INFO_PLIST_KEY_REGEXP = /(NS.+UsageDescription)|(CF.+Name)/.freeze
|
7
|
+
INFO_PLIST_KEY_REGEXP = /(NS.+UsageDescription)|(CF.+Name)|NFCReaderUsageDescription/.freeze
|
8
8
|
|
9
9
|
def initialize(label:)
|
10
10
|
@label = label
|
@@ -46,6 +46,11 @@ module AdLocalize
|
|
46
46
|
raw_label == key.raw_label
|
47
47
|
end
|
48
48
|
|
49
|
+
def ==(o)
|
50
|
+
o.class == self.class &&
|
51
|
+
o.raw_label == raw_label
|
52
|
+
end
|
53
|
+
|
49
54
|
private
|
50
55
|
|
51
56
|
def compute_label
|
@@ -15,6 +15,18 @@ module AdLocalize
|
|
15
15
|
@value = value
|
16
16
|
@comment = comment
|
17
17
|
end
|
18
|
+
|
19
|
+
def ==(o)
|
20
|
+
o.class == self.class &&
|
21
|
+
o.locale == locale &&
|
22
|
+
o.key == key &&
|
23
|
+
o.value == value &&
|
24
|
+
o.comment == comment
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_value?
|
28
|
+
value.present?
|
29
|
+
end
|
18
30
|
end
|
19
31
|
end
|
20
32
|
end
|
@@ -33,8 +33,12 @@ module AdLocalize
|
|
33
33
|
export_request.csv_paths = downloaded_files.map(&:path)
|
34
34
|
if export_request.has_csv_files?
|
35
35
|
ExportCSVFiles.new.call(export_request: export_request)
|
36
|
+
elsif export_request.has_empty_files?
|
37
|
+
# When downloading an empty spreadsheet, the content type of the downloaded file is "inode/x-empty"
|
38
|
+
LOGGER.warn("Your spreadsheet is empty. Add content and retry.")
|
36
39
|
else
|
37
|
-
|
40
|
+
# When shared configuration is misconfigured, the content type of the downloaded file is "text/html"
|
41
|
+
LOGGER.error("Invalid export request. Check the spreadsheet share configuration")
|
38
42
|
end
|
39
43
|
downloaded_files.select { |downloaded_file| File.exist?(downloaded_file.path) }.each do |downloaded_file|
|
40
44
|
downloaded_file.close
|
@@ -7,12 +7,16 @@ module AdLocalize
|
|
7
7
|
|
8
8
|
def call(export_request:, wording:)
|
9
9
|
LOGGER.debug("Starting export wording")
|
10
|
-
locales = export_request.locales.size.zero? ? wording.locales : wording.locales & export_request.locales
|
11
10
|
export_request.platforms.each do |platform|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
platform_dir = compute_platform_dir(export_request: export_request, platform: platform)
|
12
|
+
export_platform = @export_platform_factory.build(platform: platform)
|
13
|
+
if export_platform.should_export_locale_by_locale?
|
14
|
+
locales = export_request.locales.size.zero? ? wording.locales : wording.locales & export_request.locales
|
15
|
+
locales.each do |locale|
|
16
|
+
export_platform.call(wording: wording, locale: locale, platform_dir: platform_dir)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
export_platform.call(export_request: export_request, platform_dir: platform_dir)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module AdLocalize
|
2
|
+
module Interactors
|
3
|
+
module Platforms
|
4
|
+
class ExportCSVLocaleWording
|
5
|
+
def initialize
|
6
|
+
@file_system_repository = Repositories::FileSystemRepository.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(export_request:, platform_dir:)
|
10
|
+
LOGGER.debug("Starting export CSV wording")
|
11
|
+
@file_system_repository.create_directory(path: platform_dir)
|
12
|
+
export_request.csv_paths.each_with_index do |csv_path, i|
|
13
|
+
file = File.basename("localization_#{i}.csv")
|
14
|
+
FileUtils.cp(csv_path, platform_dir.join(file.to_s))
|
15
|
+
end
|
16
|
+
LOGGER.debug("CSV wording export done !")
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_export_locale_by_locale?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -14,6 +14,8 @@ module AdLocalize
|
|
14
14
|
ios_builder
|
15
15
|
when 'properties'
|
16
16
|
properties_builder
|
17
|
+
when 'csv'
|
18
|
+
csv_builder
|
17
19
|
else
|
18
20
|
raise ArgumentError.new('Unknown platform for builder factory')
|
19
21
|
end
|
@@ -38,6 +40,10 @@ module AdLocalize
|
|
38
40
|
def properties_builder
|
39
41
|
@properties_builder ||= ExportPropertiesLocaleWording.new
|
40
42
|
end
|
43
|
+
|
44
|
+
def csv_builder
|
45
|
+
@csv_builder ||= ExportCSVLocaleWording.new
|
46
|
+
end
|
41
47
|
end
|
42
48
|
end
|
43
49
|
end
|
@@ -5,19 +5,16 @@ module AdLocalize
|
|
5
5
|
@headers = CSV.foreach(csv_path).first
|
6
6
|
return unless valid?(csv_path: csv_path)
|
7
7
|
translations = []
|
8
|
+
validator = Validators::KeyValidator.new
|
8
9
|
|
9
10
|
CSV.foreach(csv_path, headers: true, skip_blanks: true) do |row|
|
10
11
|
row_translations = map_row(row: row, locales: locales)
|
11
12
|
next if row_translations.blank?
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
key.same_as?(key: translation.key) || existing_plural_key
|
18
|
-
end
|
19
|
-
end
|
20
|
-
translations.concat(new_translations)
|
14
|
+
current_key = row_translations.first.key
|
15
|
+
next if validator.has_warnings?(current_key)
|
16
|
+
|
17
|
+
translations.concat(row_translations)
|
21
18
|
end
|
22
19
|
|
23
20
|
locale_wordings = translations.group_by(&:locale).map do |locale, group|
|
@@ -10,6 +10,14 @@ module AdLocalize
|
|
10
10
|
hash[translation.key.label] = {} unless hash.key? translation.key.label
|
11
11
|
hash[translation.key.label][translation.key.plural_key] = translation.value
|
12
12
|
else
|
13
|
+
unless hash.is_a?(Hash)
|
14
|
+
LOGGER.warn "Corrupted input. Trying to insert a value for key '#{translation.key.label}' but a value already exists for '#{inner_keys[0..index-1].join(".")}'. Skipping."
|
15
|
+
break # skip this corrupted key
|
16
|
+
end
|
17
|
+
previous_value = hash[inner_key.to_s]
|
18
|
+
if !previous_value.blank? && previous_value.is_a?(Hash)
|
19
|
+
LOGGER.warn "Corrupted input. Trying to insert a value for key '#{translation.key.label}' but values already exist for keys '#{translation.key.label}.*'. Previous values will be lost."
|
20
|
+
end
|
13
21
|
hash[inner_key.to_s] = translation.value
|
14
22
|
end
|
15
23
|
else
|
@@ -17,18 +17,16 @@ module AdLocalize
|
|
17
17
|
|
18
18
|
def map_rows(values:)
|
19
19
|
translations = []
|
20
|
+
validator = Validators::KeyValidator.new
|
21
|
+
|
20
22
|
values[1..-1].each do |row|
|
21
23
|
row_translations = map_row(row: row)
|
22
24
|
next if row_translations.blank?
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
key.same_as?(key: translation.key) || existing_plural_key
|
29
|
-
end
|
30
|
-
end
|
31
|
-
translations.concat(new_translations)
|
26
|
+
current_key = row_translations.first.key
|
27
|
+
next if validator.has_warnings?(current_key)
|
28
|
+
|
29
|
+
translations.concat(row_translations)
|
32
30
|
end
|
33
31
|
translations
|
34
32
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module AdLocalize
|
2
2
|
module Requests
|
3
3
|
class ExportRequest
|
4
|
-
SUPPORTED_PLATFORMS = %w(ios android yml json properties).freeze
|
4
|
+
SUPPORTED_PLATFORMS = %w(ios android yml json properties csv).freeze
|
5
5
|
DEFAULT_EXPORT_FOLDER = 'exports'.freeze
|
6
6
|
CSV_CONTENT_TYPES = %w(text/csv text/plain application/csv).freeze
|
7
|
+
EMPTY_CONTENT_TYPE = 'inode/x-empty'.freeze
|
7
8
|
|
8
9
|
def initialize(**args)
|
9
10
|
@locales = Array(args[:locales].presence)
|
@@ -34,6 +35,10 @@ module AdLocalize
|
|
34
35
|
!@csv_paths.blank? && @csv_paths.all? { |csv_path| File.exist?(csv_path) && is_csv?(path: csv_path) }
|
35
36
|
end
|
36
37
|
|
38
|
+
def has_empty_files?
|
39
|
+
!@csv_paths.blank? && @csv_paths.all? { |csv_path| File.exist?(csv_path) && is_empty?(path: csv_path) }
|
40
|
+
end
|
41
|
+
|
37
42
|
def has_g_spreadsheet_options?
|
38
43
|
@g_spreadsheet_options.present?
|
39
44
|
end
|
@@ -61,7 +66,15 @@ module AdLocalize
|
|
61
66
|
end
|
62
67
|
|
63
68
|
def is_csv?(path:)
|
64
|
-
CSV_CONTENT_TYPES.include?(
|
69
|
+
CSV_CONTENT_TYPES.include? content_type(path: path)
|
70
|
+
end
|
71
|
+
|
72
|
+
def is_empty?(path:)
|
73
|
+
content_type(path: path) == EMPTY_CONTENT_TYPE
|
74
|
+
end
|
75
|
+
|
76
|
+
def content_type(path:)
|
77
|
+
`file --brief --mime-type "#{path}"`.strip
|
65
78
|
end
|
66
79
|
|
67
80
|
def valid_g_spreadsheet_options?
|
@@ -22,11 +22,13 @@ module AdLocalize
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def map_singulars(translations:)
|
25
|
-
translations.map { |translation| @translation_mapper.map(translation: translation) }
|
25
|
+
translations.select(&:has_value?).map { |translation| @translation_mapper.map(translation: translation) }
|
26
26
|
end
|
27
27
|
|
28
28
|
def map_plurals(plurals:)
|
29
|
-
plurals
|
29
|
+
plurals
|
30
|
+
.map { |label, translations| @translation_group_mapper.map(label: label, translations: translations.select(&:has_value?)) }
|
31
|
+
.select(&:has_translations?)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module AdLocalize
|
2
|
+
module Validators
|
3
|
+
class KeyValidator
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@existing_key_for_label = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_warnings?(current_key)
|
10
|
+
current_label = current_key.label
|
11
|
+
existing_key = @existing_key_for_label[current_label]
|
12
|
+
|
13
|
+
has_warnings = false
|
14
|
+
|
15
|
+
unless existing_key.nil?
|
16
|
+
existing_plural_key = existing_key.label == current_key.label && existing_key.plural? && current_key.singular?
|
17
|
+
existing_singular_key = existing_key.label == current_key.label && existing_key.singular? && current_key.plural?
|
18
|
+
is_same_key = existing_key.same_as?(key: current_key)
|
19
|
+
LOGGER.warn "A plural value already exist for key '#{current_label}'. Remove duplicates." if existing_plural_key
|
20
|
+
LOGGER.warn "A singular value already exist for key '#{current_label}'. Remove duplicates." if existing_singular_key
|
21
|
+
LOGGER.warn "Some values already exist for key '#{current_label}'. Remove duplicates." if is_same_key
|
22
|
+
has_warnings = is_same_key || existing_plural_key || existing_singular_key
|
23
|
+
end
|
24
|
+
|
25
|
+
@existing_key_for_label[current_label] = current_key
|
26
|
+
|
27
|
+
has_warnings
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/ad_localize/version.rb
CHANGED
data/lib/ad_localize.rb
CHANGED
@@ -53,6 +53,7 @@ require 'ad_localize/interactors/platforms/export_ios_locale_wording'
|
|
53
53
|
require 'ad_localize/interactors/platforms/export_json_locale_wording'
|
54
54
|
require 'ad_localize/interactors/platforms/export_yaml_locale_wording'
|
55
55
|
require 'ad_localize/interactors/platforms/export_properties_locale_wording'
|
56
|
+
require 'ad_localize/interactors/platforms/export_csv_locale_wording'
|
56
57
|
require 'ad_localize/interactors/platforms/export_platform_factory'
|
57
58
|
|
58
59
|
require 'ad_localize/serializers/with_template'
|
@@ -64,7 +65,7 @@ require 'ad_localize/serializers/properties_serializer'
|
|
64
65
|
require 'ad_localize/serializers/json_serializer'
|
65
66
|
require 'ad_localize/serializers/yaml_serializer'
|
66
67
|
|
67
|
-
|
68
|
+
require 'ad_localize/validators/key_validator'
|
68
69
|
|
69
70
|
module AdLocalize
|
70
71
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ad_localize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edouard Siegel
|
@@ -161,33 +161,33 @@ dependencies:
|
|
161
161
|
- !ruby/object:Gem::Version
|
162
162
|
version: '0.8'
|
163
163
|
- !ruby/object:Gem::Dependency
|
164
|
-
name:
|
164
|
+
name: googleauth
|
165
165
|
requirement: !ruby/object:Gem::Requirement
|
166
166
|
requirements:
|
167
167
|
- - "~>"
|
168
168
|
- !ruby/object:Gem::Version
|
169
|
-
version: '0.
|
169
|
+
version: '0.12'
|
170
170
|
type: :runtime
|
171
171
|
prerelease: false
|
172
172
|
version_requirements: !ruby/object:Gem::Requirement
|
173
173
|
requirements:
|
174
174
|
- - "~>"
|
175
175
|
- !ruby/object:Gem::Version
|
176
|
-
version: '0.
|
176
|
+
version: '0.12'
|
177
177
|
- !ruby/object:Gem::Dependency
|
178
|
-
name:
|
178
|
+
name: google-apis-sheets_v4
|
179
179
|
requirement: !ruby/object:Gem::Requirement
|
180
180
|
requirements:
|
181
181
|
- - "~>"
|
182
182
|
- !ruby/object:Gem::Version
|
183
|
-
version: '0.
|
183
|
+
version: '0.9'
|
184
184
|
type: :runtime
|
185
185
|
prerelease: false
|
186
186
|
version_requirements: !ruby/object:Gem::Requirement
|
187
187
|
requirements:
|
188
188
|
- - "~>"
|
189
189
|
- !ruby/object:Gem::Version
|
190
|
-
version: '0.
|
190
|
+
version: '0.9'
|
191
191
|
description: |-
|
192
192
|
AdLocalize produces localization files from platform agnostic wording.
|
193
193
|
Supported wording format : CSV. Supported export format: iOS, Android, JSON and YAML
|
@@ -229,6 +229,7 @@ files:
|
|
229
229
|
- lib/ad_localize/interactors/export_wording.rb
|
230
230
|
- lib/ad_localize/interactors/merge_wordings.rb
|
231
231
|
- lib/ad_localize/interactors/platforms/export_android_locale_wording.rb
|
232
|
+
- lib/ad_localize/interactors/platforms/export_csv_locale_wording.rb
|
232
233
|
- lib/ad_localize/interactors/platforms/export_ios_locale_wording.rb
|
233
234
|
- lib/ad_localize/interactors/platforms/export_json_locale_wording.rb
|
234
235
|
- lib/ad_localize/interactors/platforms/export_platform_factory.rb
|
@@ -261,6 +262,7 @@ files:
|
|
261
262
|
- lib/ad_localize/templates/ios/Localizable.strings.erb
|
262
263
|
- lib/ad_localize/templates/ios/Localizable.stringsdict.erb
|
263
264
|
- lib/ad_localize/templates/properties/template.properties.erb
|
265
|
+
- lib/ad_localize/validators/key_validator.rb
|
264
266
|
- lib/ad_localize/version.rb
|
265
267
|
- lib/ad_localize/view_models/translation_group_view_model.rb
|
266
268
|
- lib/ad_localize/view_models/translation_view_model.rb
|