releaf-i18n_database 0.2.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|