gettext-setup 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8cb929527d234a142edba900b86ff9b1e2a8543d
4
+ data.tar.gz: cdb14138a6bcc08bad38ac0acf373a3e53f36e97
5
+ SHA512:
6
+ metadata.gz: eb0462b300efe1a2e63239f849e4cc3cc228ea03faed2747570dac0cec5107c85999115dd21e6445ca36b39a4bb81069cdb63ac79a578d0757bc143d6fb84299
7
+ data.tar.gz: 733995b80a2dd5865746ec4e2d48bf8a7b0071b6d04686df69938e753763deed50ce74388c13e793f2acab1c71fa964cdf9e4410842aabcc72ba7d41e724be55
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'fast_gettext'
4
+
5
+ gem 'rake', :require => false
6
+
7
+ group :development do
8
+ gem 'gettext', ">= 3.0.2"
9
+ end
@@ -0,0 +1,18 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ fast_gettext (1.0.0)
5
+ gettext (3.2.1)
6
+ locale (>= 2.0.5)
7
+ text (>= 1.3.0)
8
+ locale (2.1.2)
9
+ rake (10.4.2)
10
+ text (1.3.1)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ fast_gettext
17
+ gettext (>= 3.0.2)
18
+ rake
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ gettext-setup gem
2
+
3
+ Copyright (C) 2016 Puppet, Inc.
4
+
5
+ Puppet, Inc. can be contacted at: info@puppet.com
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ https://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,105 @@
1
+ # gettext-setup gem
2
+
3
+ This is a simple gem to set up i18n for Ruby projects (including [Sinatra](www.sinatrarb.com/) web apps) using gettext and fast gettext.
4
+
5
+ This project sets the default locale to English. If the user has set a different locale in their browser preferences, and we support the user's preferred locale, strings and data formatting will be customized for that locale.
6
+
7
+ ## Terminology
8
+
9
+ **Translatable strings** - User-facing strings that are in scope for i18n (see the in scope/out of scope sections [here](https://confluence.puppetlabs.com/display/ENG/i18n#i18n-TasksandMilestones)).
10
+
11
+ **POT file** - Portable Objects Template. This is the file that stores externalized English strings. It includes the source file and line number of the string.
12
+
13
+ **PO file** - A bilingual file containing the source English strings (msgid) and target language strings (msgstr). This file is generated from the POT file and is where translated strings are added. A PO file is generated for each language.
14
+
15
+ **Transifex** - A translation management system. When PO files are updated, the updates are pulled into Transifex and translated there.
16
+
17
+ ## Setup for your project
18
+
19
+ These are the poingant bits of this example that you need to replicate in
20
+ your project:
21
+
22
+ 1. Add `gem 'gettext-setup'` to your `Gemfile`.
23
+ 1. Add `gem 'fast_gettext'` to your `Gemfile`. This line is only needed
24
+ for running the bundled `rake` task.
25
+ 1. Copy `locales/config-sample.yaml` to your project and put it into a
26
+ `locales` directory as `config.yaml`.
27
+ 1. Edit `locales/config.yaml` and make the necessary changes for your
28
+ project
29
+ 1. Add these three lines to your `Rakefile`:
30
+ ```
31
+ spec = Gem::Specification.find_by_name 'gettext-setup'
32
+ load "#{spec.gem_dir}/lib/tasks/gettext.rake"
33
+ GettextSetup.initialize(File.absolute_path('locales', File.dirname(__FILE__)))
34
+ ```
35
+ 1. Add this line to the top of your `app.rb`:
36
+ `require 'gettext-setup'`
37
+ 1. Add these lines inside the class declared in your `app.rb`:
38
+ ```
39
+ include FastGettext::Translation
40
+ GettextSetup.initialize(File.absolute_path('locales', File.dirname(__FILE__)))
41
+ before do
42
+ FastGettext.locale = GettextSetup.negotiate_locale(env["HTTP_ACCEPT_LANGUAGE"])
43
+ end
44
+ ```
45
+
46
+ ## Writing translatable code
47
+
48
+ ### Use full sentences
49
+ Write user-facing strings as full sentences rather than joining multiple strings to form a full sentence because the word order in other languages can be different to English. See [Tips on writing translation-friendly strings](https://confluence.puppetlabs.com/display/ENG/Tips+for+writing+translation-friendly+strings).
50
+
51
+ ### Use the translation function _()
52
+ Wrap user-facing strings in the `_()` function so they can be externalized to a POT file.
53
+
54
+ E.g. `_("Hello, world!")`
55
+
56
+ ### Interpolation
57
+ To add dynamic data to a string, use the following string formatting and translation function:
58
+
59
+ `_("We negotiated a locale of %{locale}") % {locale: FastGettext.locale}`
60
+
61
+ ### Pluralize with the n_() function
62
+
63
+ Wrap strings that include pluralization with the `n_()` function.
64
+
65
+ E.g. `n_("There is %{count} bicycle in %{city}", "There are %{count} bicycles in %{city}", num_bikes) % {count: num_bikes, city: "Beijing"},`
66
+
67
+ Pluralization rules vary across languages. The pluralization rules are specified in the PO file and look something like this `Plural-Forms: nplurals=2; plural=(n > 1);`. This is the pluralization rule for German. It means that German has two pluralization rules. The first rule is `plural=n > 1)` and the second rule is all other counts.
68
+
69
+ Plurals are selected from the PO file by index. Here's an example of how a
70
+ pluralized string is handled in a PO file:
71
+
72
+ `msgid "%{count} file"
73
+ `msgid_plural "%{count} files"
74
+ `msgstr[0] "%{count} Dateien"
75
+ `msgstr[1] "%{count} Datei"
76
+
77
+ The `msgid` is the singular version of the English source string that's pulled in to the POT file and PO from the code file.
78
+
79
+ The `msgid_plural` is the plural version of the English source string.
80
+
81
+ The two `msgstr` lines show that German has two rules for pluralization. The indices map to the `Plural-Forms: nplurals=2; plural=(n > 1);` rule that we specified in the PO file. The `[0]` index represents `plural=(n > 1)` and the `[1]` index represents all other pluralization cases (in other words, when the count equals 0 or 1).
82
+
83
+ ### Comments
84
+ To provide translators with some contextual information or instructions about a string, precede the string with a comment. Start the comment with "TRANSLATOR: " to make it obvious that you are providing instructions for the translator. The comment gets pulled in to the POT file and will show up as a comment in Transifex.
85
+
86
+ E.g. `# TRANSLATOR: The placeholder in this string represents the name of a parameter.`
87
+
88
+ ## Translation workflow
89
+
90
+ 1. Wrap the translation function around translatable strings in code files
91
+
92
+ 2. Run `rake gettext:pot` to parse the source code and extract translatable strings into the message catalog in `locales/<project_name>.pot`. If a POT file already exists, this rake task will update the POT file. Do this before making a pull request that includes changes to user-facing strings.
93
+
94
+ 3. Run `rake gettext:po[<lang>]` to create/update language-specific PO files. This step will be managed by the localization team, and will usually happen prior to a new release.
95
+
96
+ 4. When a PO file is updated, a git hook is used to automatically pull the new/updated strings into Transifex ready for translation.
97
+
98
+ 5. When the PO file reaches 100% translated and reviewed in Transifex, it is pulled back into the locale folder.
99
+
100
+ 6. PE checks the user's locale settings (the browser settings for web apps, or the system settings for the CLI). If we support the preferred locale, PE uses the PO file for that locale. Otherwise, it uses the default locale (en_US).
101
+
102
+ ## TODO
103
+
104
+ 1. Locale-specific formatting of numbers, dates, etc.
105
+ 2. Separate out the locales that are supported for testing/dev and production so we can add test translations without shipping them.
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+
3
+ require_relative './lib/gettext-setup/gettext_setup.rb'
4
+
5
+ import 'lib/tasks/gettext.rake'
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "gettext-setup"
7
+ spec.version = "0.1"
8
+ spec.authors = ["Puppet"]
9
+ spec.email = ["info@puppet.com"]
10
+ spec.description = "A gem to ease i18n"
11
+ spec.summary = "A gem to ease internationalization with fast_gettext"
12
+ spec.homepage = "https://github.com/puppetlabs/gettext-setup-gem"
13
+ spec.license = "ASL2"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.test_files = spec.files.grep(%r{^spec/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake"
21
+ end
@@ -0,0 +1 @@
1
+ require 'gettext-setup/gettext_setup'
@@ -0,0 +1,82 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'fast_gettext'
3
+ require 'yaml'
4
+
5
+ module GettextSetup
6
+ @@config = nil
7
+
8
+ # `locales_path` should include:
9
+ # - config.yaml
10
+ # - a .pot file for the project
11
+ # - i18n directories for languages, each with a .po file
12
+ def self.initialize(locales_path)
13
+ config_path = File.absolute_path('config.yaml', locales_path)
14
+ @@config = YAML.load_file(config_path)['gettext']
15
+ @@locales_path = locales_path
16
+
17
+ # Make the translation methods available everywhere
18
+ Object.send(:include, FastGettext::Translation)
19
+
20
+ # Define our text domain, and set the path into our root. I would prefer to
21
+ # have something smarter, but we really want this up earlier even than our
22
+ # config loading happens so that errors there can be translated.
23
+ #
24
+ # We use the PO files directly, since it works about as efficiently with
25
+ # fast_gettext, and avoids all the extra overhead of compilation down to
26
+ # machine format, etc.
27
+ FastGettext.add_text_domain(config['project_name'],
28
+ :path => locales_path,
29
+ :type => :po,
30
+ :ignore_fuzzy => false)
31
+ FastGettext.default_text_domain = config['project_name']
32
+
33
+ # Likewise, be explicit in our default language choice.
34
+ FastGettext.default_locale = default_locale
35
+ FastGettext.default_available_locales = locales
36
+ end
37
+
38
+ def self.locales_path
39
+ @@locales_path
40
+ end
41
+
42
+ def self.config
43
+ @@config
44
+ end
45
+
46
+ def self.default_locale
47
+ config['default_locale'] || "en"
48
+ end
49
+
50
+ def self.locales
51
+ explicit = Dir.glob(File::absolute_path('*/*.po', locales_path)).map do |x|
52
+ File::basename(File::dirname(x))
53
+ end
54
+ (explicit + [ default_locale]).uniq
55
+ end
56
+
57
+ # Given an HTTP Accept-Language header return the locale with the highest
58
+ # priority from it for which we have a locale available. If none exists,
59
+ # return the default locale
60
+ def self.negotiate_locale(accept_header)
61
+ unless @@config
62
+ raise ArgumentError, "No config.yaml found! Use `GettextSetup.initialize(locales_path)` to locate your config.yaml"
63
+ end
64
+ return FastGettext.default_locale if accept_header.nil?
65
+ available_locales = accept_header.split(",").map do |locale|
66
+ pair = locale.strip.split(';q=')
67
+ pair << '1.0' unless pair.size == 2
68
+ pair[0] = FastGettext.default_locale if pair[0] == '*'
69
+ pair
70
+ end.sort_by do |(locale,qvalue)|
71
+ qvalue.to_f
72
+ end.select do |(locale,_)|
73
+ FastGettext.available_locales.include?(locale)
74
+ end
75
+ if available_locales and available_locales.last
76
+ available_locales.last.first
77
+ else
78
+ # We can't satisfy the request preference. Just use the default locale.
79
+ default_locale
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,66 @@
1
+ # require 'bundler'
2
+ # puts File.absolute_path('Gemfile', Dir.pwd)
3
+ # Bundler.read_file(File.absolute_path('Gemfile', Dir.pwd))
4
+ #
5
+ require_relative '../gettext-setup/gettext_setup'
6
+ #
7
+ # GettextSetup.initialize(File.absolute_path('locales', Dir.pwd))
8
+
9
+ namespace :gettext do
10
+
11
+ def locale_path
12
+ GettextSetup.locales_path
13
+ end
14
+
15
+ def text_domain
16
+ FastGettext.text_domain
17
+ end
18
+
19
+ def files_to_translate
20
+ GettextSetup.config['source_files'].map do |p|
21
+ Dir.glob(p)
22
+ end.flatten
23
+ end
24
+
25
+ def pot_file_path
26
+ File.join(locale_path, GettextSetup.config['project_name'] + ".pot")
27
+ end
28
+
29
+ desc "Update pot files"
30
+ task :pot do
31
+ package_name = GettextSetup.config['package_name']
32
+ project_name = GettextSetup.config['project_name']
33
+ bugs_address = GettextSetup.config['bugs_address']
34
+ copyright_holder = GettextSetup.config['copyright_holder']
35
+ version=`git describe`
36
+ system("rxgettext -o locales/#{project_name}.pot --no-wrap --sort-by-file " +
37
+ "--add-comments --msgid-bugs-address '#{bugs_address}' " +
38
+ "--package-name '#{package_name}' " +
39
+ "--package-version '#{version}' " +
40
+ "--copyright-holder='#{copyright_holder}' --copyright-year=#{Time.now.year} " +
41
+ "#{files_to_translate.join(" ")}")
42
+ puts "POT file locales/#{project_name}.pot has been updated"
43
+ end
44
+
45
+ desc "Update po file for a specific language"
46
+ task :po, [:language] do |_, args|
47
+ language = args.language || ENV["LANGUAGE"]
48
+
49
+ # Let's do some pre-verification of the environment.
50
+ if language.nil?
51
+ puts "You need to specify the language to add. Either 'LANGUAGE=eo rake gettext:po' or 'rake gettext:po[LANGUAGE]'"
52
+ next
53
+ end
54
+
55
+ language_path = File.join(locale_path, language)
56
+ mkdir_p(language_path)
57
+
58
+ po_file_path = File.join(language_path,
59
+ GettextSetup.config['project_name'] + ".po")
60
+ if File.exists?(po_file_path)
61
+ system("msgmerge -U #{po_file_path} #{pot_file_path}")
62
+ else
63
+ system("msginit --no-translator -l #{language} -o #{po_file_path} -i #{pot_file_path}")
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ ---
2
+ # This is the project-specific configuration file for setting up
3
+ # fast_gettext for your project.
4
+ gettext:
5
+ # This is used for the name of the .pot and .po files; they will be
6
+ # called <project_name>.pot?
7
+ project_name: 'sinatra-i18n'
8
+ # This is used in comments in the .pot and .po files to indicate what
9
+ # project the files belong to and should bea little more desctiptive than
10
+ # <project_name>
11
+ package_name: Sinatra i18n demo
12
+ # The locale that the default messages in the .pot file are in
13
+ default_locale: en
14
+ # The email used for sending bug reports.
15
+ bugs_address: docs@puppetlabs.com
16
+ # The holder of the copyright.
17
+ copyright_holder: Puppet Labs, LLC.
18
+ # Patterns for +Dir.glob+ used to find all files that might contain
19
+ # translatable content, relative to the project root directory
20
+ source_files:
21
+ - 'app.rb'
22
+ - 'lib/**/*.rb'
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gettext-setup
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Puppet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ~>
17
+ - !ruby/object:Gem::Version
18
+ version: '1.3'
19
+ name: bundler
20
+ prerelease: false
21
+ type: :development
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: rake
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A gem to ease i18n
42
+ email:
43
+ - info@puppet.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Gemfile
49
+ - Gemfile.lock
50
+ - LICENSE
51
+ - README.md
52
+ - Rakefile
53
+ - gettext-setup.gemspec
54
+ - lib/gettext-setup.rb
55
+ - lib/gettext-setup/gettext_setup.rb
56
+ - lib/tasks/gettext.rake
57
+ - locales/config-sample.yaml
58
+ homepage: https://github.com/puppetlabs/gettext-setup-gem
59
+ licenses:
60
+ - ASL2
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
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
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.4.4
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: A gem to ease internationalization with fast_gettext
82
+ test_files: []
83
+ has_rdoc: