decidim-term_customizer 0.17.1 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/term_customizer/admin/translation_sets_admin.js.es6 +3 -1
- data/app/assets/javascripts/decidim/term_customizer/admin/translations_admin.js.es6 +6 -1
- data/app/commands/decidim/term_customizer/admin/create_translation.rb +3 -0
- data/app/commands/decidim/term_customizer/admin/destroy_translations.rb +3 -0
- data/app/commands/decidim/term_customizer/admin/duplicate_translation_set.rb +61 -0
- data/app/commands/decidim/term_customizer/admin/import_set_translations.rb +3 -0
- data/app/commands/decidim/term_customizer/admin/import_translation_keys.rb +3 -0
- data/app/commands/decidim/term_customizer/admin/update_translation.rb +8 -3
- data/app/controllers/decidim/term_customizer/admin/add_translations_controller.rb +2 -1
- data/app/controllers/decidim/term_customizer/admin/translation_sets_controller.rb +33 -0
- data/app/controllers/decidim/term_customizer/admin/translations_controller.rb +9 -3
- data/app/controllers/decidim/term_customizer/admin/translations_destroys_controller.rb +4 -1
- data/app/views/decidim/term_customizer/admin/translation_sets/index.html.erb +4 -0
- data/config/locales/ca.yml +6 -0
- data/config/locales/en.yml +6 -0
- data/config/locales/es.yml +6 -0
- data/config/locales/fi.yml +6 -0
- data/config/locales/fr.yml +6 -0
- data/config/locales/sv.yml +6 -0
- data/lib/decidim/term_customizer.rb +17 -0
- data/lib/decidim/term_customizer/admin_engine.rb +4 -0
- data/lib/decidim/term_customizer/context.rb +11 -0
- data/lib/decidim/term_customizer/context/base.rb +33 -0
- data/lib/decidim/term_customizer/context/controller_context.rb +31 -0
- data/lib/decidim/term_customizer/context/job_context.rb +53 -0
- data/lib/decidim/term_customizer/engine.rb +10 -29
- data/lib/decidim/term_customizer/loader.rb +4 -3
- data/lib/decidim/term_customizer/plural_forms_form.rb +23 -0
- data/lib/decidim/term_customizer/plural_forms_manager.rb +103 -0
- data/lib/decidim/term_customizer/version.rb +2 -2
- metadata +22 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e3682a317d9b21372199d956feec358caa08ac918beb770120905fb809f2acb
|
4
|
+
data.tar.gz: eb37d04fb232709d5b8ca49abdd4e8e4c0203bfc732a470b261538065f70c7e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b745d1e76d52d177656e7d10f29be947af94439397828d67f878a221209f8c435bdf6965978ca1d44901613ce865e52ee701ff5fd1161316b782d4e6db47586b
|
7
|
+
data.tar.gz: 103f2b361befd2ee05f6ce8877e42b29b78ffff28d2359cee08b70172387f4db6f384df9dadb6920589eecf60c918a50fff0263468f82d8bc26dd8ab4bb614c2
|
@@ -32,8 +32,13 @@ $(() => {
|
|
32
32
|
const re = new RegExp(`(${sanitizedSearch.split(" ").join("|")})`, "gi");
|
33
33
|
const modelId = item[0];
|
34
34
|
const title = item[1];
|
35
|
+
// The terms are already escaped but when they are rendered to a data
|
36
|
+
// attribute, they get unescaped when those values are used. The only
|
37
|
+
// character we need to replace is the ampersand
|
38
|
+
const value = title.replace(/&/g, "&");
|
39
|
+
|
35
40
|
const val = `${title} - ${modelId}`;
|
36
|
-
return `<div class="autocomplete-suggestion" data-model-id="${modelId}" data-val="${
|
41
|
+
return `<div class="autocomplete-suggestion" data-model-id="${modelId}" data-val="${value}">${val.replace(re, "<b>$1</b>")}</div>`;
|
37
42
|
},
|
38
43
|
onSelect: function(event, term, item) {
|
39
44
|
const $suggestions = $search.data("sc");
|
@@ -6,6 +6,8 @@ module Decidim
|
|
6
6
|
# A command with all the business logic when creating a new translation
|
7
7
|
# set in the system.
|
8
8
|
class CreateTranslation < Rectify::Command
|
9
|
+
include TermCustomizer::PluralFormsForm
|
10
|
+
|
9
11
|
# Public: Initializes the command.
|
10
12
|
#
|
11
13
|
# form - A form object with the params.
|
@@ -24,6 +26,7 @@ module Decidim
|
|
24
26
|
|
25
27
|
transaction do
|
26
28
|
@translations = create_translations
|
29
|
+
create_plural_forms(@translations)
|
27
30
|
end
|
28
31
|
|
29
32
|
if @translations.length.positive?
|
@@ -6,6 +6,8 @@ module Decidim
|
|
6
6
|
# A command with all the business logic when an admin destroys
|
7
7
|
# translations from a translation set.
|
8
8
|
class DestroyTranslations < Rectify::Command
|
9
|
+
include TermCustomizer::PluralFormsForm
|
10
|
+
|
9
11
|
# Public: Initializes the command.
|
10
12
|
#
|
11
13
|
# form - A form object with the params.
|
@@ -22,6 +24,7 @@ module Decidim
|
|
22
24
|
def call
|
23
25
|
return broadcast(:invalid) unless form.valid?
|
24
26
|
|
27
|
+
destroy_plural_forms(form.translations)
|
25
28
|
destroy_translations
|
26
29
|
|
27
30
|
broadcast(:ok)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module Admin
|
6
|
+
# This command is executed when the user duplicates a translation set from
|
7
|
+
# the admin panel.
|
8
|
+
class DuplicateTranslationSet < Rectify::Command
|
9
|
+
# Initializes a DuplicateTranslationSet Command.
|
10
|
+
#
|
11
|
+
# form - A form object with the params.
|
12
|
+
# set - The instance of the translation set to be duplicated.
|
13
|
+
def initialize(form, set)
|
14
|
+
@form = form
|
15
|
+
@set = set
|
16
|
+
end
|
17
|
+
|
18
|
+
# Updates the blog if valid.
|
19
|
+
#
|
20
|
+
# Broadcasts :ok if successful, :invalid otherwise.
|
21
|
+
def call
|
22
|
+
return broadcast(:invalid) if form.invalid?
|
23
|
+
|
24
|
+
transaction do
|
25
|
+
duplicate_translation_set!
|
26
|
+
end
|
27
|
+
|
28
|
+
broadcast(:ok, set)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :form, :set
|
34
|
+
|
35
|
+
def duplicate_translation_set!
|
36
|
+
duplicated = TermCustomizer::TranslationSet.create!(name: form.name)
|
37
|
+
|
38
|
+
# Add the constraints
|
39
|
+
set.constraints.each do |c|
|
40
|
+
duplicated.constraints.create!(
|
41
|
+
organization: form.current_organization,
|
42
|
+
subject: c.subject,
|
43
|
+
subject_type: c.subject_type
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add the translations
|
48
|
+
set.translations.each do |t|
|
49
|
+
duplicated.translations.create!(
|
50
|
+
locale: t.locale,
|
51
|
+
key: t.key,
|
52
|
+
value: t.value
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
duplicated
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -10,6 +10,8 @@ module Decidim
|
|
10
10
|
# supported import formats or a ZIP file containing a supported import
|
11
11
|
# file.
|
12
12
|
class ImportSetTranslations < Rectify::Command
|
13
|
+
include TermCustomizer::PluralFormsForm
|
14
|
+
|
13
15
|
# Public: Initializes the command.
|
14
16
|
#
|
15
17
|
# form - A form object with the params.
|
@@ -30,6 +32,7 @@ module Decidim
|
|
30
32
|
return broadcast(:invalid) if form.invalid?
|
31
33
|
|
32
34
|
@translations = import_translations
|
35
|
+
create_plural_forms(@translations)
|
33
36
|
|
34
37
|
if @translations.length.positive?
|
35
38
|
broadcast(:ok, @translations)
|
@@ -6,6 +6,8 @@ module Decidim
|
|
6
6
|
# A command with all the business logic when creating new translations
|
7
7
|
# from the keys submitted through the form.
|
8
8
|
class ImportTranslationKeys < Rectify::Command
|
9
|
+
include TermCustomizer::PluralFormsForm
|
10
|
+
|
9
11
|
# Public: Initializes the command.
|
10
12
|
#
|
11
13
|
# form - A form object with the params.
|
@@ -24,6 +26,7 @@ module Decidim
|
|
24
26
|
|
25
27
|
transaction do
|
26
28
|
@translations = create_translations
|
29
|
+
create_plural_forms(@translations)
|
27
30
|
end
|
28
31
|
|
29
32
|
if @translations.length.positive?
|
@@ -6,6 +6,8 @@ module Decidim
|
|
6
6
|
# This command is executed when the user changes a translation from the
|
7
7
|
# admin panel.
|
8
8
|
class UpdateTranslation < Rectify::Command
|
9
|
+
include TermCustomizer::PluralFormsForm
|
10
|
+
|
9
11
|
# Public: Initializes the command.
|
10
12
|
#
|
11
13
|
# form - A form object with the params.
|
@@ -25,7 +27,8 @@ module Decidim
|
|
25
27
|
return broadcast(:invalid) if form.invalid?
|
26
28
|
|
27
29
|
transaction do
|
28
|
-
update_translations!
|
30
|
+
@translations = update_translations!
|
31
|
+
create_plural_forms(@translations)
|
29
32
|
end
|
30
33
|
|
31
34
|
broadcast(:ok, translation)
|
@@ -36,7 +39,7 @@ module Decidim
|
|
36
39
|
attr_reader :form, :translation
|
37
40
|
|
38
41
|
def update_translations!
|
39
|
-
form.value.
|
42
|
+
form.value.map do |locale, value|
|
40
43
|
l_translation = TermCustomizer::Translation.find_by(
|
41
44
|
translation_set: translation.translation_set,
|
42
45
|
key: translation.key,
|
@@ -50,13 +53,15 @@ module Decidim
|
|
50
53
|
locale: locale
|
51
54
|
)
|
52
55
|
else
|
53
|
-
TermCustomizer::Translation.create!(
|
56
|
+
l_translation = TermCustomizer::Translation.create!(
|
54
57
|
translation_set: translation.translation_set,
|
55
58
|
key: form.key,
|
56
59
|
value: value,
|
57
60
|
locale: locale
|
58
61
|
)
|
59
62
|
end
|
63
|
+
|
64
|
+
l_translation
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
@@ -16,6 +16,7 @@ module Decidim
|
|
16
16
|
enforce_permission_to :create, :translation
|
17
17
|
@form = form(TranslationKeyImportForm).from_params(
|
18
18
|
params,
|
19
|
+
current_organization: current_organization,
|
19
20
|
translation_set: set
|
20
21
|
)
|
21
22
|
|
@@ -40,7 +41,7 @@ module Decidim
|
|
40
41
|
translations = directory.translations_search(params[:term])
|
41
42
|
translations.reject! { |k| reject_keys.include?(k) }
|
42
43
|
|
43
|
-
render json: translations.map { |k, v| [k, v] }
|
44
|
+
render json: translations.map { |k, v| [k, ERB::Util.html_escape(v)] }
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
@@ -75,6 +75,39 @@ module Decidim
|
|
75
75
|
redirect_to translation_sets_path
|
76
76
|
end
|
77
77
|
|
78
|
+
def duplicate
|
79
|
+
enforce_permission_to :create, :translation_set
|
80
|
+
|
81
|
+
# Automatically generate the name
|
82
|
+
name_attrs = {}.tap do |hash|
|
83
|
+
current_organization.available_locales.each do |locale|
|
84
|
+
hash["name_#{locale}"] = I18n.t(
|
85
|
+
"translation_sets.duplicate.copied_set_name",
|
86
|
+
name: set.name[locale],
|
87
|
+
locale: locale,
|
88
|
+
scope: "decidim.term_customizer.admin"
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
@form = form(TranslationSetForm).from_params(
|
94
|
+
params.merge(name_attrs),
|
95
|
+
current_organization: current_organization
|
96
|
+
)
|
97
|
+
|
98
|
+
DuplicateTranslationSet.call(@form, set) do
|
99
|
+
on(:ok) do
|
100
|
+
flash[:notice] = I18n.t("translation_sets.duplicate.success", scope: "decidim.term_customizer.admin")
|
101
|
+
redirect_to translation_sets_path
|
102
|
+
end
|
103
|
+
|
104
|
+
on(:invalid) do
|
105
|
+
flash.now[:alert] = I18n.t("translation_sets.duplicate.error", scope: "decidim.term_customizer.admin")
|
106
|
+
redirect_to translation_sets_path
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
78
111
|
private
|
79
112
|
|
80
113
|
def sets
|
@@ -69,10 +69,13 @@ module Decidim
|
|
69
69
|
enforce_permission_to :destroy, :translation, translation: translation
|
70
70
|
|
71
71
|
# Destroy all locales of the translation key
|
72
|
-
|
72
|
+
pfm = TermCustomizer::PluralFormsManager.new(current_organization)
|
73
|
+
translations = Decidim::TermCustomizer::Translation.where(
|
73
74
|
translation_set: set,
|
74
75
|
key: translation.key
|
75
|
-
)
|
76
|
+
)
|
77
|
+
pfm.destroy!(translations)
|
78
|
+
translations.destroy_all
|
76
79
|
|
77
80
|
flash[:notice] = I18n.t("translations.destroy.success", scope: "decidim.term_customizer.admin")
|
78
81
|
|
@@ -99,7 +102,10 @@ module Decidim
|
|
99
102
|
def import
|
100
103
|
enforce_permission_to :import, :translation_set, translation_set: set
|
101
104
|
|
102
|
-
@import = form(Admin::TranslationsImportForm).from_params(
|
105
|
+
@import = form(Admin::TranslationsImportForm).from_params(
|
106
|
+
params,
|
107
|
+
current_organization: current_organization
|
108
|
+
)
|
103
109
|
ImportSetTranslations.call(@import, set) do
|
104
110
|
on(:ok) do
|
105
111
|
flash[:notice] = I18n.t("translations.import.success", scope: "decidim.term_customizer.admin")
|
@@ -38,7 +38,10 @@ module Decidim
|
|
38
38
|
def set_form
|
39
39
|
@form = form(Admin::TranslationsDestroyForm).from_params(
|
40
40
|
params
|
41
|
-
).with_context(
|
41
|
+
).with_context(
|
42
|
+
current_organization: current_organization,
|
43
|
+
translation_set: set
|
44
|
+
)
|
42
45
|
end
|
43
46
|
|
44
47
|
def translation_set
|
@@ -46,6 +46,10 @@
|
|
46
46
|
<%= icon_link_to "pencil", edit_translation_set_path(set), t("actions.configure", scope: "decidim.admin"), class: "action-icon--new" %>
|
47
47
|
<% end %>
|
48
48
|
|
49
|
+
<% if allowed_to? :create, :translation_set %>
|
50
|
+
<%= icon_link_to "fork", duplicate_translation_set_path(set), t("actions.duplicate", scope: "decidim.term_customizer.admin"), method: :post, class: "action-icon--new", data: { confirm: t("actions.confirm_duplicate", scope: "decidim.term_customizer.admin") } %>
|
51
|
+
<% end %>
|
52
|
+
|
49
53
|
<% if allowed_to? :destroy, :translation_set, translation_set: set %>
|
50
54
|
<%= icon_link_to "circle-x", translation_set_path(set), t("actions.destroy", scope: "decidim.admin"), method: :delete, class: "action-icon--remove", data: { confirm: t("actions.confirm_destroy", scope: "decidim.admin") } %>
|
51
55
|
<% end %>
|
data/config/locales/ca.yml
CHANGED
@@ -26,6 +26,8 @@ ca:
|
|
26
26
|
back: Enrere
|
27
27
|
cancel: Cancel
|
28
28
|
clear_cache: Clear cache
|
29
|
+
confirm_duplicate: Are you sure you want to duplicate this set?
|
30
|
+
duplicate: Duplicate
|
29
31
|
help: Help
|
30
32
|
import: Import
|
31
33
|
new_translation: Nova traducció
|
@@ -62,6 +64,10 @@ ca:
|
|
62
64
|
success: Traducció creada amb èxit
|
63
65
|
destroy:
|
64
66
|
success: La traducció ha estat esborrada amb èxit.
|
67
|
+
duplicate:
|
68
|
+
copied_set_name: Copy of %{name}
|
69
|
+
error: Error duplicating translation set.
|
70
|
+
success: Translation set successfully duplicated.
|
65
71
|
edit:
|
66
72
|
save: Guardar
|
67
73
|
title: Set/Joc de traducció
|
data/config/locales/en.yml
CHANGED
@@ -27,6 +27,8 @@ en:
|
|
27
27
|
back: Back
|
28
28
|
cancel: Cancel
|
29
29
|
clear_cache: Clear cache
|
30
|
+
confirm_duplicate: Are you sure you want to duplicate this set?
|
31
|
+
duplicate: Duplicate
|
30
32
|
help: Help
|
31
33
|
import: Import
|
32
34
|
new_translation: New translation
|
@@ -70,6 +72,10 @@ en:
|
|
70
72
|
success: Translation set successfully created.
|
71
73
|
destroy:
|
72
74
|
success: Translation set successfully deleted.
|
75
|
+
duplicate:
|
76
|
+
copied_set_name: Copy of %{name}
|
77
|
+
error: Error duplicating translation set.
|
78
|
+
success: Translation set successfully duplicated.
|
73
79
|
edit:
|
74
80
|
save: Save
|
75
81
|
title: Translation set
|
data/config/locales/es.yml
CHANGED
@@ -26,6 +26,8 @@ es:
|
|
26
26
|
back: Volver
|
27
27
|
cancel: Cancel
|
28
28
|
clear_cache: Clear cache
|
29
|
+
confirm_duplicate: Are you sure you want to duplicate this set?
|
30
|
+
duplicate: Duplicate
|
29
31
|
help: Help
|
30
32
|
import: Import
|
31
33
|
new_translation: Nueva traducción
|
@@ -62,6 +64,10 @@ es:
|
|
62
64
|
success: Gurpo de tranducciones creado exitosamente.
|
63
65
|
destroy:
|
64
66
|
success: El grupo de traducciones ha sido creado exitosamente.
|
67
|
+
duplicate:
|
68
|
+
copied_set_name: Copy of %{name}
|
69
|
+
error: Error duplicating translation set.
|
70
|
+
success: Translation set successfully duplicated.
|
65
71
|
edit:
|
66
72
|
save: Guardar
|
67
73
|
title: Grupo de traducciones
|
data/config/locales/fi.yml
CHANGED
@@ -26,6 +26,8 @@ fi:
|
|
26
26
|
back: Takaisin
|
27
27
|
cancel: Peruuta
|
28
28
|
clear_cache: Tyhjennä välimuisti
|
29
|
+
confirm_duplicate: Haluatko varmasti kopioida tämän paketin?
|
30
|
+
duplicate: Kopioi
|
29
31
|
help: Ohjeet
|
30
32
|
import: Tuo
|
31
33
|
new_translation: Uusi käännös
|
@@ -62,6 +64,10 @@ fi:
|
|
62
64
|
success: Käännöspaketin luonti onnistui.
|
63
65
|
destroy:
|
64
66
|
success: Käännöspaketin poisto onnistui.
|
67
|
+
duplicate:
|
68
|
+
copied_set_name: 'Kopio: %{name}'
|
69
|
+
error: Käännöspaketin kopiointi epäonnistui.
|
70
|
+
success: Käännöspaketin kopiointi onnistui.
|
65
71
|
edit:
|
66
72
|
save: Tallenna
|
67
73
|
title: Käännöspaketti
|
data/config/locales/fr.yml
CHANGED
@@ -26,6 +26,8 @@ fr:
|
|
26
26
|
back: Retour
|
27
27
|
cancel: Cancel
|
28
28
|
clear_cache: Purger le cache
|
29
|
+
confirm_duplicate: Are you sure you want to duplicate this set?
|
30
|
+
duplicate: Duplicate
|
29
31
|
help: Help
|
30
32
|
import: Import
|
31
33
|
new_translation: Nouvelle traduction
|
@@ -62,6 +64,10 @@ fr:
|
|
62
64
|
success: Jeu de traduction créé avec succès.
|
63
65
|
destroy:
|
64
66
|
success: Le jeu de traduction a été supprimé.
|
67
|
+
duplicate:
|
68
|
+
copied_set_name: Copy of %{name}
|
69
|
+
error: Error duplicating translation set.
|
70
|
+
success: Translation set successfully duplicated.
|
65
71
|
edit:
|
66
72
|
save: Sauvegarder
|
67
73
|
title: Jeu de traductions
|
data/config/locales/sv.yml
CHANGED
@@ -26,6 +26,8 @@ sv:
|
|
26
26
|
back: Back
|
27
27
|
cancel: Cancel
|
28
28
|
clear_cache: Clear cache
|
29
|
+
confirm_duplicate: Are you sure you want to duplicate this set?
|
30
|
+
duplicate: Duplicate
|
29
31
|
help: Help
|
30
32
|
import: Import
|
31
33
|
new_translation: New translation
|
@@ -62,6 +64,10 @@ sv:
|
|
62
64
|
success: Translation set successfully created.
|
63
65
|
destroy:
|
64
66
|
success: Translation set successfully deleted.
|
67
|
+
duplicate:
|
68
|
+
copied_set_name: Copy of %{name}
|
69
|
+
error: Error duplicating translation set.
|
70
|
+
success: Translation set successfully duplicated.
|
65
71
|
edit:
|
66
72
|
save: Save
|
67
73
|
title: Translation set
|
@@ -4,12 +4,17 @@ require_relative "term_customizer/version"
|
|
4
4
|
require_relative "term_customizer/engine"
|
5
5
|
require_relative "term_customizer/admin"
|
6
6
|
require_relative "term_customizer/admin_engine"
|
7
|
+
require_relative "term_customizer/context"
|
7
8
|
|
8
9
|
module Decidim
|
9
10
|
module TermCustomizer
|
11
|
+
include ActiveSupport::Configurable
|
12
|
+
|
10
13
|
autoload :I18nBackend, "decidim/term_customizer/i18n_backend"
|
11
14
|
autoload :Import, "decidim/term_customizer/import"
|
12
15
|
autoload :Loader, "decidim/term_customizer/loader"
|
16
|
+
autoload :PluralFormsForm, "decidim/term_customizer/plural_forms_form"
|
17
|
+
autoload :PluralFormsManager, "decidim/term_customizer/plural_forms_manager"
|
13
18
|
autoload :Resolver, "decidim/term_customizer/resolver"
|
14
19
|
autoload :TranslationDirectory, "decidim/term_customizer/translation_directory"
|
15
20
|
autoload :TranslationImportCollection, "decidim/term_customizer/translation_import_collection"
|
@@ -19,6 +24,18 @@ module Decidim
|
|
19
24
|
|
20
25
|
EMPTY_HASH = {}.freeze
|
21
26
|
|
27
|
+
# In case you want to customize the context detection for the controllers
|
28
|
+
# and views, configure your own context resolver.
|
29
|
+
config_accessor :controller_context_class do
|
30
|
+
Decidim::TermCustomizer::Context::ControllerContext
|
31
|
+
end
|
32
|
+
|
33
|
+
# In case you want to customize the context detection for the jobs,
|
34
|
+
# configure your own context resolver.
|
35
|
+
config_accessor :job_context_class do
|
36
|
+
Decidim::TermCustomizer::Context::JobContext
|
37
|
+
end
|
38
|
+
|
22
39
|
class << self
|
23
40
|
attr_accessor :loader
|
24
41
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module Context
|
6
|
+
autoload :Base, "decidim/term_customizer/context/base"
|
7
|
+
autoload :ControllerContext, "decidim/term_customizer/context/controller_context"
|
8
|
+
autoload :JobContext, "decidim/term_customizer/context/job_context"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module Context
|
6
|
+
# A context object resolves and stores the translation context for
|
7
|
+
# different application contexts. Contexts can be e.g.
|
8
|
+
# - Controller context, which is used to display translations in
|
9
|
+
# controller messages and the views.
|
10
|
+
# - Job context, which is used to display messages within jobs, mainly
|
11
|
+
# when sending emails.
|
12
|
+
#
|
13
|
+
# The initialization method gets the data for the context which is used
|
14
|
+
# to resolve the translation context objects (organization, participatory
|
15
|
+
# space and component). These are then used to load the correct
|
16
|
+
# translations for each context based on the translation set constraints.
|
17
|
+
class Base
|
18
|
+
attr_reader :organization, :space, :component
|
19
|
+
|
20
|
+
def initialize(data)
|
21
|
+
@data = data
|
22
|
+
|
23
|
+
# Implement the resolve! method in the sub-classes
|
24
|
+
resolve!
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
attr_reader :data
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module Context
|
6
|
+
class ControllerContext < Base
|
7
|
+
def resolve!
|
8
|
+
env = data[:headers].env
|
9
|
+
controller = env["action_controller.instance"]
|
10
|
+
|
11
|
+
@organization = env["decidim.current_organization"]
|
12
|
+
|
13
|
+
# E.g. at the participatory process controller the
|
14
|
+
# `decidim.current_participatory_space` environment variable has not
|
15
|
+
# been set. Therefore, we need to fetch it directly from the
|
16
|
+
# controller using its private method. In some edge cases this may not
|
17
|
+
# be implemented (https://github.com/mainio/decidim-module-term_customizer/issues/28)
|
18
|
+
# in which case we do not have access to the participatory space.
|
19
|
+
if controller.respond_to?(:current_participatory_space, true)
|
20
|
+
@space = controller.send(
|
21
|
+
:current_participatory_space
|
22
|
+
)
|
23
|
+
end
|
24
|
+
@space ||= env["decidim.current_participatory_space"]
|
25
|
+
|
26
|
+
@component = env["decidim.current_component"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module Context
|
6
|
+
class JobContext < Base
|
7
|
+
def resolve!
|
8
|
+
# Figure out the organization and user through the job arguments if
|
9
|
+
# passed for the job.
|
10
|
+
user = nil
|
11
|
+
data[:job].arguments.each do |arg|
|
12
|
+
@organization ||= organization_from_argument(arg)
|
13
|
+
@space ||= space_from_argument(arg)
|
14
|
+
@component ||= component_from_argument(arg)
|
15
|
+
user ||= arg if arg.is_a?(Decidim::User)
|
16
|
+
end
|
17
|
+
|
18
|
+
# In case a component was found, define the space as the component
|
19
|
+
# space to avoid any conflicts.
|
20
|
+
@space = component.participatory_space if component
|
21
|
+
|
22
|
+
# In case a space was found, define the organization as the space
|
23
|
+
# organization to avoid any conflicts.
|
24
|
+
@organization = space.organization if space
|
25
|
+
|
26
|
+
# In case an organization could not be resolved any other way, check
|
27
|
+
# it through the user (if the user was passed).
|
28
|
+
@organization ||= user.organization if user
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def organization_from_argument(arg)
|
34
|
+
return arg if arg.is_a?(Decidim::Organization)
|
35
|
+
|
36
|
+
arg.organization if arg.respond_to?(:organization)
|
37
|
+
end
|
38
|
+
|
39
|
+
def space_from_argument(arg)
|
40
|
+
return arg if arg.is_a?(Decidim::Participable)
|
41
|
+
|
42
|
+
arg.participatory_space if arg.respond_to?(:participatory_space)
|
43
|
+
end
|
44
|
+
|
45
|
+
def component_from_argument(arg)
|
46
|
+
return arg if arg.is_a?(Decidim::Component)
|
47
|
+
|
48
|
+
arg.component if arg.respond_to?(:component)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -17,25 +17,13 @@ module Decidim
|
|
17
17
|
# done through a notification to get access to the `current_*`
|
18
18
|
# environment variables within Decidim.
|
19
19
|
ActiveSupport::Notifications.subscribe "start_processing.action_controller" do |_name, _started, _finished, _unique_id, data|
|
20
|
-
|
21
|
-
controller = data[:headers].env["action_controller.instance"]
|
22
|
-
|
23
|
-
# E.g. at the participatory process controller the
|
24
|
-
# `decidim.current_participatory_space` environment variable has not
|
25
|
-
# been set. Therefore, we need to fetch it directly from the
|
26
|
-
# controller using its private method.
|
27
|
-
space =
|
28
|
-
if controller.respond_to?(:current_participatory_space, true)
|
29
|
-
controller.send(:current_participatory_space)
|
30
|
-
else
|
31
|
-
env["decidim.current_participatory_space"]
|
32
|
-
end
|
20
|
+
context = TermCustomizer.controller_context_class.new(data)
|
33
21
|
|
34
22
|
# Create a new resolver instance within the current request scope
|
35
23
|
resolver = Resolver.new(
|
36
|
-
|
37
|
-
space,
|
38
|
-
|
24
|
+
context.organization,
|
25
|
+
context.space,
|
26
|
+
context.component
|
39
27
|
)
|
40
28
|
|
41
29
|
# Create the loader for the backend to fetch the translations from
|
@@ -58,22 +46,15 @@ module Decidim
|
|
58
46
|
# job that may be fired by another job (i.e. the notification job is
|
59
47
|
# always performed last).
|
60
48
|
ActiveSupport::Notifications.subscribe "perform_start.active_job" do |_name, _started, _finished, _unique_id, data|
|
61
|
-
|
62
|
-
# passed for the job.
|
63
|
-
organization = nil
|
64
|
-
user = nil
|
65
|
-
data[:job].arguments.each do |arg|
|
66
|
-
organization = arg if arg.is_a?(Decidim::Organization)
|
67
|
-
user = arg if arg.is_a?(Decidim::User)
|
68
|
-
end
|
69
|
-
|
70
|
-
# In case an organization was not passed for the job, check it through
|
71
|
-
# the user.
|
72
|
-
organization = user.organization if organization.nil? && user
|
49
|
+
context = TermCustomizer.job_context_class.new(data)
|
73
50
|
|
74
51
|
# Create resolver for the target organization or global context in
|
75
52
|
# case organization was not found
|
76
|
-
resolver = Resolver.new(
|
53
|
+
resolver = Resolver.new(
|
54
|
+
context.organization,
|
55
|
+
context.space,
|
56
|
+
context.component
|
57
|
+
)
|
77
58
|
|
78
59
|
# Create the loader for the backend to fetch the translations from
|
79
60
|
TermCustomizer.loader = Loader.new(resolver)
|
@@ -57,9 +57,10 @@ module Decidim
|
|
57
57
|
# the resolver.
|
58
58
|
def clear_cache
|
59
59
|
Rails.cache.delete_matched("#{cache_key_base}/*")
|
60
|
-
rescue NotImplementedError
|
61
|
-
# Some cache store, such as `ActiveSupport::Cache::MemCacheStore`
|
62
|
-
# support `delete_matched`.
|
60
|
+
rescue NotImplementedError, NoMethodError
|
61
|
+
# Some cache store, such as `ActiveSupport::Cache::MemCacheStore` or
|
62
|
+
# `ActiveSupport::Cache::DalliStore` do not support `delete_matched`.
|
63
|
+
# Therefore, clear all the possibly existing
|
63
64
|
# cache keys manually for each space and component.
|
64
65
|
|
65
66
|
# Clear all the "organization" translation keys.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
module PluralFormsForm
|
6
|
+
private
|
7
|
+
|
8
|
+
def create_plural_forms(translations)
|
9
|
+
plural_forms_manager.fill!(translations)
|
10
|
+
end
|
11
|
+
|
12
|
+
def destroy_plural_forms(translations)
|
13
|
+
plural_forms_manager.destroy!(translations)
|
14
|
+
end
|
15
|
+
|
16
|
+
def plural_forms_manager
|
17
|
+
@plural_forms_manager ||= TermCustomizer::PluralFormsManager.new(
|
18
|
+
form.current_organization
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module TermCustomizer
|
5
|
+
# Checks that all the plural forms are in the database for the given keys.
|
6
|
+
class PluralFormsManager
|
7
|
+
attr_reader :organization
|
8
|
+
|
9
|
+
@plural_keys = [:zero, :one, :few, :other]
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :plural_keys
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(organization)
|
16
|
+
@organization = organization
|
17
|
+
@default_locale = organization.default_locale
|
18
|
+
end
|
19
|
+
|
20
|
+
def fill!(translations)
|
21
|
+
each_plural_form(translations) do |translation, key|
|
22
|
+
add_locales_for!(translation, key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy!(translations)
|
27
|
+
each_plural_form(translations) do |translation, key|
|
28
|
+
destroy_locales_for!(translation, key)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :default_locale
|
35
|
+
|
36
|
+
def each_plural_form(translations)
|
37
|
+
keys = self.class.plural_keys.map(&:to_s)
|
38
|
+
translations.each do |tr|
|
39
|
+
# Check that the last part of the translation key matches with some
|
40
|
+
# of the plural translation keys.
|
41
|
+
next unless tr.key =~ /\.(#{keys.join("|")})$/
|
42
|
+
|
43
|
+
parts = tr.key.split(".")
|
44
|
+
plural_part = parts.pop
|
45
|
+
base_part = parts.join(".")
|
46
|
+
|
47
|
+
# If it's not a hash, it's not a plural translation
|
48
|
+
next unless I18n.exists?(base_part, default_locale)
|
49
|
+
next unless I18n.t(base_part, locale: default_locale).is_a?(Hash)
|
50
|
+
|
51
|
+
keys.each do |plural_key|
|
52
|
+
# Do not check for the translation itself
|
53
|
+
next if plural_part == plural_key
|
54
|
+
|
55
|
+
full_plural_key = "#{base_part}.#{plural_key}"
|
56
|
+
|
57
|
+
# Check that the translation actually exists, no need to process if
|
58
|
+
# it does not exist.
|
59
|
+
next unless I18n.exists?(full_plural_key, default_locale)
|
60
|
+
|
61
|
+
yield tr, full_plural_key
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_locales_for!(translation, target_key)
|
67
|
+
organization.available_locales.each do |locale|
|
68
|
+
# Skip adding the plural form for the translation itself
|
69
|
+
next if target_key == translation.key
|
70
|
+
|
71
|
+
# Check that the translation is not already added in the set
|
72
|
+
next if translation.translation_set.translations.where(
|
73
|
+
key: target_key,
|
74
|
+
locale: locale
|
75
|
+
).any?
|
76
|
+
|
77
|
+
# Add the plural form
|
78
|
+
translation.translation_set.translations.create!(
|
79
|
+
key: target_key,
|
80
|
+
locale: locale,
|
81
|
+
value: I18n.t(target_key, locale: locale, default: "")
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def destroy_locales_for!(translation, target_key)
|
87
|
+
organization.available_locales.each do |locale|
|
88
|
+
# Skip deleting the plural form for the translation itself
|
89
|
+
next if target_key == translation.key
|
90
|
+
|
91
|
+
# Find the plural form the plural form
|
92
|
+
target = translation.translation_set.translations.find_by(
|
93
|
+
key: target_key,
|
94
|
+
locale: locale
|
95
|
+
)
|
96
|
+
next unless target
|
97
|
+
|
98
|
+
target.destroy!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: decidim-term_customizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Antti Hukkanen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: decidim-admin
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.21.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.21.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: decidim-core
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.21.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.21.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: dalli
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,56 +64,56 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.
|
67
|
+
version: 0.21.0
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.
|
74
|
+
version: 0.21.0
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: decidim-dev
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: 0.
|
81
|
+
version: 0.21.0
|
82
82
|
type: :development
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: 0.
|
88
|
+
version: 0.21.0
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: decidim-participatory_processes
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 0.
|
95
|
+
version: 0.21.0
|
96
96
|
type: :development
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 0.
|
102
|
+
version: 0.21.0
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: decidim-proposals
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.
|
109
|
+
version: 0.21.0
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 0.
|
116
|
+
version: 0.21.0
|
117
117
|
description: Adds a UI to customize the terms and limit the customizations to specific
|
118
118
|
places.
|
119
119
|
email:
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- app/commands/decidim/term_customizer/admin/create_translation.rb
|
136
136
|
- app/commands/decidim/term_customizer/admin/create_translation_set.rb
|
137
137
|
- app/commands/decidim/term_customizer/admin/destroy_translations.rb
|
138
|
+
- app/commands/decidim/term_customizer/admin/duplicate_translation_set.rb
|
138
139
|
- app/commands/decidim/term_customizer/admin/import_set_translations.rb
|
139
140
|
- app/commands/decidim/term_customizer/admin/import_translation_keys.rb
|
140
141
|
- app/commands/decidim/term_customizer/admin/update_translation.rb
|
@@ -190,6 +191,10 @@ files:
|
|
190
191
|
- lib/decidim/term_customizer.rb
|
191
192
|
- lib/decidim/term_customizer/admin.rb
|
192
193
|
- lib/decidim/term_customizer/admin_engine.rb
|
194
|
+
- lib/decidim/term_customizer/context.rb
|
195
|
+
- lib/decidim/term_customizer/context/base.rb
|
196
|
+
- lib/decidim/term_customizer/context/controller_context.rb
|
197
|
+
- lib/decidim/term_customizer/context/job_context.rb
|
193
198
|
- lib/decidim/term_customizer/engine.rb
|
194
199
|
- lib/decidim/term_customizer/i18n_backend.rb
|
195
200
|
- lib/decidim/term_customizer/import.rb
|
@@ -202,6 +207,8 @@ files:
|
|
202
207
|
- lib/decidim/term_customizer/import/readers/json.rb
|
203
208
|
- lib/decidim/term_customizer/import/readers/xls.rb
|
204
209
|
- lib/decidim/term_customizer/loader.rb
|
210
|
+
- lib/decidim/term_customizer/plural_forms_form.rb
|
211
|
+
- lib/decidim/term_customizer/plural_forms_manager.rb
|
205
212
|
- lib/decidim/term_customizer/resolver.rb
|
206
213
|
- lib/decidim/term_customizer/test/factories.rb
|
207
214
|
- lib/decidim/term_customizer/translation_directory.rb
|
@@ -229,8 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
236
|
- !ruby/object:Gem::Version
|
230
237
|
version: '0'
|
231
238
|
requirements: []
|
232
|
-
|
233
|
-
rubygems_version: 2.7.6
|
239
|
+
rubygems_version: 3.0.3
|
234
240
|
signing_key:
|
235
241
|
specification_version: 4
|
236
242
|
summary: Provides possibility to customize Decidim's localized terms.
|