idioma 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (342) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +91 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/idioma/application.js +15 -0
  6. data/app/assets/javascripts/idioma/phrases.js.coffee +35 -0
  7. data/app/assets/stylesheets/idioma/application.css.scss +26 -0
  8. data/app/assets/stylesheets/idioma/forms.css.scss +19 -0
  9. data/app/assets/stylesheets/idioma/phrases.css +4 -0
  10. data/app/controllers/idioma/application_controller.rb +4 -0
  11. data/app/controllers/idioma/phrases_controller.rb +96 -0
  12. data/app/helpers/idioma/application_helper.rb +4 -0
  13. data/app/helpers/idioma/phrases_helper.rb +4 -0
  14. data/app/models/idioma/phrase.rb +115 -0
  15. data/app/models/idioma/phrase_exporter.rb +69 -0
  16. data/app/models/idioma/phrase_extractor.rb +49 -0
  17. data/app/models/idioma/phrase_importer.rb +50 -0
  18. data/app/models/idioma/redis_backend.rb +22 -0
  19. data/app/views/idioma/phrases/index.html.haml +45 -0
  20. data/app/views/layouts/idioma/application.html.haml +22 -0
  21. data/config/locales/idioma.en.yml +20 -0
  22. data/config/routes.rb +4 -0
  23. data/db/migrate/20140709015052_create_idioma_phrases.rb +14 -0
  24. data/lib/concerns/models/date_flag.rb +96 -0
  25. data/lib/idioma/engine.rb +27 -0
  26. data/lib/idioma/version.rb +3 -0
  27. data/lib/idioma.rb +23 -0
  28. data/lib/tasks/idioma_tasks.rake +15 -0
  29. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  30. data/spec/controllers/phrases_controller_spec.rb +91 -0
  31. data/spec/dummy/README.rdoc +28 -0
  32. data/spec/dummy/Rakefile +6 -0
  33. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  34. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  36. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  37. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  38. data/spec/dummy/bin/bundle +3 -0
  39. data/spec/dummy/bin/rails +4 -0
  40. data/spec/dummy/bin/rake +4 -0
  41. data/spec/dummy/config/application.rb +25 -0
  42. data/spec/dummy/config/boot.rb +5 -0
  43. data/spec/dummy/config/database.yml +28 -0
  44. data/spec/dummy/config/environment.rb +5 -0
  45. data/spec/dummy/config/environments/development.rb +37 -0
  46. data/spec/dummy/config/environments/production.rb +83 -0
  47. data/spec/dummy/config/environments/test.rb +39 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  50. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  51. data/spec/dummy/config/initializers/i18n.rb +4 -0
  52. data/spec/dummy/config/initializers/idioma.rb +9 -0
  53. data/spec/dummy/config/initializers/inflections.rb +16 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  55. data/spec/dummy/config/initializers/session_store.rb +3 -0
  56. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  57. data/spec/dummy/config/locales/en.yml +23 -0
  58. data/spec/dummy/config/routes.rb +3 -0
  59. data/spec/dummy/config/secrets.yml +22 -0
  60. data/spec/dummy/config.ru +4 -0
  61. data/spec/dummy/db/migrate/20141115171836_create_idioma_phrases.idioma.rb +15 -0
  62. data/spec/dummy/db/schema.rb +30 -0
  63. data/spec/dummy/log/development.log +25637 -0
  64. data/spec/dummy/log/test.log +4291 -0
  65. data/spec/dummy/public/404.html +67 -0
  66. data/spec/dummy/public/422.html +67 -0
  67. data/spec/dummy/public/500.html +66 -0
  68. data/spec/dummy/public/favicon.ico +0 -0
  69. data/spec/dummy/tmp/cache/assets/development/sass/0a79a4ff6e73052b217cd977d4b50fdc54118d68/_bootstrap-sprockets.scssc +0 -0
  70. data/spec/dummy/tmp/cache/assets/development/sass/0a79a4ff6e73052b217cd977d4b50fdc54118d68/_bootstrap.scssc +0 -0
  71. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_alerts.scssc +0 -0
  72. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_background-variant.scssc +0 -0
  73. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_border-radius.scssc +0 -0
  74. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_buttons.scssc +0 -0
  75. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_center-block.scssc +0 -0
  76. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_clearfix.scssc +0 -0
  77. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_forms.scssc +0 -0
  78. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_gradients.scssc +0 -0
  79. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_grid-framework.scssc +0 -0
  80. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_grid.scssc +0 -0
  81. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_hide-text.scssc +0 -0
  82. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_image.scssc +0 -0
  83. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_labels.scssc +0 -0
  84. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_list-group.scssc +0 -0
  85. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_nav-divider.scssc +0 -0
  86. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_nav-vertical-align.scssc +0 -0
  87. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_opacity.scssc +0 -0
  88. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_pagination.scssc +0 -0
  89. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_panels.scssc +0 -0
  90. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_progress-bar.scssc +0 -0
  91. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_reset-filter.scssc +0 -0
  92. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_resize.scssc +0 -0
  93. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_responsive-visibility.scssc +0 -0
  94. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_size.scssc +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_tab-focus.scssc +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_table-row.scssc +0 -0
  97. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_text-emphasis.scssc +0 -0
  98. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_text-overflow.scssc +0 -0
  99. data/spec/dummy/tmp/cache/assets/development/sass/388135616c2e0e4a55abea5d6089cd23176cca81/_vendor-prefixes.scssc +0 -0
  100. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_alerts.scssc +0 -0
  101. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_background-variant.scssc +0 -0
  102. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_border-radius.scssc +0 -0
  103. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_buttons.scssc +0 -0
  104. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_center-block.scssc +0 -0
  105. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_clearfix.scssc +0 -0
  106. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_forms.scssc +0 -0
  107. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_gradients.scssc +0 -0
  108. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_grid-framework.scssc +0 -0
  109. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_grid.scssc +0 -0
  110. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_hide-text.scssc +0 -0
  111. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_image.scssc +0 -0
  112. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_labels.scssc +0 -0
  113. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_list-group.scssc +0 -0
  114. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_nav-divider.scssc +0 -0
  115. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_nav-vertical-align.scssc +0 -0
  116. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_opacity.scssc +0 -0
  117. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_pagination.scssc +0 -0
  118. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_panels.scssc +0 -0
  119. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_progress-bar.scssc +0 -0
  120. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_reset-filter.scssc +0 -0
  121. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_resize.scssc +0 -0
  122. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_responsive-visibility.scssc +0 -0
  123. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_size.scssc +0 -0
  124. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_tab-focus.scssc +0 -0
  125. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_table-row.scssc +0 -0
  126. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_text-emphasis.scssc +0 -0
  127. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_text-overflow.scssc +0 -0
  128. data/spec/dummy/tmp/cache/assets/development/sass/6d2c3dd352078ee620f88d0e68cd2a546af6caa9/_vendor-prefixes.scssc +0 -0
  129. data/spec/dummy/tmp/cache/assets/development/sass/a3c1058d9af83b2a8b1bfae5d618b8a18753385f/_bootstrap-sprockets.scssc +0 -0
  130. data/spec/dummy/tmp/cache/assets/development/sass/a3c1058d9af83b2a8b1bfae5d618b8a18753385f/_bootstrap.scssc +0 -0
  131. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_alerts.scssc +0 -0
  132. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_badges.scssc +0 -0
  133. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_breadcrumbs.scssc +0 -0
  134. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_button-groups.scssc +0 -0
  135. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_buttons.scssc +0 -0
  136. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_carousel.scssc +0 -0
  137. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_close.scssc +0 -0
  138. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_code.scssc +0 -0
  139. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_component-animations.scssc +0 -0
  140. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_dropdowns.scssc +0 -0
  141. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_forms.scssc +0 -0
  142. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_glyphicons.scssc +0 -0
  143. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_grid.scssc +0 -0
  144. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_input-groups.scssc +0 -0
  145. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_jumbotron.scssc +0 -0
  146. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_labels.scssc +0 -0
  147. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_list-group.scssc +0 -0
  148. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_media.scssc +0 -0
  149. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_mixins.scssc +0 -0
  150. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_modals.scssc +0 -0
  151. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_navbar.scssc +0 -0
  152. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_navs.scssc +0 -0
  153. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_normalize.scssc +0 -0
  154. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_pager.scssc +0 -0
  155. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_pagination.scssc +0 -0
  156. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_panels.scssc +0 -0
  157. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_popovers.scssc +0 -0
  158. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_print.scssc +0 -0
  159. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_progress-bars.scssc +0 -0
  160. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_responsive-embed.scssc +0 -0
  161. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_responsive-utilities.scssc +0 -0
  162. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_scaffolding.scssc +0 -0
  163. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_tables.scssc +0 -0
  164. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_thumbnails.scssc +0 -0
  165. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_tooltip.scssc +0 -0
  166. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_type.scssc +0 -0
  167. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_utilities.scssc +0 -0
  168. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_variables.scssc +0 -0
  169. data/spec/dummy/tmp/cache/assets/development/sass/a7efb1bfb1ea736b4b985c80527151a3e8b6dbc6/_wells.scssc +0 -0
  170. data/spec/dummy/tmp/cache/assets/development/sass/d940cd7e88bf0a9500208e10220e6b529d01020b/application.css.scssc +0 -0
  171. data/spec/dummy/tmp/cache/assets/development/sass/d940cd7e88bf0a9500208e10220e6b529d01020b/forms.css.scssc +0 -0
  172. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_alerts.scssc +0 -0
  173. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_badges.scssc +0 -0
  174. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_breadcrumbs.scssc +0 -0
  175. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_button-groups.scssc +0 -0
  176. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_buttons.scssc +0 -0
  177. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_carousel.scssc +0 -0
  178. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_close.scssc +0 -0
  179. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_code.scssc +0 -0
  180. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_component-animations.scssc +0 -0
  181. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_dropdowns.scssc +0 -0
  182. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_forms.scssc +0 -0
  183. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_glyphicons.scssc +0 -0
  184. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_grid.scssc +0 -0
  185. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_input-groups.scssc +0 -0
  186. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_jumbotron.scssc +0 -0
  187. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_labels.scssc +0 -0
  188. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_list-group.scssc +0 -0
  189. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_media.scssc +0 -0
  190. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_mixins.scssc +0 -0
  191. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_modals.scssc +0 -0
  192. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_navbar.scssc +0 -0
  193. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_navs.scssc +0 -0
  194. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_normalize.scssc +0 -0
  195. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_pager.scssc +0 -0
  196. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_pagination.scssc +0 -0
  197. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_panels.scssc +0 -0
  198. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_popovers.scssc +0 -0
  199. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_print.scssc +0 -0
  200. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_progress-bars.scssc +0 -0
  201. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_responsive-embed.scssc +0 -0
  202. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_responsive-utilities.scssc +0 -0
  203. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_scaffolding.scssc +0 -0
  204. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_tables.scssc +0 -0
  205. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_thumbnails.scssc +0 -0
  206. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_tooltip.scssc +0 -0
  207. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_type.scssc +0 -0
  208. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_utilities.scssc +0 -0
  209. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_variables.scssc +0 -0
  210. data/spec/dummy/tmp/cache/assets/development/sass/ea7b58bf4bbb3d8d5abf667eec7914942f653de6/_wells.scssc +0 -0
  211. data/spec/dummy/tmp/cache/assets/development/sprockets/02ecd6370f91c7b9aa00319b7b66ca57 +0 -0
  212. data/spec/dummy/tmp/cache/assets/development/sprockets/034fda66e03e8dcfacf72397fb1616fb +0 -0
  213. data/spec/dummy/tmp/cache/assets/development/sprockets/0372d3378d1aec4dd7f546428d9d84df +0 -0
  214. data/spec/dummy/tmp/cache/assets/development/sprockets/071b598f6568db8d75333d67e6a54477 +0 -0
  215. data/spec/dummy/tmp/cache/assets/development/sprockets/0faf8e82aa4c81c82c3d5efd58fcaae2 +0 -0
  216. data/spec/dummy/tmp/cache/assets/development/sprockets/1665127ceea38e019fda9859305342a7 +0 -0
  217. data/spec/dummy/tmp/cache/assets/development/sprockets/16b4a10fdb8214557970232c41d57362 +0 -0
  218. data/spec/dummy/tmp/cache/assets/development/sprockets/1750899b365166d7cfff321fe7fa7acd +0 -0
  219. data/spec/dummy/tmp/cache/assets/development/sprockets/17e0784a695845bd1a32dd1346c280ea +0 -0
  220. data/spec/dummy/tmp/cache/assets/development/sprockets/1ad97a1fb78577c298b407d3d2cc4226 +0 -0
  221. data/spec/dummy/tmp/cache/assets/development/sprockets/1c146cfb664a6770a3d20305f8baaee3 +0 -0
  222. data/spec/dummy/tmp/cache/assets/development/sprockets/1d53471c5ad320073dda367e45390e1a +0 -0
  223. data/spec/dummy/tmp/cache/assets/development/sprockets/1f6b42e6726c8b498066fc910a16e643 +0 -0
  224. data/spec/dummy/tmp/cache/assets/development/sprockets/25a65c717fc9c64ba1aba14d1c14ffee +0 -0
  225. data/spec/dummy/tmp/cache/assets/development/sprockets/291cfa25c65c3163a5815d67b5f62756 +0 -0
  226. data/spec/dummy/tmp/cache/assets/development/sprockets/2acbd5c6f7047cd0e95f86968fd19f46 +0 -0
  227. data/spec/dummy/tmp/cache/assets/development/sprockets/2e4f3bcd559a961bc58e2a0e84792662 +0 -0
  228. data/spec/dummy/tmp/cache/assets/development/sprockets/2f31bab0beabd5a3f5c34b4e907a34fc +0 -0
  229. data/spec/dummy/tmp/cache/assets/development/sprockets/306a635124154ffdea9b8e8ce8b61410 +0 -0
  230. data/spec/dummy/tmp/cache/assets/development/sprockets/30e642c26825645592d13dd299e19a65 +0 -0
  231. data/spec/dummy/tmp/cache/assets/development/sprockets/3312b404b988f9a8763bd1c06b9952ef +0 -0
  232. data/spec/dummy/tmp/cache/assets/development/sprockets/3487ff606d58ba5df51a1117dba8c84b +0 -0
  233. data/spec/dummy/tmp/cache/assets/development/sprockets/357d6ae318d42fc558676b425c1a9e78 +0 -0
  234. data/spec/dummy/tmp/cache/assets/development/sprockets/361cc4bdb4a3f33a6ba7e9a7db1a5407 +0 -0
  235. data/spec/dummy/tmp/cache/assets/development/sprockets/3636dd32d14102a55225b245bd2a6489 +0 -0
  236. data/spec/dummy/tmp/cache/assets/development/sprockets/36874c0716e0da5db2dde7cf47dec6ca +0 -0
  237. data/spec/dummy/tmp/cache/assets/development/sprockets/39ce7471b9ff1c273b4f1518b5aba8f0 +0 -0
  238. data/spec/dummy/tmp/cache/assets/development/sprockets/3b25a99aa1b8d0f87755ebd53f3d7fc6 +0 -0
  239. data/spec/dummy/tmp/cache/assets/development/sprockets/3bf04cff80d6513190387eea44e4589f +0 -0
  240. data/spec/dummy/tmp/cache/assets/development/sprockets/3c284cbc7d309735cbebcaddf4467d71 +0 -0
  241. data/spec/dummy/tmp/cache/assets/development/sprockets/3d067ab624734ad0663d1425c5b201c1 +0 -0
  242. data/spec/dummy/tmp/cache/assets/development/sprockets/3fb41299c66c3e363e841ca3d76b11b7 +0 -0
  243. data/spec/dummy/tmp/cache/assets/development/sprockets/4063ddd81171d5b6dc967ca64faeca75 +0 -0
  244. data/spec/dummy/tmp/cache/assets/development/sprockets/40ca1415d6ca19cdf937bbc542925af9 +0 -0
  245. data/spec/dummy/tmp/cache/assets/development/sprockets/40e3a16192cb5bd3559b3abe6b31cefe +0 -0
  246. data/spec/dummy/tmp/cache/assets/development/sprockets/43f257974098a37cabc9a61314b816f5 +0 -0
  247. data/spec/dummy/tmp/cache/assets/development/sprockets/44657b24ddb307d1e7f85ad2ecca2e10 +0 -0
  248. data/spec/dummy/tmp/cache/assets/development/sprockets/458ca3a8c2f4224a08e724716a2f17d4 +0 -0
  249. data/spec/dummy/tmp/cache/assets/development/sprockets/4a368dccbd67682ba64048d4b24fd8a6 +0 -0
  250. data/spec/dummy/tmp/cache/assets/development/sprockets/4a85c925086e64caf1d1b700d916bdbd +0 -0
  251. data/spec/dummy/tmp/cache/assets/development/sprockets/4ce8718297a50cd3d658b5952cd8c220 +0 -0
  252. data/spec/dummy/tmp/cache/assets/development/sprockets/510c6fd27db7dfbaf0a0b0875e1a472c +0 -0
  253. data/spec/dummy/tmp/cache/assets/development/sprockets/52601bfc1fdc6967ffc898526bb67c48 +0 -0
  254. data/spec/dummy/tmp/cache/assets/development/sprockets/52f63d83d0a7b86318e8de59538598ce +0 -0
  255. data/spec/dummy/tmp/cache/assets/development/sprockets/5369fbbcf397cc9d96948fe373705d13 +0 -0
  256. data/spec/dummy/tmp/cache/assets/development/sprockets/56435206e505c649b556d17094d68fda +0 -0
  257. data/spec/dummy/tmp/cache/assets/development/sprockets/5814911eaed8f6e6be8c46d6b9cb880f +0 -0
  258. data/spec/dummy/tmp/cache/assets/development/sprockets/58f4e4ba656d78cf623d22cca4e118d9 +0 -0
  259. data/spec/dummy/tmp/cache/assets/development/sprockets/5d2ca5f96ec23ecb6926eb3732d45e40 +0 -0
  260. data/spec/dummy/tmp/cache/assets/development/sprockets/650130979c39b20be8a1c9af85b76638 +0 -0
  261. data/spec/dummy/tmp/cache/assets/development/sprockets/6a9bec079f93d94c0dbf4b7faa1441ad +0 -0
  262. data/spec/dummy/tmp/cache/assets/development/sprockets/6c75734197a9efc5a8a3a6ca1064eb41 +0 -0
  263. data/spec/dummy/tmp/cache/assets/development/sprockets/6f388bb30dc94599b503d0d9091f1d8a +0 -0
  264. data/spec/dummy/tmp/cache/assets/development/sprockets/6f88ef16a3db4dfcde35acff34596af9 +0 -0
  265. data/spec/dummy/tmp/cache/assets/development/sprockets/6f894580ff1180ef27e44fb54bfec225 +0 -0
  266. data/spec/dummy/tmp/cache/assets/development/sprockets/6f9d821dc32360a03e328a188908175f +0 -0
  267. data/spec/dummy/tmp/cache/assets/development/sprockets/7002ce8d64dafbc1a536eeeb902218c0 +0 -0
  268. data/spec/dummy/tmp/cache/assets/development/sprockets/7005283a4d4bbbdee421e3479dc12cef +0 -0
  269. data/spec/dummy/tmp/cache/assets/development/sprockets/7311218619b974306177cebe229dc84c +0 -0
  270. data/spec/dummy/tmp/cache/assets/development/sprockets/744470be6e2c66f767dd3796ce78f559 +0 -0
  271. data/spec/dummy/tmp/cache/assets/development/sprockets/75e87583a132b975027118095bf4818f +0 -0
  272. data/spec/dummy/tmp/cache/assets/development/sprockets/764d58940328aaefb24a04bef44b3789 +0 -0
  273. data/spec/dummy/tmp/cache/assets/development/sprockets/76736f185d75c28fcb1a476ae52cf30e +0 -0
  274. data/spec/dummy/tmp/cache/assets/development/sprockets/772600c69b884a0036fb15de213d3232 +0 -0
  275. data/spec/dummy/tmp/cache/assets/development/sprockets/7a3ccc02bfad9d04783b020d3dcdb67f +0 -0
  276. data/spec/dummy/tmp/cache/assets/development/sprockets/7da54db8bdd56cd00dc338448b263424 +0 -0
  277. data/spec/dummy/tmp/cache/assets/development/sprockets/7f402d16975bdcfc442e9cef98821840 +0 -0
  278. data/spec/dummy/tmp/cache/assets/development/sprockets/7f992b68655a9d27c89d97eeeaae5cff +0 -0
  279. data/spec/dummy/tmp/cache/assets/development/sprockets/812a0d810b679dbb7f5d512beef887c8 +0 -0
  280. data/spec/dummy/tmp/cache/assets/development/sprockets/81cfdb55475e7b7a5a63ffe9c204673c +0 -0
  281. data/spec/dummy/tmp/cache/assets/development/sprockets/81fce3ac36b10e033b9264e39a76d90a +0 -0
  282. data/spec/dummy/tmp/cache/assets/development/sprockets/83dafa375dd3513360fd7b4553f44113 +0 -0
  283. data/spec/dummy/tmp/cache/assets/development/sprockets/846430db48a99b44ec1b08022d0276ad +0 -0
  284. data/spec/dummy/tmp/cache/assets/development/sprockets/8747b295bb7c63b1388aef97cfb67b3c +0 -0
  285. data/spec/dummy/tmp/cache/assets/development/sprockets/87bf4781cd1e8b52a4b8fc2c0e379531 +0 -0
  286. data/spec/dummy/tmp/cache/assets/development/sprockets/8960bbc70a2914b7ed8e6f7b5b04359f +0 -0
  287. data/spec/dummy/tmp/cache/assets/development/sprockets/8abcaf5a11cddb7b0c2aa424bd1e3b80 +0 -0
  288. data/spec/dummy/tmp/cache/assets/development/sprockets/90edf8db23ea1dbf263e6391e93a483d +0 -0
  289. data/spec/dummy/tmp/cache/assets/development/sprockets/92871f270f3bebaf37c07d62016a3d7e +0 -0
  290. data/spec/dummy/tmp/cache/assets/development/sprockets/933dfcd36b972a52fa603f5234bd1e7e +0 -0
  291. data/spec/dummy/tmp/cache/assets/development/sprockets/960b52015983bd58ede5592a759c08fb +0 -0
  292. data/spec/dummy/tmp/cache/assets/development/sprockets/96eb906f063e4ce8718416772a28ddda +0 -0
  293. data/spec/dummy/tmp/cache/assets/development/sprockets/97c07e644cabf01abcec894d4e69d985 +0 -0
  294. data/spec/dummy/tmp/cache/assets/development/sprockets/9d2af4036fcf352fd6695966ba8e0006 +0 -0
  295. data/spec/dummy/tmp/cache/assets/development/sprockets/a011ecbdccaea9b25d06cedffa60f15b +0 -0
  296. data/spec/dummy/tmp/cache/assets/development/sprockets/a200c1f26bc11623541b221d0b819a31 +0 -0
  297. data/spec/dummy/tmp/cache/assets/development/sprockets/a3900259c72f7f6917024284b8bdc4fb +0 -0
  298. data/spec/dummy/tmp/cache/assets/development/sprockets/a45d05646c5fc237f0a7419ba456eaaa +0 -0
  299. data/spec/dummy/tmp/cache/assets/development/sprockets/a4819b17d0802ac0d8d7e2a9d1832752 +0 -0
  300. data/spec/dummy/tmp/cache/assets/development/sprockets/a57c75e1396ec82ae78589a9ae6b3861 +0 -0
  301. data/spec/dummy/tmp/cache/assets/development/sprockets/a5d6adcfd6cbc7beef744d02302d0a8c +0 -0
  302. data/spec/dummy/tmp/cache/assets/development/sprockets/a6e5e94828ebb7680a0a1499dda39e2c +0 -0
  303. data/spec/dummy/tmp/cache/assets/development/sprockets/ada1d0f8bc5368b25d6fbaa8a95b4ef8 +0 -0
  304. data/spec/dummy/tmp/cache/assets/development/sprockets/ada35950e2733da1d227585deb4a09fd +0 -0
  305. data/spec/dummy/tmp/cache/assets/development/sprockets/aefe71c7ac3edd29fbbb6a3e4bfe84a4 +0 -0
  306. data/spec/dummy/tmp/cache/assets/development/sprockets/b0376faf689d528b625a5a88ef0dcc7a +0 -0
  307. data/spec/dummy/tmp/cache/assets/development/sprockets/b7e39ee40edb822dde438cae9f5b0987 +0 -0
  308. data/spec/dummy/tmp/cache/assets/development/sprockets/b8c774f83a302c891103bdf82662bc8d +0 -0
  309. data/spec/dummy/tmp/cache/assets/development/sprockets/bb86516784ddda57801c5b5ca185e838 +0 -0
  310. data/spec/dummy/tmp/cache/assets/development/sprockets/be81012acaf20ecb9f67c32dbc2ee5ae +0 -0
  311. data/spec/dummy/tmp/cache/assets/development/sprockets/bfa847822a8d7778ab5f8b469491b114 +0 -0
  312. data/spec/dummy/tmp/cache/assets/development/sprockets/c7e523ec10215d71cb5d98fe9e069b35 +0 -0
  313. data/spec/dummy/tmp/cache/assets/development/sprockets/c82292a064ec438357e22805eee89191 +0 -0
  314. data/spec/dummy/tmp/cache/assets/development/sprockets/c843a7a53cf4a5dc94dfea6a59f04e4f +0 -0
  315. data/spec/dummy/tmp/cache/assets/development/sprockets/d05de76ba0f58b49a47dea63d2a5b4a6 +0 -0
  316. data/spec/dummy/tmp/cache/assets/development/sprockets/d5022437eeb42f08dd710ee8f240de2a +0 -0
  317. data/spec/dummy/tmp/cache/assets/development/sprockets/d71a839bca3a6881f8b7b42b7f05bda6 +0 -0
  318. data/spec/dummy/tmp/cache/assets/development/sprockets/d976a7c91926f70a3e80c2603de3bf69 +0 -0
  319. data/spec/dummy/tmp/cache/assets/development/sprockets/dd677fcb17536b3f6c2bf936f571a02e +0 -0
  320. data/spec/dummy/tmp/cache/assets/development/sprockets/df9a7d2c532e121a104d5b63b4441b2d +0 -0
  321. data/spec/dummy/tmp/cache/assets/development/sprockets/e29bdfdcad985cd8d26e1d31a09f00b1 +0 -0
  322. data/spec/dummy/tmp/cache/assets/development/sprockets/e46bf23d379db0e7483b2ccc0fbff9f3 +0 -0
  323. data/spec/dummy/tmp/cache/assets/development/sprockets/e5fa939c3fa26ae0df54d40f316bec75 +0 -0
  324. data/spec/dummy/tmp/cache/assets/development/sprockets/e6f47dfc8b9542ee9c6f54b1ecfde664 +0 -0
  325. data/spec/dummy/tmp/cache/assets/development/sprockets/e75d8f8a9ec139a10086a83dca74e9b3 +0 -0
  326. data/spec/dummy/tmp/cache/assets/development/sprockets/eb29baddef1d85815159f3d1089e3be4 +0 -0
  327. data/spec/dummy/tmp/cache/assets/development/sprockets/efa76e374b3ab82bde4b35f9d76d9caf +0 -0
  328. data/spec/dummy/tmp/cache/assets/development/sprockets/f1262794e42011b8c57f36f71b9815a0 +0 -0
  329. data/spec/dummy/tmp/cache/assets/development/sprockets/f5268ce26d4948c182f520c4df83b261 +0 -0
  330. data/spec/dummy/tmp/cache/assets/development/sprockets/f6f7145113c3cd4e160e3d39f7f1f56b +0 -0
  331. data/spec/dummy/tmp/cache/assets/development/sprockets/f757aee56e52254e2fb14b4f6424c937 +0 -0
  332. data/spec/dummy/tmp/cache/assets/development/sprockets/fbf4527e3604500e4c3521c4fd2deaf6 +0 -0
  333. data/spec/dummy/tmp/cache/assets/development/sprockets/ff4769a8564990f599f4e977ccd8e661 +0 -0
  334. data/spec/dummy/tmp/pids/server.pid +1 -0
  335. data/spec/dummy/tmp/restart.txt +0 -0
  336. data/spec/factories/phrase.rb +8 -0
  337. data/spec/models/phrase_exporter_spec.rb +38 -0
  338. data/spec/models/phrase_extractor_spec.rb +53 -0
  339. data/spec/models/phrase_importer_spec.rb +30 -0
  340. data/spec/models/phrase_spec.rb +80 -0
  341. data/spec/spec_helper.rb +23 -0
  342. metadata +851 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4297d3391e67e66042c2a6572edf9e8928bdd39a
4
+ data.tar.gz: 3d9c1f1a8c2efb1b012a008a7ee12fb145543af5
5
+ SHA512:
6
+ metadata.gz: 3c071cda64b47acf5fbb7653edb39c5bebe920a823dee0b28847120a5c1c584fc525ea2f1323d09349b888de58317d5b09bfa8a9a2a5547547b634b1942a3413
7
+ data.tar.gz: 449f8cd93ddc4c1fac4a435d0b189ed9afe3f496c73d18b93957326f47bcc6cf6dbab74ef37fecb3bfb4542c33269b311589b98601a7064bbd5e575f1a8fa175
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 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,91 @@
1
+ # Idioma
2
+
3
+ Idioma is a Ruby Engine to help manage the flow and editing of translations.
4
+
5
+ ### Current Features
6
+ * Imports translations into database from the config yaml files.
7
+ * Interface for managing translations.
8
+ * Duplicate translations from one locale to other locales.
9
+ * DB changes will be persisted to Redis I18n backend store if supplied.
10
+ * Exports translations from DB into CSV and YAML formats.
11
+
12
+ ### Pending Features
13
+ * Import translations from CSV into DB.
14
+ * Stats on each locale, giving percentage of translated/missing.
15
+ * Test persisting to Redis using https://github.com/guilleiguaran/fakeredis
16
+ * Improve interface by converting into SPA with Angular.
17
+
18
+ ### Starting
19
+ Add it to your gemfile.
20
+ ```ruby
21
+ gem 'idioma'
22
+ ```
23
+
24
+ Mount it in your config/routes.rb.
25
+ ```ruby
26
+ # config/routes.rb
27
+ MyApp::Application.routes.draw do
28
+ mount Idioma::Engine => "/idioma"
29
+ end
30
+ ```
31
+
32
+ ### Security
33
+ You can secure access to the Idioma interface by using [route constraints](http://guides.rubyonrails.org/routing.html#request-based-constraints).
34
+
35
+ Example 1 by IP address.
36
+ ```ruby
37
+ # config/routes.rb
38
+ idioma_constraint = lambda { |request| request.remote_ip == '127.0.0.1' }
39
+ constraints idioma_constraint do
40
+ mount Idioma::Engine => "/idioma"
41
+ end
42
+ ```
43
+
44
+ Example 2 by using Devise or another warden based authentication system.
45
+ ```ruby
46
+ # config/routes.rb
47
+ idioma_constraint = lambda do |request|
48
+ current_user = request.env['warden'].user
49
+ current_user.present? && current_user.respond_to?(:is_admin?) && current_user.is_admin?
50
+ end
51
+
52
+ constraints idioma_constraint do
53
+ mount Idioma::Engine => "/idioma"
54
+ end
55
+ ```
56
+
57
+ ### Configuration
58
+ Setting | Default | Description
59
+ ------- | ------- | -----------
60
+ default_locale | :en | Used for showing the default translation (for translators to translate from) for a given phrase
61
+ locales | [:en] | Idioma will only import translations of locales in this list... ignoring the rest
62
+ ignore_keys | ["ransack", "simple_form"] | Gems sometimes bring their own phrases that you don't actually need translated
63
+ redis_backend | nil | Should be an I18n backend of a Redis store.
64
+
65
+ ### Setup
66
+ Import the migrations into your application
67
+ ```
68
+ rake idioma:install:migrations
69
+ ```
70
+
71
+ To populate the idioma_phrases table with translations from your locales/yaml files.
72
+ ```
73
+ rake idioma:import_from_extraction
74
+ ```
75
+
76
+ To duplicate all translations from a locale to a new locale (as untranslated).
77
+ ```
78
+ rake idioma:duplicate_for_locales base_locale=en new_locale=es
79
+ ```
80
+
81
+ ### Example
82
+ ```ruby
83
+ $redis = Redis.new(:host => 'localhost', :port => 6379)
84
+ I18n.backend = I18n::Backend::KeyValue.new($redis)
85
+
86
+ Idioma.configure do |configure|
87
+ configure.default_locale = :en
88
+ configure.locales = [:en, :es, :fr]
89
+ configure.redis_backend = I18n.backend
90
+ end
91
+ ```
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Idioma'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rspec/core'
23
+ require 'rspec/core/rake_task'
24
+
25
+ desc "Run all specs in spec directory (excluding plugin specs)"
26
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
27
+
28
+ task :default => :spec
@@ -0,0 +1,15 @@
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
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
14
+ //= require jquery
15
+ //= require bootstrap-sprockets
@@ -0,0 +1,35 @@
1
+ window.InlinePhraseUpdater = class InlinePhraseUpdater
2
+ constructor: () ->
3
+ # attributes
4
+ @phraseInputs = $(".i18n_value")
5
+
6
+ # events
7
+ @phraseInputs.on "focus", (e) => @setOriginalValue(e)
8
+ @phraseInputs.on "blur", (e) => @updateIfChanged(e)
9
+
10
+ # init
11
+
12
+ setOriginalValue: (e) =>
13
+ phraseInput = $(e.target)
14
+ phraseInput.data("original", phraseInput.val())
15
+
16
+ updateIfChanged: (e) =>
17
+ phraseInput = $(e.target)
18
+ if phraseInput.data("original") != phraseInput.val()
19
+ @updateStatus(phraseInput, "status-working")
20
+ $.ajax(
21
+ type: "PUT"
22
+ url: phraseInput.data("url")
23
+ dataType: "json"
24
+ data:
25
+ phrase:
26
+ i18n_value: phraseInput.val()
27
+ ).done((data) =>
28
+ @updateStatus(phraseInput, "status-success")
29
+ ).fail((data) =>
30
+ @updateStatus(phraseInput, "status-error")
31
+ )
32
+
33
+ updateStatus: (input, status) ->
34
+ input.removeClass("status-success").removeClass("status-error").removeClass("status-working")
35
+ input.addClass(status)
@@ -0,0 +1,26 @@
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 bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
16
+ @import "bootstrap-sprockets";
17
+ @import "bootstrap";
18
+
19
+ body {
20
+ padding-top: 50px;
21
+ }
22
+
23
+ .highlight {
24
+ padding: 10px;
25
+ background-color: #f8f8f8;
26
+ }
@@ -0,0 +1,19 @@
1
+ .search {
2
+ .form-group {
3
+ padding-right: 10px;
4
+ }
5
+
6
+ label {
7
+ margin-right: 10px;
8
+ }
9
+ }
10
+
11
+ .status-working {
12
+ border-color: yellow !important;
13
+ }
14
+ .status-success {
15
+ border-color: green !important;
16
+ }
17
+ .status-error {
18
+ border-color: red !important;
19
+ }
@@ -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 Idioma
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,96 @@
1
+ #require_dependency "idioma/application_controller"
2
+
3
+ module Idioma
4
+ class PhrasesController < ApplicationController
5
+ before_action :set_phrase, only: [:edit, :update, :show]
6
+
7
+ # GET /phrases
8
+ def index
9
+ params[:locale] ||= I18n.default_locale
10
+ scope = Phrase.where(locale: params[:locale])
11
+
12
+ if params[:q].present?
13
+ scope = scope.where("i18n_key ilike ? OR i18n_value ilike ?", "%#{params[:q]}%", "%#{params[:q]}%")
14
+ end
15
+
16
+ respond_to do |format|
17
+ format.html {
18
+ @phrases = scope.paginate(:page => params[:page])
19
+ }
20
+ format.csv {
21
+ render text: PhraseExporter.to_csv(scope)
22
+ }
23
+ format.yaml {
24
+ render text: PhraseExporter.to_yaml(scope)
25
+ }
26
+ format.json {
27
+ @phrases = scope.paginate(:page => params[:page])
28
+ render json: {
29
+ meta: {
30
+ pagination: {
31
+ current_page: @phrases.current_page,
32
+ per_page: @phrases.per_page,
33
+ total_entries: @phrases.total_entries
34
+ }
35
+ },
36
+ phrases: @phrases
37
+ }
38
+ }
39
+ end
40
+
41
+ end
42
+
43
+ # GET /phrases/1
44
+ def show
45
+ respond_to do |format|
46
+ format.json {
47
+ render json: @phrase
48
+ }
49
+ end
50
+ end
51
+
52
+ # PATCH/PUT /phrases/1
53
+ def update
54
+ result = @phrase.update_and_update_backend(phrase_params)
55
+ respond_to do |format|
56
+ format.html {
57
+ if result
58
+ redirect_to [:edit, @phrase], flash: {success: t('idioma.record_updated')}
59
+ else
60
+ render :edit
61
+ end
62
+ }
63
+ format.json {
64
+ if result
65
+ render json: @phrase
66
+ else
67
+ render json: {
68
+ errors: @phrase.errors.messages
69
+ }.merge(@phrase.attributes),
70
+ status: :bad_request
71
+ end
72
+ }
73
+ end
74
+
75
+ end
76
+
77
+ private
78
+ # Use callbacks to share common setup or constraints between actions.
79
+ def set_phrase
80
+ @phrase = Phrase.find(params[:id])
81
+ rescue ActiveRecord::RecordNotFound
82
+ respond_to do |format|
83
+ format.json { render json: {}.to_json, status: :not_found }
84
+ format.html {
85
+ flash[:error] = t('idioma.record_not_found')
86
+ redirect_to phrases_path
87
+ }
88
+ end
89
+ end
90
+
91
+ # Only allow a trusted parameter "white list" through.
92
+ def phrase_params
93
+ params.require(:phrase).permit(:locale, :i18n_key, :i18n_value, :flagged_at, :notes)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,4 @@
1
+ module Idioma
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Idioma
2
+ module PhrasesHelper
3
+ end
4
+ end
@@ -0,0 +1,115 @@
1
+ module Idioma
2
+ class Phrase < ActiveRecord::Base
3
+
4
+ # == Constants ============================================================
5
+
6
+ # == Attributes ===========================================================
7
+
8
+ # == Extensions ===========================================================
9
+
10
+ # == Relationships ========================================================
11
+
12
+ # == Validations ==========================================================
13
+
14
+ validates :locale, :i18n_key, presence: true
15
+ validates :i18n_key, uniqueness: { scope: :locale }
16
+
17
+ # == Scopes ===============================================================
18
+
19
+ scope :translated, lambda { where("translated_at is not null") }
20
+ scope :untranslated, lambda { where("translated_at is null") }
21
+ scope :missing, lambda { where("i18n_value is null") }
22
+
23
+ # == Callbacks ============================================================
24
+
25
+ before_validation :strip_values
26
+
27
+ # == Class Methods ========================================================
28
+
29
+ # Given a base locale, duplicate all phrases to a set of other locales
30
+ #
31
+ # @param [Symbol] The base locale
32
+ # @param [Array] An array of other locales
33
+ def self.duplicate_for_locales(base_locale, locales)
34
+ locales = [locales] unless locales.class == Array
35
+ where(locale: base_locale).find_each do |base_phrase|
36
+ locales.each do |locale|
37
+ unless where(locale: locale, i18n_key: base_phrase.i18n_key).exists?
38
+ phrase = Phrase.create!({
39
+ locale: locale,
40
+ i18n_key: base_phrase.i18n_key
41
+ })
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # Take what's in the database and prime the i18n backend store (Redis)
48
+ def self.prime_backend
49
+ find_each do |phrase|
50
+ phrase.update_backend
51
+ end
52
+ end
53
+
54
+ # == Instance Methods =====================================================
55
+
56
+ # Update the record and then push those changes to the i18n backend
57
+ #
58
+ # @param [Hash] The Phrase attributes to update
59
+ # @return [Boolean] Whether the update was successful
60
+ def update_and_update_backend(params = {})
61
+ self.translated_at = Time.zone.now if self.untranslated?
62
+
63
+ result = self.update(params)
64
+ if result
65
+ self.update_backend
66
+ end
67
+ result
68
+ end
69
+
70
+ # Save and push the changes to the i18n backend
71
+ #
72
+ # @param [Hash] The Phrase attributes to save
73
+ # @return [Boolean] Whether the save was successful
74
+ def save_and_update_backend(params = {})
75
+ result = self.save(params)
76
+ if result
77
+ self.update_backend
78
+ end
79
+ result
80
+ end
81
+
82
+ # Will update the i18n backend if it has been configured
83
+ def update_backend
84
+ if Idioma.configuration.redis_backend
85
+ if i18n_value.present?
86
+ Idioma::RedisBackend.update_phrase(self)
87
+ else
88
+ Idioma::RedisBackend.delete_phrase(self)
89
+ end
90
+ end
91
+ end
92
+
93
+ # Is this phrase translated?
94
+ # @return [Boolean]
95
+ def translated?
96
+ translated_at.present?
97
+ end
98
+
99
+ # Is this phrase untranslated?
100
+ # @return [Boolean]
101
+ def untranslated?
102
+ !translated?
103
+ end
104
+
105
+ private
106
+
107
+ # Strip the values before validating the model
108
+ def strip_values
109
+ [:i18n_value].each do |field|
110
+ self.send("#{field}=", self.send(field).to_s.strip)
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,69 @@
1
+ module Idioma
2
+ class PhraseExporter
3
+
4
+ # Produce a CSV string of Phrases based on a scope
5
+ # @param [ActiveRecord::Relation] From the Phrase model
6
+ # @return [String] in CSV format
7
+ def self.to_csv(scope)
8
+ require 'csv'
9
+ CSV.generate do |csv_object|
10
+ csv_object << [
11
+ I18n.t("idioma.locale"),
12
+ I18n.t("idioma.key"),
13
+ I18n.t("idioma.value"),
14
+ I18n.t("idioma.translated")
15
+ ]
16
+ scope.find_each do |phrase|
17
+ csv_object << [
18
+ phrase.locale,
19
+ phrase.i18n_key,
20
+ phrase.i18n_value,
21
+ phrase.translated_at.present? ? I18n.t('idioma.ans_yes') : I18n.t('idioma.ans_no')
22
+ ]
23
+ end
24
+ end
25
+ end
26
+
27
+ # Produce a YAML string of Phrases based on a scope
28
+ # @param [ActiveRecord::Relation] From the Phrase model
29
+ # @return [String] in YAML format
30
+ def self.to_yaml(scope)
31
+ phrases = scope.order(:locale, :i18n_key).pluck(:locale, :i18n_key, :i18n_value)
32
+
33
+ phrase_hash = phrases.each_with_object({}) do |phrase, hsh|
34
+ hsh["#{phrase[0]}.#{phrase[1]}"] = phrase[2]
35
+ end
36
+
37
+ to_nested_hash(phrase_hash).to_yaml
38
+ end
39
+
40
+ private
41
+
42
+ # Will take a flat hash with dot notation (en.errors.invalid) keys and
43
+ # convert it to a nested hash.
44
+ #
45
+ # Example: {"en.hello" => "Hi"} becomes {"en" => {"hello" => "Hi"}}
46
+ #
47
+ # @param [Hash] Flat hash with dot notation keys
48
+ # @return [Hash] Nested hash
49
+ def self.to_nested_hash(input_hash)
50
+ input_hash.each_with_object({}) do |(key, value), hsh|
51
+ hsh.deep_merge!(dot_keys_to_hash(key.split("."), value))
52
+ end
53
+ end
54
+
55
+ # Will take an array of keys and a value, and convert this into a nested
56
+ # hash.
57
+ # @param [Array] Of keys
58
+ # @param [Object] Any value
59
+ # @return [Hash] Nested hash using the keys and value
60
+ def self.dot_keys_to_hash(keys, value)
61
+ if keys.length == 1
62
+ {keys.first => value}
63
+ else
64
+ {keys.shift => dot_keys_to_hash(keys, value)}
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,49 @@
1
+ module Idioma
2
+ class PhraseExtractor
3
+
4
+ # Find all of the translations that are in the locale yaml files
5
+ # and convert them into a hash of dotted hash notation key/values
6
+ # for each locale that is found
7
+ # @return [Hash] Dotted hash notation key/value pairs
8
+ def self.extract
9
+ phrase_hashes = self.get_translations
10
+
11
+ phrase_dotted_hashes = {}
12
+ # convert each locales translations to dotted hash
13
+ phrase_hashes.each do |locale, phrase_hash|
14
+ phrase_dotted_hashes[locale] = self.to_dotted_hash(phrase_hash)
15
+ end
16
+
17
+ phrase_dotted_hashes
18
+ end
19
+
20
+ # Get translations from the i18n backend
21
+ # @param [I18n::Backend, nil] A custom I18n backend
22
+ # @return [Hash] of translations separated by locale
23
+ def self.get_translations(backend = nil)
24
+ backend = I18n::Backend::Simple.new if backend.nil?
25
+ backend.send(:init_translations)
26
+ backend.send(:translations)
27
+ end
28
+
29
+ # Convert a nested Hash ({date: {format: {long: "YYYY-MM-DD"}}})
30
+ # to a dotted hash {"date.format.long" => "YYYY-MM-DD"}
31
+ # @param [Hash] Nested hash input
32
+ # @param [Hash, {}] An accumulator to store the result
33
+ # @param [String, nil] An accumulator for the key that gets built up
34
+ # @return [Hash] The end result after the conversion
35
+ def self.to_dotted_hash(source, accumulator = {}, namespace = nil)
36
+ prefix = "#{namespace}." if namespace
37
+ case source
38
+ when Hash
39
+ source.each do |key, value|
40
+ to_dotted_hash(value, accumulator, "#{prefix}#{key}")
41
+ end
42
+ else
43
+ accumulator[namespace] = source
44
+ end
45
+ accumulator
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,50 @@
1
+ module Idioma
2
+ class PhraseImporter
3
+
4
+ # Import all of the locales and phrases from the extraction
5
+ # The extraction comes from Idioma::PhraseExtractor.extract
6
+ def self.import_from_extraction
7
+ phrases = Idioma::PhraseExtractor.extract
8
+ phrases.each do |locale, locale_phrases|
9
+ next unless Idioma.configuration.locales.include?(locale.to_sym)
10
+ self.import(locale, locale_phrases)
11
+ end
12
+ end
13
+
14
+ # For a given locale, impot its phrases
15
+ #
16
+ # @param [Symbol] the locale, eg. :en
17
+ # @param [Hash] a hash of phrases which are already in dot-notation
18
+ def self.import(locale, locale_phrases)
19
+ locale_phrases.each do |key, value|
20
+ next if self.ignore_key?(key)
21
+
22
+ phrase = Idioma::Phrase.find_by(locale: locale, i18n_key: key)
23
+ if !phrase
24
+ phrase = Idioma::Phrase.new({
25
+ locale: locale,
26
+ i18n_key: key,
27
+ i18n_value: value,
28
+ translated_at: Time.zone.now
29
+ })
30
+ elsif phrase.untranslated?
31
+ phrase.i18n_value = value
32
+ phrase.translated_at = Time.zone.now if value.present?
33
+ end
34
+ phrase.save_and_update_backend
35
+ end
36
+ end
37
+
38
+ # Checks to see if a given key should be ignored based on the ignore_keys array
39
+ #
40
+ # @param [String] The key to check against
41
+ # @return [Boolean] Whether to ignore this key or not
42
+ def self.ignore_key?(key)
43
+ Idioma.configuration.ignore_keys.each do |ignore_key|
44
+ return true if key.to_s.include?(ignore_key)
45
+ end
46
+ false
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,22 @@
1
+ module Idioma
2
+
3
+ # Class for dealing with deleting and updating phrases in the i18n backend.
4
+ # This is specifically when the backend is Redis
5
+ class RedisBackend
6
+
7
+ # Delete a given Phrase from Redis
8
+ # @param [Phrase] The Phrase to delete
9
+ # @return [Boolean] Result of the del command in Redis
10
+ def self.delete_phrase(phrase)
11
+ Idioma.configuration.redis_backend.store.del("#{phrase.locale}.#{phrase.i18n_key}")
12
+ end
13
+
14
+ # Update (or create) a Phrase in Redis
15
+ # @param [Phrase] The Phrase to update or create
16
+ # @return [Boolean] Result of the store_translations command from the Redis backend (I18n::Backend)
17
+ def self.update_phrase(phrase)
18
+ Idioma.configuration.redis_backend.
19
+ store_translations(phrase.locale, {phrase.i18n_key => phrase.i18n_value}, :escape => false)
20
+ end
21
+ end
22
+ end