t9n 0.1.0
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.
- data/MIT-LICENSE +20 -0
- data/README.markdown +1 -0
- data/generators/t9n/t9n_generator.rb +57 -0
- data/generators/t9n/templates/initializer.rb +8 -0
- data/generators/t9n/templates/language.rb +3 -0
- data/generators/t9n/templates/migrations/create_languages.rb +941 -0
- data/generators/t9n/templates/migrations/create_translations.rb +20 -0
- data/generators/t9n/templates/translation.rb +3 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/t9n.rb +16 -0
- data/lib/t9n/active_record/translatable_attribute.rb +120 -0
- data/lib/t9n/backend/active_record.rb +179 -0
- data/lib/t9n/backend/exception_handler.rb +24 -0
- data/lib/t9n/backend/extension.rb +25 -0
- data/lib/t9n/models/language.rb +41 -0
- data/lib/t9n/models/translation.rb +84 -0
- data/lib/t9n/util.rb +95 -0
- data/lib/tasks/t9n.rake +18 -0
- data/rails/init.rb +1 -0
- metadata +86 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
module Perfectline
|
2
|
+
module T9n
|
3
|
+
module Models
|
4
|
+
module Translation
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.__send__(:include, Associations)
|
8
|
+
base.__send__(:include, Scopes)
|
9
|
+
base.__send__(:include, Validations)
|
10
|
+
base.__send__(:include, InstanceMethods)
|
11
|
+
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
module Associations
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.class_eval do
|
19
|
+
belongs_to :translatable, :polymorphic => true, :readonly => true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
module Scopes
|
26
|
+
|
27
|
+
def self.included(base)
|
28
|
+
base.class_eval do
|
29
|
+
named_scope :untranslated, :conditions => "value IS NULL OR value = ''"
|
30
|
+
named_scope :translated, :conditions => "value IS NOT NULL AND value != ''"
|
31
|
+
named_scope :orphans, :conditions => "translatable_id IS NULL"
|
32
|
+
|
33
|
+
named_scope :locale, lambda{ |locale| {:conditions => {:locale => locale}} }
|
34
|
+
named_scope :for, lambda{ |object| {:conditions => {:translatable_id => object.id, :translatable_type => object.class.name}} }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
module Validations
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
base.class_eval do
|
44
|
+
validates_presence_of :locale
|
45
|
+
validates_presence_of :key
|
46
|
+
validates_length_of :key, :maximum => 255
|
47
|
+
validates_uniqueness_of :key, :scope => [:locale, :translatable_id, :translatable_type]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
|
55
|
+
def available_locales
|
56
|
+
find(:all, :select => "DISTINCT locale", :order => :locale).map(&:locale)
|
57
|
+
end
|
58
|
+
|
59
|
+
def lookup(key)
|
60
|
+
translated.find(:all, :conditions => ["key = ? OR key ILIKE ?", key, "#{key}.%"], :order => :key)
|
61
|
+
end
|
62
|
+
|
63
|
+
def cache_key(locale, key, object)
|
64
|
+
if object.nil?
|
65
|
+
return "#{locale}:#{key}"
|
66
|
+
else
|
67
|
+
return "#{locale}:#{key}:#{object.class.name}_#{object.id}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
module InstanceMethods
|
74
|
+
|
75
|
+
def empty?
|
76
|
+
value.blank? || value.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/t9n/util.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Perfectline
|
5
|
+
module T9n
|
6
|
+
class Util
|
7
|
+
|
8
|
+
# sync non-default languages from the default one
|
9
|
+
def self.populate
|
10
|
+
::Translation.locale(I18n.default_locale).each do |t|
|
11
|
+
::Translation.available_locales.reject!{ |locale| I18n.default_locale?(locale) }.each do |locale|
|
12
|
+
unless ::Translation.locale(locale).exists?({:key => t.key, :translatable_id => t.translatable_id, :translatable_type => t.translatable_type})
|
13
|
+
::Translation.create!(
|
14
|
+
:locale => locale,
|
15
|
+
:key => t.key,
|
16
|
+
:value => nil,
|
17
|
+
:translatable_id => t.translatable_id,
|
18
|
+
:translatable_type => t.translatable_type
|
19
|
+
)
|
20
|
+
puts "Translation::Populate created a new translation in :#{locale} with key '#{t.key}'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# translate from google
|
27
|
+
def self.google_translate
|
28
|
+
I18n.available_locales.reject!{ |locale| I18n.default_locale?(locale) }.each do |locale|
|
29
|
+
::Translation.locale(locale).untranslated.each do |translation|
|
30
|
+
|
31
|
+
unless self.needs_human_eyes?(translation.value)
|
32
|
+
interpolation = translation.value.scan(/\{\{(.*?)\}\}/).flatten
|
33
|
+
|
34
|
+
if interpolation.empty?
|
35
|
+
translation.update_attribute(:value, Perfectline::T9n::GoogleTranslator.translate(translation.value, locale, I18n.default_locale))
|
36
|
+
else
|
37
|
+
placeholders = {}
|
38
|
+
|
39
|
+
# sub out interpolations
|
40
|
+
interpolation.each do |argument|
|
41
|
+
placeholder = Time.now.to_i
|
42
|
+
translation.value.gsub!("{{#{argument}}}", placeholder)
|
43
|
+
placeholders[placeholder] = argument
|
44
|
+
end
|
45
|
+
|
46
|
+
# translate
|
47
|
+
translated = Perfectline::T9n::GoogleTranslator.translate(translation.value, locale, I18n.default_locale)
|
48
|
+
placeholders.each{|value, argument| translated.gsub!(value, "{{#{argument}}}")}
|
49
|
+
|
50
|
+
translation.update_attribute(:value, translated)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def self.needs_human_eyes?(value)
|
61
|
+
return true if value.index('%') # date formats
|
62
|
+
return true if value =~ /^---(.*)\n/ # YAML
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
class GoogleTranslator
|
68
|
+
|
69
|
+
def self.translate(text, to, from='en')
|
70
|
+
|
71
|
+
base = 'http://ajax.googleapis.com/ajax/services/language/translate'
|
72
|
+
|
73
|
+
# assemble query params
|
74
|
+
params = {
|
75
|
+
:langpair => "#{from}|#{to}",
|
76
|
+
:q => text,
|
77
|
+
:v => 1.0
|
78
|
+
}
|
79
|
+
|
80
|
+
query = params.map{ |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
|
81
|
+
|
82
|
+
# send get request
|
83
|
+
response = Net::HTTP.get_response( URI.parse( "#{base}?#{query}" ) )
|
84
|
+
json = JSON.parse( response.body )
|
85
|
+
|
86
|
+
if json['responseStatus'] == 200
|
87
|
+
json['responseData']['translatedText']
|
88
|
+
else
|
89
|
+
raise StandardError, response['responseDetails']
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/tasks/t9n.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
namespace :translations do
|
2
|
+
|
3
|
+
desc "Clear translations cache"
|
4
|
+
task :clear => :environment do
|
5
|
+
I18n.backend.cache_clear!
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Create empty translations keys from the default locale into other available locales"
|
9
|
+
task :populate => :environment do
|
10
|
+
Perfectline::T9n::Util.populate
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Uses google to translate untranslated values. No interpolation"
|
14
|
+
task :google => :environment do
|
15
|
+
Perfectline::T9n::Util.google_translate
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 't9n'
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: t9n
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tanel Suurhans
|
8
|
+
- Tarmo Lehtpuu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-01-29 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
description: A custom AR backend for I18n, translatable model columns and virtual attributes, languages database with integration and some utilities.
|
27
|
+
email:
|
28
|
+
- tanel.suurhans@perfectline.ee
|
29
|
+
- tarmo.lehtpuu@perfectline.ee
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README.markdown
|
36
|
+
files:
|
37
|
+
- MIT-LICENSE
|
38
|
+
- README.markdown
|
39
|
+
- generators/t9n/t9n_generator.rb
|
40
|
+
- generators/t9n/templates/initializer.rb
|
41
|
+
- generators/t9n/templates/language.rb
|
42
|
+
- generators/t9n/templates/migrations/create_languages.rb
|
43
|
+
- generators/t9n/templates/migrations/create_translations.rb
|
44
|
+
- generators/t9n/templates/translation.rb
|
45
|
+
- init.rb
|
46
|
+
- install.rb
|
47
|
+
- lib/t9n.rb
|
48
|
+
- lib/t9n/active_record/translatable_attribute.rb
|
49
|
+
- lib/t9n/backend/active_record.rb
|
50
|
+
- lib/t9n/backend/exception_handler.rb
|
51
|
+
- lib/t9n/backend/extension.rb
|
52
|
+
- lib/t9n/models/language.rb
|
53
|
+
- lib/t9n/models/translation.rb
|
54
|
+
- lib/t9n/util.rb
|
55
|
+
- lib/tasks/t9n.rake
|
56
|
+
- rails/init.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://perfectline.co.uk
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.5
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Translation package including I18n AR backend, translatable attributes and Language database by PerfectLine
|
85
|
+
test_files: []
|
86
|
+
|