afalkear_translation_center 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +293 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/images/translation_center/badr_it.png +0 -0
  6. data/app/assets/images/translation_center/loading.gif +0 -0
  7. data/app/assets/images/translation_center/translation_center_logo.png +0 -0
  8. data/app/assets/javascripts/translation_center/application.js +75 -0
  9. data/app/assets/javascripts/translation_center/bootstrap.js +2025 -0
  10. data/app/assets/javascripts/translation_center/categories.js +18 -0
  11. data/app/assets/javascripts/translation_center/center.js +55 -0
  12. data/app/assets/javascripts/translation_center/inspector.js.erb +59 -0
  13. data/app/assets/javascripts/translation_center/jquery-ui.js +14912 -0
  14. data/app/assets/javascripts/translation_center/jquery.jeditable.mini.js +38 -0
  15. data/app/assets/javascripts/translation_center/routes.js +15 -0
  16. data/app/assets/javascripts/translation_center/spin.min.js +1 -0
  17. data/app/assets/javascripts/translation_center/translation_keys.js +31 -0
  18. data/app/assets/javascripts/translation_center/translations.js +245 -0
  19. data/app/assets/stylesheets/translation_center/application.css +49 -0
  20. data/app/assets/stylesheets/translation_center/bootstrap.css +5894 -0
  21. data/app/assets/stylesheets/translation_center/categories.css +29 -0
  22. data/app/assets/stylesheets/translation_center/center.css +28 -0
  23. data/app/assets/stylesheets/translation_center/inspector.css +110 -0
  24. data/app/assets/stylesheets/translation_center/translation_keys.css +48 -0
  25. data/app/assets/stylesheets/translation_center/translations.css +32 -0
  26. data/app/controllers/translation_center/application_controller.rb +42 -0
  27. data/app/controllers/translation_center/categories_controller.rb +61 -0
  28. data/app/controllers/translation_center/center_controller.rb +67 -0
  29. data/app/controllers/translation_center/translation_keys_controller.rb +93 -0
  30. data/app/controllers/translation_center/translations_controller.rb +78 -0
  31. data/app/helpers/translation_center/application_helper.rb +58 -0
  32. data/app/helpers/translation_center/categories_helper.rb +4 -0
  33. data/app/helpers/translation_center/center_helper.rb +19 -0
  34. data/app/helpers/translation_center/translation_keys_helper.rb +4 -0
  35. data/app/helpers/translation_center/translations_helper.rb +4 -0
  36. data/app/models/translation_center/activity_query.rb +46 -0
  37. data/app/models/translation_center/category.rb +46 -0
  38. data/app/models/translation_center/translation.rb +94 -0
  39. data/app/models/translation_center/translation_key.rb +188 -0
  40. data/app/views/layouts/translation_center/application.html.haml +82 -0
  41. data/app/views/translation_center/categories/_category.html.haml +11 -0
  42. data/app/views/translation_center/categories/index.html.haml +7 -0
  43. data/app/views/translation_center/categories/keys.js.haml +10 -0
  44. data/app/views/translation_center/categories/show.html.haml +32 -0
  45. data/app/views/translation_center/categories/show.js.haml +7 -0
  46. data/app/views/translation_center/center/_activity.html.haml +49 -0
  47. data/app/views/translation_center/center/dashboard.html.haml +102 -0
  48. data/app/views/translation_center/center/manage.js.haml +3 -0
  49. data/app/views/translation_center/center/search_activity.js.haml +1 -0
  50. data/app/views/translation_center/errors/exception.html.haml +50 -0
  51. data/app/views/translation_center/translation_keys/_form.html.haml +18 -0
  52. data/app/views/translation_center/translation_keys/_show.html.haml +27 -0
  53. data/app/views/translation_center/translation_keys/_show_keys.html.haml +25 -0
  54. data/app/views/translation_center/translation_keys/_translation_keys.html.haml +16 -0
  55. data/app/views/translation_center/translation_keys/destroy.js.haml +4 -0
  56. data/app/views/translation_center/translation_keys/show.html.haml +8 -0
  57. data/app/views/translation_center/translation_keys/translations.js.haml +3 -0
  58. data/app/views/translation_center/translations/_accept_translation.html.haml +6 -0
  59. data/app/views/translation_center/translations/_index.html.haml +9 -0
  60. data/app/views/translation_center/translations/_search_results.html.haml +30 -0
  61. data/app/views/translation_center/translations/_show.html.haml +35 -0
  62. data/app/views/translation_center/translations/accept.js.haml +18 -0
  63. data/app/views/translation_center/translations/destroy.js.haml +11 -0
  64. data/app/views/translation_center/translations/search.html.haml +2 -0
  65. data/app/views/translation_center/translations/search.js.haml +1 -0
  66. data/app/views/translation_center/translations/unaccept.js.haml +9 -0
  67. data/app/views/translation_center/translations/unvote.js.haml +1 -0
  68. data/app/views/translation_center/translations/vote.js.haml +1 -0
  69. data/config/routes.rb +34 -0
  70. data/lib/afalkear_translation_center.rb +12 -0
  71. data/lib/generators/translation_center/USAGE +6 -0
  72. data/lib/generators/translation_center/add_lang/add_lang_generator.rb +31 -0
  73. data/lib/generators/translation_center/add_lang/templates/migrations/add_lang_status_translation_keys.rb +5 -0
  74. data/lib/generators/translation_center/install/install_generator.rb +38 -0
  75. data/lib/generators/translation_center/install/templates/assets/translation_center_logo.png +0 -0
  76. data/lib/generators/translation_center/install/templates/config/translation_center.yml +55 -0
  77. data/lib/generators/translation_center/install/templates/migrations/create_translation_center_categories.rb +9 -0
  78. data/lib/generators/translation_center/install/templates/migrations/create_translation_center_translation_keys.rb +16 -0
  79. data/lib/generators/translation_center/install/templates/migrations/create_translation_center_translations.rb +32 -0
  80. data/lib/tasks/translation_center.rake +56 -0
  81. data/lib/translation_center/acts_as_translator.rb +22 -0
  82. data/lib/translation_center/engine.rb +15 -0
  83. data/lib/translation_center/locale/en.yml +75 -0
  84. data/lib/translation_center/translation_helpers.rb +133 -0
  85. data/lib/translation_center/translations_transfer.rb +131 -0
  86. data/lib/translation_center/version.rb +3 -0
  87. data/test/dummy/README.rdoc +261 -0
  88. data/test/dummy/Rakefile +7 -0
  89. data/test/dummy/app/assets/images/translation_center_logo.png +0 -0
  90. data/test/dummy/app/assets/javascripts/application.js +16 -0
  91. data/test/dummy/app/assets/javascripts/articles.js +2 -0
  92. data/test/dummy/app/assets/stylesheets/application.css +14 -0
  93. data/test/dummy/app/assets/stylesheets/articles.css +4 -0
  94. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  95. data/test/dummy/app/controllers/application_controller.rb +6 -0
  96. data/test/dummy/app/controllers/articles_controller.rb +85 -0
  97. data/test/dummy/app/helpers/application_helper.rb +2 -0
  98. data/test/dummy/app/helpers/articles_helper.rb +2 -0
  99. data/test/dummy/app/models/article.rb +7 -0
  100. data/test/dummy/app/models/user.rb +16 -0
  101. data/test/dummy/app/views/articles/_form.html.haml +16 -0
  102. data/test/dummy/app/views/articles/edit.html.haml +7 -0
  103. data/test/dummy/app/views/articles/index.html.haml +32 -0
  104. data/test/dummy/app/views/articles/new.html.haml +5 -0
  105. data/test/dummy/app/views/articles/show.html.haml +14 -0
  106. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  107. data/test/dummy/config/application.rb +60 -0
  108. data/test/dummy/config/boot.rb +10 -0
  109. data/test/dummy/config/database.yml +42 -0
  110. data/test/dummy/config/environment.rb +5 -0
  111. data/test/dummy/config/environments/development.rb +37 -0
  112. data/test/dummy/config/environments/production.rb +67 -0
  113. data/test/dummy/config/environments/test.rb +37 -0
  114. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  115. data/test/dummy/config/initializers/devise.rb +240 -0
  116. data/test/dummy/config/initializers/inflections.rb +15 -0
  117. data/test/dummy/config/initializers/mime_types.rb +5 -0
  118. data/test/dummy/config/initializers/secret_token.rb +7 -0
  119. data/test/dummy/config/initializers/session_store.rb +8 -0
  120. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  121. data/test/dummy/config/locales/ar.yml +6 -0
  122. data/test/dummy/config/locales/de.yml +2 -0
  123. data/test/dummy/config/locales/devise.en.yml +59 -0
  124. data/test/dummy/config/locales/en.yml +361 -0
  125. data/test/dummy/config/routes.rb +10 -0
  126. data/test/dummy/config/translation_center.yml +58 -0
  127. data/test/dummy/config.ru +4 -0
  128. data/test/dummy/db/migrate/20130410082611_devise_create_users.rb +46 -0
  129. data/test/dummy/db/migrate/20130410082701_create_articles.rb +10 -0
  130. data/test/dummy/db/migrate/20130410084711234392_create_translation_center_categories.rb +9 -0
  131. data/test/dummy/db/migrate/20130410084711235054_create_translation_center_translation_keys.rb +14 -0
  132. data/test/dummy/db/migrate/20130410084711235601_create_translation_center_translations.rb +13 -0
  133. data/test/dummy/db/migrate/20130410084711235602_install_audited.rb +28 -0
  134. data/test/dummy/db/migrate/20130410084711_acts_as_votable_migration.rb +23 -0
  135. data/test/dummy/db/migrate/20130410113111070575_add_de_status_translation_center_translation_keys.rb +5 -0
  136. data/test/dummy/db/migrate/20130417134539377014_add_ar_status_translation_center_translation_keys.rb +5 -0
  137. data/test/dummy/db/migrate/20130506103956_fix_translation_user_relation.rb +12 -0
  138. data/test/dummy/db/migrate/20130801102022_add_indicies.rb +8 -0
  139. data/test/dummy/db/schema.rb +110 -0
  140. data/test/dummy/log/test.log +0 -0
  141. data/test/dummy/public/404.html +26 -0
  142. data/test/dummy/public/422.html +26 -0
  143. data/test/dummy/public/500.html +25 -0
  144. data/test/dummy/public/favicon.ico +0 -0
  145. data/test/dummy/script/rails +6 -0
  146. data/test/dummy/spec/spec_helper.rb +38 -0
  147. data/test/dummy/test/fixtures/articles.yml +9 -0
  148. data/test/dummy/test/fixtures/posts.yml +9 -0
  149. data/test/dummy/test/fixtures/users.yml +11 -0
  150. data/test/dummy/test/functional/articles_controller_test.rb +49 -0
  151. data/test/dummy/test/functional/posts_controller_test.rb +49 -0
  152. data/test/dummy/test/unit/article_test.rb +7 -0
  153. data/test/dummy/test/unit/helpers/articles_helper_test.rb +4 -0
  154. data/test/dummy/test/unit/helpers/posts_helper_test.rb +4 -0
  155. data/test/dummy/test/unit/post_test.rb +7 -0
  156. data/test/dummy/test/unit/user_test.rb +7 -0
  157. data/test/fixtures/translation_center/categories.yml +7 -0
  158. data/test/fixtures/translation_center/translation_keys.yml +11 -0
  159. data/test/fixtures/translation_center/translations.yml +15 -0
  160. data/test/functional/translation_center/categories_controller_test.rb +51 -0
  161. data/test/functional/translation_center/center_controller_test.rb +9 -0
  162. data/test/functional/translation_center/translation_keys_controller_test.rb +51 -0
  163. data/test/functional/translation_center/translations_controller_test.rb +51 -0
  164. data/test/integration/navigation_test.rb +10 -0
  165. data/test/test_helper.rb +15 -0
  166. data/test/translation_center_test.rb +7 -0
  167. data/test/unit/helpers/translation_center/categories_helper_test.rb +6 -0
  168. data/test/unit/helpers/translation_center/center_helper_test.rb +6 -0
  169. data/test/unit/helpers/translation_center/translation_keys_helper_test.rb +6 -0
  170. data/test/unit/helpers/translation_center/translations_helper_test.rb +6 -0
  171. data/test/unit/translation_center/category_test.rb +9 -0
  172. data/test/unit/translation_center/translation_key_test.rb +9 -0
  173. data/test/unit/translation_center/translation_test.rb +9 -0
  174. metadata +418 -0
@@ -0,0 +1,46 @@
1
+ module TranslationCenter
2
+ class ActivityQuery
3
+ extend ActiveModel::Naming
4
+ include ActiveModel::Conversion
5
+
6
+ attr_accessor :translation_key_name, :translator_identifier, :lang, :created_at_gteq, :created_at_lteq
7
+
8
+ def persisted?
9
+ false
10
+ end
11
+
12
+ def initialize args={}
13
+ args ||= {}
14
+ args.each do |k,v|
15
+ instance_variable_set("@#{k}", v) unless v.blank?
16
+ end
17
+ end
18
+
19
+ # retuns and ActiveRecord Relation of Audit(s) that matches this search criteria
20
+ def activities
21
+ query = Audited::Adapters::ActiveRecord::Audit.where(auditable_id: translation_ids).scoped
22
+ query = query.where("DATE(created_at) <= DATE(?)", created_at_lteq) unless created_at_lteq.blank?
23
+ query = query.where("DATE(created_at) >= DATE(?)", created_at_gteq) unless created_at_gteq.blank?
24
+ query.order('created_at DESC')
25
+ end
26
+
27
+ protected
28
+
29
+ # return translation ids that matches this search criteria
30
+ def translation_ids
31
+ query = Translation.scoped
32
+ query = query.where(lang: lang) unless lang.blank?
33
+ query = query.joins(:translation_key).where("translation_center_translation_keys.name LIKE ?", "%#{translation_key_name}%") unless translation_key_name.blank?
34
+
35
+ if translator_identifier
36
+ translator_class = TranslationCenter::CONFIG['translator_type'].camelize.constantize
37
+ translators_ids = translator_class.where("#{TranslationCenter::CONFIG['identifier_type']} LIKE ? ", "%#{translator_identifier}%").map(&:id)
38
+
39
+ query = query.where(translator_id: translators_ids)
40
+ end
41
+
42
+ query.map(&:id)
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ module TranslationCenter
2
+ class Category < ActiveRecord::Base
3
+ has_many :translation_keys, dependent: :destroy
4
+
5
+ alias_method :keys, :translation_keys
6
+
7
+ # validations
8
+ validates :name, presence: true, uniqueness: true
9
+
10
+ # gets how much complete translation of category is in a certain language
11
+ def complete_percentage_in(lang)
12
+ if self.keys.empty?
13
+ 100
14
+ else
15
+ accepted_keys = accepted_keys(lang)
16
+ 100 * accepted_keys.count / self.keys.count
17
+ end
18
+ end
19
+
20
+ # gets the keys accepted in a certain language that belong to a category
21
+ def accepted_keys(lang)
22
+ self.keys.translated(lang)
23
+ end
24
+ alias_method :translated_keys, :accepted_keys
25
+
26
+ # gets the keys that have no translations in the language
27
+ def untranslated_keys(lang)
28
+ self.keys.untranslated(lang)
29
+ end
30
+
31
+ # gets the keys that have no translations in the language
32
+ def pending_keys(lang)
33
+ self.keys.pending(lang)
34
+ end
35
+
36
+ def all_keys(lang)
37
+ self.keys
38
+ end
39
+
40
+ # returns a name that is better for presentation
41
+ def view_name
42
+ self.name.titleize
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,94 @@
1
+ module TranslationCenter
2
+ class Translation < ActiveRecord::Base
3
+
4
+ # attr_accessible :value, :lang, :translation_key_id, :user_id, :status
5
+ # serialize as we could store arrays
6
+ serialize :value
7
+
8
+ CHANGES_PER_PAGE = 5
9
+ NUMBER_PER_PAGE = 15
10
+
11
+ belongs_to :translation_key
12
+ belongs_to :translator, polymorphic: true
13
+
14
+ alias_method :key, :translation_key
15
+ acts_as_votable
16
+ audited
17
+
18
+ # validations
19
+ validates :translation_key_id, :lang, :status, :value, presence: true
20
+ validate :one_translation_per_lang_per_key, on: :create
21
+
22
+ # returns accepted transations
23
+ #scope :accepted, where(status: 'accepted')
24
+
25
+ # returns translations in a certain language
26
+ scope :in, lambda { |lang| where(lang: lang.to_s.strip) }
27
+
28
+ # sorts translations by number of votes
29
+ # scope :sorted_by_votes, where('votable_type IS NULL OR votable_type = ?', 'TranslationCenter::Translation').select('translation_center_translations.*, count(votes.id) as votes_count').joins('LEFT OUTER JOIN votes on votes.votable_id = translation_center_translations.id').group('translation_center_translations.id').order('votes_count desc')
30
+
31
+ after_save :update_key_status
32
+ after_destroy :notify_key
33
+
34
+ def self.accepted(translation_key_id)
35
+ where(status: 'accepted', translation_key_id: translation_key_id)
36
+ end
37
+
38
+ # called after save to update the key status
39
+ def update_key_status
40
+ self.key.update_status self.lang
41
+ end
42
+
43
+ # called before destory to update the key status
44
+ def notify_key
45
+ self.key.update_status self.lang
46
+ self.audits.destroy_all
47
+ end
48
+
49
+ # returns true if the status of the translation is accepted
50
+ def accepted?
51
+ self.status == 'accepted'
52
+ end
53
+
54
+ # returns true if the status of the translation is pending
55
+ def pending?
56
+ self.status == 'pending'
57
+ end
58
+
59
+ # accept translation by changing its status and if there is an accepting translation
60
+ # make it pending
61
+ def accept
62
+ # if translation is accepted do nothing
63
+ unless self.accepted?
64
+ self.translation_key.accepted_translation_in(self.lang).try(:update_attribute, :status, 'pending')
65
+ # reload the translation key as it has changed
66
+ self.translation_key.reload
67
+ self.update_attribute(:status, 'accepted')
68
+ end
69
+
70
+ end
71
+
72
+ # unaccept a translation
73
+ def unaccept
74
+ self.update_attribute(:status, 'pending')
75
+ end
76
+
77
+ # gets recent changes on translations
78
+ # TODO: remove this method as it is not being used elsewhere
79
+ def self.recent_changes
80
+ Audited::Adapters::ActiveRecord::Audit.where('auditable_type = ?', 'TranslationCenter::Translation').search(params).relation.reorder('created_at DESC')
81
+ end
82
+
83
+ # make sure user has one translation per key per lang
84
+ def one_translation_per_lang_per_key
85
+ if Translation.where(lang: self.lang, translator_id: self.translator.id, translator_type: self.translator.class.name, translation_key_id: self.key.id).empty?
86
+ true
87
+ else
88
+ false
89
+ self.errors.add(:lang, I18n.t('.one_translation_per_lang_per_key'))
90
+ end
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,188 @@
1
+ module TranslationCenter
2
+
3
+ class TranslationKey < ActiveRecord::Base
4
+ # attr_accessible :name, :last_accessed, :category_id
5
+ belongs_to :category
6
+ has_many :translations, dependent: :destroy
7
+
8
+ # validations
9
+ validates :name, uniqueness: true
10
+ validates :name, presence: true
11
+
12
+ # called after key is created or updated
13
+ before_save :add_category
14
+
15
+ PER_PAGE = 7
16
+
17
+ scope :translated, lambda { |lang| where("#{lang.to_s}_status" => 'translated') }
18
+ scope :pending, lambda { |lang| where("#{lang.to_s}_status" => 'pending') }
19
+ scope :untranslated, lambda { |lang| where("#{lang.to_s}_status" => 'untranslated') }
20
+
21
+
22
+ # add a category of this translation key
23
+ def add_category
24
+ category_name = self.name.to_s.split('.').first
25
+ # if one word then add to general category
26
+ category_name = self.name.to_s.split('.').size == 1 ? 'general' : self.name.to_s.split('.').first
27
+ self.category = TranslationCenter::Category.find_or_create_by(name: category_name)
28
+ self.last_accessed = Time.now
29
+ end
30
+
31
+ # updates the status of the translation key depending on the translations
32
+ def update_status(lang)
33
+ if self.translations.in(lang).blank?
34
+ self.update_attribute("#{lang}_status", 'untranslated')
35
+ elsif !self.translations.in(lang).accepted(self.id).blank?
36
+ self.update_attribute("#{lang}_status", 'translated')
37
+ else
38
+ self.update_attribute("#{lang}_status", 'pending')
39
+ end
40
+ end
41
+
42
+ # returns true if the key is translated (has accepted translation) in this lang
43
+ def accepted_in?(lang)
44
+ self.send("#{lang}_status") == 'translated'
45
+ end
46
+ alias_method :translated_in?, :accepted_in?
47
+
48
+ # returns the accepted translation in certain language
49
+ def accepted_translation_in(lang)
50
+ self.translations.accepted(self.id).in(lang).first
51
+ end
52
+
53
+ # returns true if the translation key is untranslated (has no translations) in the language
54
+ def no_translations_in?(lang)
55
+ self.send("#{lang}_status") == 'untranslated'
56
+ end
57
+ alias_method :untranslated_in?, :no_translations_in?
58
+
59
+ # returns true if the key has translations in the language
60
+ def has_translations_in?(lang)
61
+ !no_translations_in?(lang)
62
+ end
63
+
64
+ # returns true if the key is pending (has translations but none is accepted)
65
+ def pending_in?(lang)
66
+ self.send("#{lang}_status") == 'pending'
67
+ end
68
+
69
+ # returns the status of the key in a language
70
+ def status(lang)
71
+ if accepted_in?(lang)
72
+ 'translated'
73
+ elsif pending_in?(lang)
74
+ 'pending'
75
+ else
76
+ 'untranslated'
77
+ end
78
+ end
79
+
80
+ # create default translation
81
+ def create_default_translation
82
+ translation = self.translations.build(value: self.name.to_s.split('.').last.titleize,
83
+ lang: :en, status: 'accepted')
84
+ translation.translator = TranslationCenter.prepare_translator
85
+
86
+ translation.save
87
+ end
88
+
89
+ def self.keys_count
90
+ TranslationKey.all.count
91
+ end
92
+
93
+ # returns the count of translated keys in lang
94
+ def self.translated_count(lang)
95
+ TranslationKey.translated(lang).count
96
+ end
97
+
98
+ # returns the count of pending keys in lang
99
+ def self.pending_count(lang)
100
+ TranslationKey.pending(lang).count
101
+ end
102
+
103
+ # returns the count of untranslated keys in lang
104
+ def self.untranslated_count(lang)
105
+ TranslationKey.untranslated(lang).count
106
+ end
107
+
108
+ # returns the percentage of translated keys in lang
109
+ def self.translated_percentage(lang)
110
+ (100.0 * TranslationKey.translated(lang).count / keys_count).round(2)
111
+ end
112
+
113
+ # returns the percentage of pending keys in lang
114
+ def self.pending_percentage(lang)
115
+ (100.0 * TranslationKey.pending(lang).count / keys_count).round(2)
116
+ end
117
+
118
+ # returns the percentage of untranslated keys in lang
119
+ def self.untranslated_percentage(lang)
120
+ (100.0 * TranslationKey.untranslated(lang).count / keys_count).round(2)
121
+ end
122
+
123
+ # builds hash of stats about the langs supported by translation center
124
+ def self.langs_stats
125
+ stats = {}
126
+ all_count = keys_count
127
+ I18n.available_locales.each do |locale|
128
+ stats[locale] = {}
129
+ stats[locale]['name'] = TranslationCenter::CONFIG['lang'][locale.to_s]['name']
130
+
131
+ translated = translated_count(locale)
132
+ pending = pending_count(locale)
133
+ untranslated = untranslated_count(locale)
134
+
135
+ stats[locale]['translated_percentage'] = (100.0 * translated / all_count).round(2)
136
+ stats[locale]['pending_percentage'] = (100.0 * pending / all_count).round(2)
137
+ stats[locale]['untranslated_percentage'] = (100.0 * untranslated / all_count).round(2)
138
+
139
+ stats[locale]['translated_count'] = translated
140
+ stats[locale]['pending_count'] = pending
141
+ stats[locale]['untranslated_count'] = untranslated
142
+ end
143
+ stats
144
+ end
145
+
146
+ def children_translations(locale)
147
+ TranslationKey.where('name LIKE ?', "#{self.name}.%").inject({}) do |translations, child|
148
+ translations[child.name.split('.').last.to_sym] = child.accepted_translation_in(locale).try(:value)
149
+ translations
150
+ end
151
+ end
152
+
153
+ def has_children?
154
+ TranslationKey.where('name LIKE ?', "#{self.name}.%").count >= 1
155
+ end
156
+
157
+ # adds a translation key with its translation to a translation yaml hash
158
+ # send the hash and the language as parameters
159
+ def add_to_hash(all_translations, lang)
160
+ levels = self.name.split('.')
161
+ add_to_hash_rec(all_translations, levels, lang.to_s)
162
+ end
163
+
164
+ private
165
+ def add_to_hash_rec(all_translations, levels, lang)
166
+ current_level = levels.first
167
+ # if we are at the bottom level just return the translation
168
+ if(levels.count == 1)
169
+ translation = self.accepted_translation_in(lang)
170
+ formatted = translation.value
171
+ # in case of arrays remove the unneeded header
172
+ formatted.to_yaml.gsub!("---\n" , '') if formatted.is_a?(Array)
173
+ {current_level => formatted}
174
+ else
175
+ levels.shift
176
+ # if the translation key doesn't exist at current level then create it
177
+ unless(all_translations.has_key?(current_level))
178
+ all_translations[current_level] = {}
179
+ end
180
+ # merge the current level with the rest of the translation key
181
+ all_translations[current_level].merge!( add_to_hash_rec(all_translations[current_level],levels, lang) )
182
+ all_translations
183
+ end
184
+ end
185
+
186
+ end
187
+
188
+ end
@@ -0,0 +1,82 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title TranslationCenter
5
+
6
+ = stylesheet_link_tag "translation_center/application", :media => "all"
7
+ = javascript_include_tag "translation_center/application"
8
+ = csrf_meta_tags
9
+ %body
10
+
11
+
12
+ .navbar.navbar-fixed-top
13
+ .navbar-inner
14
+ .container
15
+ %a.btn.btn-navbar{"data-target" => ".navbar-responsive-collapse", "data-toggle" => "collapse"}
16
+ %span.icon-bar
17
+ %span.icon-bar
18
+ %span.icon-bar
19
+ %a.brand{:href => root_url}
20
+ = favicon_link_tag
21
+ = Rails.application.class.parent_name
22
+ %em.center_title
23
+ = t('translation_center.translation_center')
24
+ .nav-collapse.collapse.navbar-responsive-collapse
25
+ %ul.nav
26
+ %li.divider-vertical
27
+ / .pull-left.nav_text
28
+ / = t('.from')
29
+ / %li.dropdown.pull-left
30
+
31
+ / %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'}
32
+ / = language_name(from_lang)
33
+ / %b.caret
34
+ / %ul.dropdown-menu
35
+ / - I18n.available_locales.each do |locale|
36
+ / %li
37
+ / %a.language_from{ href: '#', lang_sym: locale}
38
+ / = language_name(locale)
39
+
40
+ .pull-left.nav_text
41
+ %span
42
+ = t('translation_center.translate_to')
43
+ %li.dropdown.pull-left
44
+ %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'}
45
+ = language_name(to_lang)
46
+ %b.caret
47
+ %ul.dropdown-menu
48
+ - I18n.available_locales.each do |locale|
49
+ %li
50
+ %a.language_to{ href: change_locale_url(locale), lang_sym: locale}
51
+ = language_name(locale)
52
+ - if translation_admin?
53
+ .pull-left.nav_text
54
+ %span
55
+ = link_to t('translation_center.dashboard'), dashboard_path
56
+ %li.divider-vertical
57
+ %form.navbar-search
58
+ %input#search_keys.search-query{placeholder: t('translation_center.search_keys'), type: "text", autocomplete: :off}
59
+ %form.navbar-search{action: search_translations_path}
60
+ %input#translations.search-query{placeholder: t('translation_center.search_translations'), type: "text", autocomplete: :off, name: :translation_value, value: params[:translation_value]}
61
+
62
+ %ul.nav.pull-right
63
+ %li
64
+ = link_to t('translation_center.back_to_app'), main_app.root_path, target: Rails.application.class.parent_name
65
+ - if flash[:alert]
66
+ .alert.alert-error
67
+ %button{ type: 'button', class: 'close', 'data-dismiss' => 'alert' }
68
+ ×
69
+ = flash[:alert]
70
+
71
+ - if flash[:notice]
72
+ .alert.alert-success
73
+ %button{ type: 'button', class: 'close', 'data-dismiss' => 'alert' }
74
+ ×
75
+ = flash[:notice]
76
+
77
+ .container
78
+ .row
79
+ .span12
80
+ %input#tc_no_inspector{ value: 'true' ,type: :hidden }
81
+ = yield
82
+
@@ -0,0 +1,11 @@
1
+ %a.category{ href: category_path(category) }
2
+ .category_name
3
+ = category.view_name
4
+ %div
5
+ %span.label.label-info
6
+ = category.translation_keys.count
7
+ = t('.keys')
8
+ - completion = category.complete_percentage_in(to_lang)
9
+ %span{ class: completion == 100 ? 'label label-success' : 'label label-important'}
10
+ = "#{completion} %"
11
+ = t('.complete')
@@ -0,0 +1,7 @@
1
+ %h1
2
+ = t('.categories')
3
+
4
+ - @categories.each do |category|
5
+ = render 'category', category: category
6
+
7
+ %br/
@@ -0,0 +1,10 @@
1
+ - @keys.each_with_index do |key, index|
2
+ $('.translation_keys_listing').append("#{escape_javascript(render 'translation_center/translation_keys/show_keys', translation_key: key, index: -1)}")
3
+
4
+
5
+ - @keys.each_with_index do |key, index|
6
+ $('.translations_listing').append("#{escape_javascript(render 'translation_center/translation_keys/show', translation_key: key, index: -1)}")
7
+
8
+ editableTranslations();
9
+ editableKeyTranslations();
10
+
@@ -0,0 +1,32 @@
1
+ %input#category_key{ type: 'hidden', value: @category.id }
2
+ %input#current_filter{ type: 'hidden', value: current_filter }
3
+ %h1
4
+ = @category.name.camelize
5
+ %ul.nav.nav-pills
6
+
7
+ %li{class: "#{current_filter_is?('untranslated') ? 'active' : ''}"}
8
+ %a#untranslated.keys_filter{:href => "#"}
9
+ = t('.untranslated')
10
+ %span#untranslated_keys_count
11
+ = "(#{@untranslated_keys_count})"
12
+ %li{class: "#{current_filter_is?('pending') ? 'active' : ''}"}
13
+ %a#pending.keys_filter{:href => "#"}
14
+ = t('.pending')
15
+ %span#pending_keys_count
16
+ = "(#{@pending_keys_count})"
17
+ %li{class: "#{current_filter_is?('translated') ? 'active' : ''}"}
18
+ %a#translated.keys_filter{:href => "#"}
19
+ = t('.translated')
20
+ %span#translated_keys_count
21
+ = "(#{@translated_keys_count})"
22
+ %li{class: "#{current_filter_is?('all') ? 'active' : ''}"}
23
+ %a#all.keys_filter{:href => "#"}
24
+ = t('.all')
25
+ %span#all_keys_count
26
+ = "(#{@all_keys_count})"
27
+ %li
28
+ #loading
29
+ = image_tag 'translation_center/loading.gif'
30
+ .span9#category
31
+ = render 'translation_center/translation_keys/translation_keys', translation_keys: @keys, category: @category
32
+
@@ -0,0 +1,7 @@
1
+ $('#category').html("#{escape_javascript(render 'translation_center/translation_keys/translation_keys', translation_keys: @keys, category: @category)}")
2
+ $('#translated_keys_count').text("(#{@translated_keys_count})");
3
+ $('#pending_keys_count').text("(#{@pending_keys_count})");
4
+ $('#untranslated_keys_count').text("(#{@untranslated_keys_count})");
5
+ current_page = 1;
6
+ editableTranslations();
7
+ editableKeyTranslations();
@@ -0,0 +1,49 @@
1
+ - if translations_changes.empty?
2
+ .alert.alert-info
3
+ = t('.no_matches')
4
+ - else
5
+ %table.table.table-striped.table-bordered
6
+ %thead
7
+ %tr
8
+ %th
9
+ = t('.key')
10
+ %th
11
+ = t('.locale')
12
+ %th
13
+ = t('.user')
14
+ %th
15
+ = t('.changes')
16
+ %th
17
+ = t('.time')
18
+
19
+ %tbody
20
+ - translations_changes.each do |change|
21
+ %tr
22
+ %td
23
+ = link_to change.auditable.key.name, change.auditable.key, target: '_blank'
24
+ %td
25
+ = change.auditable.lang
26
+ %td
27
+ = change.auditable.translator.try TranslationCenter::CONFIG['identifier_type']
28
+ %td
29
+ %ul
30
+ - change.audited_changes.each do |change, value|
31
+ %li
32
+ = format_change(change, value)
33
+ %td
34
+ = distance_of_time_in_words_to_now change.created_at
35
+ = t('.ago')
36
+ .pagination
37
+ - query_without_page_param = request.query_string.gsub(/&?page=\d*/, '')
38
+ = link_to t('pagination.first'), "#{request.protocol}#{request.host_with_port}#{request.path}?#{query_without_page_param}&page=1"
39
+ - if @page != 1
40
+ |
41
+ = link_to t('pagination.prev'), "#{request.protocol}#{request.host_with_port}#{request.path}?#{query_without_page_param}&page=#{@page - 1}"
42
+ |
43
+ = link_to t('pagination.next'), "#{request.protocol}#{request.host_with_port}#{request.path}?#{query_without_page_param}&page=#{@page + 1}"
44
+ - if @page != @total_pages
45
+ |
46
+ = link_to t('pagination.last'), "#{request.protocol}#{request.host_with_port}#{request.path}?#{query_without_page_param}&page=#{@total_pages}"
47
+ = @page
48
+ = t('.of')
49
+ = @total_pages
@@ -0,0 +1,102 @@
1
+ %h1
2
+ = t('.controls')
3
+
4
+ .well
5
+ .alert#operation_progress
6
+ %button.close{"data-dismiss" => "alert", :type => "button"} ×
7
+ %strong
8
+ = t('.these_actions_will_affect_existing_data')
9
+ = form_tag manage_translations_path, remote: true, id: 'manage_form', class: 'form-search' do
10
+ = select_tag 'locale', options_for_select(I18n.available_locales.collect{ |locale| [language_name(locale), locale.to_s] }.insert(0, [t('.all'), 'all'])), {:prompt => t('.select_locale')}
11
+ = hidden_field_tag :manage_action
12
+ = link_to 'yaml2db', '#', class: 'manage-button btn btn-primary', 'data-action' => 'yaml2db'
13
+ = link_to 'db2yaml', '#', class: 'manage-button btn btn-primary', 'data-action' => 'db2yaml'
14
+ #spinner
15
+
16
+ %h1
17
+ = t('.dashboard')
18
+
19
+ .span12
20
+ %table.table.table-striped.table-bordered
21
+ %thead
22
+ %tr
23
+ %th
24
+ = t('.language')
25
+ %th
26
+ = t('.progress')
27
+ %th
28
+ = t('.translated')
29
+ %th
30
+ = t('.pending')
31
+ %th
32
+ = t('.untranslated')
33
+
34
+
35
+ %tbody
36
+ - @langs.each do |lang|
37
+ %tr
38
+ %td
39
+ = link_to @stats[lang]['name'], set_lang_to_path(lang: lang.to_s)
40
+ %td
41
+ .progress
42
+ .bar.bar-success{ style: "width: #{@stats[lang]['translated_percentage']}%;" }
43
+ .bar.bar-warning{ style: "width: #{@stats[lang]['pending_percentage']}%;" }
44
+ .bar.bar-danger{ style: "width: #{@stats[lang]['untranslated_percentage']}%;" }
45
+ %td
46
+ = "#{@stats[lang]['translated_count']}(#{@stats[lang]['translated_percentage']}%)"
47
+ %td
48
+ = "#{@stats[lang]['pending_count']}(#{@stats[lang]['pending_percentage']}%)"
49
+ %td
50
+ = "#{@stats[lang]['untranslated_count']}(#{@stats[lang]['untranslated_percentage']}%)"
51
+ %h1
52
+ = t('.activity')
53
+ .span12
54
+
55
+ = form_for @activity_query, url: :search_activity, html: { method: :get, id: :search_form, class: 'pull-left form-search' } do |f|
56
+ = f.text_field :translation_key_name, class: 'search_field input-medium', placeholder: 'KEY'
57
+
58
+ = f.select :lang, I18n.available_locales.collect { |locale| [locale.to_s, locale.to_s] }, {:include_blank => t('.select_locale')}, class: 'search_field'
59
+
60
+ = f.text_field :translator_identifier, class: 'search_field input-medium', placeholder: translator_identifier_placeholder
61
+
62
+ = f.text_field :created_at_gteq, class: 'search_field datepicker input-medium', placeholder: 'FROM DATE'
63
+
64
+ = f.text_field :created_at_lteq, class: 'search_field datepicker input-medium', placeholder: 'TO DATE'
65
+
66
+ %button.btn#search_activity{ type: :button }
67
+ = t('.search')
68
+ %button.btn#search_reset{ type: :button }
69
+ = t('.reset')
70
+
71
+ #activity
72
+ = render 'activity', translations_changes: @translations_changes
73
+
74
+
75
+ :javascript
76
+ $('.manage-button').click(function(){
77
+ if(confirm('Are you sure you want to perform this operation ?'))
78
+ {
79
+ $('#spinner').show();
80
+ var target = document.getElementById('spinner');
81
+ var spinner = new Spinner(spinner_params).spin(target);
82
+ $('#manage_action').val($(this).data('action'))
83
+ $('#operation_progress').removeClass('alert-success')
84
+ var msg = $(this).data('action') == 'yaml2db' ? 'Transfering yaml translations to db' : 'Transfering db translations to yaml files'
85
+ $('#operation_progress strong').text(msg)
86
+ $('#manage_form').submit()
87
+ }
88
+ return false;
89
+ })
90
+
91
+ // hit search directly when pressing enter
92
+ $(".search_field").keyup(function(event){
93
+ if(event.keyCode == 13){
94
+ $('#search_activity').click();
95
+ }
96
+ });
97
+
98
+
99
+
100
+
101
+
102
+