phraseapp-in-context-editor-ruby 1.0.2 → 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/CHANGELOG.md +27 -0
- data/lib/phraseapp-in-context-editor-ruby.rb +8 -0
- data/lib/phraseapp-in-context-editor-ruby/backend_service.rb +3 -2
- data/lib/phraseapp-in-context-editor-ruby/config.rb +16 -0
- data/lib/phraseapp-in-context-editor-ruby/delegate/i18n_delegate.rb +79 -0
- data/lib/phraseapp-in-context-editor-ruby/displayable_key_identifier.rb +46 -0
- data/lib/phraseapp-in-context-editor-ruby/fallback_keys_fetcher.rb +44 -0
- data/lib/phraseapp-in-context-editor-ruby/key_names_cache.rb +53 -0
- data/lib/phraseapp-in-context-editor-ruby/version.rb +1 -1
- data/lib/phraseapp-in-context-editor-ruby/view_helpers.rb +7 -3
- data/phraseapp-in-context-editor-ruby.gemspec +1 -0
- metadata +23 -4
- data/lib/phraseapp-in-context-editor-ruby/delegate/i18n.rb +0 -192
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01523b055b91761df927cdf84848aef55c6290ed
|
4
|
+
data.tar.gz: 784a66ff617287b86f09610e775164ea10dfa20b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a54b0688e2c1fba44dc024ab69c712dcd3bebec6148767b0a412603a4d72ef595fa18bccc2e9ff38e4153aedad9dd8f3341ef609c5a32b5f9f3e3d03703158a
|
7
|
+
data.tar.gz: a35d23543c9f8c2c8c21a11b3b077a398406c3266435581b50ae92d996eecc225d552d851ed2f2cf75bb2d9ebbc7d5b363ca1798a9625d00ae6e005ff5d8d5ad
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## [v1.0.2](https://github.com/phrase/phraseapp-in-context-editor-ruby/tree/v1.0.2) (2015-10-12)
|
4
|
+
[Full Changelog](https://github.com/phrase/phraseapp-in-context-editor-ruby/compare/v1.0.1...v1.0.2)
|
5
|
+
|
6
|
+
**Closed issues:**
|
7
|
+
|
8
|
+
- Method missing error [\#5](https://github.com/phrase/phraseapp-in-context-editor-ruby/issues/5)
|
9
|
+
|
10
|
+
**Merged pull requests:**
|
11
|
+
|
12
|
+
- 18n delegate refactoring [\#6](https://github.com/phrase/phraseapp-in-context-editor-ruby/pull/6) ([segitty](https://github.com/segitty))
|
13
|
+
|
14
|
+
## [v1.0.1](https://github.com/phrase/phraseapp-in-context-editor-ruby/tree/v1.0.1) (2015-10-07)
|
15
|
+
[Full Changelog](https://github.com/phrase/phraseapp-in-context-editor-ruby/compare/v1.0.0...v1.0.1)
|
16
|
+
|
17
|
+
**Closed issues:**
|
18
|
+
|
19
|
+
- Two translations in one HTML element [\#4](https://github.com/phrase/phraseapp-in-context-editor-ruby/issues/4)
|
20
|
+
- Why PhraseApp In-Context Editor can be enabled/disabled only for entire application? [\#3](https://github.com/phrase/phraseapp-in-context-editor-ruby/issues/3)
|
21
|
+
- Why Access Token is mandatory in configuration for In-Context Editor? [\#2](https://github.com/phrase/phraseapp-in-context-editor-ruby/issues/2)
|
22
|
+
- Problems chaneging suffix and prefix [\#1](https://github.com/phrase/phraseapp-in-context-editor-ruby/issues/1)
|
23
|
+
|
24
|
+
## [v1.0.0](https://github.com/phrase/phraseapp-in-context-editor-ruby/tree/v1.0.0) (2015-08-21)
|
25
|
+
|
26
|
+
|
27
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require 'phraseapp-in-context-editor-ruby/api_collection'
|
3
|
-
require 'phraseapp-in-context-editor-ruby/delegate/
|
3
|
+
require 'phraseapp-in-context-editor-ruby/delegate/i18n_delegate'
|
4
4
|
|
5
5
|
module PhraseApp
|
6
6
|
module InContextEditor
|
@@ -64,8 +64,9 @@ module PhraseApp
|
|
64
64
|
def phraseapp_delegate_for(args)
|
65
65
|
key = given_key_from_args(args)
|
66
66
|
return nil unless present?(key)
|
67
|
+
|
67
68
|
options = args[1].nil? ? {} : args[1]
|
68
|
-
PhraseApp::InContextEditor::Delegate::
|
69
|
+
PhraseApp::InContextEditor::Delegate::I18nDelegate.new(key, options, args)
|
69
70
|
end
|
70
71
|
|
71
72
|
def extract_normalized_key_from_args(args)
|
@@ -93,6 +93,22 @@ module PhraseApp
|
|
93
93
|
@@js_use_ssl = js_use_ssl
|
94
94
|
end
|
95
95
|
|
96
|
+
def js_path
|
97
|
+
@@js_path ||= "/assets/in-context-editor/2.0/app.js"
|
98
|
+
end
|
99
|
+
|
100
|
+
def js_path=(js_path)
|
101
|
+
@@js_path = js_path
|
102
|
+
end
|
103
|
+
|
104
|
+
def js_options
|
105
|
+
@@js_options ||= {}
|
106
|
+
end
|
107
|
+
|
108
|
+
def js_options=(js_options)
|
109
|
+
@@js_options = js_options
|
110
|
+
end
|
111
|
+
|
96
112
|
def cache_key_segments_initial
|
97
113
|
@@cache_key_segments_initial ||= ["simple_form"]
|
98
114
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'phraseapp-in-context-editor-ruby/cache'
|
4
|
+
require 'phraseapp-in-context-editor-ruby/hash_flattener'
|
5
|
+
require 'phraseapp-in-context-editor-ruby/delegate'
|
6
|
+
require 'phraseapp-in-context-editor-ruby/api_wrapper'
|
7
|
+
require 'phraseapp-in-context-editor-ruby/displayable_key_identifier'
|
8
|
+
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
module PhraseApp
|
12
|
+
module InContextEditor
|
13
|
+
module Delegate
|
14
|
+
class I18nDelegate < Base
|
15
|
+
attr_accessor :key, :display_key, :options, :api_client, :fallback_keys, :original_args
|
16
|
+
|
17
|
+
def initialize(key, options={}, original_args=nil)
|
18
|
+
@key = key
|
19
|
+
@options = options
|
20
|
+
@original_args = original_args
|
21
|
+
@display_key = DisplayableKeyIdentifier.new(api_wrapper).identify(@key, @options)
|
22
|
+
super(decorated_key_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(*args, &block)
|
26
|
+
self.class.log "Trying to execute missing method ##{args.first} on key #{@key}"
|
27
|
+
if @key.respond_to?(args.first)
|
28
|
+
to_s.send(*args)
|
29
|
+
else
|
30
|
+
data = translation_or_subkeys
|
31
|
+
if data.respond_to?(args.first)
|
32
|
+
data.send(*args, &block)
|
33
|
+
else
|
34
|
+
self.class.log "You tried to execute the missing method ##{args.first} on key #{@key} which is not supported. Please make sure you treat your translations as strings only."
|
35
|
+
original_translation = ::I18n.translate_without_phraseapp(*@original_args)
|
36
|
+
original_translation.send(*args, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def translation_or_subkeys
|
44
|
+
keys = api_wrapper.keys_with_prefix(@key)
|
45
|
+
return nil unless keys.present?
|
46
|
+
|
47
|
+
if keys.size == 1
|
48
|
+
translation_content_for_key(keys.first)
|
49
|
+
else
|
50
|
+
translation_hash = keys.inject({}) do |hash, key|
|
51
|
+
hash[key.name] = translation_content_for_key(key)
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
|
55
|
+
PhraseApp::InContextEditor::HashFlattener.expand_flat_hash(translation_hash, @key)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def translation_content_for_key(key)
|
60
|
+
default_translations = api_wrapper.default_translation(key)
|
61
|
+
return unless default_translations.present?
|
62
|
+
|
63
|
+
if key.plural
|
64
|
+
default_translations.inject({}) do |hash, translation|
|
65
|
+
hash[translation.plural_suffix.to_sym] = translation.content
|
66
|
+
hash
|
67
|
+
end
|
68
|
+
else
|
69
|
+
default_translations.first.content
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def api_wrapper
|
74
|
+
@api_wrapper ||= InContextEditor::ApiWrapper.new
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'phraseapp-in-context-editor-ruby/fallback_keys_fetcher'
|
2
|
+
require 'phraseapp-in-context-editor-ruby/key_names_cache'
|
3
|
+
|
4
|
+
module PhraseApp
|
5
|
+
module InContextEditor
|
6
|
+
class DisplayableKeyIdentifier
|
7
|
+
attr_reader :api_wrapper, :key_names_cache
|
8
|
+
|
9
|
+
def initialize(api_wrapper)
|
10
|
+
@api_wrapper = api_wrapper
|
11
|
+
@key_names_cache = KeyNamesCache.new(@api_wrapper)
|
12
|
+
end
|
13
|
+
|
14
|
+
def identify(key_name, options)
|
15
|
+
fallback_key_names = FallbackKeysFetcher.extract_fallback_keys(key_name, options)
|
16
|
+
return key_name if fallback_key_names.empty?
|
17
|
+
|
18
|
+
key_names = [key_name] | fallback_key_names
|
19
|
+
available_key_names = find_keys_within_phraseapp(key_names)
|
20
|
+
|
21
|
+
key_names.each do |item|
|
22
|
+
if available_key_names.include?(item)
|
23
|
+
return item
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return key_name
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def find_keys_within_phraseapp(key_names)
|
33
|
+
key_names_to_check_against_api = key_names - @key_names_cache.pre_fetched(key_names)
|
34
|
+
@key_names_cache.pre_cached(key_names) | key_names_returned_from_api_for(key_names_to_check_against_api)
|
35
|
+
end
|
36
|
+
|
37
|
+
def key_names_returned_from_api_for(key_names)
|
38
|
+
if key_names.size > 0
|
39
|
+
api_wrapper.keys_by_names(key_names).map { |key| key.name }
|
40
|
+
else
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module PhraseApp
|
2
|
+
module InContextEditor
|
3
|
+
class FallbackKeysFetcher
|
4
|
+
|
5
|
+
def self.extract_fallback_keys(key, options)
|
6
|
+
fallback_items = []
|
7
|
+
if options.has_key?(:default)
|
8
|
+
if options[:default].kind_of?(Array)
|
9
|
+
fallback_items = options[:default]
|
10
|
+
else
|
11
|
+
fallback_items << options[:default]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
return fallback_items.map{ |item| process_fallback_item(item, key, options) }.flatten.uniq
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.process_fallback_item(item, key, options)
|
19
|
+
fallback_keys = []
|
20
|
+
if item.kind_of?(Symbol)
|
21
|
+
fallback_key_name = item.to_s
|
22
|
+
if options.has_key?(:scope)
|
23
|
+
if options[:scope].is_a?(Array)
|
24
|
+
fallback_key_name = "#{options[:scope].join(".")}.#{item}"
|
25
|
+
else
|
26
|
+
fallback_key_name = "#{options[:scope]}.#{item}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
fallback_keys << fallback_key_name
|
30
|
+
|
31
|
+
if key == "helpers.label.#{fallback_key_name}" # http://apidock.com/rails/v3.1.0/ActionView/Helpers/FormHelper/label
|
32
|
+
fallback_keys << "activerecord.attributes.#{fallback_key_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
if key.start_with?("simple_form.") # special treatment for simple form
|
36
|
+
fallback_keys << "activerecord.attributes.#{item}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
return fallback_keys
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module PhraseApp
|
2
|
+
module InContextEditor
|
3
|
+
class KeyNamesCache
|
4
|
+
attr_reader :api_wrapper
|
5
|
+
|
6
|
+
def initialize(api_wrapper)
|
7
|
+
@api_wrapper = api_wrapper
|
8
|
+
end
|
9
|
+
|
10
|
+
def pre_cached(key_names)
|
11
|
+
unless cache.cached?(:translation_key_names)
|
12
|
+
cache.set(:translation_key_names, prefetched_key_names)
|
13
|
+
end
|
14
|
+
|
15
|
+
return key_names.select { |key_name| key_name_precached?(key_name) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def pre_fetched(key_names)
|
19
|
+
key_names.select { |key_name| covered_by_initial_caching?(key_name) }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def prefetched_key_names
|
25
|
+
prefetched = Set.new
|
26
|
+
PhraseApp::InContextEditor.cache_key_segments_initial.each do |prefix|
|
27
|
+
api_wrapper.keys_with_prefix(prefix).each do |key|
|
28
|
+
prefetched.add(key.name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
prefetched
|
32
|
+
end
|
33
|
+
|
34
|
+
def covered_by_initial_caching?(key_name)
|
35
|
+
key_name.start_with?(*PhraseApp::InContextEditor.cache_key_segments_initial)
|
36
|
+
end
|
37
|
+
|
38
|
+
def key_name_is_in_cache?(key_name)
|
39
|
+
cache.get(:translation_key_names).include?(key_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def key_name_precached?(key_name)
|
43
|
+
covered = covered_by_initial_caching?(key_name)
|
44
|
+
in_cache = key_name_is_in_cache?(key_name)
|
45
|
+
return covered && in_cache
|
46
|
+
end
|
47
|
+
|
48
|
+
def cache
|
49
|
+
Thread.current[:phraseapp_cache] ||= PhraseApp::InContextEditor::Cache.new
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -6,20 +6,24 @@ module PhraseApp
|
|
6
6
|
def phraseapp_in_context_editor_js(opts={})
|
7
7
|
return "" unless PhraseApp::InContextEditor.enabled?
|
8
8
|
|
9
|
-
|
9
|
+
# stringify to reduce possible errors when passing symbols
|
10
|
+
js_default_options = PhraseApp::InContextEditor.js_options.inject({}) { |conf, (k,v)| conf[k.to_s] = v; conf}
|
11
|
+
opts = opts.nil? ? {} : opts.inject({}) { |conf, (k,v)| conf[k.to_s] = v; conf}
|
12
|
+
|
13
|
+
# js options
|
10
14
|
configuration = {
|
11
15
|
'projectId' => PhraseApp::InContextEditor.project_id,
|
12
16
|
'prefix' => PhraseApp::InContextEditor.prefix,
|
13
17
|
'suffix' => PhraseApp::InContextEditor.suffix,
|
14
18
|
'apiBaseUrl' => "#{PhraseApp::InContextEditor.api_host}/api/v2",
|
15
|
-
}.merge(opts)
|
19
|
+
}.merge(js_default_options).merge(opts)
|
16
20
|
|
17
21
|
snippet = <<-eos
|
18
22
|
<script>
|
19
23
|
window.PHRASEAPP_CONFIG = #{configuration.to_json};
|
20
24
|
(function() {
|
21
25
|
var phraseapp = document.createElement('script'); phraseapp.type = 'text/javascript'; phraseapp.async = true;
|
22
|
-
phraseapp.src = ['#{PhraseApp::InContextEditor.js_use_ssl ? 'https' : 'http'}://', '#{PhraseApp::InContextEditor.js_host}
|
26
|
+
phraseapp.src = ['#{PhraseApp::InContextEditor.js_use_ssl ? 'https' : 'http'}://', '#{PhraseApp::InContextEditor.js_host}#{PhraseApp::InContextEditor.js_path}?', new Date().getTime()].join('');
|
23
27
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(phraseapp, s);
|
24
28
|
})();
|
25
29
|
</script>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phraseapp-in-context-editor-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dynport GmbH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '4.2'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: github_changelog_generator
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description: 'PhraseApp In-Context-Editor allows you to edit translations directly
|
126
140
|
on the website. More information: phraseapp.com'
|
127
141
|
email:
|
@@ -132,6 +146,7 @@ extra_rdoc_files: []
|
|
132
146
|
files:
|
133
147
|
- ".gitignore"
|
134
148
|
- ".travis.yml"
|
149
|
+
- CHANGELOG.md
|
135
150
|
- Gemfile
|
136
151
|
- Guardfile
|
137
152
|
- LICENSE
|
@@ -150,9 +165,12 @@ files:
|
|
150
165
|
- lib/phraseapp-in-context-editor-ruby/config.rb
|
151
166
|
- lib/phraseapp-in-context-editor-ruby/delegate.rb
|
152
167
|
- lib/phraseapp-in-context-editor-ruby/delegate/fast_gettext.rb
|
153
|
-
- lib/phraseapp-in-context-editor-ruby/delegate/
|
168
|
+
- lib/phraseapp-in-context-editor-ruby/delegate/i18n_delegate.rb
|
169
|
+
- lib/phraseapp-in-context-editor-ruby/displayable_key_identifier.rb
|
154
170
|
- lib/phraseapp-in-context-editor-ruby/engine.rb
|
171
|
+
- lib/phraseapp-in-context-editor-ruby/fallback_keys_fetcher.rb
|
155
172
|
- lib/phraseapp-in-context-editor-ruby/hash_flattener.rb
|
173
|
+
- lib/phraseapp-in-context-editor-ruby/key_names_cache.rb
|
156
174
|
- lib/phraseapp-in-context-editor-ruby/version.rb
|
157
175
|
- lib/phraseapp-in-context-editor-ruby/view_helpers.rb
|
158
176
|
- phraseapp-in-context-editor-ruby.gemspec
|
@@ -176,8 +194,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
194
|
version: 1.3.6
|
177
195
|
requirements: []
|
178
196
|
rubyforge_project: phraseapp-in-context-editor-ruby
|
179
|
-
rubygems_version: 2.
|
197
|
+
rubygems_version: 2.4.8
|
180
198
|
signing_key:
|
181
199
|
specification_version: 4
|
182
200
|
summary: Translation management solution for web and mobile applications
|
183
201
|
test_files: []
|
202
|
+
has_rdoc:
|
@@ -1,192 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
|
3
|
-
require 'phraseapp-in-context-editor-ruby/cache'
|
4
|
-
require 'phraseapp-in-context-editor-ruby/hash_flattener'
|
5
|
-
require 'phraseapp-in-context-editor-ruby/delegate'
|
6
|
-
require 'phraseapp-in-context-editor-ruby/api_wrapper'
|
7
|
-
require 'set'
|
8
|
-
|
9
|
-
module PhraseApp
|
10
|
-
module InContextEditor
|
11
|
-
module Delegate
|
12
|
-
class I18n < Base
|
13
|
-
attr_accessor :key, :display_key, :options, :api_client, :fallback_keys, :original_args
|
14
|
-
|
15
|
-
def initialize(key, options={}, original_args=nil)
|
16
|
-
@display_key = @key = key
|
17
|
-
@options = options
|
18
|
-
@original_args = original_args
|
19
|
-
|
20
|
-
@fallback_keys = []
|
21
|
-
|
22
|
-
extract_fallback_keys
|
23
|
-
identify_key_to_display if @fallback_keys.any?
|
24
|
-
super(decorated_key_name)
|
25
|
-
end
|
26
|
-
|
27
|
-
def method_missing(*args, &block)
|
28
|
-
self.class.log "Trying to execute missing method ##{args.first} on key #{@key}"
|
29
|
-
if @key.respond_to?(args.first)
|
30
|
-
to_s.send(*args)
|
31
|
-
else
|
32
|
-
data = translation_or_subkeys
|
33
|
-
if data.respond_to?(args.first)
|
34
|
-
data.send(*args, &block)
|
35
|
-
else
|
36
|
-
self.class.log "You tried to execute the missing method ##{args.first} on key #{@key} which is not supported. Please make sure you treat your translations as strings only."
|
37
|
-
original_translation = ::I18n.translate_without_phraseapp(*@original_args)
|
38
|
-
original_translation.send(*args, &block)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def identify_key_to_display
|
45
|
-
key_names = [@key] | @fallback_keys
|
46
|
-
available_key_names = find_keys_within_phraseapp(key_names)
|
47
|
-
@display_key = @key
|
48
|
-
key_names.each do |item|
|
49
|
-
if available_key_names.include?(item)
|
50
|
-
@display_key = item
|
51
|
-
break
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def find_keys_within_phraseapp(key_names)
|
57
|
-
key_names_to_check_against_api = key_names - pre_fetched(key_names)
|
58
|
-
pre_cached(key_names) | key_names_returned_from_api_for(key_names_to_check_against_api)
|
59
|
-
end
|
60
|
-
|
61
|
-
def pre_cached(key_names)
|
62
|
-
warm_translation_key_names_cache unless cache.cached?(:translation_key_names)
|
63
|
-
pre_cached_key_names = key_names.select { |key_name| key_name_precached?(key_name) }
|
64
|
-
pre_cached_key_names
|
65
|
-
end
|
66
|
-
|
67
|
-
def pre_fetched(key_names)
|
68
|
-
key_names.select { |key_name| covered_by_initial_caching?(key_name) }
|
69
|
-
end
|
70
|
-
|
71
|
-
def key_name_precached?(key_name)
|
72
|
-
covered = covered_by_initial_caching?(key_name)
|
73
|
-
in_cache = key_name_is_in_cache?(key_name)
|
74
|
-
covered && in_cache
|
75
|
-
end
|
76
|
-
|
77
|
-
def key_names_returned_from_api_for(key_names)
|
78
|
-
if key_names.size > 0
|
79
|
-
api_wrapper.keys_by_names(key_names).map{ |key| key.name }
|
80
|
-
else
|
81
|
-
[]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def key_name_is_in_cache?(key_name)
|
86
|
-
cache.get(:translation_key_names).include?(key_name)
|
87
|
-
end
|
88
|
-
|
89
|
-
def covered_by_initial_caching?(key_name)
|
90
|
-
key_name.start_with?(*PhraseApp::InContextEditor.cache_key_segments_initial)
|
91
|
-
end
|
92
|
-
|
93
|
-
def extract_fallback_keys
|
94
|
-
fallback_items = []
|
95
|
-
if @options.has_key?(:default)
|
96
|
-
if @options[:default].kind_of?(Array)
|
97
|
-
fallback_items = @options[:default]
|
98
|
-
else
|
99
|
-
fallback_items << @options[:default]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
fallback_items.each do |item|
|
104
|
-
process_fallback_item(item)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def scoped(item)
|
109
|
-
@options.has_key?(:scope) ? "#{@options[:scope]}.#{item}" : item
|
110
|
-
end
|
111
|
-
|
112
|
-
def process_fallback_item(item)
|
113
|
-
if item.kind_of?(Symbol)
|
114
|
-
entry = scoped(item.to_s)
|
115
|
-
@fallback_keys << entry
|
116
|
-
if @key == "helpers.label.#{entry}" # http://apidock.com/rails/v3.1.0/ActionView/Helpers/FormHelper/label
|
117
|
-
@fallback_keys << "activerecord.attributes.#{entry}"
|
118
|
-
end
|
119
|
-
|
120
|
-
if @key.start_with?("simple_form.") # special treatment for simple form
|
121
|
-
@fallback_keys << "activerecord.attributes.#{item.to_s}"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def translation_or_subkeys
|
127
|
-
keys = api_wrapper.keys_with_prefix(@key)
|
128
|
-
return nil unless keys.present?
|
129
|
-
|
130
|
-
if keys.size == 1
|
131
|
-
translation_content_for_key(keys.first)
|
132
|
-
else
|
133
|
-
translation_hash = keys.inject({}) do |hash, key|
|
134
|
-
hash[key.name] = translation_content_for_key(key)
|
135
|
-
hash
|
136
|
-
end
|
137
|
-
|
138
|
-
PhraseApp::InContextEditor::HashFlattener.expand_flat_hash(translation_hash, @key)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def cache
|
143
|
-
Thread.current[:phraseapp_cache] ||= build_cache
|
144
|
-
end
|
145
|
-
|
146
|
-
def build_cache
|
147
|
-
cache = PhraseApp::InContextEditor::Cache.new
|
148
|
-
end
|
149
|
-
|
150
|
-
def warm_translation_key_names_cache
|
151
|
-
cache.set(:translation_key_names, prefetched_key_names)
|
152
|
-
end
|
153
|
-
|
154
|
-
def prefetched_key_names
|
155
|
-
prefetched = Set.new
|
156
|
-
PhraseApp::InContextEditor.cache_key_segments_initial.each do |prefix|
|
157
|
-
api_wrapper.keys_with_prefix(prefix).each do |key|
|
158
|
-
prefetched.add(key.name)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
prefetched
|
162
|
-
end
|
163
|
-
|
164
|
-
def key_names_from_nested(segment, data)
|
165
|
-
key_names = Set.new
|
166
|
-
PhraseApp::InContextEditor::HashFlattener.flatten(data, nil) do |key, value|
|
167
|
-
key_names.add("#{segment}.#{key}") unless value.is_a?(Hash)
|
168
|
-
end unless (data.is_a?(String) || data.nil?)
|
169
|
-
key_names
|
170
|
-
end
|
171
|
-
|
172
|
-
def translation_content_for_key(key)
|
173
|
-
default_translations = api_wrapper.default_translation(key)
|
174
|
-
return unless default_translations.present?
|
175
|
-
|
176
|
-
if key.plural
|
177
|
-
default_translations.inject({}) do |hash, translation|
|
178
|
-
hash[translation.plural_suffix.to_sym] = translation.content
|
179
|
-
hash
|
180
|
-
end
|
181
|
-
else
|
182
|
-
default_translations.first.content
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def api_wrapper
|
187
|
-
@api_wrapper ||= InContextEditor::ApiWrapper.new
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|