idioma 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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