interpret 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +11 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +2 -0
  4. data/app/controllers/interpret/base_controller.rb +10 -0
  5. data/app/controllers/interpret/search_controller.rb +7 -0
  6. data/app/controllers/interpret/tools_controller.rb +39 -0
  7. data/app/controllers/interpret/translations_controller.rb +47 -0
  8. data/app/models/interpret/translation.rb +257 -0
  9. data/app/sweepers/interpret/base_sweeper.rb +14 -0
  10. data/app/sweepers/interpret/translation_sweeper.rb +14 -0
  11. data/app/views/interpret/search/index.html.erb +29 -0
  12. data/app/views/interpret/search/perform.html.erb +38 -0
  13. data/app/views/interpret/tools/index.html.erb +38 -0
  14. data/app/views/interpret/translations/_form.html.erb +5 -0
  15. data/app/views/interpret/translations/_listing.html.erb +22 -0
  16. data/app/views/interpret/translations/edit.html.erb +5 -0
  17. data/app/views/interpret/translations/index.html.erb +28 -0
  18. data/app/views/layouts/interpret.html.erb +41 -0
  19. data/config/routes.rb +20 -0
  20. data/interpret.gemspec +30 -0
  21. data/lib/generators/interpret/migration_generator.rb +25 -0
  22. data/lib/generators/interpret/setup_generator.rb +21 -0
  23. data/lib/generators/interpret/templates/migration.rb +16 -0
  24. data/lib/generators/interpret/views_generator.rb +16 -0
  25. data/lib/interpret/capistrano.rb +15 -0
  26. data/lib/interpret/engine.rb +23 -0
  27. data/lib/interpret/helpers.rb +45 -0
  28. data/lib/interpret/lazy_hash.rb +21 -0
  29. data/lib/interpret/logger.rb +7 -0
  30. data/lib/interpret/version.rb +3 -0
  31. data/lib/interpret.rb +30 -0
  32. data/lib/tasks/interpret.rake +11 -0
  33. data/public/javascripts/jquery.purr.js +180 -0
  34. data/public/stylesheets/folder.png +0 -0
  35. data/public/stylesheets/interpret_style.css +542 -0
  36. data/test_app/Gemfile +11 -0
  37. data/test_app/README +256 -0
  38. data/test_app/Rakefile +7 -0
  39. data/test_app/app/controllers/application_controller.rb +3 -0
  40. data/test_app/app/controllers/pages_controller.rb +3 -0
  41. data/test_app/app/helpers/application_helper.rb +2 -0
  42. data/test_app/app/sweepers/page_sweeper.rb +12 -0
  43. data/test_app/app/views/layouts/application.html.erb +15 -0
  44. data/test_app/app/views/pages/contact.html.haml +8 -0
  45. data/test_app/app/views/pages/index.html.haml +9 -0
  46. data/test_app/config/application.rb +42 -0
  47. data/test_app/config/boot.rb +13 -0
  48. data/test_app/config/database.yml +23 -0
  49. data/test_app/config/environment.rb +5 -0
  50. data/test_app/config/environments/development.rb +27 -0
  51. data/test_app/config/environments/production.rb +51 -0
  52. data/test_app/config/environments/test.rb +35 -0
  53. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test_app/config/initializers/inflections.rb +10 -0
  55. data/test_app/config/initializers/interpret.rb +2 -0
  56. data/test_app/config/initializers/mime_types.rb +5 -0
  57. data/test_app/config/initializers/secret_token.rb +7 -0
  58. data/test_app/config/initializers/session_store.rb +8 -0
  59. data/test_app/config/locales/ca.yml +6 -0
  60. data/test_app/config/locales/es.yml +48 -0
  61. data/test_app/config/routes.rb +4 -0
  62. data/test_app/config.ru +4 -0
  63. data/test_app/db/migrate/20110209185258_interpret_create_translations.rb +16 -0
  64. data/test_app/db/schema.rb +23 -0
  65. data/test_app/db/seeds.rb +0 -0
  66. data/test_app/lib/lazy_hash.rb +22 -0
  67. data/test_app/lib/tasks/.gitkeep +0 -0
  68. data/test_app/lib/tasks/setup.rake +19 -0
  69. data/test_app/public/404.html +26 -0
  70. data/test_app/public/422.html +26 -0
  71. data/test_app/public/500.html +26 -0
  72. data/test_app/public/favicon.ico +0 -0
  73. data/test_app/public/index.html +29 -0
  74. data/test_app/public/javascripts/application.js +2 -0
  75. data/test_app/public/javascripts/best_in_place.js +456 -0
  76. data/test_app/public/javascripts/controls.js +965 -0
  77. data/test_app/public/javascripts/dragdrop.js +974 -0
  78. data/test_app/public/javascripts/effects.js +1123 -0
  79. data/test_app/public/javascripts/jquery.purr.js +180 -0
  80. data/test_app/public/javascripts/prototype.js +6001 -0
  81. data/test_app/public/javascripts/rails.js +134 -0
  82. data/test_app/public/robots.txt +5 -0
  83. data/test_app/public/stylesheets/.gitkeep +0 -0
  84. data/test_app/public/stylesheets/folder.png +0 -0
  85. data/test_app/public/stylesheets/interpret_style.css +530 -0
  86. data/test_app/script/rails +6 -0
  87. data/test_app/vendor/plugins/.gitkeep +0 -0
  88. metadata +262 -0
data/interpret.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "interpret/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "interpret"
7
+ s.version = Interpret::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Roger Campos"]
10
+ s.email = ["roger@itnig.net"]
11
+ s.homepage = "https://github.com/rogercampos/interpret"
12
+ s.summary = %q{Manage your app translations with an i18n active_record backend}
13
+ s.description = %q{Manage your app translations with an i18n active_record backend}
14
+
15
+ s.rubyforge_project = "interpret"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "rails", "~> 3.0.3"
23
+ s.add_dependency "i18n", "~> 0.5.0"
24
+ s.add_dependency "i18n-active_record"
25
+ s.add_dependency "ya2yaml", ">= 0.30.0"
26
+ s.add_dependency "will_paginate", ">= 3.0.pre2"
27
+ s.add_dependency "best_in_place", ">= 0.1.7"
28
+
29
+ s.add_development_dependency "rspec-rails", ">= 2.5"
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators/migration'
2
+
3
+ module Interpret
4
+
5
+ class MigrationGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+ source_root File.expand_path("../templates", __FILE__)
8
+
9
+ desc "Creates the migration for i18n activerecord backend translations table"
10
+
11
+ def self.next_migration_number(dirname)
12
+ if ActiveRecord::Base.timestamped_migrations
13
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
14
+ else
15
+ "%.3d" % (current_migration_number(dirname) + 1)
16
+ end
17
+ end
18
+
19
+ def copy_translations_migration
20
+ migration_template "migration.rb", "db/migrate/interpret_create_translations.rb"
21
+ end
22
+
23
+ end
24
+ end
25
+
@@ -0,0 +1,21 @@
1
+ module Interpret
2
+
3
+ class SetupGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../../../public", __FILE__)
5
+ desc "Copies needed css and js files into your app's public folders"
6
+
7
+ def copy_css
8
+ copy_file "stylesheets/interpret_style.css", "public/stylesheets/interpret_style.css"
9
+ end
10
+
11
+ def copy_js
12
+ copy_file "javascripts/jquery.purr.js", "public/javascripts/jquery.purr.js"
13
+ end
14
+
15
+ def copy_images
16
+ copy_file "stylesheets/plus_icon.gif", "public/stylesheets/plus_icon.gif"
17
+ copy_file "stylesheets/minus_icon.gif", "public/stylesheets/minus_icon.gif"
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ class InterpretCreateTranslations < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :translations do |t|
4
+ t.string :locale
5
+ t.string :key
6
+ t.text :value
7
+ t.text :interpolations
8
+ t.boolean :is_proc, :default => false
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :translations
14
+ end
15
+ end
16
+
@@ -0,0 +1,16 @@
1
+ module Interpret
2
+
3
+ class ViewsGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../../../app/views", __FILE__)
5
+ desc "Copies all Interpret views to your application."
6
+
7
+ argument :scope, :required => false, :default => nil,
8
+ :desc => "The scope to copy views to"
9
+
10
+ def copy_views
11
+ scope ||= Interpret.controller.split("/").first
12
+ directory "interpret", "app/views/#{scope}"
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ namespace :interpret do
2
+ desc "Update translations keys in database"
3
+ task :update, :roles => :app, :except => { :no_release => true } do
4
+ commands = [
5
+ "RAILS_ENV=#{rails_env} rake interpret:update",
6
+ ]
7
+
8
+ run <<-CMD
9
+ cd #{release_path} &&
10
+ #{commands.join(" && ")}
11
+ CMD
12
+ end
13
+ end
14
+
15
+ after "deploy:update_code", "interpret:update"
@@ -0,0 +1,23 @@
1
+ require 'i18n/backend/active_record'
2
+ require 'interpret/logger'
3
+ require 'interpret/helpers'
4
+
5
+ module Interpret
6
+ class Engine < Rails::Engine
7
+ if Interpret.registered_envs.include?(Rails.env.to_sym)
8
+ initializer "interpret.register_i18n_active_record_backend" do |app|
9
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
10
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Flatten)
11
+
12
+ Interpret.backend = I18n::Backend::ActiveRecord.new
13
+ app.config.i18n.backend = Interpret.backend
14
+ end
15
+ end
16
+
17
+ initializer "interpret.setup_translations_logger" do |app|
18
+ logfile = File.open("#{Rails.root}/log/interpret.log", 'a')
19
+ logfile.sync = true
20
+ Interpret.logger = InterpretLogger.new(logfile)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ module Interpret
2
+ module InterpretHelpers
3
+
4
+ # Generates the html tree from the given keys
5
+ def show_interpret_tree(tree, origin_keys)
6
+ tree = tree.first[1]
7
+ unless origin_keys.nil?
8
+ origin_keys.split(".").each do |key|
9
+ tree = tree[key]
10
+ end
11
+ end
12
+ build_tree(tree, origin_keys)
13
+ end
14
+
15
+ def build_tree(hash, origin_keys = "", prev_key = "")
16
+ out = "<ul id='navigation'>"
17
+ if origin_keys.present? && prev_key.blank?
18
+ parent_key = origin_keys.split(".")[0..-2].join(".")
19
+ if parent_key.blank?
20
+ out << "<li>#{link_to "..", interpret_root_path}</li>"
21
+ else
22
+ out << "<li>#{link_to "..", interpret_root_path(:key => parent_key)}</li>"
23
+ end
24
+ end
25
+ hash.keys.each do |key|
26
+ out << "<li>"
27
+ out << "#{link_to key, interpret_root_path(:key => "#{origin_keys.blank? ? "" : "#{origin_keys}."}#{prev_key}#{key}")}"
28
+ out << "</li>"
29
+ end
30
+ out << "</ul>"
31
+ out.html_safe
32
+ end
33
+
34
+ def current_controller?(opts)
35
+ hash = Rails.application.routes.recognize_path(url_for(opts))
36
+ params[:controller] == hash[:controller]
37
+ end
38
+
39
+ def interpret_section_link_to(name, options = {}, html_options = {})
40
+ html_options.merge!({ :class => 'current' }) if current_controller?(options)
41
+ link_to name, options, html_options
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ # Gist from: https://gist.github.com/745617
2
+ module LazyHash
3
+ class << self
4
+ def lazy_add(hash, key, value, pre = nil)
5
+ skeys = key.split(".")
6
+ f = skeys.shift
7
+ if skeys.empty?
8
+ pre.nil? ? hash.send("[]=", f, value) : pre.send("[]=", f, value)
9
+ else
10
+ pre = pre.nil? ? hash.send("[]", f) : pre.send("[]", f)
11
+ lazy_add(hash, skeys.join("."), value, pre)
12
+ end
13
+ end
14
+
15
+ def build_hash
16
+ lazy = lambda { |h,k| h[k] = Hash.new(&lazy) }
17
+ Hash.new(&lazy)
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,7 @@
1
+ module Interpret
2
+ class InterpretLogger < Logger
3
+ def format_message(severity, timestamp, progname, msg)
4
+ "#{timestamp.to_formatted_s(:db)} #{msg}\n"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Interpret
2
+ VERSION = "0.1.1"
3
+ end
data/lib/interpret.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'best_in_place'
2
+ require 'will_paginate'
3
+ require 'interpret/lazy_hash'
4
+
5
+ module Interpret
6
+ mattr_accessor :backend
7
+ mattr_accessor :logger
8
+
9
+ mattr_accessor :controller
10
+ @@controller = "action_controller/base"
11
+
12
+ mattr_accessor :sweeper
13
+ @@sweeper = nil
14
+
15
+ mattr_accessor :registered_envs
16
+ @@registered_envs = [:production, :staging]
17
+
18
+ mattr_accessor :scope
19
+ @@scope = ""
20
+
21
+ # More options:
22
+ # - memoize?
23
+ # - flatten?
24
+ # - logging?
25
+ # - current_user method. If set, current_user will appear in logs, otherwise not.
26
+ end
27
+
28
+ require 'interpret/engine' if defined? Rails
29
+
30
+ ActionView::Base.send(:include, Interpret::InterpretHelpers)
@@ -0,0 +1,11 @@
1
+ namespace :interpret do
2
+ desc 'Copy all the translations from config/locales/*.yml into DB backend'
3
+ task :migrate => [:environment, "tmp:cache:clear"] do
4
+ Interpret::Translation.dump
5
+ end
6
+
7
+ desc 'Synchronize the keys used in db backend with the ones on *.yml files'
8
+ task :update => [:environment, "tmp:cache:clear"] do
9
+ Interpret::Translation.update
10
+ end
11
+ end
@@ -0,0 +1,180 @@
1
+ /**
2
+ * jquery.purr.js
3
+ * Copyright (c) 2008 Net Perspective (net-perspective.com)
4
+ * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
5
+ *
6
+ * @author R.A. Ray
7
+ * @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
8
+ * @version 0.1.0
9
+ *
10
+ * @requires jquery.js (tested with 1.2.6)
11
+ *
12
+ * @param fadeInSpeed int - Duration of fade in animation in miliseconds
13
+ * default: 500
14
+ * @param fadeOutSpeed int - Duration of fade out animationin miliseconds
15
+ default: 500
16
+ * @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
17
+ default: 4000
18
+ * @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed
19
+ default: false
20
+ * @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling
21
+ default: false
22
+ */
23
+
24
+ ( function( $ ) {
25
+
26
+ $.purr = function ( notice, options )
27
+ {
28
+ // Convert notice to a jQuery object
29
+ notice = $( notice );
30
+
31
+ // Add a class to denote the notice as not sticky
32
+ if ( !options.isSticky )
33
+ {
34
+ notice.addClass( 'not-sticky' );
35
+ };
36
+
37
+ // Get the container element from the page
38
+ var cont = document.getElementById( 'purr-container' );
39
+
40
+ // If the container doesn't yet exist, we need to create it
41
+ if ( !cont )
42
+ {
43
+ cont = '<div id="purr-container"></div>';
44
+ }
45
+
46
+ // Convert cont to a jQuery object
47
+ cont = $( cont );
48
+
49
+ // Add the container to the page
50
+ $( 'body' ).append( cont );
51
+
52
+ notify();
53
+
54
+ function notify ()
55
+ {
56
+ // Set up the close button
57
+ var close = document.createElement( 'a' );
58
+ $( close ).attr(
59
+ {
60
+ className: 'close',
61
+ href: '#close',
62
+ innerHTML: 'Close'
63
+ }
64
+ )
65
+ .appendTo( notice )
66
+ .click( function ()
67
+ {
68
+ removeNotice();
69
+
70
+ return false;
71
+ }
72
+ );
73
+
74
+ // Add the notice to the page and keep it hidden initially
75
+ notice.appendTo( cont )
76
+ .hide();
77
+
78
+ if ( jQuery.browser.msie && options.usingTransparentPNG )
79
+ {
80
+ // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
81
+ // notice style, we'll just skip the fading in.
82
+ notice.show();
83
+ }
84
+ else
85
+ {
86
+ //Fade in the notice we just added
87
+ notice.fadeIn( options.fadeInSpeed );
88
+ }
89
+
90
+ // Set up the removal interval for the added notice if that notice is not a sticky
91
+ if ( !options.isSticky )
92
+ {
93
+ var topSpotInt = setInterval( function ()
94
+ {
95
+ // Check to see if our notice is the first non-sticky notice in the list
96
+ if ( notice.prevAll( '.not-sticky' ).length == 0 )
97
+ {
98
+ // Stop checking once the condition is met
99
+ clearInterval( topSpotInt );
100
+
101
+ // Call the close action after the timeout set in options
102
+ setTimeout( function ()
103
+ {
104
+ removeNotice();
105
+ }, options.removeTimer
106
+ );
107
+ }
108
+ }, 200 );
109
+ }
110
+ }
111
+
112
+ function removeNotice ()
113
+ {
114
+ // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
115
+ // notice style, we'll just skip the fading out.
116
+ if ( jQuery.browser.msie && options.usingTransparentPNG )
117
+ {
118
+ notice.css( { opacity: 0 } )
119
+ .animate(
120
+ {
121
+ height: '0px'
122
+ },
123
+ {
124
+ duration: options.fadeOutSpeed,
125
+ complete: function ()
126
+ {
127
+ notice.remove();
128
+ }
129
+ }
130
+ );
131
+ }
132
+ else
133
+ {
134
+ // Fade the object out before reducing its height to produce the sliding effect
135
+ notice.animate(
136
+ {
137
+ opacity: '0'
138
+ },
139
+ {
140
+ duration: options.fadeOutSpeed,
141
+ complete: function ()
142
+ {
143
+ notice.animate(
144
+ {
145
+ height: '0px'
146
+ },
147
+ {
148
+ duration: options.fadeOutSpeed,
149
+ complete: function ()
150
+ {
151
+ notice.remove();
152
+ }
153
+ }
154
+ );
155
+ }
156
+ }
157
+ );
158
+ }
159
+ };
160
+ };
161
+
162
+ $.fn.purr = function ( options )
163
+ {
164
+ options = options || {};
165
+ options.fadeInSpeed = options.fadeInSpeed || 500;
166
+ options.fadeOutSpeed = options.fadeOutSpeed || 500;
167
+ options.removeTimer = options.removeTimer || 4000;
168
+ options.isSticky = options.isSticky || false;
169
+ options.usingTransparentPNG = options.usingTransparentPNG || false;
170
+
171
+ this.each( function()
172
+ {
173
+ new $.purr( this, options );
174
+ }
175
+ );
176
+
177
+ return this;
178
+ };
179
+ })( jQuery );
180
+
Binary file