releaf-i18n_database 0.2.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +19 -21
- data/app/assets/javascripts/{releaf/controllers → controllers}/releaf/i18n_database/translations.js +0 -0
- data/app/assets/stylesheets/{releaf/controllers → controllers}/releaf/i18n_database/translations.scss +0 -0
- data/app/builders/releaf/i18n_database/translations/builders_common.rb +1 -1
- data/app/builders/releaf/i18n_database/translations/index_builder.rb +1 -1
- data/app/controllers/releaf/i18n_database/translations_controller.rb +121 -127
- data/app/lib/releaf/i18n_database/parse_spreadsheet_translations.rb +62 -0
- data/app/lib/releaf/i18n_database/translations_store.rb +149 -0
- data/app/lib/releaf/i18n_database/translations_utilities.rb +6 -6
- data/app/models/releaf/i18n_database/i18n_entry.rb +21 -0
- data/app/models/releaf/i18n_database/i18n_entry_translation.rb +11 -0
- data/app/views/releaf/i18n_database/translations/_form_fields.haml +2 -2
- data/lib/releaf-i18n_database.rb +14 -3
- data/lib/releaf/i18n_database/backend.rb +56 -131
- data/lib/releaf/i18n_database/configuration.rb +8 -0
- data/lib/releaf/i18n_database/engine.rb +1 -30
- data/lib/releaf/i18n_database/humanize_missing_translations.rb +1 -1
- data/misc/translations.xlsx +0 -0
- data/spec/builders/translations/builder_common_spec.rb +1 -1
- data/spec/builders/translations/edit_builder_spec.rb +2 -2
- data/spec/builders/translations/table_builder_spec.rb +1 -1
- data/spec/controllers/i18n_backend/translations_controller_spec.rb +10 -19
- data/spec/features/translations_spec.rb +235 -16
- data/spec/fixtures/invalid.xls +3 -0
- data/spec/fixtures/invalid.xlsx +3 -0
- data/spec/lib/releaf/i18n_database/backend_spec.rb +192 -0
- data/spec/lib/releaf/i18n_database/configuration_spec.rb +13 -0
- data/spec/lib/{i18n_database → releaf/i18n_database}/humanize_missing_translations_spec.rb +7 -1
- data/spec/lib/releaf/i18n_database/parse_spreadsheet_translations_spec.rb +151 -0
- data/spec/lib/releaf/i18n_database/translations_store_spec.rb +548 -0
- data/spec/lib/{i18n_database → releaf/i18n_database}/translations_utilities_spec.rb +39 -39
- data/spec/models/i18n_database/i18n_entry_spec.rb +50 -0
- data/spec/models/i18n_database/i18n_entry_translation_spec.rb +9 -0
- metadata +45 -30
- data/app/lib/releaf/i18n_database/translations_importer.rb +0 -72
- data/app/models/releaf/i18n_database/translation.rb +0 -17
- data/app/models/releaf/i18n_database/translation_data.rb +0 -11
- data/lib/releaf/i18n_database/builders_autoload.rb +0 -10
- data/releaf-i18n_database.gemspec +0 -21
- data/spec/lib/i18n_database/backend_spec.rb +0 -337
- data/spec/lib/i18n_database/translations_importer_spec.rb +0 -17
- data/spec/models/i18n_database/translation_data_spec.rb +0 -13
- data/spec/models/i18n_database/translation_spec.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c95500c88e31844f3bb04328fae6744220abb94
|
4
|
+
data.tar.gz: 6bfb4f23bf7bab4f737ff2cfde0fc0055e4eb301
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68ca2b2d9c701db9daadfabf4a80f659253ac0b2c75bac4ea3c5aad372a57c000129deeba3ed8a95590605845bc2220bd358fcb0cfe58dd627a74d166ad30443
|
7
|
+
data.tar.gz: bcda02afedc7bec4e3921f97603929e30c0a6b74ef675f18a55b943a41dd8fb11a4c31912dff49b5faedc15772c43d1a151b699d140bf39b44f51df6149e42f4
|
data/LICENSE
CHANGED
@@ -1,24 +1,22 @@
|
|
1
1
|
Copyright (c) 2012, CubeSystems <info@cubesystems.lv>
|
2
|
-
All rights reserved.
|
3
2
|
|
4
|
-
|
5
|
-
modification, are permitted provided that the following conditions are met:
|
6
|
-
* Redistributions of source code must retain the above copyright
|
7
|
-
notice, this list of conditions and the following disclaimer.
|
8
|
-
* Redistributions in binary form must reproduce the above copyright
|
9
|
-
notice, this list of conditions and the following disclaimer in the
|
10
|
-
documentation and/or other materials provided with the distribution.
|
11
|
-
* Neither the name of the CubeSystems nor the names of its contributors may
|
12
|
-
be used to endorse or promote products derived from this software without
|
13
|
-
specific prior written permission.
|
3
|
+
MIT License
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/app/assets/javascripts/{releaf/controllers → controllers}/releaf/i18n_database/translations.js
RENAMED
File without changes
|
File without changes
|
@@ -1,171 +1,165 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
1
|
+
class Releaf::I18nDatabase::TranslationsController < ::Releaf::ActionController
|
2
|
+
def self.resource_class
|
3
|
+
Releaf::I18nDatabase::I18nEntry
|
4
|
+
end
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
def edit
|
7
|
+
@collection = resources
|
8
|
+
search(params[:search])
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def export
|
12
|
+
@collection = resources
|
13
|
+
search(params[:search])
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
15
|
+
respond_to do |format|
|
16
|
+
format.xlsx do
|
17
|
+
response.headers['Content-Disposition'] = "attachment; filename=\"#{export_file_name}\""
|
20
18
|
end
|
21
19
|
end
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
def build_breadcrumbs
|
23
|
+
super
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
end
|
25
|
+
if %w[edit update].include?(params[:action]) && !params.has_key?(:import)
|
26
|
+
@breadcrumbs << { name: I18n.t("Edit translations", scope: controller_scope_name), url: url_for(action: :edit, search: params[:search]) }
|
29
27
|
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
@collection = []
|
32
|
+
@translations_to_save = []
|
33
|
+
|
34
|
+
valid = build_updatables(params[:translations])
|
35
|
+
import_view if params.has_key?(:import)
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
format.html do
|
40
|
-
if valid
|
41
|
-
process_updatables
|
42
|
-
update_response_success
|
43
|
-
else
|
44
|
-
render_notification false, now: true
|
45
|
-
render action: :edit
|
46
|
-
end
|
37
|
+
respond_to do |format|
|
38
|
+
format.html do
|
39
|
+
if valid
|
40
|
+
process_updatables
|
41
|
+
update_response_success
|
42
|
+
else
|
43
|
+
render_notification false, now: true
|
44
|
+
render action: :edit
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
48
|
+
end
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
def resources
|
51
|
+
Releaf::I18nDatabase::TranslationsUtilities.include_localizations(super).order(:key)
|
52
|
+
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
# overwrite search here
|
55
|
+
def search(lookup_string)
|
56
|
+
@collection = Releaf::I18nDatabase::TranslationsUtilities.search(@collection, lookup_string, params[:only_blank].present?)
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
redirect_to action: :index
|
69
|
-
end
|
70
|
-
else
|
59
|
+
def import
|
60
|
+
if File.exist?(import_file_path)
|
61
|
+
begin
|
62
|
+
@collection = Releaf::I18nDatabase::ParseSpreadsheetTranslations.call(file_path: import_file_path, extension: import_file_extension)
|
63
|
+
import_view
|
64
|
+
render :edit
|
65
|
+
rescue Releaf::I18nDatabase::ParseSpreadsheetTranslations::UnsupportedFileFormatError
|
66
|
+
flash["error"] = { "id" => "resource_status", "message" => I18n.t("Unsupported file format", scope: notice_scope_name) }
|
71
67
|
redirect_to action: :index
|
72
68
|
end
|
69
|
+
else
|
70
|
+
redirect_to action: :index
|
73
71
|
end
|
72
|
+
end
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
def setup
|
81
|
-
super
|
82
|
-
@features = {
|
83
|
-
index: true
|
84
|
-
}
|
85
|
-
end
|
74
|
+
def import_view
|
75
|
+
@import = true
|
76
|
+
@breadcrumbs << { name: I18n.t("import", scope: controller_scope_name) }
|
77
|
+
end
|
86
78
|
|
87
|
-
|
88
|
-
|
89
|
-
|
79
|
+
def features
|
80
|
+
[:index, :search]
|
81
|
+
end
|
90
82
|
|
91
|
-
|
92
|
-
|
93
|
-
|
83
|
+
def action_views
|
84
|
+
super.merge(import: :edit)
|
85
|
+
end
|
94
86
|
|
95
|
-
|
87
|
+
def action_features
|
88
|
+
{index: :index}.with_indifferent_access
|
89
|
+
end
|
96
90
|
|
97
|
-
|
98
|
-
resource_class.where(id: @translation_ids_to_destroy).destroy_all unless @translation_ids_to_destroy.empty?
|
99
|
-
@translations_to_save.map(&:save!)
|
100
|
-
Releaf::I18nDatabase::Backend.translations_updated_at = Time.now
|
101
|
-
end
|
91
|
+
private
|
102
92
|
|
103
|
-
|
104
|
-
|
105
|
-
|
93
|
+
def process_updatables
|
94
|
+
resource_class.where(id: @translation_ids_to_destroy).destroy_all unless @translation_ids_to_destroy.empty?
|
95
|
+
@translations_to_save.map(&:save!)
|
96
|
+
Releaf::I18nDatabase::Backend.translations_updated_at = Time.now
|
97
|
+
end
|
106
98
|
|
107
|
-
|
108
|
-
|
109
|
-
|
99
|
+
def build_updatables translations_params
|
100
|
+
valid = true
|
101
|
+
@translation_ids_to_destroy = params.fetch(:existing_translations, "").split(",")
|
110
102
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
else
|
115
|
-
valid = false
|
116
|
-
end
|
103
|
+
translations_params ||= []
|
104
|
+
translations_params.each do |values|
|
105
|
+
translation = load_translation(values["key"], values["localizations"])
|
117
106
|
|
118
|
-
|
107
|
+
if translation.valid?
|
108
|
+
@translations_to_save << translation
|
109
|
+
@translation_ids_to_destroy.delete(translation.id.to_s)
|
110
|
+
else
|
111
|
+
valid = false
|
119
112
|
end
|
120
113
|
|
121
|
-
|
114
|
+
@collection << translation
|
122
115
|
end
|
123
116
|
|
124
|
-
|
125
|
-
|
126
|
-
translation.key = key
|
117
|
+
valid
|
118
|
+
end
|
127
119
|
|
128
|
-
|
129
|
-
|
130
|
-
|
120
|
+
def load_translation(key, localizations)
|
121
|
+
translation = Releaf::I18nDatabase::I18nEntry.where(key: key).first_or_initialize
|
122
|
+
translation.key = key
|
131
123
|
|
132
|
-
|
124
|
+
localizations.each_pair do |locale, localization|
|
125
|
+
load_translation_data(translation, locale, localization)
|
133
126
|
end
|
134
127
|
|
135
|
-
|
136
|
-
|
137
|
-
# replace existing locale value only if new one is not blank
|
138
|
-
if translation_data
|
139
|
-
translation_data.localization = localization
|
140
|
-
# always assign value for new locale
|
141
|
-
elsif translation_data.nil?
|
142
|
-
translation_data = translation.translation_data.build(lang: locale, localization: localization)
|
143
|
-
end
|
128
|
+
translation
|
129
|
+
end
|
144
130
|
|
145
|
-
|
146
|
-
|
131
|
+
def load_translation_data(translation, locale, localization)
|
132
|
+
translation_data = translation.find_or_initialize_translation(locale)
|
147
133
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
redirect_to action: :index
|
153
|
-
else
|
154
|
-
render_notification true
|
155
|
-
redirect_to({action: :edit}.merge(request.query_parameters))
|
156
|
-
end
|
134
|
+
if localization.present?
|
135
|
+
translation_data.text = localization
|
136
|
+
else
|
137
|
+
translation_data.mark_for_destruction
|
157
138
|
end
|
158
139
|
|
159
|
-
|
160
|
-
|
161
|
-
end
|
140
|
+
translation_data
|
141
|
+
end
|
162
142
|
|
163
|
-
|
164
|
-
|
143
|
+
def update_response_success
|
144
|
+
if @import
|
145
|
+
msg = 'successfuly imported %{count} translations'
|
146
|
+
flash["success"] = { "id" => "resource_status", "message" => I18n.t(msg, default: msg, count: @translations_to_save.size , scope: notice_scope_name) }
|
147
|
+
redirect_to action: :index
|
148
|
+
else
|
149
|
+
render_notification true
|
150
|
+
redirect_to({action: :edit}.merge(request.query_parameters))
|
165
151
|
end
|
152
|
+
end
|
166
153
|
|
167
|
-
|
168
|
-
|
169
|
-
|
154
|
+
def export_file_name
|
155
|
+
"#{Rails.application.class.parent_name.underscore}_translations_#{Time.now.strftime('%Y_%m_%d_%H_%M_%S')}.xlsx"
|
156
|
+
end
|
157
|
+
|
158
|
+
def import_file_path
|
159
|
+
params[:import_file].try(:tempfile).try(:path).to_s
|
160
|
+
end
|
161
|
+
|
162
|
+
def import_file_extension
|
163
|
+
File.extname(params[:import_file].original_filename).tr(".", "")
|
170
164
|
end
|
171
165
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Releaf::I18nDatabase
|
2
|
+
class ParseSpreadsheetTranslations
|
3
|
+
class UnsupportedFileFormatError < StandardError; end
|
4
|
+
include Releaf::Service
|
5
|
+
attribute :file_path, String
|
6
|
+
attribute :extension, String
|
7
|
+
|
8
|
+
def call
|
9
|
+
translations
|
10
|
+
end
|
11
|
+
|
12
|
+
def rows
|
13
|
+
@rows ||= spreadsheet.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def data_rows
|
17
|
+
rows[1..-1].reject{|row| row.first.blank? }
|
18
|
+
end
|
19
|
+
|
20
|
+
def locales
|
21
|
+
@locales ||= rows.first.reject(&:blank?)
|
22
|
+
end
|
23
|
+
|
24
|
+
def spreadsheet
|
25
|
+
begin
|
26
|
+
Roo::Spreadsheet.open(file_path, extension: extension, file_warning: :ignore)
|
27
|
+
rescue StandardError => e
|
28
|
+
if file_format_error?(e.class.name, e.message)
|
29
|
+
raise UnsupportedFileFormatError
|
30
|
+
else
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def file_format_error?(error_class_name, error_message)
|
37
|
+
return true if ['Zip::ZipError','Ole::Storage::FormatError' ].include?(error_class_name)
|
38
|
+
error_class_name == 'ArgumentError' && error_message.match("Don't know how to open file").present?
|
39
|
+
end
|
40
|
+
|
41
|
+
def translations
|
42
|
+
data_rows.map do |row|
|
43
|
+
translation_instance(row.first, row[1..-1].map(&:to_s))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def translation_instance(key, localizations)
|
48
|
+
translation = Releaf::I18nDatabase::I18nEntry.where(key: key).first_or_initialize
|
49
|
+
maintain_translation_locales(translation, localizations)
|
50
|
+
|
51
|
+
translation
|
52
|
+
end
|
53
|
+
|
54
|
+
def maintain_translation_locales(translation, localizations)
|
55
|
+
locales.each_with_index do|locale, i|
|
56
|
+
locale_translation = translation.i18n_entry_translation.find{|item| item.locale == locale }
|
57
|
+
locale_translation ||= translation.i18n_entry_translation.build(locale: locale, text: "")
|
58
|
+
locale_translation.text = localizations[i] if localizations[i].present?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
class Releaf::I18nDatabase::TranslationsStore
|
2
|
+
include Releaf::InstanceCache
|
3
|
+
attr_accessor :updated_at, :missing_keys
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
self.updated_at = Releaf::I18nDatabase::Backend.translations_updated_at
|
7
|
+
self.missing_keys = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def expired?
|
11
|
+
updated_at != Releaf::I18nDatabase::Backend.translations_updated_at
|
12
|
+
end
|
13
|
+
|
14
|
+
def exist?(key)
|
15
|
+
stored_keys.key? key
|
16
|
+
end
|
17
|
+
|
18
|
+
def lookup(locale, key, options)
|
19
|
+
translation_keys = key.split('.')
|
20
|
+
|
21
|
+
(1..translation_keys.length).each do|i|
|
22
|
+
result = dig_valid_translation(locale, translation_keys, i == 1, options)
|
23
|
+
return result if returnable_result?(result, options)
|
24
|
+
# remove second last value (going up to scope chain)
|
25
|
+
translation_keys.delete_at(translation_keys.length - 2)
|
26
|
+
end
|
27
|
+
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def dig_translation(locale, translation_keys)
|
32
|
+
translation_keys.inject(stored_translations[locale.to_sym]) do |h, key|
|
33
|
+
h[key.to_sym] if h.is_a?(Hash)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def dig_valid_translation(locale, translation_keys, first_lookup, options)
|
38
|
+
result = dig_translation(locale, translation_keys)
|
39
|
+
if invalid_result?(locale, result, first_lookup, options)
|
40
|
+
nil
|
41
|
+
else
|
42
|
+
result
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def invalid_result?(locale, result, first_lookup, options)
|
47
|
+
invalid_nonpluralized_result?(result, first_lookup, options) || invalid_pluralized_result?(locale, result, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def invalid_nonpluralized_result?(result, first_lookup, options)
|
51
|
+
result.is_a?(Hash) && !first_lookup && !options.has_key?(:count)
|
52
|
+
end
|
53
|
+
|
54
|
+
def invalid_pluralized_result?(locale, result, options)
|
55
|
+
result.is_a?(Hash) && options.has_key?(:count) && !valid_pluralized_result?(locale, options[:count], result)
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid_pluralized_result?(locale, count, result)
|
59
|
+
return false unless TwitterCldr.supported_locale?(locale)
|
60
|
+
result.key?(TwitterCldr::Formatters::Plurals::Rules.rule_for(count, locale))
|
61
|
+
end
|
62
|
+
|
63
|
+
def returnable_result?(result, options)
|
64
|
+
result.present? || options.fetch(:inherit_scopes, true) == false
|
65
|
+
end
|
66
|
+
|
67
|
+
def localization_data
|
68
|
+
Releaf::I18nDatabase::I18nEntryTranslation
|
69
|
+
.joins(:i18n_entry)
|
70
|
+
.where.not(text: '')
|
71
|
+
.pluck("CONCAT(locale, '.', releaf_i18n_entries.key) AS translation_key", "text")
|
72
|
+
.to_h
|
73
|
+
end
|
74
|
+
|
75
|
+
def stored_keys
|
76
|
+
Releaf::I18nDatabase::I18nEntry.pluck(:key).inject({}) do|h, key|
|
77
|
+
h.update(key => true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def stored_translations
|
82
|
+
stored_keys.map do |key, _|
|
83
|
+
key_hash(key)
|
84
|
+
end.inject(&:deep_merge) || {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def key_hash(key)
|
88
|
+
config.all_locales.inject({}) do |h, locale|
|
89
|
+
localized_key = "#{locale}.#{key}"
|
90
|
+
locale_hash = key_locale_hash(localized_key, localization_data[localized_key])
|
91
|
+
h.merge(locale_hash)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def config
|
96
|
+
Releaf.application.config
|
97
|
+
end
|
98
|
+
|
99
|
+
def missing?(locale, key)
|
100
|
+
missing_keys.key? "#{locale}.#{key}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def missing(locale, key, options)
|
104
|
+
# mark translation as missing
|
105
|
+
missing_keys["#{locale}.#{key}"] = true
|
106
|
+
auto_create(key, options) if auto_create?(key, options)
|
107
|
+
end
|
108
|
+
|
109
|
+
def auto_create?(key, options)
|
110
|
+
return false unless config.i18n_database.translation_auto_creation
|
111
|
+
return false if options[:auto_create] == false
|
112
|
+
return false unless auto_creation_inclusion?(key)
|
113
|
+
return false if auto_creation_exception?(key)
|
114
|
+
return false if stored_keys.key?(key)
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def auto_creation_inclusion?(key)
|
119
|
+
config.i18n_database.translation_auto_creation_patterns.find{|pattern| key.match(pattern) }.present?
|
120
|
+
end
|
121
|
+
|
122
|
+
def auto_creation_exception?(key)
|
123
|
+
config.i18n_database.translation_auto_creation_exclusion_patterns.find{|pattern| key.match(pattern) }.present?
|
124
|
+
end
|
125
|
+
|
126
|
+
def auto_create(key, options)
|
127
|
+
if pluralizable_translation?(options)
|
128
|
+
Releaf::I18nDatabase::Backend.locales_pluralizations.each do|pluralization|
|
129
|
+
Releaf::I18nDatabase::I18nEntry.create(key: "#{key}.#{pluralization}")
|
130
|
+
end
|
131
|
+
else
|
132
|
+
Releaf::I18nDatabase::I18nEntry.create(key: key)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def pluralizable_translation?(options)
|
137
|
+
options.has_key?(:count) && options[:create_plurals] == true
|
138
|
+
end
|
139
|
+
|
140
|
+
cache_instance_methods :stored_translations, :stored_keys, :localization_data
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def key_locale_hash(localized_key, localization)
|
145
|
+
localized_key.split(".").reverse.inject(localization) do |value, key|
|
146
|
+
{key.to_sym => value}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|