slimkeyfy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +22 -0
  6. data/LICENSE +21 -0
  7. data/README.md +172 -0
  8. data/bin/slimkeyfy +5 -0
  9. data/lib/.DS_Store +0 -0
  10. data/lib/slimkeyfy/console/command_line.rb +90 -0
  11. data/lib/slimkeyfy/console/io_action.rb +30 -0
  12. data/lib/slimkeyfy/console/printer.rb +50 -0
  13. data/lib/slimkeyfy/console/translate.rb +101 -0
  14. data/lib/slimkeyfy/console.rb +8 -0
  15. data/lib/slimkeyfy/slimutils/file_utils.rb +61 -0
  16. data/lib/slimkeyfy/slimutils/hash_merging.rb +84 -0
  17. data/lib/slimkeyfy/slimutils/key_generator.rb +70 -0
  18. data/lib/slimkeyfy/slimutils/yaml_processor.rb +56 -0
  19. data/lib/slimkeyfy/slimutils.rb +8 -0
  20. data/lib/slimkeyfy/transformer/base_transformer.rb +42 -0
  21. data/lib/slimkeyfy/transformer/controller_transformer.rb +20 -0
  22. data/lib/slimkeyfy/transformer/slim_transformer.rb +92 -0
  23. data/lib/slimkeyfy/transformer/whitespacer.rb +48 -0
  24. data/lib/slimkeyfy/transformer/word.rb +49 -0
  25. data/lib/slimkeyfy/transformer.rb +9 -0
  26. data/lib/slimkeyfy/version.rb +3 -0
  27. data/lib/slimkeyfy.rb +12 -0
  28. data/slimkeyfy.gemspec +21 -0
  29. data/vendor/bundle/bin/htmldiff +25 -0
  30. data/vendor/bundle/bin/ldiff +25 -0
  31. data/vendor/bundle/bin/rspec +23 -0
  32. data/vendor/bundle/build_info/diff-lcs-1.2.5.info +1 -0
  33. data/vendor/bundle/build_info/rspec-3.0.0.info +1 -0
  34. data/vendor/bundle/build_info/rspec-core-3.0.2.info +1 -0
  35. data/vendor/bundle/build_info/rspec-expectations-3.0.2.info +1 -0
  36. data/vendor/bundle/build_info/rspec-mocks-3.0.2.info +1 -0
  37. data/vendor/bundle/build_info/rspec-support-3.0.2.info +1 -0
  38. data/vendor/bundle/gems/diff-lcs-1.2.5/.autotest +3 -0
  39. data/vendor/bundle/gems/diff-lcs-1.2.5/.gemtest +0 -0
  40. data/vendor/bundle/gems/diff-lcs-1.2.5/.hoerc +2 -0
  41. data/vendor/bundle/gems/diff-lcs-1.2.5/.rspec +2 -0
  42. data/vendor/bundle/gems/diff-lcs-1.2.5/.travis.yml +22 -0
  43. data/vendor/bundle/gems/diff-lcs-1.2.5/Contributing.rdoc +64 -0
  44. data/vendor/bundle/gems/diff-lcs-1.2.5/Gemfile +20 -0
  45. data/vendor/bundle/gems/diff-lcs-1.2.5/History.rdoc +152 -0
  46. data/vendor/bundle/gems/diff-lcs-1.2.5/License.rdoc +39 -0
  47. data/vendor/bundle/gems/diff-lcs-1.2.5/Manifest.txt +38 -0
  48. data/vendor/bundle/gems/diff-lcs-1.2.5/README.rdoc +85 -0
  49. data/vendor/bundle/gems/diff-lcs-1.2.5/Rakefile +41 -0
  50. data/vendor/bundle/gems/diff-lcs-1.2.5/autotest/discover.rb +1 -0
  51. data/vendor/bundle/gems/diff-lcs-1.2.5/bin/htmldiff +32 -0
  52. data/vendor/bundle/gems/diff-lcs-1.2.5/bin/ldiff +6 -0
  53. data/vendor/bundle/gems/diff-lcs-1.2.5/docs/COPYING.txt +339 -0
  54. data/vendor/bundle/gems/diff-lcs-1.2.5/docs/artistic.txt +127 -0
  55. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/array.rb +7 -0
  56. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/block.rb +37 -0
  57. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/callbacks.rb +322 -0
  58. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/change.rb +177 -0
  59. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/htmldiff.rb +149 -0
  60. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/hunk.rb +276 -0
  61. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/internals.rb +301 -0
  62. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/ldiff.rb +195 -0
  63. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/string.rb +5 -0
  64. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs.rb +805 -0
  65. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff-lcs.rb +3 -0
  66. data/vendor/bundle/gems/rspec-3.0.0/License.txt +24 -0
  67. data/vendor/bundle/gems/rspec-3.0.0/README.md +47 -0
  68. data/vendor/bundle/gems/rspec-3.0.0/lib/rspec.rb +3 -0
  69. data/vendor/bundle/gems/rspec-core-3.0.2/.document +5 -0
  70. data/vendor/bundle/gems/rspec-core-3.0.2/.yardopts +7 -0
  71. data/vendor/bundle/gems/rspec-core-3.0.2/Changelog.md +1466 -0
  72. data/vendor/bundle/gems/rspec-core-3.0.2/License.txt +25 -0
  73. data/vendor/bundle/gems/rspec-core-3.0.2/README.md +243 -0
  74. data/vendor/bundle/gems/rspec-core-3.0.2/exe/rspec +4 -0
  75. data/vendor/bundle/gems/rspec-expectations-3.0.2/.document +5 -0
  76. data/vendor/bundle/gems/rspec-expectations-3.0.2/.yardopts +6 -0
  77. data/vendor/bundle/gems/rspec-expectations-3.0.2/Changelog.md +749 -0
  78. data/vendor/bundle/gems/rspec-expectations-3.0.2/License.txt +24 -0
  79. data/vendor/bundle/gems/rspec-expectations-3.0.2/README.md +278 -0
  80. data/vendor/bundle/gems/rspec-mocks-3.0.2/.document +5 -0
  81. data/vendor/bundle/gems/rspec-mocks-3.0.2/.yardopts +6 -0
  82. data/vendor/bundle/gems/rspec-mocks-3.0.2/Changelog.md +733 -0
  83. data/vendor/bundle/gems/rspec-mocks-3.0.2/License.txt +24 -0
  84. data/vendor/bundle/gems/rspec-mocks-3.0.2/README.md +380 -0
  85. data/vendor/bundle/gems/rspec-support-3.0.2/Changelog.md +30 -0
  86. data/vendor/bundle/gems/rspec-support-3.0.2/LICENSE.txt +22 -0
  87. data/vendor/bundle/gems/rspec-support-3.0.2/README.md +17 -0
  88. data/vendor/bundle/specifications/diff-lcs-1.2.5.gemspec +68 -0
  89. data/vendor/bundle/specifications/rspec-3.0.0.gemspec +43 -0
  90. data/vendor/bundle/specifications/rspec-core-3.0.2.gemspec +66 -0
  91. data/vendor/bundle/specifications/rspec-expectations-3.0.2.gemspec +51 -0
  92. data/vendor/bundle/specifications/rspec-mocks-3.0.2.gemspec +48 -0
  93. data/vendor/bundle/specifications/rspec-support-3.0.2.gemspec +42 -0
  94. metadata +153 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51e9f1359e2f3cec0cca00636171ddcdb452fc13
4
+ data.tar.gz: f8fe3487b10951a60283ff911bb7acd9d080d8e0
5
+ SHA512:
6
+ metadata.gz: 6ec0ec5446e2fa6853695ea7fb96d3ac4921666e001c449b39d9da379c7b6a253fd7a5b955e5e6f796ffc0314164a925f37da1ee6144ae7c4e072a61ed7ed633
7
+ data.tar.gz: 65b12829f6513726748d6a646da5524343af0b19de8f74cdefdf489fd7eeabc1fb1214e4812cbd326ab77a7567797c05fb77b4b2f3830fa1d78d8325e8b97333
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.1.1'
4
+
5
+ gem 'rspec', :require => 'spec'
6
+
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.2.5)
5
+ rspec (3.0.0)
6
+ rspec-core (~> 3.0.0)
7
+ rspec-expectations (~> 3.0.0)
8
+ rspec-mocks (~> 3.0.0)
9
+ rspec-core (3.0.2)
10
+ rspec-support (~> 3.0.0)
11
+ rspec-expectations (3.0.2)
12
+ diff-lcs (>= 1.2.0, < 2.0)
13
+ rspec-support (~> 3.0.0)
14
+ rspec-mocks (3.0.2)
15
+ rspec-support (~> 3.0.0)
16
+ rspec-support (3.0.2)
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 PhraseApp.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,172 @@
1
+ Slimkeyfy
2
+ =
3
+ Extract plain Strings from .slim views and Rails controllers to replace them with I18n's t() method. Keys with it's translations will be streamed to a YAML file.
4
+ ```ruby
5
+ slimkeyfy app/views/users/show.html.slim en
6
+ # users/show.html.slim
7
+ h1 Hello World!
8
+ # converts to
9
+ h1= t('.hello_world')
10
+ # config/locales/users.en.yaml
11
+ # en:
12
+ # user:
13
+ # show:
14
+ # hello_world: Hello World!
15
+ ```
16
+
17
+ Install
18
+ -
19
+
20
+ With Ruby Gems
21
+ ```ruby
22
+ > gem install slimkeyfy
23
+ ```
24
+
25
+ With Bundler
26
+ ```ruby
27
+ group :development do
28
+ # Github
29
+ gem 'slimkeyfy', github: 'https://github.com/phrase/slimkeyfy.git'
30
+ # or with concrete version
31
+ gem 'slimkeyfy', '~> 0.1'
32
+ end
33
+ ```
34
+
35
+ Approach
36
+ -
37
+ Most of the time tools like this go for a 80/20 approach stating that 80% can be done right and 20% have to be done manually. Our approach is similar but a bit different. Translating and tagging your Rails app can be error prone. In order to reduce this Slimkeyfy streams in every line that matches the regular expression engine and prompts you to take an action. This guarantees a higher quality but also gets us closer to the 90%. It might take a little more time than full automation. The collected data is then processed into a YAML file. If you don't provide a YAML one will be created. All your processed views and resulting translations will be merged with the existing YAML.
38
+
39
+ Usage
40
+ -
41
+ ```unix
42
+ slimkeyfy INPUT_FILENAME_OR_DIRECTORY LOCALE (e.g. en, fr) [YAML_FILE] [Options]
43
+ ```
44
+ - If you do not provide a YAML file - one will be created at configs/locales/view_folder_name.locale.yml
45
+ - If you provide one make sure that the top level locale matches your provided locale
46
+ - The YAML file will be loaded as a hash and deep_merged with the new found translations
47
+
48
+ **Stream** - walks through the given file/files and if a regex hits you will be prompted to apply (y)es, discard (n)o, tag (x) (comments suggestions above the processed line) or (a)bort (only aborts the current file).
49
+
50
+ without YAML file
51
+ ```unix
52
+ slimkeyfy path/to/your/file.html.slim en
53
+ ```
54
+ with given YAML file (has to be valid YAML! with the top level locale matching your provided locale)
55
+ ```unix
56
+ slimkeyfy path/to/your/dir/ en path/to/your/en.yml
57
+ ```
58
+ A Backup (.bak) of the old file will be created e.g. index.html.slim => index.html.slim.bak.
59
+ Providing ---no-backup creates the backups temporarily and deletes them right after you apply your changes. (be careful!)
60
+
61
+ Example Usage
62
+ -
63
+ ```unix
64
+ your_app_name/
65
+ |- app/
66
+ |- views/
67
+ |- user/
68
+ new.html.slim
69
+ show.html.slim
70
+ |- project/
71
+ index.html.slim
72
+ ...
73
+ ...
74
+ |- config/
75
+ |- locales/
76
+ en.yml
77
+ ...
78
+ ...
79
+
80
+ > pwd
81
+ ../your_app_name/
82
+
83
+ > slimkeyfy app/views/users/ en
84
+ ... choose your changes here (y/n/x/a)
85
+
86
+ > ls app/views/users/
87
+ new.html.slim
88
+ show.html.slim
89
+ new.html.slim.bak
90
+ show.html.slim.bak
91
+
92
+ > ls config/locales/
93
+ user.en.yml
94
+ en.yml
95
+
96
+ > cat ../users/new.html.slim.bak
97
+ h1 Hello World!
98
+
99
+ > cat ../users/new.html.slim
100
+ h1= t('.hello_world')
101
+
102
+ > cat config/locales/en.yml
103
+ --
104
+ en:
105
+ keys..
106
+
107
+ > cat config/locales/users.en.yml
108
+ ---
109
+ en:
110
+ users:
111
+ new:
112
+ hello_world: Hello World!
113
+ show:
114
+ ...
115
+ ```
116
+ Suggested Workflow
117
+ -
118
+ As HTML is not 100% parsable there will be errors in the conversion. To minimize your error rate we suggest to approach each view or view_folder individually. The i18n-tasks gem helped a lot by finding errors. Always double check your views and make sure that everything went smoothly. Especially double check all your links. Here is an example workflow:
119
+ ```ruby
120
+ # 1. create a branch for a view folder
121
+ > git checkout -b users_localization
122
+
123
+ # 2. slimkeyfy the view folder you would like to tag
124
+ > slimkeyfy app/views/users/ en
125
+
126
+ # 3. go through all files and verify/add missing translations
127
+ # (check against the .bak files (use git diff))
128
+ > git diff app/views/users/views.html.slim
129
+
130
+ # 4. add your translations + keys to your locale file(s)
131
+ # 4.1 optional: Use the I18n-tasks gem to find missing translations
132
+
133
+ # 5. go through all your views and click through everything to actually "see" what changed
134
+
135
+ # 6. If everything is fine - clean up (remove .baks)
136
+ > rm app/views/users/*.bak
137
+ # Optional: remove temporary YAML files
138
+ > rm config/locales/users.en.yml
139
+ ```
140
+ Testing
141
+ -
142
+ To test the application simply call rspec spec/.. from the root directory of slimkeyfy
143
+ ```unix
144
+ bundle install
145
+ bundle exec rspec spec/
146
+ ```
147
+ PhraseApp Integration
148
+ -
149
+ Now that you processed your views and moved the generated keys to your localization files it is quite easy to push it to PhraseApp. If you have not set up your account yet [take a look here](https://phraseapp.com/docs/about/setup-your-translations-with-phraseapp?language=en). Make sure that the latest gem of PhraseApp is installed by simply typing:
150
+ ```unix
151
+ > gem install phrase
152
+ ```
153
+ If you are already familiar with the PhraseApp gem you can upload your translation/localization files now. For more details on your setup have a look at our [detailed guide](https://phraseapp.com/docs/about/access-your-locale-files-with-the-api-client?language=en).
154
+
155
+ Todo
156
+ -
157
+ - YAML placeholders are currently not supported (We are working on it!).
158
+ - a dry run option where you can see what will happen if you convert.
159
+ - currently you are prompted for all hits - We would like to do 70-80% automatically and prompt for the 20-30% that cannot be decided upon.
160
+ - adding / generalizing Regular Expressions for better hit rate
161
+
162
+ Issues
163
+ -
164
+ - If you choose to take a lot of files at one time make sure to go through with it. It is not an issue to completely rerun everything (already translated strings are ignored) but should be avoided.
165
+ - some hits will not be correct, some things that should be found are not and sometimes the regex engine won't work for mysterious reasons. Slimkeyfy is a helper, it does not provide full automation. It might make your work a little easier.
166
+
167
+ References
168
+ -
169
+ * Other tools, not slim specific for this task is the [i15r gem](https://github.com/balinterdi/i15r). It can process .haml and .erb.
170
+ * I strongly recommend checking your translated app with the [i18n-tasks gem](https://github.com/glebm/i18n-tasks). It is a great tool in finding missing and unused translations.
171
+ * Always consult the [Official Rails Internationalization guide](http://guides.rubyonrails.org/i18n.html) if in doubt.
172
+ * Visit [PhraseApp on Github](https://github.com/phrase/phrase)
data/bin/slimkeyfy ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/slimkeyfy'
4
+
5
+ SlimKeyfy.translate(ARGV)
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,90 @@
1
+ require 'optparse'
2
+
3
+ class SlimKeyfy::Console::Commandline
4
+ def initialize(args)
5
+ @options = {}
6
+ @args = args
7
+ OptionParser.new(&method(:opt_scan)).parse!(@args)
8
+ end
9
+
10
+ def wrong_usage
11
+ puts "Please provide a path to .slims and a locale name. See -h for more information."
12
+ exit
13
+ end
14
+
15
+ def opt_scan(opts)
16
+ opts.banner = "
17
+ #{"Usage".white}: slimkeyfy #{"INPUT_FILENAME_OR_DIRECTORY".green} #{"LOCALE".red} #{"[YAML_FILE]".yellow} [Options]
18
+ e.g. slimkeyfy #{"app/views/users/".green} #{"en".red} #{"phrase/locales/en.yml".yellow} [Options]
19
+
20
+ #{"Description".white}: Extract plain Strings from .slim views and Rails controllers to
21
+ replace them with I18n's t() method. Keys with it's translations will be streamed
22
+ to a YAML file.
23
+
24
+ the following options are available:
25
+
26
+ "
27
+ opts.on_tail('-h', '--help', 'Show this message') do
28
+ puts opts
29
+ exit
30
+ end
31
+ opts.on_tail('-v', '--version', 'Show current version') do
32
+ puts "0.1"
33
+ exit
34
+ end
35
+ opts.on_tail('-R', '--recursive', 'If a directory is given all subdirectories will be walked either.
36
+ Without -r and a directory just the files within the first level are walked.
37
+ ') do
38
+ @options[:recursive] = true
39
+ end
40
+ opts.on_tail('-b', '--no-backup', 'No Backups - for safety reasons - are created. For minimum safety we
41
+ recommend a version control like git. Backups will still be created for
42
+ comparison but deleted right after you agree to the changes.
43
+ ') do
44
+ @options[:no_backup] = true
45
+ end
46
+ end
47
+
48
+ def run
49
+ @options[:input] = input = @args.shift
50
+ @options[:locale] = locale = @args.shift
51
+ @options[:yaml_output] = @args.shift
52
+
53
+ wrong_usage if (input.nil? or locale.nil?)
54
+
55
+ if File.directory?(input) then
56
+ directory_translate(input)
57
+ elsif File.file?(input) then
58
+ translate
59
+ else
60
+ raise "Please provide a file or directory!"
61
+ exit
62
+ end
63
+ end
64
+
65
+ def directory_translate(input)
66
+ rec = @options.fetch(:recursive, false)
67
+ SlimKeyfy::Slimutils::MFileUtils.walk(input, rec).each do |rec_input|
68
+ if File.file?(rec_input) and is_valid_ext?(rec_input) then
69
+ @options[:input] = rec_input
70
+ translate
71
+ end
72
+ end
73
+ end
74
+
75
+ def translate
76
+ unless SlimKeyfy::Slimutils::MFileUtils.is_valid_extension?(@options[:input]) then
77
+ puts "invalid extension!"
78
+ return
79
+ end
80
+ @options[:ext] = SlimKeyfy::Slimutils::MFileUtils.file_extension(@options[:input])
81
+
82
+ puts "file=#{@options[:input]}"
83
+ translate_slim = SlimKeyfy::Console::Translate.new(@options)
84
+ begin
85
+ translate_slim.stream_mode
86
+ rescue Interrupt
87
+ SlimKeyfy::Slimutils::MFileUtils.restore(translate_slim.bak_path, translate_slim.original_file_path)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,30 @@
1
+ class SlimKeyfy::Console::IOAction
2
+ def self.yes_or_no?(msg)
3
+ puts "#{msg} (y|n)"
4
+ arg = STDIN.gets.chomp
5
+ if arg =~ /[yY](es)?/ then
6
+ true
7
+ elsif arg =~ /[nN]o?/ then
8
+ false
9
+ else
10
+ puts "Provide either (y)es or (n)o!"
11
+ self.yes_or_no?(msg)
12
+ end
13
+ end
14
+ def self.choose(msg)
15
+ puts "#{msg} (y|n) (x for tagging | (a)bort)"
16
+ arg = STDIN.gets.chomp
17
+ if arg =~ /[yY](es)?/ then
18
+ "y"
19
+ elsif arg =~ /[nN]o?/ then
20
+ "n"
21
+ elsif arg =~ /x/ then
22
+ "x"
23
+ elsif arg =~ /a/ then
24
+ "a"
25
+ else
26
+ puts "Either (y)es, (n)o, (x) for tagging or (a) to abort"
27
+ self.choose(msg)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ class SlimKeyfy::Console::Printer
2
+ def self.difference(old_line, new_line, translations)
3
+ puts "#{'-'.red} #{normalize(old_line).red}"
4
+ puts "#{'+'.green} #{normalize(new_line).green} => #{translations.to_s.yellow}"
5
+ puts "-"*40
6
+ end
7
+ def self.unix_diff(bak_path, file_path)
8
+ result = "Please install colordiff or diff (brew install colordiff)"
9
+ colordiff, diff = `which colordiff`, `which diff`
10
+ if not colordiff.empty? then
11
+ result = `colordiff #{bak_path} #{file_path}`
12
+ elsif not diff.empty? then
13
+ result =`diff #{bak_path} #{file_path}`
14
+ end
15
+ if result.nil? or result.strip.empty? then
16
+ puts "No changes for comparison found!"
17
+ else
18
+ puts "#{result}"
19
+ end
20
+ end
21
+ def self.normalize(line)
22
+ line.sub(/^\s*/, " ")
23
+ end
24
+ def self.tag(old_line, translations, comment_tag)
25
+ prettified_translations = translations.map{|k, v| "#{k}: #{v}, t('.#{k.split(".").last}')" }.join(" | ")
26
+ "#{indentation(old_line)}#{comment_tag} #{prettified_translations}\n#{old_line}"
27
+ end
28
+ def self.indentation(line)
29
+ return "" if line.nil? or line.empty?
30
+ " " * (line.size - line.gsub(/^\s+/, "").size)
31
+ end
32
+ end
33
+
34
+ class String
35
+ def colorize(color_code)
36
+ "\e[#{color_code}m#{self}\e[0m"
37
+ end
38
+ def red
39
+ colorize(31)
40
+ end
41
+ def green
42
+ colorize(32)
43
+ end
44
+ def yellow
45
+ colorize(34)
46
+ end
47
+ def white
48
+ colorize(37)
49
+ end
50
+ end
@@ -0,0 +1,101 @@
1
+ class SlimKeyfy::Console::Translate
2
+
3
+ attr_reader :original_file_path, :bak_path
4
+
5
+ def initialize(options={})
6
+ @extension = options[:ext]
7
+ @transformer = transformer
8
+ @original_file_path = options[:input]
9
+ @no_backup = options.fetch(:no_backup, false)
10
+ @bak_path = SlimKeyfy::Slimutils::MFileUtils.backup(@original_file_path)
11
+ @content = SlimKeyfy::Slimutils::FileReader.read(@bak_path).split("\n")
12
+ @file_path = SlimKeyfy::Slimutils::MFileUtils.create_new_file(@original_file_path)
13
+ @key_base = generate_key_base
14
+ @yaml_processor = create_yaml_processor(options)
15
+ @new_content = []
16
+ @changes = false
17
+ end
18
+
19
+ def transformer
20
+ if @extension == "slim" then
21
+ SlimKeyfy::Transformer::SlimTransformer
22
+ elsif @extension == "rb" then
23
+ SlimKeyfy::Transformer::ControllerTransformer
24
+ else
25
+ puts "Unknown extension type!"
26
+ exit
27
+ end
28
+ end
29
+
30
+ def create_yaml_processor(options)
31
+ SlimKeyfy::Slimutils::YamlProcessor.new(options[:locale], @key_base, options.fetch(:yaml_output, nil))
32
+ end
33
+
34
+ def generate_key_base
35
+ SlimKeyfy::Slimutils::BaseKeyGenerator.generate_key_base_from_path(@original_file_path, @extension)
36
+ end
37
+
38
+ def stream_mode
39
+ @content.each_with_index do |old_line, idx|
40
+ word = SlimKeyfy::Transformer::Word.new(old_line, @key_base, @extension)
41
+ new_line, translations = @transformer.new(word, @yaml_processor).transform
42
+ if translations_are_invalid?(translations)
43
+ @yaml_processor.delete_translations(translations)
44
+ update_with(idx, old_line)
45
+ else
46
+ process_new_line(idx, old_line, new_line, translations)
47
+ @changes = true
48
+ end
49
+ end
50
+ SlimKeyfy::Slimutils::FileWriter.write(@file_path, @new_content.join("\n"))
51
+ finalize!
52
+ end
53
+
54
+ def process_new_line(idx, old_line, new_line, translations)
55
+ SlimKeyfy::Console::Printer.difference(old_line, new_line, translations)
56
+ case SlimKeyfy::Console::IOAction.choose("Changes wanted?")
57
+ when "y" then update_with(idx, new_line)
58
+ when "n" then
59
+ update_with(idx, old_line)
60
+ @yaml_processor.delete_translations(translations)
61
+ when "x" then
62
+ update_with(idx, SlimKeyfy::Console::Printer.tag(old_line, translations, comment_tag))
63
+ @yaml_processor.delete_translations(translations)
64
+ when "a" then
65
+ SlimKeyfy::Slimutils::MFileUtils.restore(@bak_path, @original_file_path)
66
+ puts "Aborted!"
67
+ exit
68
+ end
69
+ end
70
+
71
+ def finalize!
72
+ if @changes then
73
+ if SlimKeyfy::Console::IOAction.yes_or_no?("Do you like to review your changes?") then
74
+ SlimKeyfy::Console::Printer.unix_diff(@bak_path, @original_file_path)
75
+ end
76
+ if SlimKeyfy::Console::IOAction.yes_or_no?("Do you like to save your changes?") then
77
+ @yaml_processor.store!
78
+ puts "Saved! at #{@original_file_path}"
79
+ SlimKeyfy::Slimutils::MFileUtils.rm(@bak_path) if @no_backup
80
+ else
81
+ SlimKeyfy::Slimutils::MFileUtils.restore(@bak_path, @original_file_path)
82
+ puts "Restored!"
83
+ end
84
+ else
85
+ SlimKeyfy::Slimutils::MFileUtils.restore(@bak_path, @original_file_path)
86
+ puts "Nothing was changed!"
87
+ end
88
+ end
89
+
90
+ def update_with(idx, line)
91
+ @new_content[idx] = line
92
+ end
93
+
94
+ def translations_are_invalid?(translations)
95
+ translations.nil? or translations.empty?
96
+ end
97
+
98
+ def comment_tag
99
+ @transformer.slim? ? "//" : "#"
100
+ end
101
+ end
@@ -0,0 +1,8 @@
1
+ module SlimKeyfy::Console
2
+
3
+ end
4
+
5
+ require 'slimkeyfy/console/printer'
6
+ require 'slimkeyfy/console/io_action'
7
+ require 'slimkeyfy/console/command_line'
8
+ require 'slimkeyfy/console/translate'
@@ -0,0 +1,61 @@
1
+ require 'find'
2
+ require 'fileutils'
3
+
4
+ class SlimKeyfy::Slimutils::MFileUtils
5
+ def self.restore(backup_path, original_file_path)
6
+ FileUtils.cp(backup_path, original_file_path)
7
+ FileUtils.rm(backup_path)
8
+ end
9
+ def self.rm(file_path)
10
+ FileUtils.rm(file_path)
11
+ end
12
+ def self.backup(input)
13
+ original_file_path = abs_path(input)
14
+ backup_path = "#{original_file_path}.bak"
15
+ FileUtils.cp(original_file_path, backup_path)
16
+ backup_path
17
+ end
18
+ def self.create_new_file(input)
19
+ new_file_path = self.abs_path(input)
20
+ SlimKeyfy::Slimutils::FileWriter.write(new_file_path, "")
21
+ new_file_path
22
+ end
23
+ def self.abs_path(file)
24
+ File.absolute_path(file)
25
+ end
26
+ def self.walk(arg, recursive=false)
27
+ directory = abs_path(arg)
28
+ files = []
29
+ if recursive then
30
+ Find.find(directory) do |f|
31
+ files << f if File.file?(f)
32
+ end
33
+ else
34
+ files = Dir["#{directory}/*"]
35
+ end
36
+ files
37
+ end
38
+ def self.file_extension(file_path)
39
+ file_path.split(".").last
40
+ end
41
+ def self.is_valid_extension?(file_path)
42
+ ext = self.file_extension(file_path)
43
+ return false if (ext.nil? or ext.empty?)
44
+ (ext.end_with?("slim") or ext.end_with?("rb"))
45
+ end
46
+ end
47
+
48
+ class SlimKeyfy::Slimutils::FileReader
49
+ def self.read(file)
50
+ File.read(File.expand_path(file))
51
+ end
52
+ end
53
+
54
+ class SlimKeyfy::Slimutils::FileWriter
55
+ def self.write(full_path, content)
56
+ File.open(full_path, "w+") { |f| f.write(content) }
57
+ end
58
+ def self.append(full_path, content)
59
+ open(full_path, 'a') { |f| f.puts content}
60
+ end
61
+ end