i18n_dashboard 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +80 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/i18n_dashboard/application.js +17 -0
  5. data/app/assets/javascripts/i18n_dashboard/bootstrap.js.coffee +4 -0
  6. data/app/assets/javascripts/i18n_dashboard/translations.js.coffee +20 -0
  7. data/app/assets/stylesheets/i18n_dashboard/application.css +13 -0
  8. data/app/assets/stylesheets/i18n_dashboard/bootstrap_and_overrides.css +7 -0
  9. data/app/assets/stylesheets/i18n_dashboard/translations.css +4 -0
  10. data/app/controllers/i18n_dashboard/application_controller.rb +4 -0
  11. data/app/controllers/i18n_dashboard/translations_controller.rb +21 -0
  12. data/app/helpers/i18n_dashboard/application_helper.rb +18 -0
  13. data/app/helpers/i18n_dashboard/translations_helper.rb +4 -0
  14. data/app/models/i18n_dashboard/translation.rb +44 -0
  15. data/app/views/i18n_dashboard/translations/index.html.haml +51 -0
  16. data/app/views/layouts/i18n_dashboard/application.html.haml +32 -0
  17. data/config/routes.rb +6 -0
  18. data/lib/assets/javascripts/jquery.autosize.js +192 -0
  19. data/lib/i18n_dashboard.rb +7 -0
  20. data/lib/i18n_dashboard/engine.rb +51 -0
  21. data/lib/i18n_dashboard/version.rb +3 -0
  22. data/lib/tasks/i18n_dashboard_tasks.rake +4 -0
  23. data/test/dummy/README.rdoc +261 -0
  24. data/test/dummy/Rakefile +7 -0
  25. data/test/dummy/app/assets/images/favicon.ico +0 -0
  26. data/test/dummy/app/assets/javascripts/application.js +15 -0
  27. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  28. data/test/dummy/app/controllers/application_controller.rb +3 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/test/dummy/config.ru +4 -0
  32. data/test/dummy/config/application.rb +60 -0
  33. data/test/dummy/config/boot.rb +10 -0
  34. data/test/dummy/config/database.yml +24 -0
  35. data/test/dummy/config/environment.rb +6 -0
  36. data/test/dummy/config/environments/development.rb +37 -0
  37. data/test/dummy/config/environments/production.rb +67 -0
  38. data/test/dummy/config/environments/test.rb +37 -0
  39. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  40. data/test/dummy/config/initializers/inflections.rb +15 -0
  41. data/test/dummy/config/initializers/mime_types.rb +5 -0
  42. data/test/dummy/config/initializers/secret_token.rb +7 -0
  43. data/test/dummy/config/initializers/session_store.rb +8 -0
  44. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/test/dummy/config/locales/en.yml +5 -0
  46. data/test/dummy/config/routes.rb +4 -0
  47. data/test/dummy/db/development.sqlite3 +0 -0
  48. data/test/dummy/db/test.sqlite3 +0 -0
  49. data/test/dummy/log/development.log +14335 -0
  50. data/test/dummy/log/test.log +420 -0
  51. data/test/dummy/public/404.html +26 -0
  52. data/test/dummy/public/422.html +26 -0
  53. data/test/dummy/public/500.html +25 -0
  54. data/test/dummy/public/favicon.ico +0 -0
  55. data/test/dummy/script/rails +6 -0
  56. data/test/dummy/tmp/cache/assets/C17/E40/sprockets%2F4308b5901b3134f6b1541f8a69276431 +0 -0
  57. data/test/dummy/tmp/cache/assets/C27/B00/sprockets%2F1b3e7717131812885279d16959cad225 +0 -0
  58. data/test/dummy/tmp/cache/assets/C29/8A0/sprockets%2Fa899e19256a0845205636938010c6fe5 +0 -0
  59. data/test/dummy/tmp/cache/assets/C57/880/sprockets%2F7610404e10c842a8cb69d7741678e619 +0 -0
  60. data/test/dummy/tmp/cache/assets/C7A/CA0/sprockets%2Fe62364e35231a761b76b13037f954c2f +0 -0
  61. data/test/dummy/tmp/cache/assets/C87/3F0/sprockets%2F1b04f197ed371938f027965191b01ff8 +0 -0
  62. data/test/dummy/tmp/cache/assets/C88/5F0/sprockets%2F69589b2e73a9d05247a6744a00b9d086 +0 -0
  63. data/test/dummy/tmp/cache/assets/C8C/9A0/sprockets%2F61288a069b85281ec267a04d9865cf26 +0 -0
  64. data/test/dummy/tmp/cache/assets/C98/FD0/sprockets%2F0b08d527a505c32173844d01cbc8353b +0 -0
  65. data/test/dummy/tmp/cache/assets/CA0/550/sprockets%2F36f109f19a5f50760020a2350aee6b76 +0 -0
  66. data/test/dummy/tmp/cache/assets/CA2/670/sprockets%2Fde3f90c262d351a812781a381174c0e4 +0 -0
  67. data/test/dummy/tmp/cache/assets/CA2/790/sprockets%2Fa91323b76385b2492b331611cf3a1ee8 +0 -0
  68. data/test/dummy/tmp/cache/assets/CA7/C90/sprockets%2F1e61531b0c665288f42cd0e490de4362 +0 -0
  69. data/test/dummy/tmp/cache/assets/CAB/B40/sprockets%2Fdf24253c225938243de61f4b8e45b350 +0 -0
  70. data/test/dummy/tmp/cache/assets/CB2/880/sprockets%2Fdf63ab7177a704396db76e501e950065 +0 -0
  71. data/test/dummy/tmp/cache/assets/CB3/530/sprockets%2F33561d49d5d2e8b94325b5c34f056f70 +0 -0
  72. data/test/dummy/tmp/cache/assets/CB3/CE0/sprockets%2F061634a9f7e57e6a32b2163094cdf675 +0 -0
  73. data/test/dummy/tmp/cache/assets/CB7/BF0/sprockets%2F88d248598b413e816ecc4a301d702c89 +0 -0
  74. data/test/dummy/tmp/cache/assets/CC4/5E0/sprockets%2Fb4fb33ba57d762df1313232c20172c16 +0 -0
  75. data/test/dummy/tmp/cache/assets/CCF/160/sprockets%2F2a21280366fbd1b4b3b27f8b5b391175 +0 -0
  76. data/test/dummy/tmp/cache/assets/CD6/C30/sprockets%2F68a84eca6a0b8a025698c5a4f1553113 +0 -0
  77. data/test/dummy/tmp/cache/assets/CD7/690/sprockets%2F324f37142a49a78eb59c69dc043221ba +0 -0
  78. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  79. data/test/dummy/tmp/cache/assets/CDA/4A0/sprockets%2Fa4de2f6e912b73e5465154c91360d2b4 +0 -0
  80. data/test/dummy/tmp/cache/assets/CDB/530/sprockets%2F065cdf3144ff76d3672a96b1c4b04534 +0 -0
  81. data/test/dummy/tmp/cache/assets/CDB/FE0/sprockets%2F40ead92d2446ed8d412cc6185222791e +0 -0
  82. data/test/dummy/tmp/cache/assets/CDC/1E0/sprockets%2F794ffe755fdbc072f65081d71400b132 +0 -0
  83. data/test/dummy/tmp/cache/assets/CDE/CB0/sprockets%2Fd0d9c1b1b5416f7830ff460128f267b8 +0 -0
  84. data/test/dummy/tmp/cache/assets/CDF/E80/sprockets%2F13e20c9963f428d80d010b7fd6916a6e +0 -0
  85. data/test/dummy/tmp/cache/assets/CE2/070/sprockets%2Fb88b47b5b7145e2d4a09586357a0d48a +0 -0
  86. data/test/dummy/tmp/cache/assets/CE3/290/sprockets%2F8140ecc79e862a4e363353a1f505f7c7 +0 -0
  87. data/test/dummy/tmp/cache/assets/CE3/910/sprockets%2F0f69e891e76f603460bb2d4be73754a0 +0 -0
  88. data/test/dummy/tmp/cache/assets/D04/A50/sprockets%2F9a5702b9d21b6b356fd1245a532eac48 +0 -0
  89. data/test/dummy/tmp/cache/assets/D09/490/sprockets%2Fa45021c6df1675785caf177e3a33b6f0 +0 -0
  90. data/test/dummy/tmp/cache/assets/D0A/9D0/sprockets%2Fe026d4c914a79065f1bdb1443c52e9e4 +0 -0
  91. data/test/dummy/tmp/cache/assets/D0E/220/sprockets%2F74dd8ae13eb4fd2039d80f63379710a3 +0 -0
  92. data/test/dummy/tmp/cache/assets/D12/340/sprockets%2F9c4299f1befb5b336eee0021648720e7 +0 -0
  93. data/test/dummy/tmp/cache/assets/D14/DF0/sprockets%2Fdc7d2699f906aa73df210a647b906f32 +0 -0
  94. data/test/dummy/tmp/cache/assets/D17/4C0/sprockets%2F700827acd727b6fc8361f454c68a5cd7 +0 -0
  95. data/test/dummy/tmp/cache/assets/D19/4B0/sprockets%2F81b5e5d4982b62a61608083ffd8aa9f4 +0 -0
  96. data/test/dummy/tmp/cache/assets/D1A/960/sprockets%2F5f29e96153e76650daf023ef6eb60c85 +0 -0
  97. data/test/dummy/tmp/cache/assets/D20/A40/sprockets%2Fa8a7dde52a9693a9c76c4521b659717e +0 -0
  98. data/test/dummy/tmp/cache/assets/D23/130/sprockets%2Fd23bf67170bd556698cf57dc98d74a43 +0 -0
  99. data/test/dummy/tmp/cache/assets/D27/B40/sprockets%2Fdeed00121b4375a3b720cef0d19825b4 +0 -0
  100. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  101. data/test/dummy/tmp/cache/assets/D34/650/sprockets%2F506eb0870b70db1817ad51fa7e826fb1 +0 -0
  102. data/test/dummy/tmp/cache/assets/D35/130/sprockets%2F02d1845ddb029d6e52168ecd80bb443d +0 -0
  103. data/test/dummy/tmp/cache/assets/D37/0E0/sprockets%2F7d091415f6d7c0e87302b6cd2fc0d3e3 +0 -0
  104. data/test/dummy/tmp/cache/assets/D38/640/sprockets%2F4a303ec194ba2adad59e674b62666c72 +0 -0
  105. data/test/dummy/tmp/cache/assets/D44/3B0/sprockets%2F7f7402dea766db136ffa0a8e915e3645 +0 -0
  106. data/test/dummy/tmp/cache/assets/D45/900/sprockets%2F4ea0c0d9f777c1c3e6ac2c949c526358 +0 -0
  107. data/test/dummy/tmp/cache/assets/D47/AE0/sprockets%2Fda6c6f8491d0926e5bd66c99e1a4c502 +0 -0
  108. data/test/dummy/tmp/cache/assets/D4C/8F0/sprockets%2F91c3748be4d5d83687d62df1c745b4cb +0 -0
  109. data/test/dummy/tmp/cache/assets/D4D/C80/sprockets%2Fbd91e31998a5390c39c8dfe9e0b2a268 +0 -0
  110. data/test/dummy/tmp/cache/assets/D4E/010/sprockets%2F503bf76de6b580b6084697a0bce9ff94 +0 -0
  111. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  112. data/test/dummy/tmp/cache/assets/D52/510/sprockets%2Fafa6f0e91783285a62239f19abd9e88f +0 -0
  113. data/test/dummy/tmp/cache/assets/D52/660/sprockets%2Fbd777ea944a4e6eac534918e3486dc66 +0 -0
  114. data/test/dummy/tmp/cache/assets/D53/1C0/sprockets%2F5f2c389e5a57cf95066e26bf39c29d5a +0 -0
  115. data/test/dummy/tmp/cache/assets/D54/690/sprockets%2F2e04d9409cb8227f7f85ef58c59fa0e6 +0 -0
  116. data/test/dummy/tmp/cache/assets/D59/0F0/sprockets%2F4270ea9dbd84ff48e02ba315a0ab7230 +0 -0
  117. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  118. data/test/dummy/tmp/cache/assets/D5E/D60/sprockets%2Fa16542dae11a0c28f64da023d98e7bc5 +0 -0
  119. data/test/dummy/tmp/cache/assets/D66/1D0/sprockets%2F126f2983156b26d20a9dece1fe2cca54 +0 -0
  120. data/test/dummy/tmp/cache/assets/D67/550/sprockets%2F325bfe833d0bef2dbc4d4116992c272d +0 -0
  121. data/test/dummy/tmp/cache/assets/D6B/A30/sprockets%2F4953faaf0994fdf44c268a2d3a2e34a1 +0 -0
  122. data/test/dummy/tmp/cache/assets/D6C/730/sprockets%2F8a4c656c6d8f2d130805564fbf0decb2 +0 -0
  123. data/test/dummy/tmp/cache/assets/D6D/3A0/sprockets%2F5072c9166eb56e59594fd1cdcaa0a81b +0 -0
  124. data/test/dummy/tmp/cache/assets/D6D/860/sprockets%2F13bcde6be1a8a4a0699a69a12c9f3944 +0 -0
  125. data/test/dummy/tmp/cache/assets/D70/B60/sprockets%2F0e4af1c70210cea20082a802eb4cba0e +0 -0
  126. data/test/dummy/tmp/cache/assets/D74/170/sprockets%2Fa202c9cbd617a6e5a8522ee738f8da59 +0 -0
  127. data/test/dummy/tmp/cache/assets/D81/650/sprockets%2Fbf62048d8e17fec958bfc40f4f9337f1 +0 -0
  128. data/test/dummy/tmp/cache/assets/D86/550/sprockets%2Fe37f7c1b22f998df87811f6e19df1e5a +0 -0
  129. data/test/dummy/tmp/cache/assets/D89/610/sprockets%2Fc413e3b81dc0aaca2de9b91e8146320e +0 -0
  130. data/test/dummy/tmp/cache/assets/D8E/930/sprockets%2F3eefd876c4c21f796f2875ca958dd63f +0 -0
  131. data/test/dummy/tmp/cache/assets/D8F/350/sprockets%2Fa2f17c30139a4611cf50cbbeed328e9d +0 -0
  132. data/test/dummy/tmp/cache/assets/D9B/3B0/sprockets%2Fe136169a133e4e357fe0fdca6b27bdd7 +0 -0
  133. data/test/dummy/tmp/cache/assets/DA0/C20/sprockets%2F29563dbecedcba0e44f34d6f135769c2 +0 -0
  134. data/test/dummy/tmp/cache/assets/DA3/160/sprockets%2Fd553d92fe1ffa3e59eaebc7c10600797 +0 -0
  135. data/test/dummy/tmp/cache/assets/DA7/A80/sprockets%2Fccfbd170e39dfb846de914e97036b64a +0 -0
  136. data/test/dummy/tmp/cache/assets/DAA/DA0/sprockets%2Ff94eca2ba5f45236fc224fef7f25c579 +0 -0
  137. data/test/dummy/tmp/cache/assets/DAE/2F0/sprockets%2F5bf09d27baa4bbd128e151a2d0fa60a3 +0 -0
  138. data/test/dummy/tmp/cache/assets/DAE/E10/sprockets%2F0cd4f3341cb9a98f2d9d53d4ffc96f90 +0 -0
  139. data/test/dummy/tmp/cache/assets/DB7/310/sprockets%2F1fbb9e98965bbf2ac579e2b31dd8f894 +0 -0
  140. data/test/dummy/tmp/cache/assets/DBD/790/sprockets%2Fe83ef87fc9a96e7df0ea82d5f7542e09 +0 -0
  141. data/test/dummy/tmp/cache/assets/DC4/310/sprockets%2Fce37cfc9e43c166c4f6e0a426602acca +0 -0
  142. data/test/dummy/tmp/cache/assets/DC8/410/sprockets%2Fbce5aec46efaa4562dd4397cd6c26113 +0 -0
  143. data/test/dummy/tmp/cache/assets/DD1/1D0/sprockets%2F3ba28ff187fc1853310effb2ffc77be2 +0 -0
  144. data/test/dummy/tmp/cache/assets/DD7/DC0/sprockets%2F94f1451efc5534b6e18becb9ff751aed +0 -0
  145. data/test/dummy/tmp/cache/assets/DDB/660/sprockets%2F4f4d7807fefc271ae9681d46cbfa7d3c +0 -0
  146. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  147. data/test/dummy/tmp/cache/assets/DDC/780/sprockets%2F6cdaf95075508fdf1d6f9caed58bc912 +0 -0
  148. data/test/dummy/tmp/cache/assets/DDC/AF0/sprockets%2Fc930d4549ca9885a8fec4ebb7b64bec4 +0 -0
  149. data/test/dummy/tmp/cache/assets/DE3/1E0/sprockets%2F585396ba7ec073f6dfbfb617e9c6ae7e +0 -0
  150. data/test/dummy/tmp/cache/assets/DE6/600/sprockets%2F9cc3fd4df486f860e8d7ddf3645c0ef4 +0 -0
  151. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  152. data/test/dummy/tmp/cache/assets/E10/1F0/sprockets%2F9fe678546e13bdced97f0143fdca7efc +0 -0
  153. data/test/dummy/tmp/cache/assets/E4D/ED0/sprockets%2Faf66ce6d0cda4622cc0ddeabf0950ca8 +0 -0
  154. data/test/dummy/tmp/cache/assets/E53/920/sprockets%2Fb53cddcfb4c8ce49c1e0610f4b0be9be +0 -0
  155. data/test/dummy/tmp/cache/assets/E87/E70/sprockets%2Fa441ed46c0f3abe7f8f6dc0b3ad8ecce +0 -0
  156. data/test/functional/i18n_dashboard/translations_controller_test.rb +9 -0
  157. data/test/i18n_dashboard_test.rb +7 -0
  158. data/test/test_helper.rb +18 -0
  159. data/test/unit/helpers/i18n_dashboard/translations_helper_test.rb +6 -0
  160. data/test/unit/i18n_dashboard/translation_test.rb +75 -0
  161. metadata +491 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # I18n Dashboard
2
+
3
+ [![Build Status](https://travis-ci.org/fourmach/i18n_dashboard.png?branch=master)](https://travis-ci.org/fourmach/i18n_dashboard)
4
+ [![Gem Version](https://badge.fury.io/rb/i18n_dashboard.png)](http://badge.fury.io/rb/i18n_dashboard)
5
+ [![Code Climate](https://codeclimate.com/github/fourmach/i18n_dashboard.png)](https://codeclimate.com/github/fourmach/i18n_dashboard)
6
+ [![Coverage Status](https://coveralls.io/repos/fourmach/i18n_dashboard/badge.png?branch=master)](https://coveralls.io/r/fourmach/i18n_dashboard?branch=master)
7
+
8
+
9
+ Rails Engine for I18n management with redis as backend.
10
+
11
+ ## Screenshots
12
+
13
+ ![#](https://raw.github.com/fourmach/i18n_dashboard/master/doc/screenshot-1.png)
14
+ ![#](https://raw.github.com/fourmach/i18n_dashboard/master/doc/screenshot-2.png)
15
+
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ``` ruby
22
+ gem 'i18n_dashboard'
23
+ ```
24
+
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Modify your config/routes.rb and add:
31
+
32
+ ``` ruby
33
+ mount I18nDashboard::Engine => '/i18n_dashboard'
34
+ ```
35
+
36
+ Add to the bottom of config/environment.rb
37
+ ``` ruby
38
+ I18nDashboard::Engine.load!
39
+ ```
40
+
41
+
42
+ ## Customize
43
+
44
+ Redis configuration:
45
+
46
+ ``` ruby
47
+ I18nDashboard::Engine.redis = Redis.new
48
+ ```
49
+
50
+ Customize layout
51
+
52
+ ``` ruby
53
+ I18nDashboard::TranslationsController.layout 'admin'
54
+ ```
55
+ And add `//= require i18n_dashboard/application` to your javascript.
56
+
57
+
58
+ But beware, you may have to change somethings in your template like:
59
+
60
+ ``` ruby
61
+ # partials
62
+ render 'admin_menu'
63
+
64
+ # change by for example
65
+ render 'application/admin_menu'
66
+
67
+ # or routes
68
+ admin_root_path
69
+ # add the prefix main_app
70
+ main_app.admin_root_path
71
+ ```
72
+
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork it
77
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
78
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
79
+ 4. Push to the branch (`git push origin my-new-feature`)
80
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'I18nDashboard'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,17 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require jquery.autosize
16
+ //= require twitter/bootstrap
17
+ //= require_tree .
@@ -0,0 +1,4 @@
1
+ jQuery ->
2
+ $("a[rel=popover]").popover()
3
+ $(".tooltip").tooltip()
4
+ $("a[rel=tooltip]").tooltip()
@@ -0,0 +1,20 @@
1
+ jQuery ->
2
+ $('#form-translation textarea').autosize()
3
+
4
+ $('.add-translation').click (event) ->
5
+ event.preventDefault()
6
+ $('#form-translation #locale').val('')
7
+ $('#form-translation #key').val('')
8
+ $('#form-translation #value').val('')
9
+ $('#form-translation #value').trigger('autosize')
10
+ $('#form-translation #value').focus()
11
+
12
+ $('.edit-translation').click (event) ->
13
+ event.preventDefault()
14
+ $('#form-translation #locale').val($(@).data('locale'))
15
+ $('#form-translation #key').val($(@).data('key'))
16
+ $('#form-translation #value').val($(@).html().trim())
17
+
18
+ $('#form-translation #value').trigger('autosize')
19
+ $('#form-translation #value').focus()
20
+ $('#form-translation #value')[0].setSelectionRange(0,0)
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,7 @@
1
+ /*
2
+ =require twitter-bootstrap-static/bootstrap
3
+
4
+ Use Font Awesome icons (default)
5
+ To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites"
6
+ =require twitter-bootstrap-static/fontawesome
7
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ module I18nDashboard
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ require_dependency "i18n_dashboard/application_controller"
2
+
3
+ module I18nDashboard
4
+ class TranslationsController < ApplicationController
5
+
6
+ def index
7
+ @translations = Translation.all(params[:query])
8
+ end
9
+
10
+ def create
11
+ Translation.create(params[:key], params[:value], params[:locale])
12
+ redirect_to root_path, :notice => "Added translations"
13
+ end
14
+
15
+ def destroy
16
+ Translation.destroy(params[:id])
17
+ redirect_to root_path, :notice => "Key deleted"
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module I18nDashboard
2
+ module ApplicationHelper
3
+ def title(page_title, show_title = true)
4
+ @show_title = show_title
5
+ if @show_title
6
+ content_for(:title) { h(page_title.to_s) }
7
+ end
8
+ end
9
+
10
+ def show_title?
11
+ @show_title
12
+ end
13
+
14
+ def humanize_key(key)
15
+ key.split('.').last.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module I18nDashboard
2
+ module TranslationsHelper
3
+ end
4
+ end
@@ -0,0 +1,44 @@
1
+ module I18nDashboard
2
+ class Translation
3
+
4
+
5
+ def self.all(string = nil)
6
+ keys = Engine.redis.sunion('keys', 'system_keys')
7
+ if string.present?
8
+ keys = keys.grep(/#{string}/)
9
+ end
10
+ keys.sort
11
+ end
12
+
13
+ def self.keys
14
+ Engine.redis.smembers('keys').sort!
15
+ end
16
+
17
+ def self.system_keys
18
+ Engine.redis.smembers('system_keys').sort!
19
+ end
20
+
21
+ def self.system_key?(key)
22
+ Engine.redis.sismember('system_keys', key)
23
+ end
24
+
25
+ def self.create(key, value, locale)
26
+ if key.present?
27
+ Engine.redis.sadd('keys', key)
28
+ I18n.backend.store_translations(locale, {key => value}, :escape => false)
29
+ end
30
+ end
31
+
32
+ def self.exists?(key, locale)
33
+ Engine.redis.exists("#{locale}.#{key}")
34
+ end
35
+
36
+ def self.destroy(key)
37
+ Engine.redis.srem('keys', key)
38
+ I18n.available_locales.each do |locale|
39
+ Engine.redis.del("#{locale}.#{key}")
40
+ end
41
+ I18n.reload!
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,51 @@
1
+ - title "Translations"
2
+
3
+ #add-translation.modal.hide.fade
4
+ .modal-header
5
+ %a.close{"data-dismiss" => "modal"} ×
6
+ %h3 Translation
7
+ .modal-body
8
+ .row
9
+ = form_tag translations_path, id: 'form-translation' do
10
+ .span1
11
+ = label_tag :locale
12
+ = text_field_tag :locale, '', class: 'span1', autofocus: true
13
+
14
+ .span4
15
+ = label_tag :key
16
+ = text_field_tag :key, '', class: 'span4'
17
+
18
+ .span5
19
+ = label_tag :value
20
+ = text_area_tag :value, '', class: 'span5'
21
+ .span2
22
+ %br
23
+ = button_tag "Submit", class: 'btn'
24
+
25
+ .navbar
26
+ .navbar-inner
27
+ = form_tag translations_path, class: 'navbar-form pull-left', method: :get do
28
+ = text_field_tag :query, params[:query], hint: 'Search', autofocus: true
29
+ = button_tag 'search', class: 'btn'
30
+ = link_to 'clear', translations_path, class: 'btn'
31
+
32
+ .pull-right
33
+ = link_to 'new', '#', data: { toggle: "modal", target: '#add-translation'}, class: 'btn add-translation'
34
+ %hr/
35
+ %table.table.table-hover
36
+ %thead
37
+ %th key
38
+ - I18n.available_locales.each do |locale|
39
+ %th= locale
40
+ %tbody
41
+ - @translations.each do |key|
42
+ %tr
43
+ %td= key
44
+ - I18n.available_locales.each do |locale|
45
+ %td
46
+ = link_to '#', data: {key: key, locale: locale, toggle: "modal", target: '#add-translation'}, class: "edit-translation #{(I18nDashboard::Translation.exists?(key, locale) ? nil : 'text-error')}" do
47
+ = t(key, locale: locale, default: humanize_key(key))
48
+ %td
49
+ - unless I18nDashboard::Translation.system_key?(key)
50
+ = link_to translation_path(key), method: :delete, class: 'btn btn-mini btn-danger' do
51
+ %i.icon-trash
@@ -0,0 +1,32 @@
1
+ !!!
2
+ %html{lang: I18n.locale}
3
+ %head
4
+ %meta{:charset => "utf-8"}
5
+ %title
6
+ = content_for?(:title) ? (yield(:title) + " - I18n Dashboard") : "I18n Dashboard"
7
+ %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
8
+ %meta{:content => "Fourmach.com", :name => "author"}
9
+
10
+ = stylesheet_link_tag "i18n_dashboard/application", media: nil
11
+
12
+ / Le HTML5 shim, for IE6-8 support of HTML5 elements
13
+ /[if lt IE 9]
14
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
15
+
16
+ = csrf_meta_tag
17
+ %body{id: "#{controller.controller_name}-#{controller.action_name}"}
18
+ / = render 'application/admin_menu'
19
+
20
+ .container
21
+ %h1= yield(:title)
22
+
23
+ #flash
24
+ - flash.each do |key, value|
25
+ .alert{ :class => "alert-#{key}" }
26
+ = value
27
+
28
+
29
+ = yield
30
+
31
+ = javascript_include_tag "i18n_dashboard/application"
32
+
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ I18nDashboard::Engine.routes.draw do
2
+
3
+ root to: "translations#index"
4
+ resources :translations, only: [:index, :create, :destroy]
5
+
6
+ end
@@ -0,0 +1,192 @@
1
+ /*!
2
+ jQuery Autosize v1.16.7
3
+ (c) 2013 Jack Moore - jacklmoore.com
4
+ updated: 2013-03-20
5
+ license: http://www.opensource.org/licenses/mit-license.php
6
+ */
7
+
8
+
9
+ (function ($) {
10
+ var
11
+ defaults = {
12
+ className: 'autosizejs',
13
+ append: '',
14
+ callback: false
15
+ },
16
+ hidden = 'hidden',
17
+ borderBox = 'border-box',
18
+ lineHeight = 'lineHeight',
19
+ supportsScrollHeight,
20
+
21
+ // border:0 is unnecessary, but avoids a bug in FireFox on OSX (http://www.jacklmoore.com/autosize#comment-851)
22
+ copy = '<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; width: 0; overflow:hidden;"/>',
23
+
24
+ // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value.
25
+ copyStyle = [
26
+ 'fontFamily',
27
+ 'fontSize',
28
+ 'fontWeight',
29
+ 'fontStyle',
30
+ 'letterSpacing',
31
+ 'textTransform',
32
+ 'wordSpacing',
33
+ 'textIndent'
34
+ ],
35
+ oninput = 'oninput',
36
+ onpropertychange = 'onpropertychange',
37
+
38
+ // to keep track which textarea is being mirrored when adjust() is called.
39
+ mirrored,
40
+
41
+ // the mirror element, which is used to calculate what size the mirrored element should be.
42
+ mirror = $(copy).data('autosize', true)[0];
43
+
44
+ // test that line-height can be accurately copied.
45
+ mirror.style.lineHeight = '99px';
46
+ if ($(mirror).css(lineHeight) === '99px') {
47
+ copyStyle.push(lineHeight);
48
+ }
49
+ mirror.style.lineHeight = '';
50
+
51
+ $.fn.autosize = function (options) {
52
+ options = $.extend({}, defaults, options || {});
53
+
54
+ if (mirror.parentNode !== document.body) {
55
+ $(document.body).append(mirror);
56
+
57
+ mirror.value = "\n\n\n";
58
+ mirror.scrollTop = 9e4;
59
+ supportsScrollHeight = mirror.scrollHeight === mirror.scrollTop + mirror.clientHeight;
60
+ }
61
+
62
+ return this.each(function () {
63
+ var
64
+ ta = this,
65
+ $ta = $(ta),
66
+ minHeight,
67
+ active,
68
+ resize,
69
+ boxOffset = 0,
70
+ callback = $.isFunction(options.callback);
71
+
72
+ if ($ta.data('autosize')) {
73
+ // exit if autosize has already been applied, or if the textarea is the mirror element.
74
+ return;
75
+ }
76
+
77
+ if ($ta.css('box-sizing') === borderBox || $ta.css('-moz-box-sizing') === borderBox || $ta.css('-webkit-box-sizing') === borderBox){
78
+ boxOffset = $ta.outerHeight() - $ta.height();
79
+ }
80
+
81
+ minHeight = Math.max(parseInt($ta.css('minHeight'), 10) - boxOffset, $ta.height());
82
+
83
+ resize = ($ta.css('resize') === 'none' || $ta.css('resize') === 'vertical') ? 'none' : 'horizontal';
84
+
85
+ $ta.css({
86
+ overflow: hidden,
87
+ overflowY: hidden,
88
+ wordWrap: 'break-word',
89
+ resize: resize
90
+ }).data('autosize', true);
91
+
92
+ function initMirror() {
93
+ mirrored = ta;
94
+ mirror.className = options.className;
95
+
96
+ // mirror is a duplicate textarea located off-screen that
97
+ // is automatically updated to contain the same text as the
98
+ // original textarea. mirror always has a height of 0.
99
+ // This gives a cross-browser supported way getting the actual
100
+ // height of the text, through the scrollTop property.
101
+ $.each(copyStyle, function(i, val){
102
+ mirror.style[val] = $ta.css(val);
103
+ });
104
+ }
105
+
106
+ // Using mainly bare JS in this function because it is going
107
+ // to fire very often while typing, and needs to very efficient.
108
+ function adjust() {
109
+ var height, overflow, original;
110
+
111
+ if (mirrored !== ta) {
112
+ initMirror();
113
+ }
114
+
115
+ // the active flag keeps IE from tripping all over itself. Otherwise
116
+ // actions in the adjust function will cause IE to call adjust again.
117
+ if (!active) {
118
+ active = true;
119
+ mirror.value = ta.value + options.append;
120
+ mirror.style.overflowY = ta.style.overflowY;
121
+ original = parseInt(ta.style.height,10);
122
+
123
+ // Update the width in case the original textarea width has changed
124
+ // A floor of 0 is needed because IE8 returns a negative value for hidden textareas, raising an error.
125
+ mirror.style.width = Math.max($ta.width(), 0) + 'px';
126
+
127
+ if (supportsScrollHeight) {
128
+ height = mirror.scrollHeight;
129
+ } else { // IE6 & IE7
130
+ mirror.scrollTop = 0;
131
+ mirror.scrollTop = 9e4;
132
+ height = mirror.scrollTop;
133
+ }
134
+
135
+ var maxHeight = parseInt($ta.css('maxHeight'), 10);
136
+ // Opera returns '-1px' when max-height is set to 'none'.
137
+ maxHeight = maxHeight && maxHeight > 0 ? maxHeight : 9e4;
138
+ if (height > maxHeight) {
139
+ height = maxHeight;
140
+ overflow = 'scroll';
141
+ } else if (height < minHeight) {
142
+ height = minHeight;
143
+ }
144
+ height += boxOffset;
145
+ ta.style.overflowY = overflow || hidden;
146
+
147
+ if (original !== height) {
148
+ ta.style.height = height + 'px';
149
+ if (callback) {
150
+ options.callback.call(ta,ta);
151
+ }
152
+ }
153
+
154
+ // This small timeout gives IE a chance to draw it's scrollbar
155
+ // before adjust can be run again (prevents an infinite loop).
156
+ setTimeout(function () {
157
+ active = false;
158
+ }, 1);
159
+ }
160
+ }
161
+
162
+ if (onpropertychange in ta) {
163
+ if (oninput in ta) {
164
+ // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions,
165
+ // so binding to onkeyup to catch most of those occassions. There is no way that I
166
+ // know of to detect something like 'cut' in IE9.
167
+ ta[oninput] = ta.onkeyup = adjust;
168
+ } else {
169
+ // IE7 / IE8
170
+ ta[onpropertychange] = adjust;
171
+ }
172
+ } else {
173
+ // Modern Browsers
174
+ ta[oninput] = adjust;
175
+ }
176
+
177
+ $(window).on('resize', function(){
178
+ active = false;
179
+ adjust();
180
+ });
181
+
182
+ // Allow for manual triggering if needed.
183
+ $ta.on('autosize', function(){
184
+ active = false;
185
+ adjust();
186
+ });
187
+
188
+ // Call adjust in case the textarea already contains text.
189
+ adjust();
190
+ });
191
+ };
192
+ }(window.jQuery || window.Zepto));