autolang 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/Gemfile +11 -0
- data/Gemfile.lock +36 -0
- data/Rakefile +18 -0
- data/Readme.md +48 -0
- data/VERSION +1 -0
- data/autolang.gemspec +48 -0
- data/lib/autolang.rb +68 -0
- data/lib/tasks/autolang.rake +75 -0
- data/spec/autolang_spec.rb +84 -0
- metadata +103 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.0.4)
|
5
|
+
diff-lcs (1.1.2)
|
6
|
+
git (1.2.5)
|
7
|
+
i18n (0.5.0)
|
8
|
+
jeweler (1.5.2)
|
9
|
+
bundler (~> 1.0.0)
|
10
|
+
git (>= 1.2.5)
|
11
|
+
rake
|
12
|
+
json (1.5.1)
|
13
|
+
mocha (0.9.12)
|
14
|
+
rake (0.8.7)
|
15
|
+
rspec (2.5.0)
|
16
|
+
rspec-core (~> 2.5.0)
|
17
|
+
rspec-expectations (~> 2.5.0)
|
18
|
+
rspec-mocks (~> 2.5.0)
|
19
|
+
rspec-core (2.5.1)
|
20
|
+
rspec-expectations (2.5.0)
|
21
|
+
diff-lcs (~> 1.1.2)
|
22
|
+
rspec-mocks (2.5.0)
|
23
|
+
sishen-rtranslate (1.5)
|
24
|
+
activesupport (>= 2.2.0)
|
25
|
+
json (>= 1.1.3)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
i18n
|
32
|
+
jeweler
|
33
|
+
mocha
|
34
|
+
rake
|
35
|
+
rspec
|
36
|
+
sishen-rtranslate
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
task :default do
|
2
|
+
sh "rspec spec"
|
3
|
+
end
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = 'autolang'
|
9
|
+
gem.summary = "Kick-start new translation via google translate"
|
10
|
+
gem.email = "michael@grosser.it"
|
11
|
+
gem.homepage = "http://github.com/grosser/#{gem.name}"
|
12
|
+
gem.authors = ["Chris Blackburn", "Michael Grosser"]
|
13
|
+
end
|
14
|
+
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
18
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
Autolang
|
2
|
+
========
|
3
|
+
|
4
|
+
Goal
|
5
|
+
====
|
6
|
+
- Kick-start your translation!
|
7
|
+
- Translate all your Gettext - msgids to another language using google-translate.
|
8
|
+
- Provide a simple interface for other translation tasks
|
9
|
+
|
10
|
+
|
11
|
+
Install
|
12
|
+
=======
|
13
|
+
|
14
|
+
gem install autolang
|
15
|
+
|
16
|
+
Add to Gemfile
|
17
|
+
gem "autolang", :group=>:development
|
18
|
+
|
19
|
+
OR as Rails plugin
|
20
|
+
rails plugin install git://github.com/grosser/autolang.git
|
21
|
+
|
22
|
+
OR copy rake tasks
|
23
|
+
curl https://github.com/grosser/autolang/raw/master/lib/tasks/autolang.rake > lib/tasks/autolang.rake
|
24
|
+
|
25
|
+
Usage
|
26
|
+
=====
|
27
|
+
Translate your pot file to any other language:
|
28
|
+
|
29
|
+
# to translate into spanish (=es), when current apps name is myapp (from myapp.pot)
|
30
|
+
L=es POT_FILE=/app/po/my_app.pot rake autolang:translate
|
31
|
+
|
32
|
+
Translation examples
|
33
|
+
====================
|
34
|
+
- Car|Engine -> Motor
|
35
|
+
- hello %{name} -> hallo %{name}
|
36
|
+
|
37
|
+
TODO
|
38
|
+
====
|
39
|
+
- Do not convert "& to "and", use something 'smarter'.
|
40
|
+
|
41
|
+
Authors
|
42
|
+
=======
|
43
|
+
Original by [Chris Blackburn](cbciweb.com) released under MIT license
|
44
|
+
|
45
|
+
Enhanced by
|
46
|
+
|
47
|
+
- [Michael Grosser](http://grosser.it)
|
48
|
+
- [Hans Engel](http://engel.uk.to/)
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/autolang.gemspec
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{autolang}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Chris Blackburn", "Michael Grosser"]
|
12
|
+
s.date = %q{2011-03-19}
|
13
|
+
s.email = %q{michael@grosser.it}
|
14
|
+
s.files = [
|
15
|
+
"Gemfile",
|
16
|
+
"Gemfile.lock",
|
17
|
+
"Rakefile",
|
18
|
+
"Readme.md",
|
19
|
+
"VERSION",
|
20
|
+
"autolang.gemspec",
|
21
|
+
"lib/autolang.rb",
|
22
|
+
"lib/tasks/autolang.rake",
|
23
|
+
"spec/autolang_spec.rb"
|
24
|
+
]
|
25
|
+
s.homepage = %q{http://github.com/grosser/autolang}
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
s.rubygems_version = %q{1.4.2}
|
28
|
+
s.summary = %q{Kick-start new translation via google translate}
|
29
|
+
s.test_files = [
|
30
|
+
"spec/autolang_spec.rb"
|
31
|
+
]
|
32
|
+
|
33
|
+
if s.respond_to? :specification_version then
|
34
|
+
s.specification_version = 3
|
35
|
+
|
36
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
37
|
+
s.add_runtime_dependency(%q<i18n>, [">= 0"])
|
38
|
+
s.add_runtime_dependency(%q<sishen-rtranslate>, [">= 0"])
|
39
|
+
else
|
40
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
41
|
+
s.add_dependency(%q<sishen-rtranslate>, [">= 0"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
45
|
+
s.add_dependency(%q<sishen-rtranslate>, [">= 0"])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/lib/autolang.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rtranslate'
|
2
|
+
require 'rtranslate/language'
|
3
|
+
|
4
|
+
class Autolang
|
5
|
+
VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
|
6
|
+
|
7
|
+
def self.extract_msgid(text)
|
8
|
+
return nil if text.match(/^msgid/).nil?
|
9
|
+
msgid = text.scan(/"(.+)"/)[0]
|
10
|
+
return nil if msgid.nil?
|
11
|
+
msgid[0].to_s.gsub(' | ','|')
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.translate(text)
|
15
|
+
e = TranslationEscaper.new(text)
|
16
|
+
|
17
|
+
@translator = Translate::RTranslate.new unless @translator
|
18
|
+
e.unescape @translator.translate(e.escaped, :from => 'ENGLISH', :to => ENV['L'].dup, :userip => '127.0.0.1')
|
19
|
+
end
|
20
|
+
|
21
|
+
# protects text from evil translation robots
|
22
|
+
# by ensuring phrases that should not be translated (Car|Engine, %{name}, ...)
|
23
|
+
# stay untranslated
|
24
|
+
class TranslationEscaper
|
25
|
+
attr_accessor :escaped
|
26
|
+
|
27
|
+
def initialize(text)
|
28
|
+
@text = text
|
29
|
+
self.escaped = escape_text
|
30
|
+
end
|
31
|
+
|
32
|
+
def unescape(translation)
|
33
|
+
remove_placeholders(translation)
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def escape_text
|
39
|
+
@placeholders = []
|
40
|
+
text = @text
|
41
|
+
if text =~ /^([^\s]+\|)/
|
42
|
+
@cut_off = $1
|
43
|
+
text = text.sub($1,'')
|
44
|
+
end
|
45
|
+
text = add_placeholder(text, /(%\{.+\})/ )
|
46
|
+
text = text.gsub('&','and')#& cannot be translated
|
47
|
+
end
|
48
|
+
|
49
|
+
# replace stuff that would get messed up in translation
|
50
|
+
# through a non-translateable placeholder
|
51
|
+
def add_placeholder(text,regex)
|
52
|
+
if text =~ regex
|
53
|
+
@placeholders << $1
|
54
|
+
text = text.sub($1,"PH#{@placeholders.length-1}")
|
55
|
+
end
|
56
|
+
text
|
57
|
+
end
|
58
|
+
|
59
|
+
# swap placeholders with original values
|
60
|
+
def remove_placeholders(text)
|
61
|
+
@placeholders.each_index do |i|
|
62
|
+
replaced = @placeholders[i]
|
63
|
+
text = text.sub("PH#{i}",replaced)
|
64
|
+
end
|
65
|
+
text
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# Copyright © 2008 Chris Blackburn <cblackburn : at : cbciweb.com>
|
4
|
+
#
|
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
|
+
require 'autolang'
|
17
|
+
|
18
|
+
namespace :autolang do
|
19
|
+
desc "Translate strings into a new language."
|
20
|
+
task :translate do
|
21
|
+
if !ENV['L'] or !ENV['POT_FILE']
|
22
|
+
puts "Usage: L=language_code POT_FILE=po/my_app.pot rake autolang:translate"
|
23
|
+
puts " language_codes are 2 letter ISO 639 codes "
|
24
|
+
puts " if you do not have a pot file, use gettext and updatepo first (google helps...)"
|
25
|
+
puts ""
|
26
|
+
puts "Example: Translate all msgids into Spanish."
|
27
|
+
puts " L=es POT_FILE=po/my_app.pot rake autolang:translate"
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
|
31
|
+
pot_file = ENV['POT_FILE']
|
32
|
+
po_file = File.join(File.dirname(pot_file),ENV['L'],"#{ENV['L']}.po")
|
33
|
+
|
34
|
+
# If the directory doesn't exist created it
|
35
|
+
lang_dir = File.dirname(po_file)
|
36
|
+
if !FileTest.exist?(lang_dir)
|
37
|
+
puts "Creating new language directory: #{lang_dir}"
|
38
|
+
Dir.mkdir(lang_dir)
|
39
|
+
end
|
40
|
+
|
41
|
+
# copy the main po file if it doesn't exist
|
42
|
+
if !FileTest.exist?(po_file)
|
43
|
+
puts "Generating new language file: #{po_file}"
|
44
|
+
`msginit -i #{pot_file} -o #{po_file} -l #{ENV['L']}`
|
45
|
+
end
|
46
|
+
|
47
|
+
# translate existing po file
|
48
|
+
lines = []
|
49
|
+
msgid = ""
|
50
|
+
msgstr = ""
|
51
|
+
puts "Translating..."
|
52
|
+
File.foreach(po_file) do |line|
|
53
|
+
#read string to translate
|
54
|
+
if msgid = Autolang.extract_msgid(line)
|
55
|
+
puts msgid
|
56
|
+
puts msgstr = Autolang.translate(msgid)
|
57
|
+
puts '-'*80
|
58
|
+
|
59
|
+
#replace translation
|
60
|
+
elsif line =~ /^msgstr/
|
61
|
+
unless msgstr.empty?
|
62
|
+
line = "msgstr \"#{msgstr}\""
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#output to po file
|
67
|
+
lines << line.strip
|
68
|
+
end
|
69
|
+
|
70
|
+
#write new translation file
|
71
|
+
File.open(po_file, "w+") do |file|
|
72
|
+
file.write(lines*"\n")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'mocha'
|
5
|
+
$LOAD_PATH.unshift 'lib'
|
6
|
+
require 'autolang'
|
7
|
+
|
8
|
+
describe Autolang do
|
9
|
+
it "has a VERSION" do
|
10
|
+
Autolang::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
11
|
+
end
|
12
|
+
|
13
|
+
describe :extract_msgid do
|
14
|
+
it "finds message in text" do
|
15
|
+
Autolang.extract_msgid('msgid "hello"').should == 'hello'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "does not find empty message" do
|
19
|
+
Autolang.extract_msgid('msgid ""').should == nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not find non-existing message" do
|
23
|
+
Autolang.extract_msgid('msgstr "hello"').should == nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe :translate do
|
28
|
+
before do
|
29
|
+
ENV['L']='es'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "translates a word" do
|
33
|
+
Autolang.translate('hello').should == 'hola'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "converts html entities" do
|
37
|
+
Autolang.translate('sales & tax').should == 'impuesto sobre ventas y'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "converts html entities back" do
|
41
|
+
Autolang.translate('"&&&"').should == '"Andandand"'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "translates with strange signs" do
|
45
|
+
Autolang.translate('production').should == 'producción'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "translates with | " do
|
49
|
+
Autolang.translate('Auto|hello').should == 'hola'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "translates with %{}" do
|
53
|
+
Autolang.translate('hello %{name}').should == 'hola %{name}'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Autolang::TranslationEscaper do
|
59
|
+
t = Autolang::TranslationEscaper
|
60
|
+
describe :escaped do
|
61
|
+
it "replaces piped subsections" do
|
62
|
+
e = t.new('Car|be gone')
|
63
|
+
e.escaped.should == 'be gone'
|
64
|
+
e.unescape('geh weg').should == 'geh weg'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "does not replace regular pipes" do
|
68
|
+
e = t.new('Eat my pipe | fool')
|
69
|
+
e.escaped.should == 'Eat my pipe | fool'
|
70
|
+
e.unescape('Iss mein Rohr | idiot').should == 'Iss mein Rohr | idiot'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "replaces %{something}" do
|
74
|
+
e = t.new('can i have a %{name}, please.')
|
75
|
+
e.escaped.should == 'can i have a PH0, please.'
|
76
|
+
e.unescape('kann ich bitte ein PH0 haben.').should == 'kann ich bitte ein %{name} haben.'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "replaces at the end of sentences" do
|
80
|
+
e = t.new('hello %{name}')
|
81
|
+
e.unescape('hello PH0').should == 'hello %{name}'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: autolang
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chris Blackburn
|
14
|
+
- Michael Grosser
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-03-19 00:00:00 +01:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
requirement: *id001
|
34
|
+
name: i18n
|
35
|
+
prerelease: false
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
requirement: *id002
|
48
|
+
name: sishen-rtranslate
|
49
|
+
prerelease: false
|
50
|
+
description:
|
51
|
+
email: michael@grosser.it
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- Gemfile
|
60
|
+
- Gemfile.lock
|
61
|
+
- Rakefile
|
62
|
+
- Readme.md
|
63
|
+
- VERSION
|
64
|
+
- autolang.gemspec
|
65
|
+
- lib/autolang.rb
|
66
|
+
- lib/tasks/autolang.rake
|
67
|
+
- spec/autolang_spec.rb
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://github.com/grosser/autolang
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.4.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Kick-start new translation via google translate
|
102
|
+
test_files:
|
103
|
+
- spec/autolang_spec.rb
|