decidim-term_customizer 0.17.1 → 0.18.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/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 +29 -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/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: ddc3ca2291e44d29a3d8a137006a7ba1e94ad55490a77059eb2a3fc9837a8fa2
|
4
|
+
data.tar.gz: c387dad256fb3d261ca71926116831ebca56d89dc5d402fd2f6cfedb7bd59ed2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f141278212906ccb425248ee375d604e478e564ae4a424f17d1d3dffa9588560dbd03055df58a0f7ee5ce33d443e0ab15a35228b025d035a9f0357d723db1a9c
|
7
|
+
data.tar.gz: 76663c880f493298b93252390259a9c1f3f3dc3279b2f18b7b92b73e3af4abade578a0756c79c496167b48d78295dd02dfdc4d96bdae4e00bb21933eccd393ca
|
@@ -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,29 @@
|
|
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.
|
17
|
+
@space =
|
18
|
+
if controller.respond_to?(:current_participatory_space, true)
|
19
|
+
controller.send(:current_participatory_space)
|
20
|
+
else
|
21
|
+
env["decidim.current_participatory_space"]
|
22
|
+
end
|
23
|
+
|
24
|
+
@component = env["decidim.current_component"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
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)
|
@@ -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.18.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: 2019-
|
11
|
+
date: 2019-08-28 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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.18.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.
|