lesli_babel 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.
- checksums.yaml +7 -0
- data/Rakefile +5 -0
- data/app/assets/config/lesli_babel_manifest.js +7 -0
- data/app/assets/images/lesli_babel/babel-logo.svg +157 -0
- data/app/assets/javascripts/lesli_babel/application.js +3288 -0
- data/app/assets/stylesheets/lesli_babel/application.scss +41 -0
- data/app/assets/stylesheets/lesli_babel/dashboards.scss +55 -0
- data/app/assets/stylesheets/lesli_babel/modules.scss +33 -0
- data/app/assets/stylesheets/lesli_babel/translations.scss +58 -0
- data/app/controllers/lesli_babel/application_controller.rb +37 -0
- data/app/controllers/lesli_babel/buckets_controller.rb +79 -0
- data/app/controllers/lesli_babel/clones_controller.rb +80 -0
- data/app/controllers/lesli_babel/dashboards_controller.rb +38 -0
- data/app/controllers/lesli_babel/modules_controller.rb +91 -0
- data/app/controllers/lesli_babel/relevants_controller.rb +38 -0
- data/app/controllers/lesli_babel/strings_controller.rb +142 -0
- data/app/controllers/lesli_babel/translations_controller.rb +134 -0
- data/app/jobs/lesli_babel/application_job.rb +7 -0
- data/app/mailers/lesli_babel/application_mailer.rb +6 -0
- data/app/models/lesli_babel/application_record.rb +36 -0
- data/app/models/lesli_babel/bucket.rb +6 -0
- data/app/models/lesli_babel/clone.rb +24 -0
- data/app/models/lesli_babel/dashboard.rb +35 -0
- data/app/models/lesli_babel/module.rb +35 -0
- data/app/models/lesli_babel/relevant.rb +21 -0
- data/app/models/lesli_babel/string/activity.rb +5 -0
- data/app/models/lesli_babel/string/discussion.rb +68 -0
- data/app/models/lesli_babel/string.rb +225 -0
- data/app/models/lesli_babel/translation.rb +5 -0
- data/app/services/lesli_babel/module_service.rb +18 -0
- data/app/services/lesli_babel/old/translations_android_service.rb +82 -0
- data/app/services/lesli_babel/old/translations_clone_service.rb +161 -0
- data/app/services/lesli_babel/old/translations_flutter_service.rb +102 -0
- data/app/services/lesli_babel/old/translations_ios_service.rb +119 -0
- data/app/services/lesli_babel/old/translations_js_service.rb +114 -0
- data/app/services/lesli_babel/old/translations_middleman_service.rb +77 -0
- data/app/services/lesli_babel/old/translations_rails_service.rb +119 -0
- data/app/services/lesli_babel/old/translations_service.rb +97 -0
- data/app/services/lesli_babel/old/translations_synchronization_service.rb +215 -0
- data/app/services/lesli_babel/string_service.rb +80 -0
- data/app/views/lesli_babel/buckets/_form.html.erb +17 -0
- data/app/views/lesli_babel/buckets/edit.html.erb +6 -0
- data/app/views/lesli_babel/buckets/index.html.erb +25 -0
- data/app/views/lesli_babel/buckets/new.html.erb +5 -0
- data/app/views/lesli_babel/buckets/show.html.erb +4 -0
- data/app/views/lesli_babel/clones/_form.html.erb +19 -0
- data/app/views/lesli_babel/clones/edit.html.erb +20 -0
- data/app/views/lesli_babel/clones/index.html.erb +20 -0
- data/app/views/lesli_babel/clones/new.html.erb +20 -0
- data/app/views/lesli_babel/clones/show.html.erb +20 -0
- data/app/views/lesli_babel/dashboards/show.html.erb +1 -0
- data/app/views/lesli_babel/dashboards/stats..html.erb +1 -0
- data/app/views/lesli_babel/modules/_form.html.erb +17 -0
- data/app/views/lesli_babel/modules/edit.html.erb +1 -0
- data/app/views/lesli_babel/modules/index.html.erb +1 -0
- data/app/views/lesli_babel/modules/new.html.erb +1 -0
- data/app/views/lesli_babel/modules/show.html.erb +1 -0
- data/app/views/lesli_babel/partials/_engine-navigation.html.erb +37 -0
- data/app/views/lesli_babel/partials/_engine-sidebar.html.erb +45 -0
- data/app/views/lesli_babel/relevants/edit.html.erb +20 -0
- data/app/views/lesli_babel/relevants/index.html.erb +21 -0
- data/app/views/lesli_babel/relevants/new.html.erb +20 -0
- data/app/views/lesli_babel/relevants/show.html.erb +20 -0
- data/app/views/lesli_babel/string/activities/_form.html.erb +17 -0
- data/app/views/lesli_babel/string/activities/edit.html.erb +6 -0
- data/app/views/lesli_babel/string/activities/index.html.erb +25 -0
- data/app/views/lesli_babel/string/activities/new.html.erb +5 -0
- data/app/views/lesli_babel/string/activities/show.html.erb +4 -0
- data/app/views/lesli_babel/string/discussions/_form.html.erb +17 -0
- data/app/views/lesli_babel/string/discussions/edit.html.erb +6 -0
- data/app/views/lesli_babel/string/discussions/index.html.erb +25 -0
- data/app/views/lesli_babel/string/discussions/new.html.erb +5 -0
- data/app/views/lesli_babel/string/discussions/show.html.erb +4 -0
- data/app/views/lesli_babel/strings/_form.html.erb +17 -0
- data/app/views/lesli_babel/strings/edit.html.erb +6 -0
- data/app/views/lesli_babel/strings/index.html.erb +25 -0
- data/app/views/lesli_babel/strings/new.html.erb +5 -0
- data/app/views/lesli_babel/strings/show.html.erb +4 -0
- data/app/views/lesli_babel/translations/_form.html.erb +17 -0
- data/app/views/lesli_babel/translations/edit.html.erb +6 -0
- data/app/views/lesli_babel/translations/index.html.erb +1 -0
- data/app/views/lesli_babel/translations/new.html.erb +5 -0
- data/app/views/lesli_babel/translations/show.html.erb +1 -0
- data/config/routes.rb +63 -0
- data/db/migrate/v1.0/0901100110_create_lesli_babel_modules.rb +42 -0
- data/db/migrate/v1.0/0901110110_create_lesli_babel_buckets.rb +43 -0
- data/db/migrate/v1.0/0901120110_create_lesli_babel_strings.rb +80 -0
- data/lib/lesli_babel/engine.rb +54 -0
- data/lib/lesli_babel/version.rb +3 -0
- data/lib/lesli_babel.rb +6 -0
- data/lib/tasks/lesli_babel_tasks.rake +121 -0
- data/lib/vue/application.js +46 -0
- data/lib/vue/apps/dashboards/show.vue +85 -0
- data/lib/vue/apps/modules/show.vue +97 -0
- data/lib/vue/apps/relevants/index.vue +47 -0
- data/lib/vue/apps/translations/index.vue +64 -0
- data/lib/vue/components/actions.vue +29 -0
- data/lib/vue/components/form-label-editor.vue +439 -0
- data/lib/vue/components/form-string-new.vue +171 -0
- data/lib/vue/stores/module.js +49 -0
- data/lib/vue/stores/statistics.js +42 -0
- data/lib/vue/stores/strings.js +141 -0
- data/lib/vue/stores/translations.js +73 -0
- data/license +674 -0
- data/readme.md +19 -0
- metadata +149 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module LesliBabel
|
|
2
|
+
class TranslationsRailsService
|
|
3
|
+
|
|
4
|
+
def self.build
|
|
5
|
+
|
|
6
|
+
engines_installed = Rails.application.config.lesli_settings["engines"].map do |engine|
|
|
7
|
+
engine[:name]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# get all rails engines to buil
|
|
11
|
+
engines = Module
|
|
12
|
+
.where("platform in ('rails_core', 'rails_builder', 'rails_engine', 'standard')")
|
|
13
|
+
.where("name in (?)", engines_installed.push("Core","LesliMails"))
|
|
14
|
+
.map do |engine|
|
|
15
|
+
engine[:id]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# get strings filtered by module (only rails translations)
|
|
19
|
+
strings = TranslationsService.strings(engines)
|
|
20
|
+
|
|
21
|
+
strings = strings.select(
|
|
22
|
+
:id,
|
|
23
|
+
:label,
|
|
24
|
+
:status,
|
|
25
|
+
:context,
|
|
26
|
+
:priority,
|
|
27
|
+
:need_help,
|
|
28
|
+
:need_translation,
|
|
29
|
+
Rails.application.config.lesli_settings["configuration"]["locales"],
|
|
30
|
+
"cloud_babel_modules.id as engine_id",
|
|
31
|
+
"cloud_babel_buckets.id as bucket_id",
|
|
32
|
+
"cloud_babel_buckets.name as bucket_name",
|
|
33
|
+
"cloud_babel_modules.name as engine_name",
|
|
34
|
+
"cloud_babel_modules.platform as platform",
|
|
35
|
+
"'' as path"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
translations = {}
|
|
39
|
+
|
|
40
|
+
available_locales = Rails.application.config.lesli_settings["configuration"]["locales"]
|
|
41
|
+
|
|
42
|
+
# add key for every available language (required by i18n Rails gem)
|
|
43
|
+
available_locales.each do |lang|
|
|
44
|
+
translations[lang] = { }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
strings.each do |string|
|
|
48
|
+
module_name = string[:engine_name].downcase.sub("cloud", "")
|
|
49
|
+
engine_code = string[:engine_name].underscore
|
|
50
|
+
engine_name = string[:engine_name]
|
|
51
|
+
bucket_name = string[:bucket_name]
|
|
52
|
+
platform = string[:platform]
|
|
53
|
+
|
|
54
|
+
available_locales.each do |lang|
|
|
55
|
+
|
|
56
|
+
# translations path for lesli core
|
|
57
|
+
file_path = Rails.root.join("config", "locales", bucket_name, "#{ bucket_name.gsub("/","_") }.#{ lang }.yml")
|
|
58
|
+
|
|
59
|
+
# translations path for translations for engines
|
|
60
|
+
if platform == "rails_builder" || platform == "rails_engine" || platform == "standard"
|
|
61
|
+
file_path = Rails.root.join("engines", engine_name, "config", "locales", bucket_name, "#{ bucket_name }.#{ lang }.yml")
|
|
62
|
+
file_path = Rails.root.join("config", "locales", engine_code, bucket_name, "#{ bucket_name.gsub("/","_") }.#{ lang }.yml")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
file_id = file_path.to_s.to_sym
|
|
66
|
+
|
|
67
|
+
unless translations[lang].has_key? file_id
|
|
68
|
+
translations[lang][file_id] = { }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
unless translations[lang][file_id].has_key? module_name
|
|
72
|
+
translations[lang][file_id][module_name] = { }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
unless translations[lang][file_id][module_name].has_key? bucket_name
|
|
76
|
+
translations[lang][file_id][module_name][bucket_name] = { }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# send debug message for missing translations
|
|
80
|
+
string[lang] = ":" + string.path + ":" if string[lang].blank?
|
|
81
|
+
|
|
82
|
+
translations[lang][file_id][module_name][bucket_name][string.label] = string[lang]
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
translations.each do |file_by_language|
|
|
89
|
+
|
|
90
|
+
lang = file_by_language[0]
|
|
91
|
+
file_by_controller = file_by_language[1]
|
|
92
|
+
|
|
93
|
+
file_by_controller.each do |file|
|
|
94
|
+
|
|
95
|
+
file_path = file[0].to_s
|
|
96
|
+
translations = file[1]
|
|
97
|
+
|
|
98
|
+
# creates folder and subfolders
|
|
99
|
+
FileUtils.makedirs(File.dirname(file_path))
|
|
100
|
+
|
|
101
|
+
# creates translation file for every available language
|
|
102
|
+
translation_file = File.new(file_path, "w+")
|
|
103
|
+
|
|
104
|
+
translation_file.write({ "#{lang}": translations}.to_yaml)
|
|
105
|
+
|
|
106
|
+
translation_file.close
|
|
107
|
+
|
|
108
|
+
p "file added: #{ file_path }"
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
LC::Response.service true, translations
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
|
|
3
|
+
Lesli
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2020, all rights reserved.
|
|
6
|
+
|
|
7
|
+
All the information provided by this platform is protected by international laws related to
|
|
8
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
9
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
10
|
+
pictures and any other information belongs to the owner of this platform.
|
|
11
|
+
|
|
12
|
+
Without the written permission of the owner, any replication, modification,
|
|
13
|
+
transmission, publication is strictly forbidden.
|
|
14
|
+
|
|
15
|
+
For more information read the license file including with this software.
|
|
16
|
+
|
|
17
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
18
|
+
// ·
|
|
19
|
+
|
|
20
|
+
=end
|
|
21
|
+
module LesliBabel
|
|
22
|
+
class TranslationsService
|
|
23
|
+
|
|
24
|
+
def self.restart_server
|
|
25
|
+
return if Rails.env != "production"
|
|
26
|
+
system "bundle exec rake i18n:js:export RAILS_ENV=production"
|
|
27
|
+
FileUtils.touch Rails.root.join("tmp", "restart.txt")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.clean
|
|
31
|
+
|
|
32
|
+
# store full path to translation files for every language
|
|
33
|
+
files_to_delete = []
|
|
34
|
+
|
|
35
|
+
# remove javascript translation cache
|
|
36
|
+
files_to_delete.push(Rails.root.join("public", "javascripts", "translations.js"))
|
|
37
|
+
|
|
38
|
+
# get translation files for engines only
|
|
39
|
+
Lesli::engines.each do |engine|
|
|
40
|
+
files_to_delete.push(Rails.root.join("engines", engine["name"], "config", "locales"))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# include translation files for lesli core
|
|
44
|
+
files_to_delete.push(Rails.root.join("config", "locales"))
|
|
45
|
+
|
|
46
|
+
# include external app translations
|
|
47
|
+
files_to_delete.push(Rails.root.join("public", "tmp", "locales"))
|
|
48
|
+
|
|
49
|
+
# delete all the translation files found
|
|
50
|
+
files_to_delete.each do |file|
|
|
51
|
+
FileUtils.rm_rf(file)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
LC::Response.service true, files_to_delete
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.strings engines_id=nil, buckets_id=nil
|
|
59
|
+
|
|
60
|
+
# get strings with bucket and module information
|
|
61
|
+
strings = String
|
|
62
|
+
.joins("inner join cloud_babel_buckets on cloud_babel_buckets.id = cloud_babel_strings.cloud_babel_buckets_id and cloud_babel_buckets.deleted_at is NULL")
|
|
63
|
+
.joins("inner join cloud_babel_modules on cloud_babel_modules.id = cloud_babel_buckets.cloud_babel_modules_id and cloud_babel_modules.deleted_at is NULL")
|
|
64
|
+
.where("cloud_babel_modules.id in (?)", TranslationsService.installed_engines_id)
|
|
65
|
+
|
|
66
|
+
# filter by specific engines
|
|
67
|
+
if engines_id
|
|
68
|
+
strings = strings.where("cloud_babel_modules.id in (?)", engines_id)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# filter by specific engine buckets
|
|
72
|
+
if buckets_id
|
|
73
|
+
strings = strings.where("cloud_babel_buckets.id in (?)", buckets_id)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
strings
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.strings_for_apps engines_id=nil, buckets_id=nil
|
|
81
|
+
|
|
82
|
+
strings = strings(engines_id, buckets_id)
|
|
83
|
+
strings = strings.select(
|
|
84
|
+
:id,
|
|
85
|
+
:label,
|
|
86
|
+
"cloud_babel_modules.name as engine_name",
|
|
87
|
+
"cloud_babel_buckets.name as bucket_name",
|
|
88
|
+
"cloud_babel_modules.platform",
|
|
89
|
+
Rails.application.config.lesli_settings["configuration"]["locales"]
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
strings
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020, all rights reserved.
|
|
4
|
+
|
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
|
9
|
+
|
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
|
11
|
+
transmission, publication is strictly forbidden.
|
|
12
|
+
|
|
13
|
+
For more information read the license file including with this software.
|
|
14
|
+
|
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
16
|
+
// ·
|
|
17
|
+
|
|
18
|
+
=end
|
|
19
|
+
|
|
20
|
+
module LesliBabel
|
|
21
|
+
class TranslationsSynchronizationService
|
|
22
|
+
|
|
23
|
+
# IMPORTANT: If you modify this file please check the CloneService that contains a modified
|
|
24
|
+
# copy of this synchronization code
|
|
25
|
+
def self.remote_sync double_way_sync=false
|
|
26
|
+
|
|
27
|
+
host = "http://localhost:8080"
|
|
28
|
+
host = "https://api.datenbanken.dev/v2"
|
|
29
|
+
instance_code = LC::System::Info.instance[:code].gsub("_","-")
|
|
30
|
+
|
|
31
|
+
# if special namespace is configured in the lesli.yml settings
|
|
32
|
+
# this is useful when we need install an instance and customize
|
|
33
|
+
# the translations for a client
|
|
34
|
+
#instance_code = Rails.application.config.lesli.dig(:configuration, :babel, :namespace)
|
|
35
|
+
|
|
36
|
+
api_endpoint = "#{host}/buckets/#{instance_code}-babel/documents"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# get last sync data
|
|
40
|
+
response = Faraday.get("#{api_endpoint}/last")
|
|
41
|
+
response = FastJsonparser.parse(response.body)
|
|
42
|
+
response = response[:documents][0]
|
|
43
|
+
|
|
44
|
+
# if first time sync
|
|
45
|
+
response = FastJsonparser.parse({ modules: [], buckets: [], strings: [] }.to_json) if response.blank?
|
|
46
|
+
|
|
47
|
+
# add new modules
|
|
48
|
+
response[:modules].each do |babel_module|
|
|
49
|
+
next if babel_module[:name].blank?
|
|
50
|
+
|
|
51
|
+
local_module = CloudBabel::Module
|
|
52
|
+
.create_with({
|
|
53
|
+
created_at: babel_module[:created_at],
|
|
54
|
+
platform: babel_module[:platform]
|
|
55
|
+
}).find_or_create_by({ name: babel_module[:name] })
|
|
56
|
+
|
|
57
|
+
platform = babel_module[:platform]
|
|
58
|
+
platform = "rails_engine" if babel_module[:name].start_with?("Cloud")
|
|
59
|
+
platform = "rails_core" if babel_module[:name] == "Core"
|
|
60
|
+
platform = "rails_builder" if ["MitwerkenCloud", "DeutscheLeibrenten", "LesliCloud"].include?(babel_module[:name])
|
|
61
|
+
|
|
62
|
+
local_module.platform = platform
|
|
63
|
+
local_module.updated_at = DateTime.now
|
|
64
|
+
local_module.save
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# working with buckets
|
|
69
|
+
babel_reference_modules = {}
|
|
70
|
+
|
|
71
|
+
response[:buckets].each do |babel_bucket|
|
|
72
|
+
|
|
73
|
+
next if babel_bucket[:name].blank?
|
|
74
|
+
|
|
75
|
+
# reference to modules that buckets belongs to
|
|
76
|
+
# this reference as string is necessary because the id of the module can change
|
|
77
|
+
# between synchronizations, thats why we search for the id of the module every time
|
|
78
|
+
if babel_reference_modules[babel_bucket[:reference_module]].blank?
|
|
79
|
+
babel_reference_modules[babel_bucket[:reference_module]] =
|
|
80
|
+
CloudBabel::Module.find_by(name: babel_bucket[:reference_module])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# add new bucket
|
|
84
|
+
CloudBabel::Bucket
|
|
85
|
+
.create_with({
|
|
86
|
+
created_at: babel_bucket[:created_at],
|
|
87
|
+
module: babel_reference_modules[babel_bucket[:reference_module]]
|
|
88
|
+
}).find_or_create_by({
|
|
89
|
+
name: babel_bucket[:name],
|
|
90
|
+
reference_module: babel_bucket[:reference_module]
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# · working with strings
|
|
96
|
+
babel_reference_buckets = {}
|
|
97
|
+
|
|
98
|
+
response[:strings].each do |remote_string|
|
|
99
|
+
# reference to modules that buckets belongs to
|
|
100
|
+
# this reference as string is necessary because the id of the module or bucket can change
|
|
101
|
+
# between synchronizations, thats why we search for the id of the module every time
|
|
102
|
+
if babel_reference_buckets[remote_string[:reference_bucket]].blank?
|
|
103
|
+
remote_string[:reference_bucket] ||= remote_string[:reference_module_bucket]
|
|
104
|
+
babel_reference_buckets[remote_string[:reference_bucket]] =
|
|
105
|
+
CloudBabel::Bucket.find_by(
|
|
106
|
+
name: remote_string[:reference_bucket].split("-")[1],
|
|
107
|
+
reference_module: remote_string[:reference_bucket].split("-")[0]
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Do not sync labes that do not have a valid module and bucket reference
|
|
112
|
+
next if babel_reference_buckets[remote_string[:reference_bucket]].blank?
|
|
113
|
+
|
|
114
|
+
remote_string_reference = "#{babel_reference_buckets[remote_string[:reference_bucket]].reference_module}-#{babel_reference_buckets[remote_string[:reference_bucket]].name}"
|
|
115
|
+
|
|
116
|
+
# add new string if it does not exist
|
|
117
|
+
local_string = CloudBabel::String.with_deleted.create_with({
|
|
118
|
+
bucket: babel_reference_buckets[remote_string[:reference_bucket]]
|
|
119
|
+
}).find_or_create_by({
|
|
120
|
+
label: remote_string[:label],
|
|
121
|
+
reference_module_bucket: remote_string_reference
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
# if status changed
|
|
125
|
+
if remote_string[:status] != local_string["status"]
|
|
126
|
+
|
|
127
|
+
remote_string[:last_update_status] = Time.now if remote_string[:last_update_status].blank?
|
|
128
|
+
local_string["last_update_status"] = Time.now if local_string["last_update_status"].blank?
|
|
129
|
+
|
|
130
|
+
# check if remote is newer than local
|
|
131
|
+
if (remote_string[:last_update_status] > local_string["last_update_status"])
|
|
132
|
+
|
|
133
|
+
# if so, update local translation with the incoming
|
|
134
|
+
local_string["status"] = remote_string[:status]
|
|
135
|
+
local_string["last_update_status"] = remote_string[:last_update_status]
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# if context changed
|
|
142
|
+
if remote_string[:context] != local_string["context"]
|
|
143
|
+
|
|
144
|
+
remote_string[:last_update_context] = Time.now if remote_string[:last_update_context].blank?
|
|
145
|
+
local_string["last_update_context"] = Time.now if local_string["last_update_context"].blank?
|
|
146
|
+
|
|
147
|
+
# check if remote is newer than local
|
|
148
|
+
if (remote_string[:last_update_context] > local_string["last_update_context"])
|
|
149
|
+
|
|
150
|
+
# if so, update local translation with the incoming
|
|
151
|
+
local_string["context"] = remote_string[:context]
|
|
152
|
+
local_string["last_update_context"] = remote_string[:last_update_context]
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# check if necessary to update any translation
|
|
159
|
+
# due babel can work as client and server at the same time, we have to synchronize labels for all supported languages
|
|
160
|
+
I18n.available_locales.each do |locale|
|
|
161
|
+
|
|
162
|
+
# parse the remote time for comparison, if no time use the current time
|
|
163
|
+
remote_time = Time.parse remote_string[:"last_update_#{locale}"] rescue Time.now.getutc
|
|
164
|
+
|
|
165
|
+
# parse the remote time for comparison, if no time use old time so we can update the string
|
|
166
|
+
local_time = Time.parse local_string["last_update_#{locale}"] rescue Time.parse("Jan 1900")
|
|
167
|
+
|
|
168
|
+
# if translation changed
|
|
169
|
+
if local_string[locale] != remote_string[:"#{locale}"]
|
|
170
|
+
|
|
171
|
+
# check if remote is newer than local
|
|
172
|
+
if (remote_time > local_time)
|
|
173
|
+
|
|
174
|
+
# if so, update local translation with the incoming
|
|
175
|
+
local_string[locale] = local_time
|
|
176
|
+
local_string["last_update_#{locale}"] = remote_time
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
local_string.save
|
|
185
|
+
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
return LC::Response.service(true) if double_way_sync == false
|
|
189
|
+
|
|
190
|
+
# · Collect modules, buckets and strings for syncronization
|
|
191
|
+
|
|
192
|
+
# get and parse modules
|
|
193
|
+
modules = CloudBabel::Module.all.map do |babel_module|
|
|
194
|
+
babel_module.as_json
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# get and parse buckets
|
|
198
|
+
buckets = CloudBabel::Bucket.all.map do |babel_bucket|
|
|
199
|
+
babel_bucket.as_json
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# get and parse strings including the deleted ones
|
|
203
|
+
strings = CloudBabel::String.with_deleted.all.map do |babel_string|
|
|
204
|
+
babel_string.as_json
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# send latest translation to raven
|
|
208
|
+
response = Faraday.post(api_endpoint, ({ modules: modules, buckets: buckets, strings: strings }).to_json, "Content-Type" => "application/json")
|
|
209
|
+
|
|
210
|
+
LC::Response.service true
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module LesliBabel
|
|
2
|
+
class StringService < Lesli::ApplicationLesliService
|
|
3
|
+
|
|
4
|
+
def list engines_id=nil, buckets_id=nil
|
|
5
|
+
|
|
6
|
+
# get strings with bucket and module information
|
|
7
|
+
strings = String
|
|
8
|
+
.joins("inner join lesli_babel_buckets on lesli_babel_buckets.id = lesli_babel_strings.bucket_id and lesli_babel_buckets.deleted_at is NULL")
|
|
9
|
+
.joins("inner join lesli_babel_modules on lesli_babel_modules.id = lesli_babel_buckets.module_id and lesli_babel_modules.deleted_at is NULL")
|
|
10
|
+
.where("lesli_babel_modules.id in (?)", ModuleService.new(current_user, query).list())
|
|
11
|
+
|
|
12
|
+
# filter by specific engines
|
|
13
|
+
if engines_id
|
|
14
|
+
strings = strings.where("lesli_babel_modules.id in (?)", engines_id)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# filter by specific engine buckets
|
|
18
|
+
if buckets_id
|
|
19
|
+
strings = strings.where("lesli_babel_buckets.id in (?)", buckets_id)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
strings
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def index params
|
|
26
|
+
strings = self.list.select(
|
|
27
|
+
:id,
|
|
28
|
+
:label,
|
|
29
|
+
:status,
|
|
30
|
+
:context,
|
|
31
|
+
Lesli.config.locales.keys,
|
|
32
|
+
"lesli_babel_modules.id as engine_id",
|
|
33
|
+
"lesli_babel_buckets.id as bucket_id",
|
|
34
|
+
"lesli_babel_buckets.name as bucket_name",
|
|
35
|
+
"lesli_babel_modules.name as engine_name",
|
|
36
|
+
"lesli_babel_modules.platform as platform",
|
|
37
|
+
"'' as path"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
strings = strings
|
|
41
|
+
.page(query[:pagination][:page])
|
|
42
|
+
.per(query[:pagination][:perPage])
|
|
43
|
+
.order(:updated_at)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def stats
|
|
47
|
+
|
|
48
|
+
Rails.cache.fetch("babel/strings/stats", expires_in: 1.hour) do
|
|
49
|
+
|
|
50
|
+
# total translations registered in babel
|
|
51
|
+
total_strings = self.list.count
|
|
52
|
+
|
|
53
|
+
# total translations by language
|
|
54
|
+
total_strings_translations = []
|
|
55
|
+
|
|
56
|
+
#Rails.application.config.lesli.dig(:configuration, :locales_available).each do |locale|
|
|
57
|
+
Lesli.config.locales.each do |locale|
|
|
58
|
+
total_strings_translations.push({
|
|
59
|
+
code: locale[0],
|
|
60
|
+
name: locale[1],
|
|
61
|
+
total: self.list.where("#{locale[0]} is not null").where("#{locale[0]} != ''").count
|
|
62
|
+
})
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# total translations that needs help
|
|
66
|
+
total_strings_waiting_for_help = self.list.where(:status => 1).count
|
|
67
|
+
|
|
68
|
+
# total translations that needs translation
|
|
69
|
+
total_strings_waiting_for_translation = self.list.where(:status => 2).count
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
total_strings: total_strings,
|
|
73
|
+
total_strings_translations: total_strings_translations,
|
|
74
|
+
total_strings_waiting_for_help: total_strings_waiting_for_help,
|
|
75
|
+
total_strings_waiting_for_translation: total_strings_waiting_for_translation
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%= form_with(model: bucket, local: true) do |form| %>
|
|
2
|
+
<% if bucket.errors.any? %>
|
|
3
|
+
<div id="error_explanation">
|
|
4
|
+
<h2><%= pluralize(bucket.errors.count, "error") %> prohibited this bucket from being saved:</h2>
|
|
5
|
+
|
|
6
|
+
<ul>
|
|
7
|
+
<% bucket.errors.full_messages.each do |message| %>
|
|
8
|
+
<li><%= message %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<div class="actions">
|
|
15
|
+
<%= form.submit %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<p id="notice"><%= notice %></p>
|
|
2
|
+
|
|
3
|
+
<h1>Buckets</h1>
|
|
4
|
+
|
|
5
|
+
<table>
|
|
6
|
+
<thead>
|
|
7
|
+
<tr>
|
|
8
|
+
<th colspan="3"></th>
|
|
9
|
+
</tr>
|
|
10
|
+
</thead>
|
|
11
|
+
|
|
12
|
+
<tbody>
|
|
13
|
+
<% @buckets.each do |bucket| %>
|
|
14
|
+
<tr>
|
|
15
|
+
<td><%= link_to 'Show', bucket %></td>
|
|
16
|
+
<td><%= link_to 'Edit', edit_bucket_path(bucket) %></td>
|
|
17
|
+
<td><%= link_to 'Destroy', bucket, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
|
18
|
+
</tr>
|
|
19
|
+
<% end %>
|
|
20
|
+
</tbody>
|
|
21
|
+
</table>
|
|
22
|
+
|
|
23
|
+
<br>
|
|
24
|
+
|
|
25
|
+
<%= link_to 'New Bucket', new_bucket_path %>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (c) 2021, all rights reserved.
|
|
4
|
+
|
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
|
9
|
+
|
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
|
11
|
+
transmission, publication is strictly forbidden.
|
|
12
|
+
|
|
13
|
+
For more information read the license file including with this software.
|
|
14
|
+
|
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
16
|
+
// ·
|
|
17
|
+
|
|
18
|
+
=end
|
|
19
|
+
%>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<%
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (c) 2021, all rights reserved.
|
|
4
|
+
|
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
|
9
|
+
|
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
|
11
|
+
transmission, publication is strictly forbidden.
|
|
12
|
+
|
|
13
|
+
For more information read the license file including with this software.
|
|
14
|
+
|
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
16
|
+
// ·
|
|
17
|
+
|
|
18
|
+
=end
|
|
19
|
+
%>
|
|
20
|
+
<router-view></router-view>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<%
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (c) 2021, all rights reserved.
|
|
4
|
+
|
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
|
9
|
+
|
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
|
11
|
+
transmission, publication is strictly forbidden.
|
|
12
|
+
|
|
13
|
+
For more information read the license file including with this software.
|
|
14
|
+
|
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
16
|
+
// ·
|
|
17
|
+
|
|
18
|
+
=end
|
|
19
|
+
%>
|
|
20
|
+
<router-view></router-view>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<%
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (c) 2021, all rights reserved.
|
|
4
|
+
|
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
|
9
|
+
|
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
|
11
|
+
transmission, publication is strictly forbidden.
|
|
12
|
+
|
|
13
|
+
For more information read the license file including with this software.
|
|
14
|
+
|
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
16
|
+
// ·
|
|
17
|
+
|
|
18
|
+
=end
|
|
19
|
+
%>
|
|
20
|
+
<router-view></router-view>
|