weeler 0.0.4 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.rspec +1 -1
- data/.travis.yml +7 -2
- data/CHANGELOG.md +149 -1
- data/LICENSE.txt +2 -2
- data/README.md +83 -1
- data/app/.DS_Store +0 -0
- data/app/assets/javascripts/weeler/init.js.coffee +13 -2
- data/app/assets/javascripts/weeler/lib/notify.js +18 -0
- data/app/assets/javascripts/weeler/lib/sortable.js +9 -0
- data/app/assets/stylesheets/weeler/init.css.erb +2 -1
- data/app/assets/stylesheets/weeler/style.css.scss +22 -0
- data/app/controllers/concerns/weeler/section_seo.rb +16 -0
- data/app/controllers/weeler/administration_controller.rb +11 -0
- data/app/controllers/weeler/application_controller.rb +5 -0
- data/app/controllers/weeler/base_controller.rb +16 -12
- data/app/controllers/weeler/configuration_controller.rb +9 -0
- data/app/controllers/weeler/content_controller.rb +12 -0
- data/app/controllers/weeler/home_controller.rb +5 -2
- data/app/controllers/weeler/seo_items_controller.rb +24 -0
- data/app/controllers/weeler/settings_controller.rb +21 -0
- data/app/controllers/weeler/static_sections_controller.rb +19 -0
- data/app/controllers/weeler/translations_controller.rb +36 -18
- data/app/models/concerns/weeler/seoable.rb +61 -0
- data/app/models/concerns/weeler/sluger.rb +32 -0
- data/app/models/settings.rb +2 -0
- data/app/models/weeler/seo.rb +9 -0
- data/app/views/kaminari/{_first_page.html.erb → weeler/_first_page.html.erb} +1 -1
- data/app/views/kaminari/{_gap.html.erb → weeler/_gap.html.erb} +1 -1
- data/app/views/kaminari/{_last_page.html.erb → weeler/_last_page.html.erb} +1 -1
- data/app/views/kaminari/{_next_page.html.erb → weeler/_next_page.html.erb} +1 -1
- data/app/views/kaminari/{_page.html.erb → weeler/_page.html.erb} +0 -0
- data/app/views/kaminari/{_paginator.html.erb → weeler/_paginator.html.erb} +1 -1
- data/app/views/kaminari/{_prev_page.html.erb → weeler/_prev_page.html.erb} +1 -1
- data/app/views/layouts/weeler/base.html.haml +22 -0
- data/{lib/generators/weeler/templates/views/weeler/example/index.html.erb → app/views/weeler/administration/_filter.html.haml} +0 -0
- data/app/views/weeler/administration/_header_row.html.haml +5 -0
- data/app/views/weeler/administration/_row.html.haml +5 -0
- data/app/views/weeler/administration/_side_navbar.html.haml +8 -0
- data/app/views/weeler/administration/index.html.haml +17 -0
- data/app/views/weeler/administration/welcome.html.haml +5 -0
- data/app/views/weeler/base/_flash.html.haml +3 -0
- data/app/views/weeler/base/_footer.html.haml +2 -0
- data/app/views/weeler/base/_header_navbar.html.haml +19 -0
- data/app/views/weeler/base/_side_navbar.html.haml +2 -0
- data/app/views/weeler/configuration/_side_navbar.html.haml +12 -0
- data/app/views/weeler/configuration/index.html.haml +3 -0
- data/app/views/weeler/content/_error_messages.html.haml +5 -0
- data/app/views/weeler/content/_form.html.haml +6 -0
- data/app/views/weeler/content/_list.html.haml +23 -0
- data/app/views/weeler/content/_object_seo.html.haml +31 -0
- data/app/views/weeler/content/_side_navbar.html.haml +17 -0
- data/app/views/weeler/content/_sortable_list.html.haml +24 -0
- data/app/views/weeler/content/edit.html.haml +2 -0
- data/app/views/weeler/content/index.html.haml +10 -0
- data/app/views/weeler/content/new.html.haml +2 -0
- data/app/views/weeler/content/welcome.html.haml +3 -0
- data/app/views/weeler/home/_side_navbar.html.haml +8 -0
- data/app/views/weeler/home/about.html.haml +15 -0
- data/app/views/weeler/home/index.html.haml +3 -0
- data/app/views/weeler/seo_items/edit.html.haml +28 -0
- data/app/views/weeler/seo_items/index.html.haml +15 -0
- data/app/views/weeler/settings/index.html.haml +19 -0
- data/app/views/weeler/static_sections/show.html.haml +26 -0
- data/app/views/weeler/translations/_form.html.haml +27 -0
- data/app/views/weeler/translations/_translation.html.haml +11 -0
- data/app/views/weeler/translations/edit.html.haml +14 -0
- data/app/views/weeler/translations/index.html.haml +76 -0
- data/app/views/weeler/translations/new.html.haml +13 -0
- data/lib/.DS_Store +0 -0
- data/lib/generators/weeler/.DS_Store +0 -0
- data/lib/generators/weeler/install_generator.rb +30 -26
- data/lib/generators/weeler/templates/assets/javascripts/weeler/app/index.js +2 -0
- data/lib/generators/weeler/templates/assets/stylesheets/weeler/app/index.css +4 -0
- data/lib/generators/weeler/templates/controllers/weeler/application_controller.rb +6 -0
- data/lib/generators/weeler/templates/initializers/weeler.rb +30 -2
- data/lib/generators/weeler/templates/migrations/create_weeler_seos.rb +14 -0
- data/lib/generators/weeler/templates/migrations/create_weeler_settings.rb +17 -0
- data/lib/generators/weeler/templates/migrations/translate_weeler_seos.rb +15 -0
- data/lib/generators/weeler/templates/views/weeler/.keep +0 -0
- data/lib/i18n/backend/weeler.rb +102 -22
- data/lib/i18n/backend/weeler/dedupe.rb +31 -0
- data/lib/i18n/backend/weeler/exporter.rb +67 -5
- data/lib/i18n/backend/weeler/html_checker.rb +41 -0
- data/lib/i18n/backend/weeler/importer.rb +30 -13
- data/lib/i18n/backend/weeler/translation.rb +12 -7
- data/lib/i18n/humanize_missing_translations.rb +1 -0
- data/lib/i18n/weeler.rb +8 -2
- data/lib/tasks/weeler.rake +8 -0
- data/lib/weeler.rb +80 -7
- data/lib/weeler/.DS_Store +0 -0
- data/lib/weeler/action_controller/acts/restful.rb +185 -0
- data/lib/weeler/action_dispatch/routing/mapper.rb +87 -0
- data/lib/weeler/action_view/helpers/form_helper.rb +13 -0
- data/lib/weeler/action_view/helpers/image_form_helper.rb +84 -0
- data/lib/weeler/action_view/helpers/translation_helper.rb +15 -0
- data/lib/weeler/deprecator.rb +9 -0
- data/lib/weeler/engine.rb +18 -4
- data/lib/weeler/version.rb +7 -1
- data/rspec.html +426 -147
- data/spec/.DS_Store +0 -0
- data/spec/controllers/translations_controller_spec.rb +76 -5
- data/spec/dummy/app/controllers/weeler/posts_controller.rb +3 -7
- data/spec/dummy/app/models/post.rb +17 -0
- data/spec/dummy/app/models/translation.rb +2 -0
- data/spec/dummy/config/locales/en.yml +4 -1
- data/spec/dummy/config/routes.rb +3 -3
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140123083704_create_weeler_seos.rb +14 -0
- data/spec/dummy/db/migrate/20140123083705_create_weeler_settings.rb +17 -0
- data/spec/dummy/db/migrate/{20131015144900_create_weeler_translations.rb → 20140123083706_create_weeler_translations.rb} +0 -0
- data/spec/dummy/db/migrate/20140123083707_translate_weeler_seos.rb +15 -0
- data/spec/dummy/db/migrate/20140718103237_create_posts.rb +12 -0
- data/spec/dummy/db/migrate/20140726151210_create_translations.rb +12 -0
- data/spec/dummy/db/schema.rb +59 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +221 -0
- data/spec/factories/dummy_posts.rb +6 -0
- data/spec/fixtures/.DS_Store +0 -0
- data/spec/routing/routes_spec.rb +4 -4
- data/spec/spec_helper.rb +14 -3
- data/spec/weeler/action_controller/acts/restful_spec.rb +155 -0
- data/spec/weeler/action_view/helpers/form_helper_spec.rb +26 -0
- data/spec/weeler/action_view/helpers/translation_helper_spec.rb +16 -0
- data/spec/weeler/i18n/backend/weeler/dedupe_spec.rb +21 -0
- data/spec/weeler/i18n/backend/weeler/exporter_spec.rb +2 -4
- data/spec/weeler/i18n/backend/weeler/importer_spec.rb +5 -2
- data/spec/weeler/i18n/backend/weeler_spec.rb +121 -23
- data/weeler.gemspec +15 -7
- metadata +207 -85
- data/.DS_Store +0 -0
- data/app/assets/stylesheets/weeler/vendor/bootstrap.css +0 -6086
- data/app/views/layouts/weeler/base.html.erb +0 -40
- data/app/views/weeler/home/about.html.erb +0 -16
- data/app/views/weeler/home/index.html.erb +0 -4
- data/app/views/weeler/shared/_flash.html.erb +0 -17
- data/app/views/weeler/shared/_footer.html.erb +0 -3
- data/app/views/weeler/shared/_header_navbar.html.erb +0 -18
- data/app/views/weeler/shared/_side_navbar.html.erb +0 -14
- data/app/views/weeler/translations/_form.html.erb +0 -43
- data/app/views/weeler/translations/_translation.html.erb +0 -11
- data/app/views/weeler/translations/edit.html.erb +0 -19
- data/app/views/weeler/translations/index.html.erb +0 -103
- data/app/views/weeler/translations/new.html.erb +0 -19
- data/lib/generators/weeler/templates/controllers/weeler/example_controller.rb.example +0 -7
- data/lib/i18n/backend/weeler/exporter/active_record.rb +0 -37
- data/lib/i18n/backend/weeler/exporter/active_record_relation.rb +0 -38
- data/lib/i18n/backend/weeler/store_procs.rb +0 -39
- data/lib/weeler/route_mapper.rb +0 -41
- data/spec/dummy/db/production.sqlite3 +0 -0
- data/spec/dummy/log/test.log +0 -88454
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.header.container
|
|
2
|
+
.row
|
|
3
|
+
.col-lg-12.col-md-12
|
|
4
|
+
.page-header
|
|
5
|
+
%h1 New translation
|
|
6
|
+
.edit_user.container
|
|
7
|
+
.row
|
|
8
|
+
.col-lg-12.col-md-12
|
|
9
|
+
= form_for @translation, {url: weeler_translations_path, html: {class: "form-horizontal", role: "form"}} do |f|
|
|
10
|
+
= render partial: "form", locals: {translation: @translation, f: f}
|
|
11
|
+
%p.text-center
|
|
12
|
+
%button.btn.btn-primary{type: "submit"} Save
|
|
13
|
+
%a.btn.btn-link{href: weeler_translations_path} Cancel
|
data/lib/.DS_Store
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -29,14 +29,18 @@ module Weeler
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
#def install_models
|
|
33
|
-
# copy_files 'models', 'app/models'
|
|
34
|
-
#end
|
|
35
|
-
|
|
36
32
|
def install_views
|
|
37
33
|
copy_files 'views', 'app/views'
|
|
38
34
|
end
|
|
39
35
|
|
|
36
|
+
def install_javascripts_assets
|
|
37
|
+
copy_files 'assets/javascripts', 'lib/assets/javascripts'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def install_stylesheets_assets
|
|
41
|
+
copy_files 'assets/stylesheets', 'lib/assets/stylesheets'
|
|
42
|
+
end
|
|
43
|
+
|
|
40
44
|
def install_controllers
|
|
41
45
|
copy_files 'controllers', 'app/controllers'
|
|
42
46
|
end
|
|
@@ -45,37 +49,37 @@ module Weeler
|
|
|
45
49
|
def add_weeler_routes
|
|
46
50
|
weeler_routes = "mount_weeler_at \"weeler\" do \n"
|
|
47
51
|
weeler_routes << " # weeler_resources :example, include_in_weeler_menu: true \n"
|
|
52
|
+
weeler_routes << " # Also you orderable and imageable concerns \n"
|
|
48
53
|
weeler_routes << " end"
|
|
49
54
|
route weeler_routes
|
|
50
55
|
end
|
|
51
56
|
|
|
57
|
+
private
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
raise ArgumetnError if subdir.blank?
|
|
59
|
-
raise ArgumetnError if dest_dir.blank?
|
|
59
|
+
def copy_files subdir, dest_dir
|
|
60
|
+
raise ArgumEnterror unless subdir.is_a? String
|
|
61
|
+
raise ArgumEnterror unless dest_dir.is_a? String
|
|
62
|
+
raise ArgumetnError if subdir.blank?
|
|
63
|
+
raise ArgumetnError if dest_dir.blank?
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
65
|
+
get_file_list(subdir).each do |image|
|
|
66
|
+
copy_file [subdir, image].join('/'), [dest_dir, image].join('/')
|
|
64
67
|
end
|
|
68
|
+
end
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
def get_file_list subdir
|
|
71
|
+
raise ArgumentError unless subdir.is_a? String
|
|
72
|
+
raise ArgumetnError if subdir.blank?
|
|
73
|
+
dir = get_current_dir
|
|
74
|
+
search_path = [dir, 'templates', subdir].join('/') + '/'
|
|
75
|
+
file_list = Dir.glob(search_path + '**/*').map { |filename| File.directory?(filename) ? nil : filename.sub(search_path, '') }
|
|
76
|
+
file_list.delete nil
|
|
77
|
+
return file_list
|
|
78
|
+
end
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
def get_current_dir
|
|
81
|
+
File.dirname(__FILE__)
|
|
82
|
+
end
|
|
79
83
|
|
|
80
84
|
end
|
|
81
85
|
end
|
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
Weeler.setup do |config|
|
|
2
2
|
|
|
3
|
+
# Use Weeler I18n transaltion engine (ActiveRecord store).
|
|
4
|
+
#
|
|
3
5
|
# config.use_weeler_i18n = true
|
|
4
|
-
# config.create_missing_translations
|
|
5
|
-
|
|
6
|
+
# config.create_missing_translations = true # Create translation in database if it missing
|
|
7
|
+
|
|
8
|
+
# Require user method weeler use in before filter. (e.g. require_user)
|
|
9
|
+
#
|
|
10
|
+
# config.required_user_method = nil
|
|
11
|
+
|
|
12
|
+
# You can define logout path (e.g. "/logout")
|
|
13
|
+
#
|
|
14
|
+
# config.logout_path = nil
|
|
15
|
+
|
|
16
|
+
# Menu items in Content section. There you must create resources in app.
|
|
17
|
+
#
|
|
18
|
+
# config.content_menu_items = []
|
|
19
|
+
|
|
20
|
+
# If you don't want to create model in your app and use only single page CMS, then you should use this property.
|
|
21
|
+
# e.g. {about: ['about_us.title', 'about_us.about_text_html', 'about_us.our_company', 'about_us.our_company_text_html']}
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
# config.static_sections = [] # Menu items in Content section under Static. Resourses uses I18n translaitons
|
|
25
|
+
|
|
26
|
+
# Menu items in Administration section. There you must create resources in app.
|
|
27
|
+
#
|
|
28
|
+
# config.administration_menu_items = []
|
|
29
|
+
|
|
30
|
+
# You can exclude translation groups from weeler administration
|
|
31
|
+
# By default theres already excluded [:activerecord, :attributes, :helpers, :views, :i18n, :weeler]
|
|
32
|
+
#
|
|
33
|
+
# config.excluded_i18n_groups += ["number", "date", "scopes", "named_routes", "named_routes_path", "path_names", "errors", "routes"]
|
|
6
34
|
|
|
7
35
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateWeelerSeos < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :weeler_seos do |t|
|
|
4
|
+
t.string :title
|
|
5
|
+
t.text :description
|
|
6
|
+
t.text :keywords
|
|
7
|
+
t.string :section
|
|
8
|
+
t.references :seoable, index: true, polymorphic: true
|
|
9
|
+
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
add_index :weeler_seos, :section
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateWeelerSettings < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :settings do |t|
|
|
4
|
+
t.string :var, :null => false
|
|
5
|
+
t.text :value, :null => true
|
|
6
|
+
t.integer :thing_id, :null => true
|
|
7
|
+
t.string :thing_type, :limit => 30, :null => true
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :settings, [ :thing_type, :thing_id, :var ], :unique => true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.down
|
|
15
|
+
drop_table :settings
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class TranslateWeelerSeos < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
Weeler::Seo.create_translation_table!({
|
|
4
|
+
title: :string,
|
|
5
|
+
description: :text,
|
|
6
|
+
keywords: :text
|
|
7
|
+
}, {
|
|
8
|
+
:migrate_data => true
|
|
9
|
+
})
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.down
|
|
13
|
+
Weeler::Seo.drop_translation_table! :migrate_data => true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
File without changes
|
data/lib/i18n/backend/weeler.rb
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
require 'i18n/backend/base'
|
|
2
2
|
require 'i18n/backend/weeler/translation'
|
|
3
|
+
require 'i18n/backend/weeler/dedupe'
|
|
4
|
+
require 'i18n/backend/weeler/html_checker'
|
|
3
5
|
require 'i18n/backend/weeler/exporter'
|
|
4
6
|
require 'i18n/backend/weeler/importer'
|
|
5
7
|
|
|
6
8
|
module I18n
|
|
7
9
|
module Backend
|
|
10
|
+
# I18n backend by weeler for storing translations in database and caching.
|
|
11
|
+
#
|
|
12
|
+
# It implements storing all translation in <tt>Translation</tt> active record moduel table.
|
|
13
|
+
# When application is running, it stores translation in cache for better performance.
|
|
14
|
+
#
|
|
15
|
+
# Also this backend provides extra moduls:
|
|
16
|
+
# * HTML checher, for storing html translations.
|
|
17
|
+
# * exporter - for export all translations in xlsx
|
|
18
|
+
# * importer - for importing all translations
|
|
19
|
+
# * Dedupe - you should use if you find duplicated keys
|
|
20
|
+
#
|
|
8
21
|
class Weeler
|
|
22
|
+
attr_accessor :i18n_cache
|
|
23
|
+
|
|
9
24
|
PLURAL_KEYS = ["zero", "one", "other"]
|
|
10
25
|
|
|
11
|
-
autoload :
|
|
26
|
+
autoload :HtmlChecker, 'i18n/backend/weeler/html_checker'
|
|
27
|
+
autoload :Translation, 'i18n/backend/weeler/dedupe'
|
|
12
28
|
autoload :Translation, 'i18n/backend/weeler/translation'
|
|
13
29
|
autoload :Exporter, 'i18n/backend/weeler/exporter'
|
|
14
30
|
autoload :Importer, 'i18n/backend/weeler/importer'
|
|
@@ -16,59 +32,123 @@ module I18n
|
|
|
16
32
|
module Implementation
|
|
17
33
|
include Base, Flatten
|
|
18
34
|
|
|
19
|
-
def available_locales
|
|
20
|
-
begin
|
|
21
|
-
Translation.available_locales
|
|
22
|
-
rescue ::ActiveRecord::StatementInvalid
|
|
23
|
-
[]
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
35
|
def store_translations(locale, data, options = {})
|
|
28
36
|
escape = options.fetch(:escape, true)
|
|
29
37
|
flatten_translations(locale, data, escape, false).each do |key, value|
|
|
30
38
|
Translation.locale(locale).lookup(expand_keys(key)).delete_all
|
|
31
|
-
Translation.create(:
|
|
39
|
+
Translation.create(locale: locale.to_s, key: key.to_s, value: value)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reload_cache
|
|
44
|
+
i18n_cache.clear
|
|
45
|
+
|
|
46
|
+
Translation.all.each do |translation|
|
|
47
|
+
i18n_cache.write [translation.locale, translation.key], translation if translation.value.present?
|
|
32
48
|
end
|
|
49
|
+
|
|
50
|
+
i18n_cache.write('UPDATED_AT', Settings.i18n_updated_at) if ActiveRecord::Base.connection.table_exists?('settings')
|
|
33
51
|
end
|
|
34
52
|
|
|
35
53
|
protected
|
|
36
54
|
|
|
37
55
|
def lookup(locale, key, scope = [], options = {})
|
|
38
56
|
key = normalize_flat_keys(locale, key, scope, options[:separator])
|
|
57
|
+
return lookup_in_cache(locale, key, scope, options)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def lookup_in_cache locale, key, scope = [], options = {}
|
|
63
|
+
# reload cache if cache timestamp differs from last translations update
|
|
64
|
+
reload_cache if ((!ActiveRecord::Base.connection.table_exists?('settings')) || i18n_cache.read('UPDATED_AT') != Settings.i18n_updated_at)
|
|
65
|
+
|
|
66
|
+
return nil if i18n_cache.read([:missing, [locale, key]])
|
|
67
|
+
|
|
68
|
+
keys = expand_keys key
|
|
69
|
+
|
|
70
|
+
keys.reverse.each do |check_key|
|
|
71
|
+
|
|
72
|
+
result = i18n_cache.read([locale, check_key])
|
|
73
|
+
|
|
74
|
+
return result.value unless result.blank?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# mark translation as missing
|
|
78
|
+
i18n_cache.write([:missing, [locale, key]], true)
|
|
79
|
+
|
|
80
|
+
if ::Weeler.create_missing_translations
|
|
81
|
+
return store_empty_translation locale, key, options
|
|
82
|
+
else
|
|
83
|
+
return nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def lookup_in_database locale, key, scope = [], options = {}
|
|
39
88
|
result = Translation.locale(locale).lookup(key).load
|
|
40
89
|
|
|
41
90
|
if result.empty?
|
|
42
91
|
if ::Weeler.create_missing_translations
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
92
|
+
return store_empty_translation locale, key, options
|
|
93
|
+
else
|
|
94
|
+
return nil
|
|
46
95
|
end
|
|
47
|
-
nil
|
|
48
96
|
elsif result.first.key == key
|
|
49
|
-
result.first
|
|
97
|
+
translation = result.first
|
|
98
|
+
if translation.value.blank?
|
|
99
|
+
fallback_value = fallback_backend_translation locale, key
|
|
100
|
+
translation.update_attributes value: fallback_value if fallback_value.present?
|
|
101
|
+
end
|
|
102
|
+
return translation.value
|
|
50
103
|
else
|
|
51
104
|
chop_range = (key.size + FLATTEN_SEPARATOR.size)..-1
|
|
52
105
|
result = result.inject({}) do |hash, r|
|
|
53
106
|
hash[r.key.slice(chop_range)] = r.value
|
|
54
107
|
hash
|
|
55
108
|
end
|
|
56
|
-
result.deep_symbolize_keys
|
|
109
|
+
return result.deep_symbolize_keys
|
|
57
110
|
end
|
|
58
111
|
end
|
|
59
112
|
|
|
60
113
|
# For a key :'foo.bar.baz' return ['foo', 'foo.bar', 'foo.bar.baz']
|
|
61
|
-
def expand_keys(
|
|
62
|
-
|
|
114
|
+
def expand_keys(not_expanded_key)
|
|
115
|
+
not_expanded_key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, key|
|
|
63
116
|
keys << [keys.last, key].compact.join(FLATTEN_SEPARATOR)
|
|
64
117
|
end
|
|
65
118
|
end
|
|
66
119
|
|
|
67
120
|
# Store single empty translation
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
121
|
+
def store_empty_translation locale, singular_key, options
|
|
122
|
+
return_value = nil
|
|
123
|
+
interpolations = options.keys - I18n::RESERVED_KEYS
|
|
124
|
+
|
|
125
|
+
keys = options[:count] ? PLURAL_KEYS.map { |k| [singular_key, k].join(FLATTEN_SEPARATOR) } : [singular_key]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
keys.each do |key|
|
|
129
|
+
translation = Weeler::Translation.find_or_initialize_by locale: locale.to_s, key: key
|
|
130
|
+
translation.interpolations = interpolations
|
|
131
|
+
fallback_value = fallback_backend_translation locale, key
|
|
132
|
+
if fallback_value.present?
|
|
133
|
+
translation.value = fallback_value
|
|
134
|
+
translation.save
|
|
135
|
+
reload_cache
|
|
136
|
+
else
|
|
137
|
+
translation.save
|
|
138
|
+
end
|
|
139
|
+
return_value = translation.value
|
|
140
|
+
end
|
|
141
|
+
return_value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def fallback_backend_translation locale, key
|
|
146
|
+
if I18n.backend.backends.size > 1
|
|
147
|
+
alternative_backend = I18n.backend.backends[1]
|
|
148
|
+
alternative_backend.send(:lookup, locale, key)
|
|
149
|
+
else
|
|
150
|
+
nil
|
|
151
|
+
end
|
|
72
152
|
end
|
|
73
153
|
|
|
74
154
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# This module is intended to be mixed into the Weeler backend to allow
|
|
2
|
+
# remove all dublicates from translation table
|
|
3
|
+
#
|
|
4
|
+
# I18n.backend = I18n::Backend::Weeler.new
|
|
5
|
+
# I18n::Backend::Weeler::Translation.send(:include, I18n::Backend::Weeler::Dedupe)
|
|
6
|
+
|
|
7
|
+
module I18n
|
|
8
|
+
module Backend
|
|
9
|
+
class Weeler
|
|
10
|
+
module Dedupe
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
def dedupe
|
|
15
|
+
# find all models and group them on keys which should be common
|
|
16
|
+
grouped = all.group_by{|model| [model.locale,model.key] }
|
|
17
|
+
grouped.values.each do |duplicates|
|
|
18
|
+
# the first one we want to keep right?
|
|
19
|
+
first_one = duplicates.shift # or pop for last one
|
|
20
|
+
# if there are any more left, they are duplicates
|
|
21
|
+
# so delete all of them
|
|
22
|
+
duplicates.each{|double| double.destroy} # duplicates can now be destroyed
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Translation.send(:include, Dedupe)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
# Weeler I18n backend export helper module.
|
|
2
|
+
#
|
|
3
|
+
# Export all translations in excel (xlsx)
|
|
4
|
+
#
|
|
5
|
+
# def export
|
|
6
|
+
# respond_to do |format|
|
|
7
|
+
# format.xlsx do
|
|
8
|
+
# outstrio = StringIO.new
|
|
9
|
+
# outstrio.write(I18n::Backend::Weeler::Translation.all.as_xlsx_package.to_stream.read)
|
|
10
|
+
# send_data(outstrio.string, filename: "translations" + '.xlsx')
|
|
11
|
+
# end
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
|
|
1
15
|
begin
|
|
2
16
|
require 'axlsx'
|
|
3
|
-
require 'i18n/backend/weeler/exporter/active_record'
|
|
4
|
-
require 'i18n/backend/weeler/exporter/active_record_relation'
|
|
5
17
|
rescue LoadError => e
|
|
6
18
|
puts "can't use Exporter because: #{e.message}"
|
|
7
19
|
end
|
|
@@ -9,10 +21,60 @@ end
|
|
|
9
21
|
module I18n
|
|
10
22
|
module Backend
|
|
11
23
|
class Weeler
|
|
24
|
+
module Exporter
|
|
25
|
+
extend ActiveSupport::Concern
|
|
26
|
+
|
|
27
|
+
module ClassMethods
|
|
28
|
+
|
|
29
|
+
# Prepare xlsx package from current scope
|
|
30
|
+
# Stores all translations in translations worksheet.
|
|
31
|
+
def as_xlsx_package
|
|
32
|
+
package = Axlsx::Package.new
|
|
33
|
+
package.use_shared_strings = true
|
|
34
|
+
|
|
35
|
+
sheet = package.workbook.add_worksheet(name: "translations")
|
|
36
|
+
|
|
37
|
+
locales = I18n.available_locales
|
|
38
|
+
sheet.add_row(Translation.title_row(locales))
|
|
12
39
|
|
|
13
|
-
|
|
14
|
-
|
|
40
|
+
types = []
|
|
41
|
+
(locales.size + 1).times { types << :string }
|
|
15
42
|
|
|
43
|
+
included_keys = []
|
|
44
|
+
|
|
45
|
+
self.current_scope.each do |translation|
|
|
46
|
+
unless included_keys.include? translation.key
|
|
47
|
+
sheet.add_row(Translation.translation_row_by_key_and_locales(translation.key, locales), types: types)
|
|
48
|
+
included_keys << translation.key
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
return package
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def title_row locales
|
|
55
|
+
row = [ 'Key' ]
|
|
56
|
+
locales.each do |locale|
|
|
57
|
+
row.push(locale.capitalize)
|
|
58
|
+
end
|
|
59
|
+
row
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def translation_row_by_key_and_locales key, locales
|
|
63
|
+
row = [ key ]
|
|
64
|
+
locales.each do |locale|
|
|
65
|
+
result = Translation.locale(locale).lookup(key).load
|
|
66
|
+
if result.first.present?
|
|
67
|
+
row.push(result.first.value)
|
|
68
|
+
else
|
|
69
|
+
row.push("")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
row
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Translation.send(:include, self)
|
|
77
|
+
end
|
|
16
78
|
end
|
|
17
79
|
end
|
|
18
|
-
end
|
|
80
|
+
end
|