lolita-i18n 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +29 -0
  2. data/Gemfile +11 -25
  3. data/History.rdoc +7 -0
  4. data/README.md +1 -1
  5. data/Rakefile +4 -46
  6. data/app/assets/javascripts/lolita/i18n/application.js +1 -1
  7. data/app/assets/javascripts/lolita/i18n/i18n.js +87 -0
  8. data/app/assets/stylesheets/lolita/i18n/application.scss +8 -7
  9. data/app/controllers/lolita/i18n_controller.rb +27 -9
  10. data/app/helpers/lolita/i18n_helper.rb +40 -7
  11. data/app/views/lolita/i18n/index.html.haml +23 -14
  12. data/config/locales/en.yml +7 -2
  13. data/config/locales/lv.yml +7 -2
  14. data/config/routes.rb +2 -10
  15. data/lib/lolita-i18n.rb +11 -77
  16. data/lib/lolita-i18n/configuration.rb +56 -0
  17. data/lib/lolita-i18n/exceptions.rb +6 -0
  18. data/lib/lolita-i18n/rails.rb +0 -1
  19. data/lib/lolita-i18n/request.rb +219 -0
  20. data/lib/lolita-i18n/version.rb +11 -0
  21. data/lolita-i18n.gemspec +18 -96
  22. data/spec/controllers/lolita/i18n_controller_spec.rb +64 -30
  23. data/spec/helpers/lolita/i18n_helper_spec.rb +70 -0
  24. data/spec/lolita-i18n/configuration_spec.rb +63 -0
  25. data/spec/lolita-i18n/exceptions_spec.rb +15 -0
  26. data/spec/lolita-i18n/request_spec.rb +238 -0
  27. data/spec/lolita-i18n/version_spec.rb +8 -0
  28. data/spec/lolita_i18n_spec.rb +38 -0
  29. data/spec/rails_spec_helper.rb +11 -0
  30. data/spec/requests/translating_spec.rb +51 -0
  31. data/spec/requests/translation_list_spec.rb +36 -0
  32. data/spec/routing/routes_spec.rb +11 -0
  33. data/spec/spec_helper.rb +26 -18
  34. data/spec/{rails_app → test_app}/app/controllers/application_controller.rb +2 -2
  35. data/spec/test_app/config/application.rb +19 -0
  36. data/spec/test_app/config/boot.rb +11 -0
  37. data/spec/{rails_app → test_app}/config/enviroment.rb +4 -4
  38. data/spec/test_app/config/enviroments/test.rb +44 -0
  39. data/spec/test_app/config/initializers/lolita_i18n.rb +4 -0
  40. data/spec/test_app/config/initializers/token.rb +7 -0
  41. data/spec/test_app/config/locales/en.yml +10 -0
  42. data/spec/test_app/config/locales/lv.yml +2 -0
  43. data/spec/test_app/config/locales/ru.yml +2 -0
  44. data/spec/test_app/config/mongoid.yml +6 -0
  45. data/spec/{rails_app → test_app}/config/routes.rb +2 -2
  46. data/spec/test_app/log/.gitkeep +0 -0
  47. data/spec/test_app/log/development.log +734 -0
  48. metadata +69 -80
  49. data/VERSION +0 -1
  50. data/app/assets/javascripts/lolita/i18n/i18n.js.coffee +0 -135
  51. data/lib/lolita-i18n/backend.rb +0 -87
  52. data/spec/lolita-i18n/backend_spec.rb +0 -33
  53. data/spec/rails_app/config/application.rb +0 -18
  54. data/spec/rails_app/config/initializers/lolita_i18n.rb +0 -16
  55. data/spec/rails_app/config/locales/en.yml +0 -10
  56. data/spec/rails_app/config/locales/lv.yml +0 -2
data/.gitignore ADDED
@@ -0,0 +1,29 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+
15
+ # jeweler generated
16
+ pkg
17
+ Gemfile.lock
18
+
19
+ spec/rails_app/log/*.log
20
+ .idea
21
+
22
+ .rvmrc
23
+ tmp
24
+ .sass-cache
25
+ .rspec
26
+ pkg
27
+ spec/test_app/coverage.data
28
+ spec/test_app/coverage
29
+ spec/tst_app/log
data/Gemfile CHANGED
@@ -1,30 +1,16 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "lolita", '~>3.2.0.rc.6'
4
- gem "hiredis", "~> 0.3.1"
5
- gem "redis", "~> 2.2.2", :require => ["redis/connection/hiredis", "redis"]
6
- gem "yajl-ruby", "~> 1.0.0"
7
- gem "easy_translate", "~> 0.2.1"
8
-
9
- group :development do
10
- gem "shoulda", ">= 0"
11
- gem "bundler", "~> 1.0.0"
12
- gem "jeweler", "~> 1.5.2"
13
- gem "rcov", ">= 0"
14
- end
3
+ gemspec
15
4
 
16
5
  group :test do
17
- gem "rspec","~>2.6.0"
18
- gem "rspec-rails", "~>2.6.0"
19
- gem "webmock", "~> 1.7.6"
20
- # gem "mongo", "~> 1.3.0"
21
- # gem "mongoid", "~> 2.0.0"
22
- # gem "bson_ext", "~> 1.4.0"
23
-
24
- # For ruby 1.9.3
25
- # curl -OL http://rubyforge.org/frs/download.php/75414/linecache19-0.5.13.gem
26
- # gem install linecache19-0.5.13.gem
27
- # And then ruby-debug-base19x via
28
- # gem install --pre ruby-debug-base19x
29
- gem 'ruby-debug-base19x'
6
+ gem "rails", "~>3.2.2"
7
+ gem "cover_me", "~>1.2.0"
8
+ gem "bson_ext", "~>1.6.2"
9
+ gem "mongoid", "~>2.4.8"
10
+ gem "rspec","~>2.9.0"
11
+ gem "rspec-rails", "~>2.9.0"
12
+ gem "capybara", "~> 1.1.2"
13
+ gem 'capybara-webkit', "~>0.11.0"
14
+ gem "sass", "~>3.1.15"
15
+
30
16
  end
data/History.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ === Version 0.4.0
2
+ * Changes
3
+ * Google translations removed.
4
+ * Updated translation backend to be more OO
5
+ * 100% test coverage
6
+ * Interface and usability updated
7
+
1
8
  === Version 0.2.0
2
9
  * Enhancements
3
10
  * Redis configuration and access to attributes goes through Lolita.i18n
data/README.md CHANGED
@@ -4,7 +4,7 @@ Lolita I18n is Lolita[https://github.com/ithouse/lolita] plugin, that enables .y
4
4
 
5
5
  ## Usage
6
6
 
7
- * setup rails 3.1 project with ["Lolita"](https://github.com/ithouse/lolita)
7
+ * setup rails >3.1 project with ["Lolita"](https://github.com/ithouse/lolita)
8
8
  * setup [Redis DB](http://redis.io) on your server
9
9
  * add `gem 'lolita-i18n'` into Gemfile
10
10
  * in your lolita setup block add `config.i18n.store = {:db => REDIS_DB}` or `config.i18n.store = Redis.new`
data/Rakefile CHANGED
@@ -1,46 +1,4 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "lolita-i18n"
16
- gem.homepage = "http://github.com/ithouse/lolita-i18n"
17
- gem.license = "MIT"
18
- gem.summary = %Q{Lolita plugin, that enables .yml management}
19
- gem.description = %Q{Lolita plugin, that enables .yml files management from administrative interface. Also faster access to translations, that DB store}
20
- gem.email = "support@ithouse.lv"
21
- gem.authors = ["ITHouse (Latvia)","Arturs Meisters", "Gatis Tomsons"]
22
- # Include your dependencies below. Runtime dependencies are required when using your gem,
23
- # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
- # gem.add_development_dependency 'rspec', '> 1.2.3'
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
28
-
29
- require 'rake/testtask'
30
- Rake::TestTask.new(:test) do |test|
31
- test.libs << 'lib' << 'test'
32
- test.pattern = 'test/**/test_*.rb'
33
- test.verbose = true
34
- end
35
-
36
- task :default => :test
37
-
38
- require 'rdoc/task'
39
- RDoc::Task.new do |rdoc|
40
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
-
42
- rdoc.rdoc_dir = 'rdoc'
43
- rdoc.title = "lolita-i18n #{version}"
44
- rdoc.rdoc_files.include('README*')
45
- rdoc.rdoc_files.include('lib/**/*.rb')
46
- end
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler::GemHelper.install_tasks
@@ -1,2 +1,2 @@
1
1
  //= require jquery
2
- //= require_tree .
2
+ //= require ./i18n
@@ -0,0 +1,87 @@
1
+ $(function(){
2
+
3
+ $('#active_locale').change(function(){
4
+ params("active_locale",$(this).val())
5
+ })
6
+
7
+ $('#show_untranslated').change(function(){
8
+ params("show_untranslated", $(this).is(':checked') ? "1" : false)
9
+ })
10
+
11
+ var resize = function($textarea) {
12
+ $textarea[0].style.height = 'auto';
13
+ $textarea[0].style.height = ($textarea[0].scrollHeight + $textarea.data("offset") ) + 'px';
14
+ }
15
+
16
+ var reset_size = function($textarea){
17
+ $textarea[0].style.height = 'auto';
18
+ $textarea[0].style.height = ($textarea.data("offset") ) + 'px';
19
+ }
20
+
21
+ $("textarea").each(function(){
22
+ var t = $(this)[0]
23
+ var offset= !window.opera ? (t.offsetHeight - t.clientHeight) : (t.offsetHeight + parseInt(window.getComputedStyle(t, null).getPropertyValue('border-top-width'))) ;
24
+ $(this).data("offset",offset)
25
+ })
26
+
27
+ $("textarea").keyup(function(){
28
+ resize($(this))
29
+ })
30
+
31
+ $("textarea").focus(function(){
32
+ resize($(this))
33
+ $(this).data("original-text",$(this).val())
34
+ })
35
+
36
+ $("textarea").blur(function(){
37
+ if($(this).data("original-text")!=$(this).val()){
38
+ $(this).data("original-text",false)
39
+ var $td = $(this).parents("td:eq(0)")
40
+ var key = $td.data("key")
41
+ var locale = $td.data("locale")
42
+ var $textareas = $("td[data-key='"+key+"'] textarea");
43
+ var result_str = ""
44
+ var result_arr = false
45
+ var result_json = false
46
+
47
+ if($textareas.length > 1){
48
+ $textareas.each(function(index){
49
+ var current_key = locale + "." + $(this).attr("name")
50
+ var m_data = current_key.match(/\[(\d+)\]$/)
51
+ if(m_data){
52
+ result_arr = result_arr || []
53
+ result_arr[parseInt(m_data[m_data.length-1])] = $(this).val()
54
+ }else{
55
+ result_json = result_json || {}
56
+ keys = current_key.split(".")
57
+ json_key = keys[keys.length-1]
58
+ result_json[json_key] = $(this).val()
59
+ }
60
+ })
61
+ }else{
62
+ result_str = $textareas.eq(0).val()
63
+ }
64
+
65
+ new_id = Base64.encode(key)
66
+ save(result_arr || result_json || result_str, new_id)
67
+ }
68
+ reset_size($(this))
69
+ })
70
+
71
+ var save = function(post_data,id){
72
+ $.ajax({
73
+ type: 'PUT',
74
+ url: '/lolita/i18n/' + id,
75
+ data: {translation: post_data},
76
+ dataType: 'json',
77
+ success: function(data){
78
+ if(data.error){
79
+ show_error_msg( data.error)
80
+ }
81
+ },
82
+ error: function(request){
83
+ show_error_msg("Connection error! Translation is not saved!")
84
+ }
85
+ })
86
+ }
87
+ })
@@ -3,10 +3,10 @@
3
3
  */
4
4
  .clear { clear: both; height: 0; }
5
5
 
6
- div.i18n-box div.list {
6
+ /*div.i18n-box div.list {
7
7
  background-color: white;
8
8
  overflow: none;
9
- }
9
+ }*/
10
10
  .i18n-language-switch{
11
11
  overflow: hidden;
12
12
  list-style: none;
@@ -29,9 +29,7 @@ span.hint {
29
29
  color: #666;
30
30
  display: block;
31
31
  }
32
- #i18n_edit textarea {
33
- height: 100px;
34
- }
32
+
35
33
  div.list div.actions {
36
34
  padding: 10px;
37
35
  .filters {
@@ -68,7 +66,8 @@ div.list table {
68
66
  box-sizing: border-box;
69
67
  padding: 3px 10px;
70
68
  width: 100%;
71
- min-height: 50px;
69
+ min-height: 25px;
70
+ height: 25px;
72
71
  color: #494949;
73
72
  }
74
73
  td, th {
@@ -76,10 +75,12 @@ div.list table {
76
75
  padding: 5px 20px;
77
76
  line-height: 20px;
78
77
  }
78
+ td.grouped{
79
+ padding-left: 0px;
80
+ }
79
81
  thead th {
80
82
  line-height: 30px;
81
83
  select {
82
- float: right;
83
84
  margin-top: 5px;
84
85
  }
85
86
  }
@@ -5,27 +5,38 @@ class Lolita::I18nController < ApplicationController
5
5
  layout "lolita/application"
6
6
 
7
7
  def index
8
- @translation_keys=Lolita.i18n.flatten_keys
8
+ authorization_proxy.authorize!(:read, self.resource_class)
9
+ @translations = i18n_request.translations(@active_locale)
10
+
11
+ if params[:sort] && params[:sort].to_s == "1"
12
+ @translations = i18n_request.sort_translations(@translations)
13
+ end
9
14
  end
10
15
 
11
16
  def update
17
+ authorization_proxy.authorize!(:update, self.resource_class)
12
18
  respond_to do |format|
13
19
  format.json do
14
- error = false
15
20
  begin
16
- Lolita::I18n::Backend.set(params[:id],params[:translation])
17
- rescue Lolita::I18n::Exceptions::MissingInterpolationArgument => e
18
- error = e.to_s
21
+ if saved = i18n_request.update_key
22
+ notice(::I18n.t("lolita-i18n.Successful update"))
23
+ else
24
+ error(::I18n.t("lolita-i18n.Error"))
25
+ end
26
+ render :nothing => true, :json => {error: !saved && ::I18n.t("lolita-i18n.Error") }
27
+ rescue Lolita::I18n::Exceptions::MissingInterpolationArgument => er
28
+ render :nothing => true, :json => {error: er.to_s}
29
+ rescue Exception => e
30
+ render :nothing => true, :json => {error: "Key is not saved. Some error accured." }
19
31
  end
20
- render :nothing => true, :json => {error: error}
21
32
  end
22
33
  end
23
34
  end
24
35
 
25
36
  private
26
37
 
27
- def is_lolita_resource?
28
- true
38
+ def lolita_mapping
39
+ Lolita.mappings[:i18n]
29
40
  end
30
41
 
31
42
  def next_locale
@@ -33,7 +44,14 @@ class Lolita::I18nController < ApplicationController
33
44
  end
34
45
 
35
46
  def set_current_locale
36
- @active_locale = (params[:active_locale] || next_locale).to_sym
47
+ @active_locale = ::I18n.available_locales.include?(params[:active_locale].to_s.to_sym) ? params[:active_locale] : nil
48
+ @active_locale ||= next_locale
49
+ @active_locale = @active_locale.to_sym
50
+ @active_locale = nil if @active_locale == ::I18n.default_locale
51
+ end
52
+
53
+ def i18n_request
54
+ @i18n_request ||= Lolita::I18n::Request.new(params)
37
55
  end
38
56
 
39
57
  end
@@ -1,17 +1,50 @@
1
1
  module Lolita
2
2
  module I18nHelper
3
3
  def locale_options
4
- (::I18n::available_locales).collect{|locale|
5
- [::I18n.t(locale, :default => locale), locale] unless [::I18n.default_locale,@active_locale].include?(locale)
6
- }.compact.insert(0,[::I18n.t("lolita-i18n.choose-other-language", :default => ::I18n.t("lolita-i18n.choose-other-language", :locale => "en")),""])
4
+ [[::I18n.t("lolita-i18n.choose-other-language"),nil]] +
5
+ (::I18n.available_locales - [::I18n.default_locale]).sort.map{|locale|
6
+ [::I18n.t("#{locale}", :default => locale.to_s.upcase), locale]
7
+ }
7
8
  end
8
9
 
9
- def show_translation key
10
- ::I18n.t(key, :locale => @active_locale, :default => '')
10
+ def translation active_locale, key, original_key, translation, original
11
+ %Q{
12
+ <td style="width:450px", data-key="#{active_locale}.#{original_key}" data-locale="#{active_locale}">
13
+ <p>
14
+ #{text_area_tag "#{active_locale}.#{key}", translation}
15
+ </p>
16
+ </td>
17
+ <td style="width:90%" data-key="#{::I18n.default_locale}.#{original_key}" data-locale="#{::I18n.default_locale}">
18
+ <p>
19
+ #{text_area_tag "#{::I18n.default_locale}.#{key}", original}
20
+ </p>
21
+ #{!key.blank? && "<span class='hint'>#{key}</span>"}
22
+ </td>
23
+ }
11
24
  end
12
25
 
13
- def is_untranslated key
14
- ::I18n.t(key, :locale => @active_locale, :default => "").blank?
26
+ def translation_visible? value
27
+ !!(!params[:show_untranslated] || value.is_a?(Array) || value.is_a?(Hash) || (params[:show_untranslated] && value.blank?))
28
+ end
29
+
30
+ def any_translation_visible? values
31
+ if values.is_a?(Array)
32
+ values.empty? || values.detect{|value| translation_visible?(value)}
33
+ elsif values.is_a?(Hash)
34
+ values.empty? || values.detect{|key,value| translation_visible?(value)}
35
+ else
36
+ translation_visible?(values)
37
+ end
38
+ end
39
+
40
+ def sort_link
41
+ sort_params = unless params[:sort]
42
+ params.merge({:sort => 1})
43
+ else
44
+ params.reject{|k,v| k == "sort" || k == :sort}
45
+ end
46
+ url_for_sort = url_for(sort_params)
47
+ link_to(raw("#{::I18n.t(::I18n.default_locale)} #{params[:sort] && "&uArr;"}"), url_for_sort, :id => "translation_sort_link")
15
48
  end
16
49
  end
17
50
  end
@@ -2,30 +2,39 @@
2
2
  = stylesheet_link_tag "lolita/i18n/application", :media => "screen,projection"
3
3
  - content_for :script do
4
4
  = javascript_include_tag "lolita/i18n/application"
5
- .box.i18n-bo
5
+ .box.i18n-box
6
6
  .boxtitle
7
- %h1.black= ::I18n.t('lolita-i18n.title', :default => ::I18n.t('lolita-i18n.title', :locale => 'en'))
7
+ %h1.black= ::I18n.t('lolita-i18n.title', :default => ::I18n.t('lolita-i18n.title'))
8
8
  .arrow
9
9
  .list
10
10
  %div.actions
11
11
  .filters
12
12
  = check_box_tag "show_untranslated", nil, params[:show_untranslated]
13
- = label_tag "show_untranslated", ::I18n.t('lolita-i18n.show-untranslated', :default => ::I18n.t('lolita-i18n.show-untranslated', :locale => 'en'))
13
+ = label_tag "show_untranslated", ::I18n.t('lolita-i18n.show-untranslated', :default => ::I18n.t('lolita-i18n.show-untranslated'))
14
14
  %table
15
15
  %thead
16
16
  %tr
17
17
  %th{:style => "width:450px"}
18
- = label_tag :active_locale, I18n.t(@active_locale, :default => @active_locale)
19
18
  - if locale_options.size > 1
20
- = select_tag :active_locale, options_for_select(locale_options), :id => "active_locale"
21
- %th{:style => "width:90%"}= ::I18n.t(::I18n.default_locale)
19
+ = select_tag :active_locale, options_for_select(locale_options,@active_locale.to_sym), :id => "active_locale"
20
+ %th{:style => "width:90%"}= raw(sort_link)
22
21
  %tbody
23
- - @translation_keys.each do |key|
24
- - if !params[:show_untranslated] or is_untranslated(key)
22
+ - active_locale = @active_locale
23
+ - @translations.each do |key,value|
24
+ - if @active_locale && any_translation_visible?(value[:translation])
25
25
  %tr
26
- %td{:style => "width:450px", :'data-key' => key, :'data-locale' => @active_locale}
27
- %p= show_translation key
28
- %td{:style => "width:90%", :'data-key' => key, :'data-locale' => ::I18n.default_locale}
29
- %p= ::I18n.t(key, :locale => ::I18n.default_locale, :default => "")
30
- %span.hint
31
- = key
26
+ - if value[:original_translation].is_a?(Hash) || value[:original_translation].is_a?(Array)
27
+ %td.grouped{:colspan => "2"}
28
+ %table
29
+ - if value[:original_translation].is_a?(Hash)
30
+ - value[:original_translation].each do |c_key,c_value|
31
+ - if translation_visible?(value[:translation][c_key])
32
+ %tr
33
+ = raw(translation(@active_locale,"#{key}.#{c_key}",key,value[:translation][c_key],c_value))
34
+ - else
35
+ - value[:original_translation].each_with_index do |c_value,index|
36
+ - if translation_visible?(value[:translation][index])
37
+ %tr
38
+ = raw(translation(@active_locale, "#{key}[#{index}]", key, value[:translation][index], c_value))
39
+ - else
40
+ = raw(translation(@active_locale, key, key, value[:translation], value[:original_translation]))