i18n_backend_database_rails3 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/Gemfile +4 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +125 -0
  4. data/Rakefile +1 -0
  5. data/data/locales.yml +4 -0
  6. data/generators/i18n_backend_database/i18n_backend_database_generator.rb +8 -0
  7. data/generators/i18n_backend_database/templates/migrate/create_i18n_tables.rb +19 -0
  8. data/i18n_backend_database.gemspec +24 -0
  9. data/init.rb +1 -0
  10. data/lib/controllers/locales_controller.rb +86 -0
  11. data/lib/controllers/translations_controller.rb +141 -0
  12. data/lib/ext/i18n.rb +68 -0
  13. data/lib/google_language.rb +30 -0
  14. data/lib/i18n_backend_database.rb +9 -0
  15. data/lib/i18n_backend_database/database.rb +263 -0
  16. data/lib/i18n_backend_database/version.rb +7 -0
  17. data/lib/i18n_util.rb +148 -0
  18. data/lib/models/locale.rb +67 -0
  19. data/lib/models/translation.rb +46 -0
  20. data/lib/models/translation_option.rb +26 -0
  21. data/lib/public/images/custom1_bar.gif +0 -0
  22. data/lib/public/images/custom1_box.gif +0 -0
  23. data/lib/public/images/percentImage.png +0 -0
  24. data/lib/public/images/percentImage_back.png +0 -0
  25. data/lib/public/images/percentImage_back1.png +0 -0
  26. data/lib/public/images/percentImage_back2.png +0 -0
  27. data/lib/public/images/percentImage_back3.png +0 -0
  28. data/lib/public/images/percentImage_back4.png +0 -0
  29. data/lib/public/javascripts/jsProgressBarHandler.js +509 -0
  30. data/lib/routing.rb +15 -0
  31. data/lib/views/layouts/translations.html.haml +16 -0
  32. data/lib/views/locales/edit.html.haml +16 -0
  33. data/lib/views/locales/index.html.haml +14 -0
  34. data/lib/views/locales/new.html.haml +14 -0
  35. data/lib/views/locales/show.html.haml +10 -0
  36. data/lib/views/translations/asset_translations.html.haml +23 -0
  37. data/lib/views/translations/edit.html.haml +24 -0
  38. data/lib/views/translations/index.html.haml +21 -0
  39. data/lib/views/translations/new.html.haml +14 -0
  40. data/lib/views/translations/show.html.haml +21 -0
  41. data/lib/views/translations/translations.html.haml +20 -0
  42. data/lib/views/translations/update.rjs +7 -0
  43. data/routes.rb +3 -0
  44. data/spec/assets/public/es/favicons/favicon1.gif +0 -0
  45. data/spec/assets/public/es/images/icons/icon1.gif +0 -0
  46. data/spec/assets/public/es/images/image1.gif +0 -0
  47. data/spec/assets/public/favicons/favicon1.gif +0 -0
  48. data/spec/assets/public/favicons/favicon2.gif +0 -0
  49. data/spec/assets/public/images/icons/icon1.gif +0 -0
  50. data/spec/assets/public/images/icons/icon2.gif +0 -0
  51. data/spec/assets/public/images/image1.gif +0 -0
  52. data/spec/assets/public/images/image2.gif +0 -0
  53. data/spec/assets/public/images/promo/sfc08_140x400_3.gif +0 -0
  54. data/spec/assets/views/test_view1.html.erb +1 -0
  55. data/spec/assets/views/test_view2.html.erb +30 -0
  56. data/spec/caching_spec.rb +87 -0
  57. data/spec/controllers/locales_controller_spec.rb +173 -0
  58. data/spec/controllers/locales_routing_spec.rb +59 -0
  59. data/spec/controllers/translations_controller_spec.rb +189 -0
  60. data/spec/controllers/translations_routing_spec.rb +59 -0
  61. data/spec/database_spec.rb +199 -0
  62. data/spec/i18n_ext_spec.rb +40 -0
  63. data/spec/localize_spec.rb +66 -0
  64. data/spec/localize_text_spec.rb +76 -0
  65. data/spec/models/locale_spec.rb +111 -0
  66. data/spec/models/translation_spec.rb +44 -0
  67. data/spec/spec_helper.rb +16 -0
  68. data/spec/translate_asset_spec.rb +57 -0
  69. data/spec/translate_spec.rb +546 -0
  70. data/tasks/i18n.rake +60 -0
  71. metadata +143 -0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in i18n-backend-database.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2008, 2009, 2010, 2011
2
+ ELC Technologies. All rights reserved.
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,125 @@
1
+ h1. A Database Backend For Rails I18N
2
+
3
+ Stores your translations in the database, rather than yaml files. As you tag items with i18n.t() throughout your code base, all untranslated items are marked and added to the database. An admin panel is provided so translators can quickly translate untranslated text. All lookups occur in a cache store of your choice prior to hitting the database.
4
+
5
+ h2. DISCLAIMER!
6
+
7
+ * -In implementing this into another project, I realized that the currency support is currently broken. It basically boils down to the i18n gem accessing some of the Rails i18n yaml's in a different way than others. In this case, it's requesting a parent key, and expects a hash to be returned containing the children. This is not baked in the plugin at the moment, and any contributions toward this would be well received.- Thank you wlorentson!
8
+
9
+ * The translations_controller is unprotected, and you'll probably want to add some kind of authorization filter to it to make sure the outside world can't access it.
10
+
11
+ h2. Installation
12
+
13
+ <pre>
14
+ <code>
15
+ script/generate i18n_backend_database # add migration
16
+ rake db:migrate # migrate
17
+
18
+ rake i18n:populate:load_default_locales # populate default locales
19
+ rake i18n:populate:from_rails # populate the locales and translations tables from all Rails Locale YAML files.
20
+ rake i18n:populate:from_application # populate the translation tables from translation calls within the application.
21
+ rake i18n:populate:synchronize_translations # create non-default locale translation records from default locale translations.
22
+ rake i18n:populate:all # run all populate tasks.
23
+ rake i18n:translate:google # translate all untranslated string values using Google Language Translation API.
24
+ </code>
25
+ </pre>
26
+
27
+
28
+ In config/initialisers/i18n.rb
29
+
30
+ <pre>
31
+ <code>
32
+ I18n.backend = I18n::Backend::Database.new # registers the backend
33
+ I18n.backend.cache_store = :memory_store # optional: specify an alternate cache store
34
+ I18n.backend.localize_text_tag = '##' # optional: specify an alternate localize text tag, the default is ^^
35
+ </code>
36
+ </pre>
37
+
38
+ In config/routes.rb to register admin panel routes
39
+
40
+ <pre>
41
+ <code>
42
+ map.from_plugin 'i18n_backend_database'
43
+ </code>
44
+ </pre>
45
+
46
+ h2. Use
47
+
48
+ All non-user generated text provided by the application needs to be wrapped in a call to I18n.t().
49
+ <pre>
50
+ <code>
51
+ I18n.t("Hello there!")
52
+ </code>
53
+ </pre>
54
+
55
+ Interpolation is handled by passing in key/value pairs as a value to an interpolation tag ( {{ }} ).
56
+ <pre>
57
+ <code>
58
+ I18n.t("Hello there {{name}}!", :name => "Dylan")
59
+ </code>
60
+ </pre><pre>
61
+ <code>
62
+ I18n.t("Click {{here}} or {{there}}", :here => "link_to(I18n.t('midnite'), croix_path)", :there => "link_to(I18n.t('staten_island'), wu_path)")
63
+ </code>
64
+ </pre>
65
+
66
+ Pluralization is handled by passing in a "count" key value pair, which is a unique interpolation value.
67
+ <pre>
68
+ <code>
69
+ I18n.t("You are {{count}} years old", :count => 100)
70
+ </code>
71
+ </pre>
72
+
73
+ Links to external documents that need to be translated should be tagged as well.
74
+ <pre>
75
+ <code>
76
+ I18n.t('http://www.elctech.com/core')
77
+ </code>
78
+ </pre>
79
+
80
+ All fragment cache view blocks need to have their keys prepended with the current locale.
81
+ <pre>
82
+ <code>
83
+ cache("#{I18n.locale}-footer_#{controller.action_name}")
84
+ </code>
85
+ </pre>
86
+
87
+ Date/Time localization is handled by using the I18n.l method. The format used will be :default (see next item for explanation).
88
+ <pre>
89
+ <code>
90
+ I18n.l(@user.joined_at)
91
+ </code>
92
+ </pre>
93
+
94
+ Date/Time localization can take a format parameter that corresponds to a key in the translations table (the Rails defaults :default, :short, and :long are available). We could in theory create our own like en.date.formats.espn_default.
95
+ <pre>
96
+ <code>
97
+ I18n.l(@user.joined_at, :format => :default)
98
+ I18n.l(@user.joined_at, :format => :short)
99
+ I18n.l(@user.joined_at, :format => :espn_default)
100
+ </code>
101
+ </pre>
102
+
103
+ Date/Time localization can take a custom format string as well.
104
+ <pre>
105
+ <code>
106
+ I18n.l(@user.joined_at, :format => "%B %e, %Y")
107
+ </code>
108
+ </pre>
109
+
110
+ Text stored in a database can be localized by tagging the text being stored and then localizing in the view etc.
111
+ <pre>
112
+ <code>
113
+ I18n.tlt("is now friends with") => "^^is now friends with^^"
114
+ I18n.lt("shane ^^is now friends with^^ dylan") => "shane ahora es con amigos dylan"
115
+ </code>
116
+ </pre>
117
+
118
+ Images can be translated with the I18n.ta tag
119
+ <pre>
120
+ <code>
121
+ <%= image_tag(I18n.ta("logos/elc.gif"), :size => "134x75") %>
122
+ </code>
123
+ </pre>
124
+ In this example, for a locale es, there should be an image: public/es/images/logos/elc.gif
125
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ en:
2
+ name: English
3
+ es:
4
+ name: Spanish
@@ -0,0 +1,8 @@
1
+ class I18nBackendDatabaseGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record { |m|
4
+ m.migration_template "migrate/create_i18n_tables.rb", "db/migrate",
5
+ :migration_file_name => "create_i18n_tables"
6
+ }
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ class CreateI18nTables < ActiveRecord::Migration
2
+ def change
3
+ create_table :locales do |t|
4
+ t.string :code
5
+ t.string :name
6
+ end
7
+ add_index :locales, :code
8
+
9
+ create_table :translations do |t|
10
+ t.string :key
11
+ t.text :raw_key
12
+ t.text :value
13
+ t.integer :pluralization_index, :default => 1
14
+ t.integer :locale_id
15
+ end
16
+ add_index :translations, [:locale_id, :key, :pluralization_index]
17
+
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "i18n_backend_database/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{i18n_backend_database_rails3}
7
+
8
+ s.authors = ["Dylan Stamat", "Hector Bustillos"]
9
+ s.date = %q{2012-01-23}
10
+ s.description = %q{This is a gem based on the original repo of Dylan Stamat, which add's cool functions to manage i18n}
11
+ s.email = %w{hector.bustillos@crowdint.com}
12
+ s.has_rdoc = false
13
+ s.version = I18n::Backend::Database::VERSION
14
+ s.homepage = "https://github.com/hecbuma/i18n_backend_database"
15
+ s.summary = %q{Cool utils and admin for I18n}
16
+
17
+ s.rubyforge_project = "compass-bootstrap"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+
24
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'i18n_backend_database'
@@ -0,0 +1,86 @@
1
+ class LocalesController < ActionController::Base
2
+ prepend_view_path(File.join(File.dirname(__FILE__), "..", "views"))
3
+ # GET /locales
4
+ # GET /locales.xml
5
+ def index
6
+ @locales = Locale.find(:all)
7
+
8
+ respond_to do |format|
9
+ format.html # index.html.erb
10
+ format.xml { render :xml => @locales }
11
+ end
12
+ end
13
+
14
+ # GET /locales/1
15
+ # GET /locales/1.xml
16
+ def show
17
+ @locale = Locale.find_by_code(params[:id])
18
+
19
+ respond_to do |format|
20
+ format.html # show.html.erb
21
+ format.xml { render :xml => @locale }
22
+ end
23
+ end
24
+
25
+ # GET /locales/new
26
+ # GET /locales/new.xml
27
+ def new
28
+ @locale = Locale.new
29
+
30
+ respond_to do |format|
31
+ format.html # new.html.erb
32
+ format.xml { render :xml => @locale }
33
+ end
34
+ end
35
+
36
+ # GET /locales/1/edit
37
+ def edit
38
+ @locale = Locale.find_by_code(params[:id])
39
+ end
40
+
41
+ # POST /locales
42
+ # POST /locales.xml
43
+ def create
44
+ @locale = Locale.new(params[:locale])
45
+
46
+ respond_to do |format|
47
+ if @locale.save
48
+ flash[:notice] = 'Locale was successfully created.'
49
+ format.html { redirect_to(@locale) }
50
+ format.xml { render :xml => @locale, :status => :created, :location => @locale }
51
+ else
52
+ format.html { render :action => "new" }
53
+ format.xml { render :xml => @locale.errors, :status => :unprocessable_entity }
54
+ end
55
+ end
56
+ end
57
+
58
+ # PUT /locales/1
59
+ # PUT /locales/1.xml
60
+ def update
61
+ @locale = Locale.find_by_code(params[:id])
62
+
63
+ respond_to do |format|
64
+ if @locale.update_attributes(params[:locale])
65
+ flash[:notice] = 'Locale was successfully updated.'
66
+ format.html { redirect_to(@locale) }
67
+ format.xml { head :ok }
68
+ else
69
+ format.html { render :action => "edit" }
70
+ format.xml { render :xml => @locale.errors, :status => :unprocessable_entity }
71
+ end
72
+ end
73
+ end
74
+
75
+ # DELETE /locales/1
76
+ # DELETE /locales/1.xml
77
+ def destroy
78
+ @locale = Locale.find_by_code(params[:id])
79
+ @locale.destroy
80
+
81
+ respond_to do |format|
82
+ format.html { redirect_to(locales_url) }
83
+ format.xml { head :ok }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,141 @@
1
+ class TranslationsController < ActionController::Base
2
+ prepend_view_path(File.join(File.dirname(__FILE__), "..", "views"))
3
+ layout 'translations'
4
+ before_filter :find_locale
5
+
6
+ ## FIXME: you'll probably want add authorization to this controller!
7
+
8
+ # GET /translations
9
+ # GET /translations.xml
10
+ def index
11
+ @translations = @locale.translations.find(:all, :order => "raw_key, pluralization_index")
12
+
13
+ respond_to do |format|
14
+ format.html # index.html.erb
15
+ format.xml { render :xml => @translations }
16
+ end
17
+ end
18
+
19
+ # GET /translations
20
+ # GET /translations.xml
21
+ def translations
22
+ @locale ||= Locale.default_locale
23
+ @translation_option = TranslationOption.find(params[:translation_option])
24
+
25
+ if @translation_option == TranslationOption.translated
26
+ @translations = @locale.translations.translated
27
+ else
28
+ @translations = @locale.translations.untranslated
29
+ end
30
+
31
+ respond_to do |format|
32
+ format.html # index.html.erb
33
+ format.xml { render :xml => @translations }
34
+ end
35
+ end
36
+
37
+ # GET /asset_translations
38
+ # GET /asset_translations.xml
39
+ def asset_translations
40
+ @locale ||= Locale.default_locale
41
+ @translation_option = TranslationOption.find(params[:translation_option])
42
+
43
+ @asset_translations = I18n.asset_translations
44
+ @untranslated_assets = I18n.untranslated_assets(@locale.code)
45
+ @percentage_translated = (((@asset_translations.size - @untranslated_assets.size).to_f / @asset_translations.size.to_f * 100).round) rescue 0
46
+
47
+ if @translation_option == TranslationOption.translated
48
+ @asset_translations = @asset_translations.reject{|e| @untranslated_assets.include?(e)}
49
+ else
50
+ @asset_translations = @untranslated_assets
51
+ end
52
+
53
+ respond_to do |format|
54
+ format.html # index.html.erb
55
+ format.xml { render :xml => @untranslated_assets }
56
+ end
57
+ end
58
+
59
+ # GET /translations/1
60
+ # GET /translations/1.xml
61
+ def show
62
+ @translation = @locale.translations.find(params[:id])
63
+
64
+ respond_to do |format|
65
+ format.html # show.html.erb
66
+ format.xml { render :xml => @translation }
67
+ end
68
+ end
69
+
70
+ # GET /translations/new
71
+ # GET /translations/new.xml
72
+ def new
73
+ @translation = Translation.new
74
+
75
+ respond_to do |format|
76
+ format.html # new.html.erb
77
+ format.xml { render :xml => @translation }
78
+ end
79
+ end
80
+
81
+ # GET /translations/1/edit
82
+ def edit
83
+ @translation = @locale.translations.find(params[:id])
84
+ end
85
+
86
+ # POST /translations
87
+ # POST /translations.xml
88
+ def create
89
+ @translation = @locale.translations.build(params[:translation])
90
+
91
+ respond_to do |format|
92
+ if @translation.save
93
+ flash[:notice] = 'Translation was successfully created.'
94
+ format.html { redirect_to locale_translation_path(@locale, @translation) }
95
+ format.xml { render :xml => @translation, :status => :created, :location => @translation }
96
+ else
97
+ format.html { render :action => "new" }
98
+ format.xml { render :xml => @translation.errors, :status => :unprocessable_entity }
99
+ end
100
+ end
101
+ end
102
+
103
+ # PUT /translations/1
104
+ # PUT /translations/1.xml
105
+ def update
106
+ @translation = @locale.translations.find(params[:id])
107
+ @first_time_translating = @translation.value.nil?
108
+
109
+ respond_to do |format|
110
+ if @translation.update_attributes(params[:translation])
111
+ format.html do
112
+ flash[:notice] = 'Translation was successfully updated.'
113
+ redirect_to locale_translation_path(@locale, @translation)
114
+ end
115
+ format.xml { head :ok }
116
+ format.js {}
117
+ else
118
+ format.html { render :action => "edit" }
119
+ format.xml { render :xml => @translation.errors, :status => :unprocessable_entity }
120
+ end
121
+ end
122
+ end
123
+
124
+ # DELETE /translations/1
125
+ # DELETE /translations/1.xml
126
+ def destroy
127
+ @translation = @locale.translations.find(params[:id])
128
+ @translation.destroy
129
+
130
+ respond_to do |format|
131
+ format.html { redirect_to(locale_translations_url) }
132
+ format.xml { head :ok }
133
+ end
134
+ end
135
+
136
+ private
137
+
138
+ def find_locale
139
+ @locale = Locale.find_by_code(params[:locale_id])
140
+ end
141
+ end