Merge pull request #5685 from consuldemocracy/customization_docs

Update documentation to customize the application
This commit is contained in:
Javi Martín
2024-09-11 13:46:25 +02:00
committed by GitHub
44 changed files with 1149 additions and 558 deletions

View File

@@ -123,8 +123,8 @@
//= require_tree ./admin
//= require_tree ./sdg
//= require_tree ./sdg_management
//= require custom
//= require_tree ./custom
//= require custom
var initialize_modules = function() {
"use strict";

View File

@@ -1,7 +1,23 @@
// Overrides and adds customized javascripts in this file
// Read more on documentation:
// * English: https://github.com/consuldemocracy/consuldemocracy/blob/master/CUSTOMIZE_EN.md#javascript
// * Spanish: https://github.com/consuldemocracy/consuldemocracy/blob/master/CUSTOMIZE_ES.md#javascript
// Add calls to your custom JavaScript code using this file.
//
// We recommend creating your custom JavaScript code under the
// `app/assets/javascripts/custom/` folder and calling it from here.
//
// See the `docs/en/customization/javascript.md` file for more information.
var initialize_modules = function() {
"use strict";
// Add calls to your custom code here; this will be called when
// loading a page.
};
var destroy_non_idempotent_modules = function() {
"use strict";
// Add calls to your custom code here when your JavaScript code added
// in `initialize_modules` is not idempotent.
};
$(document).on("turbolinks:load", initialize_modules);
$(document).on("turbolinks:before-cache", destroy_non_idempotent_modules);

View File

View File

View File

@@ -2,6 +2,8 @@ Rails.application.routes.draw do
mount Ckeditor::Engine => "/ckeditor"
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
draw :custom
draw :account
draw :admin
draw :budget

28
config/routes/custom.rb Normal file
View File

@@ -0,0 +1,28 @@
# Add your custom routes here.
#
# For example, if you'd like to add a new section in the admin area
# to manage happy thoughts and verify they've become true, you can
# write:
#
# namespace :admin do
# resources :happy_thoughts do
# member do
# put :verify
# end
# end
# end
#
# Or, if, for example, you'd like to add a form to edit debates in the
# admin area:
#
# namespace :admin do
# resources :debates, only: [:edit, :update]
# end
#
# Doing so, the existing debates routes in the admin area will be kept,
# and the routes to edit and update them will be added.
#
# Note that the routes you define on this file will take precedence
# over the default routes. So, if you define a route for `/proposals`,
# the default action for `/proposals` will not be used and the one you
# define will be used instead.

View File

@@ -29,14 +29,19 @@
* [Customization](customization/customization.md)
* [Introduction](customization/introduction.md)
* [Translations and Texts](customization/translations.md)
* [Translations and texts](customization/translations.md)
* [Images](customization/images.md)
* [Views and Styles](customization/views_and_styles.md)
* [Javascript](customization/javascript.md)
* [Styles with CSS](customization/css.md)
* [JavaScript](customization/javascript.md)
* [Models](customization/models.md)
* [Controllers](customization/controllers.md)
* [Views and HTML](customization/views.md)
* [Components](customization/components.md)
* [Other Ruby classes (GraphQL, lib, mailers, builders)](customization/ruby.md)
* [Gems](customization/gems.md)
* [Overwriting Application](customization/overwriting.md)
* [Application configuration](customization/application.md)
* [Routes](customization/routes.md)
* [Tests](customization/tests.md)
* [Technical Features](features/features.md)
* [OAuth](features/oauth.md)
@@ -45,6 +50,7 @@
* [Configure Census Connection](features/census_configuration.md)
* [Local Census](features/local_census.md)
* [Multitenancy](features/multitenancy.md)
* [User content translations](features/user_content_translations.md)
* [Open Source project](open_source/open_source.md)
* [Code of conduct](open_source/code_of_conduct.md)

View File

@@ -0,0 +1,25 @@
# Customizing application configuration
## Overwriting application.rb
If you need to extend or modify the `config/application.rb` file, you can do so using the `config/application_custom.rb` file. For example, if you'd like to change the application timezone to the Canary Islands, just add:
```ruby
module Consul
class Application < Rails::Application
config.time_zone = "Atlantic/Canary"
end
end
```
In this particular case, note that the application time zone can alternatively be modified by editing the `config/secrets.yml` file.
Remember that in order to apply these changes you'll need to restart the application.
## Overwriting environment configuration
If you'd like to customize the development, test, staging, preproduction or production environments, you can do so by editing the files under `config/environments/custom/`.
Note that changes in `config/environments/custom/production.rb` are also applied to the staging and preproduction environments, and changes in `config/environments/custom/staging.rb` are also applied to the preproduction environment.
And remember that in order to apply these changes you'll need to restart the application.

View File

@@ -1,4 +1,4 @@
# Components
# Customizing components
For components, customization can be used to change both the logic (included in a `.rb` file) and the view (included in a `.erb` file). If you only want to customize the logic for, let's say, the `Admin::TableActionsComponent`, create a file named `app/components/custom/admin/table_actions_component.rb` with the following content:
@@ -10,6 +10,8 @@ class Admin::TableActionsComponent
end
```
Check the [models customization](models.md) section for more information about customizing Ruby classes.
If, on the other hand, you also want to customize the view, you need a small modification. Instead of the previous code, use:
```ruby
@@ -22,4 +24,4 @@ class Admin::TableActionsComponent
end
```
This will make the component use the view in `app/components/custom/admin/table_actions_component.html.erb`. You can create this file and customize it to your needs.
This will make the component use the view in `app/components/custom/admin/table_actions_component.html.erb`. You can create this file and customize it to your needs, the same way you can [customize views](views.md).

View File

@@ -0,0 +1,26 @@
# Customizing controllers
Just like models, controllers are written using Ruby code, so their customization is similar, only we'll use the `app/controllers/custom/` folder instead of the `app/models/custom/` folder. Check the [models customization](models.md) section for more information.
## Customizing allowed parameters
When customizing Consul Democracy, sometimes you might want to add a new field to a form. Other than [customizing the view](views.md) or [the component](components.md) that renders that form, you need to modify the controller so the new field is accepted. If not, the new field will silently be ignored; this is done to prevent [mass assignment attacks](https://en.wikipedia.org/wiki/Mass_assignment_vulnerability).
For example, let's say you've modified the `SiteCustomization::Page` model so it uses a field called `author_nickname` and you've added that field to the form to create a custom page in the admin area. To add the allowed parameter to the controller, create a file `app/controllers/custom/admin/site_customization/pages_controller.rb` with the following content:
```ruby
load Rails.root.join("app", "controllers", "admin", "site_customization", "pages_controller.rb")
class Admin::SiteCustomization::PagesController
private
alias_method :consul_allowed_params, :allowed_params
def allowed_params
consul_allowed_params + [:author_nickname]
end
end
```
Note we're aliasing and then calling the original `allowed_params` method, so all the parameters allowed in the original code will also be allowed in our custom method.

View File

@@ -0,0 +1,58 @@
# Customizing styles with CSS
Consul Democracy uses stylesheets written using [Sass](http://sass-lang.com/guide) with the SCSS syntax and placed under the `app/assets/stylesheets/` folder.
In order to make changes to styles, you can add them directly to a file under `app/assets/stylesheets/custom/`. Alternatively, you can use the `app/assets/stylesheets/custom.scss` file.
For example, to change the margin of the footer, create an `app/assets/stylesheets/custom/layout.scss` file with the following content:
```scss
.footer {
margin-top: $line-height;
}
```
This will overwrite the `margin-top` property applied to the `.footer` selector.
Note that CSS precedence rules still apply, so if there's a rule defining the `margin-top` property for the `body .footer` selector, the code above will be ignored. So, to effectively overwrite properties for certain elements, use the exact same selector used in the original code.
## Sass variables
Consul Democracy uses variables and functions defined by the [Foundation framework](http://foundation.zurb.com/) and adds a few other variables. In order to overwrite these variables, use the `app/assets/stylesheets/_consul_custom_overrides.scss` file. For example, to change the background color of the footer, add:
```scss
$footer: #fdfdfd;
```
The variables you can override are defined in the `_settings.scss` and `_consul_settings.scss` files.
To define new variables, you can use the `app/assets/stylesheets/_custom_settings.scss` file.
## CSS variables
In multi-tenant applications, Sass variables have a limitation: their value will be the same for every tenant.
So, for the most commonly customized colors, Consul Democracy provides CSS variables, which allow you to define different colors for different tenants.
For example, you can customize the brand, buttons, links and main layout colors for just the main tenant with:
```scss
.tenant-public {
--anchor-color: #372;
--anchor-color-hover: #137;
--brand: #153;
--brand-secondary: #134a00;
--button-background-hover: #fa0;
--button-background-hover-contrast: #{$black};
--footer: #e6e6e6;
--main-header: #351;
--top-links: var(--main-header);
--subnavigation: #ffd;
}
```
Check the `app/assets/stylesheets/custom/tenants.scss` file for more information.
## Accessibility
To maintain an appropriate accessibility level, if you add new colors, use a [Color contrast checker](http://webaim.org/resources/contrastchecker/) (WCAG AA is mandatory, WCAG AAA is recommended).

View File

@@ -1,11 +1,16 @@
# Customization
* [Introduction](introduction.md)
* [Translations and Texts](translations.md)
* [Translations and texts](translations.md)
* [Images](images.md)
* [Views and Styles](views_and_styles.md)
* [Javascript](javascript.md)
* [Styles with CSS](css.md)
* [JavaScript](javascript.md)
* [Models](models.md)
* [Controllers](controllers.md)
* [Views and HTML](views.md)
* [Components](components.md)
* [Other Ruby classes (GraphQL, lib, mailers, builders)](ruby.md)
* [Gems](gems.md)
* [Overwriting Application](overwriting.md)
* [Application configuration](application.md)
* [Routes](routes.md)
* [Tests](tests.md)

View File

@@ -1,9 +1,9 @@
# Gemfile
# Customizing the Gemfile
To add new gems (libraries) you can edit the `Gemfile_custom` file. For example to add [rails-footnotes](https://github.com/josevalim/rails-footnotes) gem you would just add:
To add new gems (external tools/libraries written in Ruby) you can edit the `Gemfile_custom` file. For example, to add the [rails-footnotes](https://github.com/josevalim/rails-footnotes) gem you would add:
```ruby
gem 'rails-footnotes', '~> 4.0'
gem "rails-footnotes", "~> 4.0"
```
And then just do the classic Ruby on Rails flow `bundle install` and following any gem specific install steps from it's own documentation.
And then run `bundle install` and follow any gem specific installation steps from its documentation.

View File

@@ -1,17 +1,21 @@
# Images
# Customizing images
If you want to overwrite any image, firstly you need to find out the filename, and by default it will be located under `app/assets/images`. For example if you want to change the header logo (`app/assets/images/logo_header.png`) you must create another file with the exact same file name under `app/assets/images/custom` folder. The images and icons that you will most likely want to change are:
If you want to overwrite any image, first you need to find out its filename, which will be located under `app/assets/images/`. For example, if you'd like to change the header logo (`app/assets/images/logo_header.png`), create another file with the exact same filename under the `app/assets/images/custom/` folder. Please note that, due to restrictions in the way Ruby on Rails loads images, **you will also have to rename the original file**. In the example, rename `app/assets/images/logo_header.png` to (for example) `app/assets/images/original_logo_header.png` and then create your custom image in `app/assets/images/custom/logo_header.png`.
* apple-touch-icon-200.png
* icon_home.png
* logo_email.png
* logo_header.png
* map.jpg
* social_media_icon.png
* social_media_icon_twitter.png
The images and icons that you will most likely want to change are:
* `apple-touch-icon-200.png`
* `icon_home.png`
* `logo_email.png`
* `logo_header.png`
* `map.jpg`
* `social_media_icon.png`
* `social_media_icon_twitter.png`
Note that, instead of customizing the image using the method explained above, many of these images can be customized in the admin area, under the "Site content custom images" section.
## City Map
You'll find the city map at [`/app/assets/images/map.jpg`](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg), just replace it with an image of your cities districts ([example](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg)).
You'll find the city map at `/app/assets/images/map.jpg`. You can replace it with an image of your city districts, like this [map image example](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg).
Afterwards we recommend you to use an online tool like <http://imagemap-generator.dariodomi.de/> or <https://www.image-map.net/> to generate the html coordinates to be able to generate a [image-map](https://www.w3schools.com/tags/tag_map.asp) for each of the districts. Those coordinates should be introduced on the respective Geozones at the admin geozones panel (`/admin/geozones`).
Afterwards, we recommend you use an online tool like <http://imagemap-generator.dariodomi.de/> or <https://www.image-map.net/> to generate the html coordinates to be able to generate an [image-map](https://www.w3schools.com/tags/tag_map.asp) for each of the districts. Those coordinates should be introduced on the respective geozones at the admin geozones panel (`/admin/geozones`).

View File

@@ -1,145 +1,57 @@
# Customization
You can modify your own Consul Democracy to have your custom visual style, but first you'll have to [create your own fork from](../getting_started/create.md).
You can modify your own Consul Democracy to adapt it to the visual style of your institution. To do so, first you'll have to [create your own fork](../getting_started/create.md).
We've created an specific structure where you can overwrite and customize the application in a way that will let you keep updating it from Consul Democracy's main repository, without having conflicts on code merging or risking loosing your customization changes. We try to make Consul Democracy as vanilla as possible to help other developers onboard the codebase.
The main principle to follow when customizing Consul Democracy is doing so in a way that custom changes are isolated so, when updating to a new version of Consul Democracy, it'll be easier to check which code belongs to the application and how the code changed in the new version. Otherwise, it'll be very hard to adapt your custom changes to the new version.
For that purpose, Consul Democracy includes custom folders so you rarely have to touch the original application files.
## Special Folders and Files
In order to customize your Consul Democracy fork, you'll make use of some `custom` folders on the following paths:
* `config/locales/custom/`
* `app/assets/images/custom/`
* `app/views/custom/`
* `app/assets/javascripts/custom/`
* `app/assets/stylesheets/custom/`
* `app/components/custom/`
* `app/controllers/custom/`
* `app/form_builders/custom/`
* `app/graphql/custom/`
* `app/lib/custom/`
* `app/mailers/custom/`
* `app/models/custom/`
* `app/models/custom/concerns/`
* `app/views/custom/`
* `config/locales/custom/`
* `spec/components/custom/`
* `spec/controllers/custom/`
* `spec/models/custom/`
* `spec/routing/custom/`
* `spec/system/custom/`
Also these are the files where you can apply some customization:
There are also files where you can apply some customizations:
* `app/assets/javascripts/custom.js`
* `app/assets/stylesheets/custom.css`
* `app/assets/stylesheets/_custom_settings.css`
* `app/assets/javascripts/custom.js`
* `app/assets/stylesheets/_consul_custom_overrides.css`
* `config/application_custom.rb`
* `config/environments/custom/development.rb`
* `config/environments/custom/preproduction.rb`
* `config/environments/custom/production.rb`
* `config/environments/custom/staging.rb`
* `config/environments/custom/test.rb`
* `config/routes/custom.rb`
* `Gemfile_custom`
* `config/application.custom.rb`
## Remote translations on demand by the user
Using these files, you will be able to customize [translations](translations.md), [images](images.md), [CSS](css.md), [JavaScript](javascript.md), [HTML views](views.md), any Ruby code like [models](models.md), [controllers](controllers.md), [components](components.md) or [other Ruby classes](ruby.md), [gems](gems.md), [application configuration](application.md), [routes](routes.md) and [tests](tests.md).
The aim of this service is to be able to offer all the dynamic contents of the application (proposals, debates, budget investments and comments) in different languages without the need for a user or administrator to have created each one of their translations.
## Running the tests
When a user visits a page with a language where there is untranslated content, they will have a button to request the translation of all the content. This content will be sent to an automatic translator (in this case [Microsoft TranslatorText](https://azure.microsoft.com/en-us/products/cognitive-services/translator/)) and as soon as the response is obtained, all these translations will be available to any user.
When customizing the code, it is **very important** that all the tests in your test suite are still passing. If not, there will be issues when upgrading to a new version of Consul Democracy (or even when updating the custom changes) that won't be detected until the code is running on production. Consul Democracy includes more than 6000 tests checking the way the application behaves; without them, it'd be impossible to make sure that new code doesn't break any existing behavior.
### Getting started
So, first, make sure you've [configured your fork](../getting_started/configuration.md) so it uses a continuous integration system that runs all the tests whenever you make changes to the code. When changing the code, we recommend opening pull requests (a.k.a. merge requests) using a development branch so the tests run before the custom changes are added to the `master` branch.
In order to use this functionality, the following steps are necessary:
Then, if some tests fail, check one of the tests and see whether the test fails because the custom code contains a bug or because the test checks a behavior that no longer applies due to your custom changes (for example, you might modify the code so only verified users can add comments, but there might be a test checking that any user can add comments, which is the default behavior). If the test fails due to a bug in the custom code, fix it ;). If it fails due to a behavior that no longer applies, check the [tests customization](tests.md) section.
1. Have an api key to connect to the translation service. For this we need an [Azure account](https://azure.microsoft.com/en-us/)
1. Once you are logged into the Azure portal, subscribe to the Translator in Cognitive Service.
1. Once you have subscribed to the Translator Text service, you will have access to 2 api keys in the section **Resource Management > Keys and Endpoint** that will be necessary for the configuration of the translation service in your application.
### Configuration
To activate the translation service in your application you must complete the following steps:
#### Add api key in the application
In the previous section we have commented that once subscribed to the translation service we have 2 api keys. To configure the service correctly in our application we must add one of the two api keys in the file `secrets.yml` in section `apis:` with the key `microsoft_api_key` as we can see in the following image:
![Add api key to secrets](../../img/translations/remote_translations/add-api-key-to-secrets.png)
#### Activate module
Once we have the new key in the `secrets.yml` we can now proceed to activate the module. To activate the functionality you must follow 2 steps:
1. Execute the following command `bin/rake settings:create_remote_translations_setting RAILS_ENV=production`
1. Accessing through the administration panel of your application to the section **Configuración > Funcionalidades** and activate module **Traducciones Remotas** as shown below:
![Active remote translations](../../img/translations/remote_translations/active-remote-translations-en.png)
### Use Cases
Once we have the api key in our `secrets.yml` and the activated module, users will already be able to use the functionality.
We attach some screenshots of how the application interacts with our users:
* When a user visits a page in a language without translated content, an informative text will appear at the top of the page and a button to request the translation. (**Note:** *If user visit page with a language not supported by the translation service, no text or translation button will be displayed. See section: Available languages for remote translation*)
![Display text and button](../../img/translations/remote_translations/display-text-and-button-en.png)
* Once the user click the `Translate page` button, the translations are enqueued and the page is reloaded with a notice (*Informing that the translations have been requested correctly*) and an informative text in the header (*explaining when you will be able to see these translations*).
![Display notice and text after enqueued translations](../../img/translations/remote_translations/display-notice-and-text-after-enqueued-en.png)
* If an user visit a page that does not have translations but have already been requested by another user. The application will not show you the translate button, but an informative text in the header (*explaining when you will be able to see these translations*).
![Display text explaining that translations are pending](../../img/translations/remote_translations/display-text-translations-pending-en.png)
* The translation request, response processing and data saving are delegated to `Delayed Jobs` and as soon as they are processed, the user will be able to read them after page refresh.
![Display translated content](../../img/translations/remote_translations/display-translated-content-en.png)
### Available languages for remote translation
Currently these are all the [available languages](https://api.cognitive.microsofttranslator.com/languages?api-version=3.0) in the translation service:
```yml
["af", "am", "ar", "as", "az", "ba", "bg", "bn", "bo", "bs", "ca", "cs", "cy", "da", "de", "dv", "el", "en", "es", "et", "eu", "fa", "fi", "fil", "fj", "fo", "fr", "fr-CA", "ga", "gl", "gu", "ha", "he", "hi", "hr", "hsb", "ht", "hu", "hy", "id", "ig", "ikt", "is", "it", "iu", "iu-Latn", "ja", "ka", "kk", "km", "kmr", "kn", "ko", "ku", "ky", "ln", "lo", "lt", "lug", "lv", "lzh", "mg", "mi", "mk", "ml", "mn-Cyrl", "mn-Mong", "mr", "ms", "mt", "mww", "my", "nb", "ne", "nl", "nso", "nya", "or", "otq", "pa", "pl", "prs", "ps", "pt", "pt-PT", "ro", "ru", "run", "rw", "sk", "sl", "sm", "sn", "so", "sq", "sr-Cyrl", "sr-Latn", "st", "sv", "sw", "ta", "te", "th", "ti", "tk", "tlh-Latn", "tlh-Piqd", "tn", "to", "tr", "tt", "ty", "ug", "uk", "ur", "uz", "vi", "xh", "yo", "yua", "yue", "zh-Hans", "zh-Hant", "zu"]
```
Of all the languages that Consul Democracy currently has defined (`available_locales`) in `config/application.rb` the only one that is not listed above and therefore no translation service is offered is Valencian `["val"]`.
### Pricing
The translation service used has the most competitive [pricing](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/translator/).
The price for each 1 Million characters translated is $10 and there is no fixed cost per month.
Although technical measures have been taken to prevent misuse of this service, we recommend the creation of Alerts offered by Azure so that an Administrator can be notified in the event of detecting unusual use of the service. This service has a cost of $0.10 per month.
To create an Alert in Azure we must follow the following steps:
1. Sign in to the **Azure Portal**.
1. Access the **Translator** service created earlier.
1. Go to **Monitoring > Alerts** in the side menu:
1. Go to **Create alert rule**.
1. In **Select a signal** select `Text Characters Translated`.
1. Once selected we must define the logic of the Alert to suit our needs. Ex: Fill "Operator" field with "Greater than" option, fill "Aggregation type" field with "Total" option and fill "Threshold value" field with the number of characters we consider should be translated before being notified. In this section you can also set the time period and frequency of evaluation.
1. In order to be notified we have to create an **Action Group** and associate it with this Alert we're creating. To do this, access the button **Create** and fill out the form. As you can see there are different types of actions, we must select **Email/SMS/Push/Voice** and configure the option that we consider convenient according to our needs.
1. Once this group of actions has been created, it is directly associated with the rule we are creating.
1. Finally, all you have to do is add a name and click on the **Review + create**
### Add a new translation service
If you want to integrate more translation services for any reason (new translation service appears, you want to change to include languages that are currently not supported, etc.) the code is ready to be added.
This is made possible by the `RemoteTranslations::Caller` class which is an intermediate layer between untranslated content management and the currently used Microsoft Translation Client.
A good solution for adding another translation service would be to replace the call to the `MicrosoftTranslateClient` in the `translations` method of `RemoteTranslations::Caller` with the new service implemented.
If you want to coexist with both should only be managed in which case we want to use one or the other, either through specific conditions in the code or through a management in the Settings of the application.
```ruby
class RemoteTranslationsCaller
...
def translations
@translations ||= RemoteTranslations::Microsoft::Client.new.call(fields_values, locale)
# Add new RemoteTranslations Client
# @translations = RemoteTranslations::NewTranslateClient::Client.new.call(fields_values, locale_to)
end
...
end
```
## Translation interface
The aim of this feature is to allow users the introduction of dynamic contents in many languages at the same time. From the administration panel you can activate or deactivate it. If you deactivate this feature (default configuration) users will be able to enter one single translation.
### Enable module
To activate this feature you must follow 2 steps:
1. Execute the following command `bin/rake settings:create_translation_interface_setting RAILS_ENV=production` (This is only required for already existing intallations, for new Consul Democracy installations this step is not needed).
2. Accessing as administrator user to the administration panel of your Consul Democracy application to the section **Configuration > Features** and activating the feature called **Translation Interface** as you can see next:
![Active interface translations](../../img/translations/interface_translations/active-interface-translations-en.png)
### Use Cases
* When the translation interface is active:
As you can see in the image below translation interface has two selectors, the firt one "Select language" is to switch between enabled languages and the second one "Add language" is to add new languages to the form. Translatable fields appears with a blue background to facilitate users to distinguish between translatable and not translatable fields. Additionally interface provides a link `Remove language` to delete the current language shown at "Select language". If a user accidentally removes a translation he can recover it re-adding it to the form.
This feature is visible during creation and edition of translatable resources.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-enabled-en.png)
* When the translation interface is disabled:
When this feature is deactivated users will see standard forms without translation interface and without translation highlight.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-disabled-en.png)
We also **strongly recommend adding tests for your custom changes**, so you'll have a way to know whether these changes keep working when upgrading to a new version of Consul Democracy.

View File

@@ -1,15 +1,52 @@
# Javascript
# Customizing JavaScript
If you want to add some custom Javascript code, `app/assets/javascripts/custom.js` is the file to do it. For example to create a new alert just add:
In order to add custom JavaScript code, you can create a file under `app/assets/javascripts/custom/`.
## Adding new functions
To create a new function, we need to define it and then call it when the browser loads a page.
For example, in order to create an alert, we can create the file `app/assets/javascripts/custom/alert.js` with the following content:
```js
$(function(){
alert('foobar');
});
(function() {
"use strict";
App.Alert = {
initialize: function() {
alert("foobar");
}
};
}).call(this);
```
If you work with Coffeescript code you can check it with [coffeelint](http://www.coffeelint.org/) (install with `npm install -g coffeelint`) :
Then, edit the `initialize_modules` function in `app/assets/javascripts/custom.js`:
```bash
coffeelint .
```js
var initialize_modules = function() {
"use strict";
// Add calls to your custom code here; this will be called when
// loading a page
App.Alert.initialize();
};
```
## Overwriting existing functions
In Consul Democracy, functions are defined as object properties. That means that, in order to overwrite a function, you can simply redefine the property of the object containing it. Where possible, it's recommended that your custom code calls the original code and only modifies the cases where it should behave differently. This way, when upgrading to a new version of Consul Democracy that updates the original functions, your custom functions will automatically include the modifications in the original code as well. Sometimes this won't be possible, though, which means you might need to change your custom function when upgrading.
For example, let's change the `generatePassword` function in `app/assets/javascripts/managers.js`. To do so, create a file `app/assets/javascripts/custom/managers.js` with the following content:
```js
(function() {
"use strict";
App.Managers.consulGeneratePassword = App.Managers.generatePassword;
App.Managers.generatePassword = function() {
return App.Managers.consulGeneratePassword() + "custom";
};
}).call(this);
```
This will return what the original function returns followed by the "custom" string.

View File

@@ -1,75 +1,63 @@
# Models
# Customizing models
If you need to create new models or customize existent ones, you can do it so at the `app/models/custom` folder. Keep in mind that for old models you'll need to firstly require the dependency.
In order to create new models or customize existing ones, you can use the `app/models/custom/` folder.
For example for Madrid's City Hall fork its required to check the zip code's format (it always starts with 280 followed by 2 digits). That check is at `app/models/custom/verification/residence.rb`:
If you're adding a new model that doesn't exist in the original Consul Democracy, simply add it to that folder.
If, on the other hand, you are changing a model that exists in the application, create a file in `app/models/custom/` with same name as the file you're changing. For example, if you're changing the `app/models/budget/investment.rb` file, create a file named `app/models/custom/budget/investment.rb` and require the original one:
```ruby
load Rails.root.join("app", "models", "verification", "residence.rb")
load Rails.root.join("app", "models", "budget", "investment.rb")
class Verification::Residence
validate :postal_code_in_madrid
validate :residence_in_madrid
def postal_code_in_madrid
errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code?
class Budget
class Investment
end
def residence_in_madrid
return if errors.any?
unless residency_valid?
errors.add(:residence_in_madrid, false)
store_failed_attempt
Lock.increase_tries(user)
end
end
private
def valid_postal_code?
postal_code =~ /^280/
end
end
```
Do not forget to cover your changes with a test at the `spec/models/custom` folder. Following the example we could create `spec/models/custom/residence_spec.rb`:
Since the custom file requires the original one, at this point, the custom model will behave exactly as the original.
Note that, if we do not require the original file, that file won't be loaded and the custom model will do nothing, which will likely result in errors.
## Adding new methods
In order to add a new method, simply add the new code to the model. For example, let's add a scope that returns the investments created last month:
```ruby
require 'rails_helper'
describe Verification::Residence do
let(:residence) { build(:verification_residence, document_number: "12345678Z") }
describe "verification" do
describe "postal code" do
it "should be valid with postal codes starting with 280" do
residence.postal_code = "28012"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
residence.postal_code = "28023"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
end
it "should not be valid with postal codes not starting with 280" do
residence.postal_code = "12345"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
residence.postal_code = "13280"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.")
end
end
load Rails.root.join("app", "models", "budget", "investment.rb")
class Budget
class Investment
scope :last_month, -> { where(created_at: 1.month.ago..) }
end
end
```
With this code, the custom model will have all the methods of the original model (because it loads the original file) plus the `last_month` scope.
## Modifying existing methods
When modifying existing methods, it is strongly recommended that, when possible, **your custom code calls the original code** and only modifies the cases where it should behave differently. This way, when upgrading to a new version of Consul Democracy that updates the original methods, your custom methods will automatically include the modifications in the original code as well. Sometimes this won't be possible, though, which means you might need to change your custom method when upgrading.
For example, to change the common abilities model so only verified users can create comments, we'll create a file `app/models/custom/abilities/common.rb` with the following content:
```ruby
load Rails.root.join("app", "models", "abilities", "common.rb")
module Abilities
class Common
alias_method :consul_initialize, :initialize # create a copy of the original method
def initialize(user)
consul_initialize(user) # call the original method
cannot :create, Comment # undo the permission added in the original method
if user.level_two_or_three_verified?
can :create, Comment
end
end
end
end
```
You can find another example in the `app/models/custom/setting.rb` file.

View File

@@ -1,14 +0,0 @@
# Overwriting application.rb
If you need to extend or modify the `config/application.rb` just do it at the `config/application_custom.rb` file. For example if you want to change de default language to English, just add:
```ruby
module Consul
class Application < Rails::Application
config.i18n.default_locale = :en
config.i18n.available_locales = [:en, :es]
end
end
```
Remember that in order to see this changes live you'll need to restart the server.

View File

@@ -0,0 +1,27 @@
# Customizing routes
When adding custom controller actions, you also need to define a route to configure the URL that will be used for those actions. You can do so by editing the `config/routes/custom.rb` file.
For example, if you'd like to add a new section in the admin area to manage happy thoughts and verify they've become true, you can write:
```ruby
namespace :admin do
resources :happy_thoughts do
member do
put :verify
end
end
end
```
Or, if, for example, you'd like to add a form to edit debates in the admin area:
```ruby
namespace :admin do
resources :debates, only: [:edit, :update]
end
```
Doing so, the existing debates routes in the admin area will be kept, and the routes to edit and update them will be added.
Note that the routes you define on this file will take precedence over the default routes. So, if you define a route for `/proposals`, the default action for `/proposals` will not be used and the one you define will be used instead.

View File

@@ -0,0 +1,30 @@
# Customizing other Ruby classes
Other than models, controllers and components, there are a few other folders containing Ruby code:
* `app/form_builders/`
* `app/graphql/`
* `app/lib/`
* `app/mailers/`
The files in these folders can be customized like any other Ruby file (see [customizing models](models.md) for more information).
For example, in order to customize the `app/form_builders/consul_form_builder.rb` file, create a file `app/form_builders/custom/consul_form_builder.rb` with the following content:
```ruby
load Rails.root.join("app", "form_builders", "consul_form_builder.rb")
class ConsulFormBuilder
# Your custom logic here
end
```
Or, in order to customize the `app/lib/remote_translations/caller.rb` file, create a file `app/lib/custom/remote_translations/caller.rb` with the following content:
```ruby
load Rails.root.join("app", "lib", "remote_translations", "caller.rb")
class RemoteTranslations::Caller
# Your custom logic here
end
```

View File

@@ -0,0 +1,66 @@
# Customizing tests
Tests check whether the application behaves as expected. For this reason, it is **extremely important** that you write tests for all the features you introduce or modify. Without tests, you'll have no reliable way to confirm that the application keeps working as expected whenever you change the code or upgrade to a new version of Consul Democracy. Consul Democracy contains more than 6000 tests checking the way the application behaves; without them, it'd be impossible to make sure that new code doesn't break any existing behavior.
Since running the tests on your development machine might take more than an hour, we recommend [configuring your fork](../getting_started/configuration.md) so it uses a continuous integration system that runs all the tests whenever you make changes to the code. When changing the code, we recommend running the tests in a development branch by opening pull requests (a.k.a. merge requests) so the tests run before the custom changes are added to the `master` branch.
Then, if some tests fail, check one of the tests and see whether the test fails because the custom code contains a bug or because the test checks a behavior that no longer applies due to your custom changes (for example, you might modify the code so only verified users can add comments, but there might be a test checking that any user can add comments, which is the default behavior). If the test fails due to a bug in the custom code, fix it ;). If it fails due to a behavior that no longer applies, then you'll have to change the test.
Changing a test is a two-step process:
1. Make sure the test checking the default behavior in Consul Democracy isn't run anymore
2. Write a new test for the new behavior
For the first step, add a `:consul` tag to the test or block of tests. For example, let's check this code:
```ruby
describe Users::PublicActivityComponent, controller: UsersController do
describe "follows tab" do
context "public interests is checked" do
it "is displayed for everyone" do
# (...)
end
it "is not displayed when the user isn't following any followables", :consul do
# (...)
end
it "is the active tab when the follows filters is selected", :consul do
# (...)
end
end
context "public interests is not checked", :consul do
it "is displayed for its owner" do
# (...)
end
it "is not displayed for anonymous users" do
# (...)
end
it "is not displayed for other users" do
# (...)
end
it "is not displayed for administrators" do
# (...)
end
end
end
end
```
In the first context, only the first test will be executed. The other two tests will be ignored because they contain the `:consul` tag.
The second context contains the `:consul` tag itself, so none of its tests will be executed.
Remember: whenever you add a `:consul` tag to a test because the application no longer behaves as that test expects, write a new test checking the new behavior. If you don't, the chances of people getting 500 errors (or, even worse, errors that nobody notices) when visiting your page will dramatically increase.
To add a custom test, use the custom folders inside the `spec/` folder:
* `spec/components/custom/`
* `spec/controllers/custom/`
* `spec/models/custom/`
* `spec/routing/custom/`
* `spec/system/custom/`

View File

@@ -1,38 +1,38 @@
# Translations and Texts
# Customizing translations and texts
## Translations
Currently, Consul Democracy is totally or partially translated to multiple languages. You can find the translations at the [Crowdin project](https://translate.consuldemocracy.org/).
Please [join the translators](https://crwd.in/consul) to help us complete existing ones, or contact us through [Consul Democracy's gitter](https://gitter.im/consul/consul) to become a proofreader and validate translators' contributions.
Please [join the translators](https://crwd.in/consul) to help us complete existing languages, or contact us through [Consul Democracy's discussions](https://github.com/consuldemocracy/consuldemocracy/discussions) to become a proofreader and validate translators' contributions.
If your language isn't already present in the Crowdin project, please [open an issue](https://github.com/consuldemocracy/consuldemocracy/issues/new?title=New%20language&body=Hello%20I%20would%20like%20to%20have%20my%20language%20INSERT%20YOUR%20LANGUAGE%20NAME%20added%20to%20Consul%20Democracy) and we'll set it up in a breeze.
If you want to check existing translations of the user-facing texts you can find them organized in YML files under `config/locales/` folder. Take a look at the official Ruby on Rails [internationalization guide](http://guides.rubyonrails.org/i18n.html) to better understand the translations system.
The existing translations of the user-facing texts are organized in YAML files under the `config/locales/` folder. Take a look at the official Ruby on Rails [internationalization guide](http://guides.rubyonrails.org/i18n.html) to better understand the translations system.
## Custom Texts
## Custom texts
Since Consul Democracy is always evolving with new features, and in order to make your fork easier to be updated, we strongly recommend translation files not to be modified, but instead "overwritten" with custom translation files in case a text needs to be customized for you.
Since Consul Democracy is always evolving with new features, and in order to make it easier to update your fork, we strongly recommend that translation files aren't modified, but instead "overwritten" with custom translation files in case you need to customize a text.
So if you just want to change some of the existing texts, you can just drop your changes at the `config/locales/custom/` folder. We strongly recommend to include only those texts that you want to change instead of a whole copy of the original file. For example if you want to customize the text "Ayuntamiento de Madrid, 2016" that appears on every page's footer, firstly you want to locate where it's used (`app/views/layouts/_footer.html.erb`) and look at the locale identifier inside the code:
So, if you'd like to change some of the existing texts, you can add your changes to the `config/locales/custom/` folder. You should only include the texts you'd like to change instead of copying the original file. For example, if you'd like to customize the text "CONSUL DEMOCRACY, 2024" (or the current year) that appears on the footer of every page, first locate where it's used (in this case, `app/components/layouts/footer_component.html.erb`) and look at the locale identifier inside the code:
```ruby
```erb
<%= t("layouts.footer.copyright", year: Time.current.year) %>
```
Then find the file where this identifier will be located (in that case `config/locales/es/general.yml`) following this structure (we're only displaying the relevant parts in the following snippet):
Then find the file where this identifier will be located (in this case, `config/locales/en/general.yml`), and create a file under `config/locales/custom/` (in this case, create a file named `config/locales/custom/en/general.yml`) with the following content:
```yml
es:
en:
layouts:
footer:
copyright: Ayuntamiento de Madrid, %{year}
copyright: Your Organization, %{year}
```
In order to customize it, you should create a new file `config/locales/custom/es/general.yml` with just that content, and change "Ayuntamiento de Madrid" with our organization name. We strongly recommend to make copies from `config/locales/` and modify or delete the lines as needed to keep the indentation structure and avoid issues.
Note that custom locale files should only include your custom texts and not the original texts. This way it'll be easier to upgrade to a new version of Consul Democracy.
## Maintaining your Custom Texts & Languages
## Maintaining your custom texts and languages
Consul Democracy has the [i18n-tasks](https://github.com/glebm/i18n-tasks) gem, it's an awesome helping tool to manage i18n translations. Just check `i18n-tasks health` for a nice report.
Consul Democracy uses the [i18n-tasks](https://github.com/glebm/i18n-tasks) gem, which is an awesome tool to manage translations. Run `i18n-tasks health` for a nice report.
If you have a custom language different than English, you should add it to the [i18n-tasks.yml config file both `base_locale` and `locales`](https://github.com/consuldemocracy/consuldemocracy/blob/master/config/i18n-tasks.yml#L4-L7) variables so your language files will be checked as well.
If you have a custom language different than English, you should add it to both `base_locale` and `locales` variables in the [i18n-tasks.yml config file](https://github.com/consuldemocracy/consuldemocracy/blob/master/config/i18n-tasks.yml#L3-L6), so your language files will be checked as well.

View File

@@ -0,0 +1,11 @@
# Customizing views and HTML
Just like most Ruby on Rails application, Consul Democracy uses ERB templates to render HTML. These templates are traditionally placed in the `app/views/` folder.
Unlike [Ruby code](models.md), [CSS code](css.md) or [JavaScript code](javascript.md), it isn't possible to overwrite only certain parts of an ERB template. So, in order to customize a view, find the correct file under the `app/views/` folder and copy it to `app/views/custom/`, keeping as well any sub-folder structure, and then apply your customizations. For example, to customize `app/views/welcome/index.html.erb`, copy it to `app/views/custom/welcome/index.html.erb`.
In order to keep track of your custom changes, when using git, we recommend copying the original file to the custom folder in one commit (without any modifications) and then modifying the custom file in a different commit. When upgrading to a new version of Consul Democracy, this will make it easier to check the differences between the view in the old version of Consul Democracy, the view in the new version of Consul Democracy, and your custom changes.
As mentioned earlier, the custom file will completely overwrite the original one. This means that, when upgrading to a new version of Consul Democracy, the changes in the original file will be ignored. You'll have to check the changes in the original file and apply them to your custom file if appropriate.
**Note**: Consul Democracy only uses the `app/views/` folder for code written before 2021. Code written since then is placed under the `app/components/` folder. The main reason is that components allow extracting some of the logic to a Ruby file, and maintaining custom Ruby code is easier than maintaining custom ERB code.

View File

@@ -1,33 +0,0 @@
# Views and Styles
## Views (HTML)
If you want to change any page HTML you can just find the correct file under the `app/views` folder and put a copy at `app/views/custom` keeping as well any sub-folder structure, and then apply your customizations. For example if you want to customize `app/views/pages/conditions.html` you'll have to make a copy at `app/views/custom/pages/conditions.html.erb` (note the `pages` subdirectory).
## CSS Styles with SASS
In order to make changes to any CSS selector (custom style sheets), you can add them directly at `app/assets/stylesheets/custom.scss`. For example to change the header color (`.top-links`) you can just add:
```css
.top-links {
background: red;
}
```
If you want to change any [foundation](http://foundation.zurb.com/) variable, you can do it at the `app/assets/stylesheets/_custom_settings.scss` file. For example to change the main application color just add:
```css
$brand: #446336;
```
We use [SASS, with SCSS syntax](http://sass-lang.com/guide) as CSS preprocessor.
Also you can check your scss files syntax with
```bash
scss-lint
```
## Accessibility
To maintain accessibility level, if you add new colors use a [Color contrast checker](http://webaim.org/resources/contrastchecker/) (WCAG AA is mandatory, WCAG AAA is recommended).

View File

@@ -0,0 +1,123 @@
# Translations of user content
## Remote translations on demand by the user
The aim of this service is to be able to offer all the dynamic contents of the application (proposals, debates, budget investments and comments) in different languages without the need for a user or administrator to have created each one of their translations.
When a user visits a page with a language where there is untranslated content, they will have a button to request the translation of all the content. This content will be sent to an automatic translator (in this case [Microsoft TranslatorText](https://azure.microsoft.com/en-us/products/cognitive-services/translator/)) and as soon as the response is obtained, all these translations will be available to any user.
### Getting started
In order to use this functionality, the following steps are necessary:
1. Have an api key to connect to the translation service. For this we need an [Azure account](https://azure.microsoft.com/en-us/)
1. Once you are logged into the Azure portal, subscribe to the Translator in Cognitive Service.
1. Once you have subscribed to the Translator Text service, you will have access to 2 api keys in the section **Resource Management > Keys and Endpoint** that will be necessary for the configuration of the translation service in your application.
### Configuration
To activate the translation service in your application you must complete the following steps:
#### Add api key in the application
In the previous section we have commented that once subscribed to the translation service we have 2 api keys. To configure the service correctly in our application we must add one of the two api keys in the file `secrets.yml` in section `apis:` with the key `microsoft_api_key` as we can see in the following image:
![Add api key to secrets](../../img/translations/remote_translations/add-api-key-to-secrets.png)
#### Activate module
Once we have the new key in the `secrets.yml` we can now proceed to activate the module. To activate the functionality you must follow 2 steps:
1. Execute the following command `bin/rake settings:create_remote_translations_setting RAILS_ENV=production`
1. Accessing through the administration panel of your application to the section **Configuración > Funcionalidades** and activate module **Traducciones Remotas** as shown below:
![Active remote translations](../../img/translations/remote_translations/active-remote-translations-en.png)
### Use Cases
Once we have the api key in our `secrets.yml` and the activated module, users will already be able to use the functionality.
We attach some screenshots of how the application interacts with our users:
* When a user visits a page in a language without translated content, an informative text will appear at the top of the page and a button to request the translation. (**Note:** *If user visit page with a language not supported by the translation service, no text or translation button will be displayed. See section: Available languages for remote translation*)
![Display text and button](../../img/translations/remote_translations/display-text-and-button-en.png)
* Once the user click the `Translate page` button, the translations are enqueued and the page is reloaded with a notice (*Informing that the translations have been requested correctly*) and an informative text in the header (*explaining when you will be able to see these translations*).
![Display notice and text after enqueued translations](../../img/translations/remote_translations/display-notice-and-text-after-enqueued-en.png)
* If an user visit a page that does not have translations but have already been requested by another user. The application will not show you the translate button, but an informative text in the header (*explaining when you will be able to see these translations*).
![Display text explaining that translations are pending](../../img/translations/remote_translations/display-text-translations-pending-en.png)
* The translation request, response processing and data saving are delegated to `Delayed Jobs` and as soon as they are processed, the user will be able to read them after page refresh.
![Display translated content](../../img/translations/remote_translations/display-translated-content-en.png)
### Available languages for remote translation
Currently these are all the [available languages](https://api.cognitive.microsofttranslator.com/languages?api-version=3.0) in the translation service:
```yml
["af", "am", "ar", "as", "az", "ba", "bg", "bn", "bo", "bs", "ca", "cs", "cy", "da", "de", "dv", "el", "en", "es", "et", "eu", "fa", "fi", "fil", "fj", "fo", "fr", "fr-CA", "ga", "gl", "gu", "ha", "he", "hi", "hr", "hsb", "ht", "hu", "hy", "id", "ig", "ikt", "is", "it", "iu", "iu-Latn", "ja", "ka", "kk", "km", "kmr", "kn", "ko", "ku", "ky", "ln", "lo", "lt", "lug", "lv", "lzh", "mg", "mi", "mk", "ml", "mn-Cyrl", "mn-Mong", "mr", "ms", "mt", "mww", "my", "nb", "ne", "nl", "nso", "nya", "or", "otq", "pa", "pl", "prs", "ps", "pt", "pt-PT", "ro", "ru", "run", "rw", "sk", "sl", "sm", "sn", "so", "sq", "sr-Cyrl", "sr-Latn", "st", "sv", "sw", "ta", "te", "th", "ti", "tk", "tlh-Latn", "tlh-Piqd", "tn", "to", "tr", "tt", "ty", "ug", "uk", "ur", "uz", "vi", "xh", "yo", "yua", "yue", "zh-Hans", "zh-Hant", "zu"]
```
Of all the languages that Consul Democracy currently has defined (`available_locales`) in `config/application.rb` the only one that is not listed above and therefore no translation service is offered is Valencian `["val"]`.
### Pricing
The translation service used has the most competitive [pricing](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/translator/).
The price for each 1 Million characters translated is $10 and there is no fixed cost per month.
Although technical measures have been taken to prevent misuse of this service, we recommend the creation of Alerts offered by Azure so that an Administrator can be notified in the event of detecting unusual use of the service. This service has a cost of $0.10 per month.
To create an Alert in Azure we must follow the following steps:
1. Sign in to the **Azure Portal**.
1. Access the **Translator** service created earlier.
1. Go to **Monitoring > Alerts** in the side menu:
1. Go to **Create alert rule**.
1. In **Select a signal** select `Text Characters Translated`.
1. Once selected we must define the logic of the Alert to suit our needs. Ex: Fill "Operator" field with "Greater than" option, fill "Aggregation type" field with "Total" option and fill "Threshold value" field with the number of characters we consider should be translated before being notified. In this section you can also set the time period and frequency of evaluation.
1. In order to be notified we have to create an **Action Group** and associate it with this Alert we're creating. To do this, access the button **Create** and fill out the form. As you can see there are different types of actions, we must select **Email/SMS/Push/Voice** and configure the option that we consider convenient according to our needs.
1. Once this group of actions has been created, it is directly associated with the rule we are creating.
1. Finally, all you have to do is add a name and click on the **Review + create**
### Add a new translation service
If you want to integrate more translation services for any reason (new translation service appears, you want to change to include languages that are currently not supported, etc.) the code is ready to be added.
This is made possible by the `RemoteTranslations::Caller` class which is an intermediate layer between untranslated content management and the currently used Microsoft Translation Client.
A good solution for adding another translation service would be to replace the call to the `MicrosoftTranslateClient` in the `translations` method of `RemoteTranslations::Caller` with the new service implemented.
If you want to coexist with both should only be managed in which case we want to use one or the other, either through specific conditions in the code or through a management in the Settings of the application.
```ruby
class RemoteTranslationsCaller
...
def translations
@translations ||= RemoteTranslations::Microsoft::Client.new.call(fields_values, locale)
# Add new RemoteTranslations Client
# @translations = RemoteTranslations::NewTranslateClient::Client.new.call(fields_values, locale_to)
end
...
end
```
## Translation interface
The aim of this feature is to allow users the introduction of dynamic contents in many languages at the same time. From the administration panel you can activate or deactivate it. If you deactivate this feature (default configuration) users will be able to enter one single translation.
### Enable module
To activate this feature you must follow 2 steps:
1. Execute the following command `bin/rake settings:create_translation_interface_setting RAILS_ENV=production` (This is only required for already existing intallations, for new Consul Democracy installations this step is not needed).
2. Accessing as administrator user to the administration panel of your Consul Democracy application to the section **Configuration > Features** and activating the feature called **Translation Interface** as you can see next:
![Active interface translations](../../img/translations/interface_translations/active-interface-translations-en.png)
### Use Cases
* When the translation interface is active:
As you can see in the image below translation interface has two selectors, the firt one "Select language" is to switch between enabled languages and the second one "Add language" is to add new languages to the form. Translatable fields appears with a blue background to facilitate users to distinguish between translatable and not translatable fields. Additionally interface provides a link `Remove language` to delete the current language shown at "Select language". If a user accidentally removes a translation he can recover it re-adding it to the form.
This feature is visible during creation and edition of translatable resources.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-enabled-en.png)
* When the translation interface is disabled:
When this feature is deactivated users will see standard forms without translation interface and without translation highlight.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-disabled-en.png)

View File

@@ -29,14 +29,19 @@
* [Personalización](customization/customization.md)
* [Introducción](customization/introduction.md)
* [Traducciones y Textos](customization/translations.md)
* [Traducciones y textos](customization/translations.md)
* [Imágenes](customization/images.md)
* [Vistas y Estilos](customization/views_and_styles.md)
* [Javascript](customization/javascript.md)
* [Estilos con CSS](customization/css.md)
* [JavaScript](customization/javascript.md)
* [Modelos](customization/models.md)
* [Controladores](customization/controllers.md)
* [Vistas y HTML](customization/views.md)
* [Componentes](customization/components.md)
* [Otras clases de Ruby (GraphQL, lib, mailers, builders)](customization/ruby.md)
* [Gemas](customization/gems.md)
* [Adaptar la aplicación](customization/overwriting.md)
* [Configuración de la aplicación](customization/application.md)
* [Rutas](customization/routes.md)
* [Tests](customization/tests.md)
* [Funcionalidades Técnicas](features/features.md)
* [OAuth](features/oauth.md)
@@ -45,6 +50,7 @@
* [Configurar conexión con el Censo](features/census_configuration.md)
* [Local Census](features/local_census.md)
* [Multitenancy](features/multitenancy.md)
* [Traducciones de contenido de usuario](features/user_content_translations.md)
* [Proyecto Open Source](open_source/open_source.md)
* [Código de conducta](open_source/code_of_conduct.md)

View File

@@ -0,0 +1,25 @@
# Personalización de la configuración de la aplicación
## Personalizar application.rb
Cuando necesites extender o modificar el `config/application.rb`, puedes hacerlo a través del fichero `config/application_custom.rb`. Por ejemplo, si quieres modificar la zona horaria de la aplicación para que utilice la de las Islas Canarias, añade:
```ruby
module Consul
class Application < Rails::Application
config.time_zone = "Atlantic/Canary"
end
end
```
En este caso concreto, la zona horaria de la aplicación también puede modificarse editando el fichero `config/secrets.yml`.
Recuerda que para ver reflejados estos cambios debes reiniciar la aplicación.
## Personalizar la configuración de los entornos
Para personalizar los entornos de desarrollo, test, "staging", preproducción o producción, puedes editar los ficheros en `config/environments/custom/`.
Ten en cuenta que los cambios en `config/environments/custom/production.rb` se aplicarán también a los entornos de "staging" y de preproducción, y que los cambios en `config/environments/custom/staging.rb` se aplicarán también al entorno de preproducción.
Y recuerda que para ver reflejados estos cambios debes reiniciar la aplicación.

View File

@@ -1,4 +1,4 @@
# Componentes
# Personalización de componentes
En el caso de los componentes, la personalización puede utilizarse para cambiar tanto la lógica (incluida en un archivo `.rb`) como la vista (incluida en un archivo `.erb`). Si solo quieres personalizar la lógica, por ejemplo del componente `Admin::TableActionsComponent`, crea el archivo `app/components/custom/admin/table_actions_component.rb` con el siguiente contenido:
@@ -10,6 +10,8 @@ class Admin::TableActionsComponent
end
```
Consulta la sección de [personalización de modelos](models.md) para más información sobre personalizar clases de Ruby.
Si, por el contrario, también quieres personalizar la vista, necesitas una pequeña modificación. En lugar del código anterior, utiliza:
```ruby
@@ -22,4 +24,4 @@ class Admin::TableActionsComponent
end
```
Esto hará que el componente utilice la vista en `app/components/custom/admin/table_actions_component.html.erb`. Puedes crear este archivo y personalizarlo según tus necesidades.
Esto hará que el componente utilice la vista en `app/components/custom/admin/table_actions_component.html.erb`. Puedes crear este archivo y personalizarlo según tus necesidades, de la misma manera en que puedes [personalizar vistas](views.md).

View File

@@ -0,0 +1,26 @@
# Personalización de controladores
Al igual que los modelos, los controladores están escritos en Ruby, con lo cual su personalización es similar solo que usaremos el directorio `app/controllers/custom/` en lugar del directorio `app/models/custom/`. Echa un vistazo a la documentación de [personalización de modelos](models.md) para más información.
## Personalización de parámetros permitidos
Al personalizar Consul Democracy, a veces querrás añadir un nuevo campo en un formulario. Además de [personalizar la vista](views.md) o [el componente](components.md) que renderiza ese formulario, tendrás que modificar el controlador para que acepte el nuevo campo. En caso contrario, el nuevo campo será ignorado completamente; esta práctica se utiliza para evitar [ataques de asignación masiva](https://en.wikipedia.org/wiki/Mass_assignment_vulnerability).
Por ejemplo, supongamos que has modificado el modelo `SiteCustomization::Page` para que utilice un campo llamado `author_nickname` y has añadido ese campo al formulario para crear una nueva página en el área de administración. Para añadir este campo a la lista de parámetros permitidos por el controlador, crea el archivo `app/controllers/custom/admin/site_customization/pages_controller.rb` con el siguiente contenido:
```ruby
load Rails.root.join("app", "controllers", "admin", "site_customization", "pages_controller.rb")
class Admin::SiteCustomization::PagesController
private
alias_method :consul_allowed_params, :allowed_params
def allowed_params
consul_allowed_params + [:author_nickname]
end
end
```
Nótese cómo estamos creando un alias para el método original `allowed_params` y luego estamos llamando a ese alias. De esta manera, todos los parámetros permitidos por el código original también estarán permitidos en nuestro método personalizado.

View File

@@ -0,0 +1,58 @@
# Personalización de estilos con CSS
Consul Democracy usa hojas de estilo escritas utilizando [Sass](http://sass-lang.com/guide) con la sintaxis SCSS y ubicadas en el directorio `app/assets/stylesheets/`.
Para cambiar estilos, puedes añadirlos directamente en algún fichero bajo `app/assets/stylesheets/custom/`. Como alternativa, puedes usar el fichero `app/assets/stylesheets/custom.scss`.
Por ejemplo, para cambiar el margen del pie de página, crear el archivo `app/assets/stylesheets/custom/layout.scss` con el siguiente contenido:
```scss
.footer {
margin-top: $line-height;
}
```
Esto sobrescribirá la propiedad `margin-top` del selector `.footer`.
Las reglas de precedencia de CSS siguen aplicándose en ese caso, con lo que si hay una regla definiendo la propiedad `margin-top` para el selector `body .footer`, el código anterior será ignorado. Por lo tanto, para sobrescribir propiedades de ciertos elementos de forma adecuada, usa exactamente el mismo selector utilizado en el código original.
## Variables de Sass
Consul Democracy utiliza variables y funciones definidas en el [framework Foundation](http://foundation.zurb.com/) y añade algunas variables más. Para sobrescribir estas variables, usa el archivo `app/assets/stylesheets/_consul_custom_overrides.scss`. Por ejemplo, para cambiar el color de fondo del pie de página, añade:
```scss
$footer: #fdfdfd;
```
Las variables que puedes sobrescribir están definidas en los ficheros `_settings.scss` y `_consul_settings.scss`.
Para definir nuevas variables, puedes usar el fichero `app/assets/stylesheets/_custom_settings.scss`.
## Variables de CSS
En aplicaciones multientidad, las variables de Sass tienen una limitación: su valor será el mismo para todas las entidades.
Debido a esto, para los colores más frecuentemente personalizados, Consul Democracy proporciona variables de CSS, con las que puedes definir diferentes colores para diferentes entidades.
Por ejemplo, puedes personalizar los colores de los principales elementos de la aplicación así como de enlaces y botones con:
```scss
.tenant-public {
--anchor-color: #372;
--anchor-color-hover: #137;
--brand: #153;
--brand-secondary: #134a00;
--button-background-hover: #fa0;
--button-background-hover-contrast: #{$black};
--footer: #e6e6e6;
--main-header: #351;
--top-links: var(--main-header);
--subnavigation: #ffd;
}
```
Echa un vistazo al archivo `app/assets/stylesheets/custom/tenants.scss` para más información.
## Accesibilidad
Para mantener el nivel de accesibilidad, si añades colores nuevos, utiliza un [comprobador de contraste de color](http://webaim.org/resources/contrastchecker/) (WCAG AA es obligatorio, WCAG AAA es recomendable).

View File

@@ -1,11 +1,16 @@
# Customization
# Personalización del código
* [Introducción](introduction.md)
* [Traducciones y Textos](translations.md)
* [Traducciones y textos](translations.md)
* [Imágenes](images.md)
* [Vistas y Estilos](views_and_styles.md)
* [Javascript](javascript.md)
* [Estilos con CSS](css.md)
* [JavaScript](javascript.md)
* [Modelos](models.md)
* [Controladores](controllers.md)
* [Vistas y HTML](views.md)
* [Componentes](components.md)
* [Otras clases de Ruby (GraphQL, lib, mailers, builders)](ruby.md)
* [Gemas](gems.md)
* [Adaptar la aplicación](overwriting.md)
* [Configuración de la aplicación](application.md)
* [Rutas](routes.md)
* [Tests](tests.md)

View File

@@ -1,9 +1,9 @@
# Gemfile
# Personalización del Gemfile
Para agregar librerías (gems) nuevas puedes hacerlo en el fichero `Gemfile_custom`. Por ejemplo si quieres agregar la gema [rails-footnotes](https://github.com/josevalim/rails-footnotes) debes hacerlo agregandole
Para añadir gemas (herramientas externas escritas en Ruby) nuevas puedes editar el fichero `Gemfile_custom`. Por ejemplo, si quieres añadir la gema [rails-footnotes](https://github.com/josevalim/rails-footnotes), añade:
```ruby
gem 'rails-footnotes', '~> 4.0'
gem "rails-footnotes", "~> 4.0"
```
Y siguiendo el flujo clásico en Ruby on Rails (`bundle install` y seguir con los pasos específicos de la gema en la documentación)
Tras esto, ejecuta `bundle install` y sigue los pasos de instalación específicos de la gema que aparecerán en su documentación.

View File

@@ -1,6 +1,8 @@
# Imágenes
# Personalización de imágenes
Si quieres sobreescribir alguna imagen debes primero fijarte el nombre que tiene, por defecto se encuentran en `app/assets/images`. Por ejemplo si quieres modificar `app/assets/images/logo_header.png` debes poner otra con ese mismo nombre en el directorio `app/assets/images/custom`. Los iconos que seguramente quieras modificar son:
Si quieres sobrescribir alguna imagen, primero debes fijarte en el nombre que tiene. Por defecto, se encuentran en `app/assets/images/`. Por ejemplo, si quieres modificar el logo de la cabecera (`app/assets/images/logo_header.png`), crea otro archivo con ese mismo nombre en el directorio `app/assets/images/custom/`. Ten en cuenta que, debido a restricciones en la forma en que Ruby on Rails carga imágenes, **tendrás que renombrar el archivo original**. En el ejemplo, renombra `app/assets/images/logo_header.png` a (por ejemplo) `app/assets/images/original_logo_header.png` y a continuación crea tu imagen personalizada en `app/assets/images/custom/logo_header.png`.
Las imágenes e iconos que seguramente quieras modificar son:
* apple-touch-icon-200.png
* icon_home.png
@@ -10,8 +12,10 @@ Si quieres sobreescribir alguna imagen debes primero fijarte el nombre que tiene
* social_media_icon.png
* social_media_icon_twitter.png
Ten en cuenta que, en vez de personalizar estas imágenes utilizando el método explicado anteriormente, muchas de estas imágenes pueden personalizarse desde el área de administración, en la sección "Contenido del sitio, personalizar imágenes".
## Mapa de la ciudad
Puedes encontrar el mapa de la ciudad en [`/app/assets/images/map.jpg`](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg), simplemente reemplazalo con una imagen de los distritos de tu ciudad ([ejemplo](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg)).
Puedes encontrar el mapa de la ciudad en `/app/assets/images/map.jpg` y reemplazarlo con una imagen de los distritos de tu ciudad, como esta [imagen de ejemplo de mapa](https://github.com/consuldemocracy/consuldemocracy/blob/master/app/assets/images/map.jpg).
Después te recomendamos utilizar una herramienta online como <http://imagemap-generator.dariodomi.de/> o <https://www.image-map.net/> para generar las coordenadas para poder establecer un [image-map](https://www.w3schools.com/tags/tag_map.asp) sobre cada distrito. Estas coordenadas deben ser introducidas en la respectiva Geozona creada en el panel de administración (`/admin/geozones`)
Después te recomendamos utilizar una herramienta como <http://imagemap-generator.dariodomi.de/> o <https://www.image-map.net/> para generar las coordenadas para poder establecer un [image-map](https://www.w3schools.com/tags/tag_map.asp) sobre cada distrito. Estas coordenadas deben ser introducidas en la respectiva geozona creada en el panel de administración (`/admin/geozones`).

View File

@@ -1,147 +1,57 @@
# Personalización
# Personalización de código
Puedes modificar Consul Democracy y ponerle tu propia imagen, para esto debes primero [crear tu propio fork](../getting_started/create.md).
Puedes modificar Consul Democracy y adaptarlo a la imagen y a la manera de trabajar de tu institución. Para esto, debes primero [crear tu propio "fork"](../getting_started/create.md).
Hemos creado una estructura específica donde puedes sobreescribir y personalizar la aplicación para que puedas actualizar sin que tengas problemas al hacer merge y se sobreescriban por error tus cambios. Intentamos que Consul Democracy sea una aplicación Ruby on Rails lo más plain vanilla posible para facilitar el acceso de nuevas desarrolladoras.
La principal regla a seguir al personalizar código de Consul Democracy es hacerlo de manera que los cambios personalizados estén separados del resto del código. De esta forma, al actualizar a una nueva versión de Consul Democracy, será más fácil comprobar qué código pertenece a la aplicación y cómo cambia el código en la nueva versión. En caso contrario, será muy difícil adaptar tus cambios personalizados a la nueva versión.
Con este fin, Consul Democracy incluye directorios "custom" para que rara vez tengas que cambiar los archivos originales.
## Ficheros y directorios especiales
Para adaptar tu fork de Consul Democracy puedes utilizar alguno de los directorios `custom` que están en las rutas:
Para adaptar tu "fork" de Consul Democracy, puedes utilizar alguno de los directorios `custom` que están en las rutas:
* `config/locales/custom/`
* `app/assets/images/custom/`
* `app/views/custom/`
* `app/assets/javascripts/custom/`
* `app/assets/stylesheets/custom/`
* `app/components/custom/`
* `app/controllers/custom/`
* `app/form_builders/custom/`
* `app/graphql/custom/`
* `app/lib/custom/`
* `app/mailers/custom/`
* `app/models/custom/`
* `app/models/custom/concerns/`
* `app/views/custom/`
* `config/locales/custom/`
* `spec/components/custom/`
* `spec/controllers/custom/`
* `spec/models/custom/`
* `spec/routing/custom/`
* `spec/system/custom/`
Aparte de estos directorios también cuentas con ciertos ficheros para:
Aparte de estos directorios, también puedes utilizar los siguientes ficheros:
* `app/assets/javascripts/custom.js`
* `app/assets/stylesheets/custom.css`
* `app/assets/stylesheets/_custom_settings.css`
* `app/assets/javascripts/custom.js`
* `app/assets/stylesheets/_consul_custom_overrides.css`
* `config/application_custom.rb`
* `config/environments/custom/development.rb`
* `config/environments/custom/preproduction.rb`
* `config/environments/custom/production.rb`
* `config/environments/custom/staging.rb`
* `config/environments/custom/test.rb`
* `config/routes/custom.rb`
* `Gemfile_custom`
* `config/application.custom.rb`
## Traducciones remotas bajo demanda del usuario
Utilizando estos ficheros, podrás personalizar [traducciones](translations.md), [imágenes](images.md), [CSS](css.md), [JavaScript](javascript.md), [vistas HTML](views.md), cualquier código de Ruby como [modelos](models.md), [controladores](controllers.md), [componentes](components.md) u [otras clases de Ruby](ruby.md), [gemas](gems.md), [configuración de la aplicación](application.md), [rutas](routes.md) y [tests](tests.md).
Este servicio tiene como objetivo poder ofrecer todos los contenidos dinámicos de la aplicación (propuestas, debates, inversiones presupuestarias y comentarios) en diferentes idiomas sin la necesidad de que un usuario ó un administrador haya creado cada una de sus traducciones.
## Ejecutar los tests
Cuando un usuario accede a una pantalla con un idioma donde parte del contenido dinámico que esta visualizando no tiene traducciones, dispondrá de un botón para solicitar la traducción de todo el contenido. Este contenido se enviará a un traductor automático (en este caso [Microsoft TranslatorText](https://azure.microsoft.com/es-es/products/cognitive-services/translator/)) y en cuanto se obtenga la respuesta, todas estas traducciones estarán disponibles para cualquier usuario.
Al personalizar el código, es **muy importante** que todos los tests de la aplicación sigan pasando. En caso contrario, habrá fallos al actualizar a una nueva versión de Consul Democracy (o incluso al actualizar los cambios personalizados) y estos fallos no serán detectados hasta que el código esté ya ejecutándose en producción. Consul Democracy incluye más de 6000 tests que comprueban la manera en que se comporta la aplicación; sin ellos, sería imposible asegurarse de que el código nuevo no rompe comportamientos existentes.
### Como empezar
Así que, en primer lugar, asegúrate de haber [configurado tu "fork"](../getting_started/configuration.md) para que utilice un sistema de integración continua que ejecute todos los tests cada vez que hagas cambios en el código. Recomendamos ejecutar estos tests en una rama de desarrollo abriendo una "pull request" (también llamada "merge request") para que los tests se ejecuten antes de que los cambios personalizados se añadan a la rama `master`.
Para poder utilizar esta funcionalidad es necesario realizar los siguientes pasos:
En caso de que alguno de los tests falle, echa un vistazo a uno de los tests y comprueba si falla por un fallo en el código personalizado o porque el test comprueba un comportamiento que ha cambiado con los cambios personalizados (por ejemplo, puede que modifiques el código para que solamente los usuarios verificados puedan añadir comentarios, pero puede que haya un test que compruebe que cualquier usuario puede añadir comentarios, ya que es el comportamiento por defecto). Si el test falla debido a un fallo en el código personalizado, arréglalo ;). Si falla debido a un comportamiento que ha cambiado, consulta la sección de [personalización de tests](tests.md).
1. Disponer de una api key para conectarse con el servicio de traducción. Para ello necesitamos una [cuenta en Azure](https://azure.microsoft.com/es-es/)
1. Una vez que haya iniciado sesión en el portal de Azure, subscríbase a Traductor en Cognitive Services.
1. Una vez subscrito al servicio de Translator Text, tendrá accesibles 2 api keys en la sección **Administración de recursos > Claves y punto de conexión** que serán necesarias para la configuración del servicio de traducciones en su aplicación.
### Configuración
Para activar el servicio de traducciones en su aplicación debe completar los siguientes pasos
#### Añadir api key en la aplicación
En el apartado anterior hemos comentado que una vez subscritos al servicio de traducciones disponemos de 2 api keys. Para configurar el servicio correctamente en nuestra aplicación deberemos añadir una de las dos api keys en el archivo `secrets.yml` en la sección `apis:` con la key `microsoft_api_key` como podemos ver en la siguiente imágen:
![Add api key to secrets](../../img/translations/remote_translations/add-api-key-to-secrets.png)
#### Activar funcionalidad
Una vez disponemos de la nueva key en el `secrets.yml` ya podemos proceder a activar la funcionalidad. Para activar la funcionalidad deberá realizar 2 pasos:
1. Ejecutar el siguiente comando `bin/rake settings:create_remote_translations_setting RAILS_ENV=production`
1. Acceder a través del panel de administración de su aplicación a la sección **Configuración > Funcionalidades** y activar el módulo de **Traducciones Remotas** como se puede ver a continuación:
![Active remote translations](../../img/translations/remote_translations/active-remote-translations-es.png)
### Funcionalidad
Una vez tenemos la api key en nuestro `secrets.yml` y el módulo activado, los usuarios ya podrán utilizar la funcionalidad.
Para aclarar el funcionamiento, se adjuntan unos pantallazos de como interactua la aplicación con nuestros usuarios:
* Cuando un usuario accede a una pantalla en un idioma en el que no están disponibles todas las traducciones, le aparecerá un texto en la parte superior de la pantalla y un botón para poder solicitar la traducción. (**Nota:** *En el caso de acceder con un idioma no soportado por el servicio de traducción no se mostrará ningún texto ni botón de traducción. Ver sección: Idiomas disponibles para la traducción remota*)
![Display text and button](../../img/translations/remote_translations/display-text-and-button-es.png)
* Una vez el usuario pulsa el botón de `Traducir página` se encolan las traducciones y se recarga la pantalla con un notice (*informando que se han solicitado correctamente las traducciones*) y un texto informativo en la cabecera (*explicando cuando podrá ver estas traducciones*).
![Display notice and text after enqueued translations](../../img/translations/remote_translations/display-notice-and-text-after-enqueued-es.png)
* Si un usuario accede a una pantalla que no dispone de traducciones pero ya han sido solicitadas por otro usuario. La aplicación no le mostrará el botón de traducir, pero si un texto informativo en la cabecera (*explicando cuando podrá ver estas traducciones*).
![Display text explaining that translations are pending](../../img/translations/remote_translations/display-text-translations-pending-es.png)
* Las peticiones de traducción se delegan a `Delayed Job` y en cuanto haya sido procesada, el usuario después de refrescar su página podrá ver el contenido traducido.
![Display translated content](../../img/translations/remote_translations/display-translated-content-es.png)
### Idiomas disponibles para la traducción remota
Actualmente estos son todos los [idiomas disponibles](https://api.cognitive.microsofttranslator.com/languages?api-version=3.0) en el servicio de traducción:
```yml
["af", "am", "ar", "as", "az", "ba", "bg", "bn", "bo", "bs", "ca", "cs", "cy", "da", "de", "dv", "el", "en", "es", "et", "eu", "fa", "fi", "fil", "fj", "fo", "fr", "fr-CA", "ga", "gl", "gu", "ha", "he", "hi", "hr", "hsb", "ht", "hu", "hy", "id", "ig", "ikt", "is", "it", "iu", "iu-Latn", "ja", "ka", "kk", "km", "kmr", "kn", "ko", "ku", "ky", "ln", "lo", "lt", "lug", "lv", "lzh", "mg", "mi", "mk", "ml", "mn-Cyrl", "mn-Mong", "mr", "ms", "mt", "mww", "my", "nb", "ne", "nl", "nso", "nya", "or", "otq", "pa", "pl", "prs", "ps", "pt", "pt-PT", "ro", "ru", "run", "rw", "sk", "sl", "sm", "sn", "so", "sq", "sr-Cyrl", "sr-Latn", "st", "sv", "sw", "ta", "te", "th", "ti", "tk", "tlh-Latn", "tlh-Piqd", "tn", "to", "tr", "tt", "ty", "ug", "uk", "ur", "uz", "vi", "xh", "yo", "yua", "yue", "zh-Hans", "zh-Hant", "zu"]
```
De todos los idiomas que actualmente tiene Consul Democracy definidos (`available_locales`) en `config/application.rb` el único que no está en la lista anterior y por lo tanto no se ofrece servicio de traducción es el valenciano `["val"]`.
### Costes
El servicio de traducción utilizado tiene los [precios](https://azure.microsoft.com/es-es/pricing/details/cognitive-services/translator/) más competitivos del mercado.
El precio por cada 1 Millón de caracteres traducidos asciende a 10 $ y sin ningún tipo de coste fijo al mes.
Aunque se han tomado medidas técnicas para evitar un mal uso de este servicio, recomendamos la creación de Alertas que ofrece Azure para que un Administrador pueda ser notificado en el caso de detectar un uso fuera de lo común del servicio. Este servicio tiene un coste de 0,10 $ al mes.
Para crear una Alerta en Azure debemos seguir los siguientes pasos:
1. Inicie sesión en **Azure Portal**.
1. Accede al servicio **Traductor** creado anteriormente.
1. Accede en el menu lateral a **Supervisión > Alertas**:
1. Accedemos a **Crear regla de alertas**
1. En **Selección de una señal** seleccionamos `Text Characters Translated`
1. Una vez seleccionada debemos definir la lógica de la Alerta para que se ajuste a nuestras necesidades. Ej: Rellene el campo "Operador" con el valor "Mayor que", rellene el campo "Tipo de Agregación" con el valor "Total" y por último rellene el campo "Valor del umbral" por el número de caracteres que consideramos que deben traducirse antes de ser notificados. En esta sección también se puede configurar el periodo de tiempo y la frecuencia de evaluación.
1. Para poder ser notificados tenemos que crear un **Grupo de Acciones** y asociarla a esta Alerta que estamos creando. Para ello accedemos al botón de **Crear** y rellenamos el formulario. Como se puede observar hay diferentes tipos de acciones, debemos seleccionar **Correo electrónico/SMS/Insertar/Voz** y configurar la opción que consideremos conveniente según nuestras necesidades.
1. Una vez creado este grupo de acciones, ya queda directamente asociado a la regla que estamos creando.
1. Por último ya solo queda añadir un nombre y clicar sobre el botón **Revisar y crear**
### Añadir un nuevo servicio de traducción
En el caso de que se quieran integrar más servicios de traducción por cualquier motivo (aparece un nuevo en el mercado más competitivo, se quiere cambiar para contemplar los idiomas que actualmente no tienen soporte, etc) se ha dejado preparado el código para poder añadirlo con las mínimas modificaciones posibles.
Esto es posible gracias a la class `RemoteTranslations::Caller` que es una capa intermedia entre la gestión de los contenidos sin traducir y el Cliente de traducción de Microsoft utilizado actualmente.
Una buena solución para añadir otro servicio de traducción sería sustituir la llamada al `MicrosoftTranslateClient` dentro del método `translations` del `RemoteTranslations::Caller` por el nuevo servicio implementado.
En caso de querer convivir con ambos sólo debería gestionarse en que caso queremos utilizar uno u otro, ya sea mediante condiciones especificas en el código o mediante una gestión en los Settings de la aplicación.
```ruby
class RemoteTranslationsCaller
...
def translations
@translations ||= RemoteTranslations::Microsoft::Client.new.call(fields_values, locale)
# Add new RemoteTranslations Client
# @translations = RemoteTranslations::NewTranslateClient::Client.new.call(fields_values, locale_to)
end
...
end
```
## Interfaz de traducción
Esta funcionalidad permite a los usuarios introducir contenidos dinámicos en diferentes idiomas a la vez. Cualquier usuario administrador de Consul Democracy puede activar o desactivar esta funcionalidad a través del panel de administración de la aplicación. Si desactivas esta funcionalidad (configuración de la funcionalidad por defecto) los usuarios sólo podrán introducir un idioma.
### Activar funcionalidad
Para activar la funcionalidad deberá realizar 2 pasos:
1. Ejecutar el siguiente comando `bin/rake settings:create_translation_interface_setting RAILS_ENV=production` (Este paso sólo es necesario para instalaciones de Consul Democracy existentes que incorporan esta funcionalidad, para nuevas instalaciones no es necesario)
1. Accedediendo como usuario administrador a través del panel de administración de su aplicación a la sección **Configuración > Funcionalidades** y activando el módulo de **Interfaz de traducción** como se puede ver a continuación:
![Active interface translations](../../img/translations/interface_translations/active-interface-translations-es.png)
### Casos de uso
Dependiendo de si activamos o desactivamos el módulo de **Interfaz de traducción** veremos los formularios accesibles por el usuario de la siguiente manera:
* Cuando la interfaz de traducción esta activa:
Como podemos ver en la imagen a continuación la interfaz de traducción tiene 2 selectores, el primero "Seleccionar idioma" permite cambiar entre los lenguajes activos y el segundo selector "Añadir idioma" permite añadir nuevos idiomas al formulario. Los campos traducibles se pueden distinguir fácilmente mediante un fondo azul de los que no lo son. También disponemos de un botón `Eliminar idioma` para eliminar un idioma en caso de necesitarlo. Si un usuario elimina accidentalmente un idioma puede recuperarlo añadiendo dicho idioma otra vez al formulario.
Esta funcionalidad está visible tanto para las páginas de creación como para las páginas de edición.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-enabled-es.png)
* Cuando la interfaz de traducción esta desactivada:
Cuando esta funcionalidad está desactivada los formularios se renderizan sin la interfaz de traducción y sin resaltar los campos traducibles con fondo azul.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-disabled-es.png)
**Recomendamos encarecidamente añadir tests a tus cambios personalizados** para que tengas una forma de comprobar si estos cambios siguen funcionando cuando actualices a una nueva versión de Consul Democracy.

View File

@@ -1,15 +1,52 @@
# Javascript
# Personalización de JavaScript
Si quieres agregar código Javascript puedes hacerlo en el fichero `app/assets/javascripts/custom.js`. Por ejemplo si quieres que salga una alerta puedes poner lo siguiente:
Para añadir código de JavaScript personalizado, crea un fichero en `app/assets/javascripts/custom/`.
## Añadir nuevas funciones
Para crear una nueva función, necesitas definirla y hacer que se llame cuando el navegador carga una página.
Por ejemplo, para crear una alerta, podemos crear el fichero `app/assets/javascripts/custom/alert.js` con el siguiente contenido:
```js
$(function(){
alert('foobar');
});
(function() {
"use strict";
App.Alert = {
initialize: function() {
alert("foobar");
}
};
}).call(this);
```
Si trabajas con código coffeescript puedes revisarlo con [coffeelint](http://www.coffeelint.org/) (instalalo con `npm install -g coffeelint`) :
A continuación, edita la función `initialize_modules` del fichero `app/assets/javascripts/custom.js`:
```bash
coffeelint .
```js
var initialize_modules = function() {
"use strict";
// Add calls to your custom code here; this will be called when
// loading a page
App.Alert.initialize();
};
```
## Sobrescribir funciones existentes
En Consul Democracy, las funciones de JavaScript se definen como propiedades de un objeto. Esto quiere decir que, para sobrescribir una función, basta con redefinir la propiedad del objeto que la contiene. Siempre que sea posible, recomendamos que tu código personalizado llame al código original y solamente modifique los casos en que debería comportarse de forma diferente. De este modo, al actualizar a una versión de Consul Democracy que actualice las funciones originales, tus funciones personalizadas incluirán las modificaciones del código original automáticamente. En ocasiones, hacer esto no será posible, con lo que tendrás que cambiar tu función personalizada al actualizar.
Como ejemplo, vamos a cambiar la función `generatePassword` del fichero `app/assets/javascripts/managers.js`. Para ello, crea el fichero `app/assets/javascripts/custom/managers.js` con el siguiente contenido:
```js
(function() {
"use strict";
App.Managers.consulGeneratePassword = App.Managers.generatePassword;
App.Managers.generatePassword = function() {
return App.Managers.consulGeneratePassword() + "custom";
};
}).call(this);
```
Esto devolverá lo que devuelve la función original seguida del texto "custom".

View File

@@ -1,75 +1,63 @@
# Modelos
# Personalización de modelos
Si quieres agregar modelos nuevos, o modificar o agregar métodos a uno ya existente puedes hacerlo en `app/models/custom`. En el caso de los modelos antiguos debes primero hacer un require de la dependencia.
Si quieres agregar modelos nuevos, o modificar o agregar métodos a uno ya existente, puedes utilizar el directorio `app/models/custom/`.
Por ejemplo en el caso del Ayuntamiento de Madrid se requiere comprobar que el código postal durante la verificación sigue un cierto formato (empieza con 280). Esto se realiza creando este fichero en `app/models/custom/verification/residence.rb`:
Si estás añadiendo un nuevo modelo que no existe en el código original de Consul Democracy, simplemente añade el modelo a ese directorio.
Si, por el contrario, estás cambiando un modelo que existe en la aplicación, crea un fichero en `app/models/custom/` con el mismo nombre que el fichero que estás cambiando. Por ejemplo, para cambiar el fichero `app/models/budget/investment.rb`, crea un fichero llamado `app/models/custom/budget/investment.rb` que cargue el original:
```ruby
load Rails.root.join("app", "models", "verification", "residence.rb")
load Rails.root.join("app", "models", "budget", "investment.rb")
class Verification::Residence
validate :postal_code_in_madrid
validate :residence_in_madrid
def postal_code_in_madrid
errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code?
class Budget
class Investment
end
def residence_in_madrid
return if errors.any?
unless residency_valid?
errors.add(:residence_in_madrid, false)
store_failed_attempt
Lock.increase_tries(user)
end
end
private
def valid_postal_code?
postal_code =~ /^280/
end
end
```
No olvides poner los tests relevantes en `spec/models/custom`, siguiendo con el ejemplo pondriamos lo siguiente en `spec/models/custom/residence_spec.rb`:
Como el fichero personalizado carga el original, con este código el modelo personalizado se comportará exactamente igual que el original.
Nótese que, si no se carga el fichero original, el modelo personalizado no hará nada, lo cual hará que la aplicación no se comporte correctamente.
## Añadir nuevos métodos
Para añadir un método nuevo, simplemente añade el nuevo código al modelo. Por ejemplo, para añadir un método de tipo "scope" que devuelva los proyectos de gasto creados durante el último mes:
```ruby
require 'rails_helper'
describe Verification::Residence do
let(:residence) { build(:verification_residence, document_number: "12345678Z") }
describe "verification" do
describe "postal code" do
it "should be valid with postal codes starting with 280" do
residence.postal_code = "28012"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
residence.postal_code = "28023"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
end
it "should not be valid with postal codes not starting with 280" do
residence.postal_code = "12345"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
residence.postal_code = "13280"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.")
end
end
load Rails.root.join("app", "models", "budget", "investment.rb")
class Budget
class Investment
scope :last_month, -> { where(created_at: 1.month.ago..) }
end
end
```
Con este código, el modelo personalizado tendrá todos los métodos del modelo original (ya que carga el archivo original) más el método de tipo "scope" `last_month`.
## Modificar métodos existentes
Al modificar métodos existentes, recomendamos encarecidamente que, siempre que sea posible, **tu código personalizado llame al código original** y solamente modifique los casos en que debería comportarse de forma diferente. De este modo, al actualizar a una nueva versión de Consul Democracy que actualice los métodos originales, tus métodos personalizados incluirán las modificaciones del código original automáticamente. En ocasiones, hacer esto no será posible, con lo cual tendrás que cambiar tu método personalizado al actualizar.
Por ejemplo, para cambiar el modelo `Abilities::Common` para que solamente los usuarios verificados puedan crear comentarios, crearemos el archivo `app/models/custom/abilities/common.rb` con el siguiente contenido:
```ruby
load Rails.root.join("app", "models", "abilities", "common.rb")
module Abilities
class Common
alias_method :consul_initialize, :initialize # create a copy of the original method
def initialize(user)
consul_initialize(user) # call the original method
cannot :create, Comment # undo the permission added in the original method
if user.level_two_or_three_verified?
can :create, Comment
end
end
end
end
```
Puedes encontrar otro ejemplo de modelo personalizado en el archivo `app/models/custom/setting.rb`.

View File

@@ -1,14 +0,0 @@
# Adaptar application.rb
Cuando necesites extender o modificar el `config/application.rb` puedes hacerlo a través del fichero `config/application_custom.rb`. Por ejemplo si quieres modificar el idioma por defecto al inglés pondrías lo siguiente:
```ruby
module Consul
class Application < Rails::Application
config.i18n.default_locale = :en
config.i18n.available_locales = [:en, :es]
end
end
```
Recuerda que para ver reflejado estos cambios debes reiniciar el servidor de desarrollo.

View File

@@ -0,0 +1,27 @@
# Personalización de rutas
Al añadir acciones de controlador personalizadas, necesitas definir una ruta que configure la URL que se usará para esas acciones. Puedes hacerlo editando el fichero `config/routes/custom.rb`.
Por ejemplo, para añadir una nueva sección al área de administración para gestionar pensamientos felices ("happy thoughts", en inglés) y verificar que se han hecho realidad, puedes escribir el siguiente código:
```ruby
namespace :admin do
resources :happy_thoughts do
member do
put :verify
end
end
end
```
O, si, por ejemplo, quisieras añadir un formulario para editar debates en el área de administración:
```ruby
namespace :admin do
resources :debates, only: [:edit, :update]
end
```
Al hacer esto, las rutas existentes de debates en el área de administración se mantendrán, y a ellas se añadirán las rutas "edit" y "update".
Las rutas que defines en este fichero tendrán precedencia sobre las rutas por defecto. Así que, si defines una ruta para `/proposals`, la acción por defecto para `/proposals` no se utilizará sino que en su lugar se usará la que definas tú.

View File

@@ -0,0 +1,30 @@
# Personalización de otras clases de Ruby
Aparte de modelos, controladores y componentes, hay otros directorios que contienen código de Ruby:
* `app/form_builders/`
* `app/graphql/`
* `app/lib/`
* `app/mailers/`
Los ficheros en estos directorios pueden personalizarse como cualquier otro fichero de Ruby (véase [personalización de modelos](models.md) para más información).
Por ejemplo, para personalizar el fichero `app/form_builders/consul_form_builder.rb`, crea el archivo `app/form_builders/custom/consul_form_builder.rb` con el siguiente contenido:
```ruby
load Rails.root.join("app", "form_builders", "consul_form_builder.rb")
class ConsulFormBuilder
# Your custom logic here
end
```
O, para personalizar el fichero `app/lib/remote_translations/caller.rb`, crea el archivo `app/lib/custom/remote_translations/caller.rb` con el siguiente contenido:
```ruby
load Rails.root.join("app", "lib", "remote_translations", "caller.rb")
class RemoteTranslations::Caller
# Your custom logic here
end
```

View File

@@ -0,0 +1,66 @@
# Personalización de tests
Los tests comprueban que la aplicación se comporta de la manera esperada. Por esta razón, es **extremadamente importante** que escribas tests para todas las funcionalidades que añadas o modifiques. Sin tests, no tendrás una manera fiable de confirmar que la aplicación sigue comportándose correctamente cuando cambias el código o cuando actualizas a una nueva versión de Consul Democracy. Consul Democracy incluye más de 6000 tests que comprueban la manera en que se comporta la aplicación; sin ellos, sería imposible asegurarse de que el código nuevo no rompe comportamientos existentes.
Como ejecutar los tests en tu máquina de desarrollo puede llevar más de una hora, recomendamos [configurar tu "fork"](../getting_started/configuration.md) para que use un sistema de integración continua que ejecute todos los tests cada vez que hagas cambios en el código. Recomendamos ejecutar estos tests en una rama de desarrollo abriendo una "pull request" (también llamada "merge request") para que los tests se ejecuten antes de que los cambios personalizados se añadan a la rama `master`.
En caso de que alguno de los tests falle, echa un vistazo a uno de los tests y comprueba si falla por un fallo en el código personalizado o porque el test comprueba un comportamiento que ha cambiado con los cambios personalizados (por ejemplo, puede que modifiques el código para que solamente los usuarios verificados puedan añadir comentarios, pero puede que haya un test que compruebe que cualquier usuario puede añadir comentarios, ya que es el comportamiento por defecto). Si el test falla debido a un fallo en el código personalizado, arréglalo ;). Si falla debido a un comportamiento que ha cambiado, tendrás que cambiar el test.
Cambiar un test es un proceso que consiste en dos pasos:
1. Asegurarse de que el test que comprueba el comportamiento por defecto de Consul Democracy deja de ejecutarse
2. Escribir un nuevo test para el nuevo comportamiento
Para el primer paso, añade una etiqueta `:consul` al test o al bloque de tests. Como ejemplo, veamos este código:
```ruby
describe Users::PublicActivityComponent, controller: UsersController do
describe "follows tab" do
context "public interests is checked" do
it "is displayed for everyone" do
# (...)
end
it "is not displayed when the user isn't following any followables", :consul do
# (...)
end
it "is the active tab when the follows filters is selected", :consul do
# (...)
end
end
context "public interests is not checked", :consul do
it "is displayed for its owner" do
# (...)
end
it "is not displayed for anonymous users" do
# (...)
end
it "is not displayed for other users" do
# (...)
end
it "is not displayed for administrators" do
# (...)
end
end
end
end
```
En el primer bloque de tipo "context", solamente el primer test se ejecutará. Los otros dos tests no se ejecutarán ya que contienen la etiqueta `:consul`.
El segundo bloque de tipo "context" contiene la etiqueta `:consul` en el propio bloque, con lo que ninguno de sus tests se ejecutarán.
Recuerda: cuando añadas una etiqueta `:consul` a un test porque la aplicación ya no se comporta como describe ese test, escribe un nuevo test comprobando el nuevo comportamiento. De no hacerlo, la probabilidad de que la gente que visita tu página se encuentre errores 500 (o, peor aún, errores de los que nadie se da cuenta) aumentará de manera drástica.
Para escribir un test personalizado, utiliza los directorios `custom` dentro de `spec/`:
* `spec/components/custom/`
* `spec/controllers/custom/`
* `spec/models/custom/`
* `spec/routing/custom/`
* `spec/system/custom/`

View File

@@ -1,39 +1,38 @@
# Traducciones y Textos
# Personalización de traducciones y textos
## Traducciones
Actualmente Consul Democracy esta traducido total o parcialmente a multiples idiomas, visita el proyecto en [Crowdin](https://translate.consuldemocracy.org/)
Actualmente Consul Democracy está traducido total o parcialmente a múltiples idiomas. Visita el [proyecto en Crowdin](https://translate.consuldemocracy.org/) para comprobar el estado de las traducciones.
[Únete a los traductores](https://crwd.in/consul) para ayudar a completar los existentes, o contacta con nosotros a través del [gitter de Consul Democracy](https://gitter.im/consul/consul) para convertirte en Revisor y validar las contribuciones de los traductores.
[Únete a los traductores](https://crwd.in/consul) para ayudar a completar los idiomas existentes, o contacta con nosotros a través de [las conversaciones de Consul Democracy](https://github.com/consuldemocracy/consuldemocracy/discussions) para convertirte en revisor y validar las contribuciones de los traductores.
En el caso de que tu lenguage no este presente en el proyecto de Crowdin, por favor [abre una incicencia](https://github.com/consuldemocracy/consuldemocracy/issues/new?title=New%20language&body=Hello%20I%20would%20like%20to%20have%20my%20language%20INSERT%20YOUR%20LANGUAGE%20NAME%20added%20to%20Consul%20Democracy) y lo añadiremos rápidamente.
En el caso de que tu idioma no esté presente en el proyecto de Crowdin, por favor [abre una incidencia](https://github.com/consuldemocracy/consuldemocracy/issues/new?title=New%20language&body=Hello%20I%20would%20like%20to%20have%20my%20language%20INSERT%20YOUR%20LANGUAGE%20NAME%20added%20to%20Consul%20Democracy) y lo añadiremos rápidamente.
Si quieres ver las traducciones de los textos de la web, puedes encontrarlos en los ficheros formato YML disponibles en `config/locales/`. Puedes leer la [guía de internacionalización](http://guides.rubyonrails.org/i18n.html) de Ruby on Rails sobre como funciona este sistema.
Si quieres ver las traducciones de los textos de la web, puedes encontrarlos en los ficheros en formato YAML disponibles en `config/locales/`. Puedes leer la [guía de internacionalización](http://guides.rubyonrails.org/i18n.html) de Ruby on Rails para aprender cómo funciona este sistema.
## Textos personalizados
Dado que Consul Democracy está en evolución continua con nuevas funcionalidades, y para que mantener tu fork actualizado sea más sencillo, recomendamos no modificar los ficheros de traducciones, es una mejor idea "sobreescribirlos" usando ficheros personalizados en caso de necesidad de alterar un texto.
Dado que Consul Democracy está en evolución continua con nuevas funcionalidades, y para que mantener tu "fork" actualizado sea más sencillo, recomendamos no modificar los ficheros de traducciones sino sobrescribirlos usando ficheros personalizados en caso de que quieras cambiar un texto.
Así pues las adaptaciones las debes poner en el directorio `config/locales/custom/`, recomendamos poner solo los textos que quieras personalizar. Por ejemplo si quieres personalizar el texto de "Ayuntamiento de Madrid, 2016" que se encuentra en el footer en todas las páginas, primero debemos ubicar en que plantilla se encuentra (`app/views/layouts/_footer.html.erb`), vemos que en el código pone lo siguiente:
Así que, para cambiar algunos de los textos existentes, puedes añadir tus cambios en el directorio `config/locales/custom/`. Recomendamos encarecidamente poner solamente los textos que quieras personalizar en lugar de copiar todo el contenido del archivo original. Por ejemplo, si quieres personalizar el texto "CONSUL DEMOCRACY, 2024" (o el año actual) que se encuentra en el pie de página, primero debemos encontrar dónde se utiliza (en este caso, `app/components/layouts/footer_component.html.erb`), y comprobar el identificador de traducción que aparece en el código:
```ruby
```erb
<%= t("layouts.footer.copyright", year: Time.current.year) %>
```
Y que en el fichero `config/locales/es/general.yml` sigue esta estructura (solo ponemos lo relevante para este caso):
Localiza el fichero en el que se encuentra este identificador (en este caso, `config/locales/es/general.yml`) y crea un archivo en `config/locales/custom/` (en este caso, crea el archivo `config/locales/custom/es/general.yml`) con el siguiente contenido:
```yml
es:
layouts:
footer:
copyright: Ayuntamiento de Madrid, %{year}
copyright: Tu Organización, %{year}
```
Si creamos el fichero `config/locales/custom/es/general.yml` y modificamos "Ayuntamiento de Madrid" por el nombre de la organización que se este haciendo la modificación. Recomendamos directamente copiar los ficheros `config/locales/` e ir revisando y corrigiendo las que querramos, borrando las líneas que no querramos traducir.
Es importante que los ficheros de `config/locales/custom/` solamente incluyan textos personalizados y no los textos originales. De este modo, será más fácil actualizar a una nueva versión de Consul Democracy.
## Mantener tus Textos Personalizados y Lenguajes
## Mantener tus textos personalizados y lenguajes
Consul Democracy tiene la gema [i18n-tasks](https://github.com/glebm/i18n-tasks), es una herramienta estupenda para gestionar textos i18n. Prueba en tu consola `i18n-tasks health` para ver un reporte de estado.
Consul Democracy utiliza la gema [i18n-tasks](https://github.com/glebm/i18n-tasks), que es una herramienta estupenda para gestionar traducciones. Ejecuta en una consola `i18n-tasks health` para ver un informe de estado.
Si tienes un lenguaje propio diferente al Inglés, deberias añadirlo al fichero de configuración [i18n-tasks.yml para las variables `base_locale` y `locales`](https://github.com/consuldemocracy/consuldemocracy/blob/master/config/i18n-tasks.yml#L4-L7) de forma que los ficheros de tu idioma también sean comprobados.
Si tienes un idioma propio diferente al inglés, deberías añadirlo a las variables `base_locale` y `locales` del [fichero de configuración i18n-tasks.yml](https://github.com/consuldemocracy/consuldemocracy/blob/master/config/i18n-tasks.yml#L3-L6), de forma que los ficheros de tu idioma también sean comprobados.

View File

@@ -0,0 +1,11 @@
# Personalización de vistas y HTML
Al igual que la mayoría de aplicaciones hechas con Ruby on Rails, Consul Democracy utiliza ficheros ERB para generar HTML. Estos ficheros tradicionalmente se encuentran en el directorio `app/views/`.
A diferencia del [código de Ruby](models.md), [código de CSS](css.md) o [código de JavaScript](javascript.md), no es posible sobrescribir solamente partes de un fichero ERB. Así que, para personalizar una vista, tendrás que encontrar el archivo que quieras cambiar en el directorio `app/views/` y copiarlo en `app/views/custom/`, manteniendo la estructura de subdirectorios, y posteriormente aplicar las personalizaciones. Por ejemplo, si quieres personalizar `app/views/welcome/index.html.erb`, tendrás que copiarlo en `app/views/custom/welcome/index.html.erb`.
Para que sea más fácil llevar la cuenta de tus cambios personalizados, al utilizar el sistema de control de versiones git, recomendamos copiar el archivo original al directorio personalizado en un "commit" (sin modificar este fichero) y modificar el archivo personalizado en otro "commit" distinto. Esto hará que, al actualizar a una nueva versión de Consul Democracy, sea más fácil comprobar las diferencias entre la vista de la versión anterior de Consul Democracy, la vista de la nueva versión de Consul Democracy, y tus cambios personalizados.
Como se ha mencionado anteriormente, el archivo personalizado sobrescribirá el original completamente. Esto quiere decir que, al actualizar a una nueva versión de Consul Democracy, los cambios en el archivo original serán ignorados. Tendrás que comprobar los cambios en el archivo original y aplicarlos a tu fichero personalizado cuando corresponda.
**Nota**: Consul Democracy solamente utiliza el directorio `app/views/` para código escrito antes del año 2021. El código escrito desde entonces se encuentra en el directorio `app/components/`. La razón principal es que los componentes permiten extraer parte de la lógica en un archivo de Ruby, y mantener código Ruby personalizado es más sencillo que mantener código ERB personalizado.

View File

@@ -1,33 +0,0 @@
# Vistas y Estilos
## Vistas (HTML)
Si quieres modificar el HTML de alguna página puedes hacerlo copiando el HTML de `app/views` y poniendolo en `app/views/custom` respetando los subdirectorios que encuentres ahí. Por ejemplo si quieres modificar `app/views/pages/conditions.html` debes copiarlo y modificarla en `app/views/custom/pages/conditions.html.erb`
## Estilos CSS con SASS
Si quieres cambiar algun selector CSS (de las hojas de estilo) puedes hacerlo en el fichero `app/assets/stylesheets/custom.scss`. Por ejemplo si quieres cambiar el color del header (`.top-links`) puedes hacerlo agregando:
```css
.top-links {
background: red;
}
```
Si quieres cambiar alguna variable de [foundation](http://foundation.zurb.com/) puedes hacerlo en el fichero `app/assets/stylesheets/_custom_settings.scss`. Por ejemplo para cambiar el color general de la aplicación puedes hacerlo agregando:
```css
$brand: #446336;
```
Usamos un preprocesador de CSS, [SASS, con la sintaxis SCSS](http://sass-lang.com/guide).
Además puedes comprobar la sintaxis de tus ficheros scss con:
```bash
scss-lint
```
## Accesibilidad
Para mantener el nivel de accesibilidad, si añades colores nuevos utiliza un [Comprobador de contraste de color](http://webaim.org/resources/contrastchecker/) (WCAG AA es obligatorio, WCAG AAA es recomendable)

View File

@@ -0,0 +1,125 @@
# Traducciones de contenido de usuario
## Traducciones remotas bajo demanda del usuario
Este servicio tiene como objetivo poder ofrecer todos los contenidos dinámicos de la aplicación (propuestas, debates, inversiones presupuestarias y comentarios) en diferentes idiomas sin la necesidad de que un usuario ó un administrador haya creado cada una de sus traducciones.
Cuando un usuario accede a una pantalla con un idioma donde parte del contenido dinámico que esta visualizando no tiene traducciones, dispondrá de un botón para solicitar la traducción de todo el contenido. Este contenido se enviará a un traductor automático (en este caso [Microsoft TranslatorText](https://azure.microsoft.com/es-es/products/cognitive-services/translator/)) y en cuanto se obtenga la respuesta, todas estas traducciones estarán disponibles para cualquier usuario.
### Como empezar
Para poder utilizar esta funcionalidad es necesario realizar los siguientes pasos:
1. Disponer de una api key para conectarse con el servicio de traducción. Para ello necesitamos una [cuenta en Azure](https://azure.microsoft.com/es-es/)
1. Una vez que haya iniciado sesión en el portal de Azure, subscríbase a Traductor en Cognitive Services.
1. Una vez subscrito al servicio de Translator Text, tendrá accesibles 2 api keys en la sección **Administración de recursos > Claves y punto de conexión** que serán necesarias para la configuración del servicio de traducciones en su aplicación.
### Configuración
Para activar el servicio de traducciones en su aplicación debe completar los siguientes pasos
#### Añadir api key en la aplicación
En el apartado anterior hemos comentado que una vez subscritos al servicio de traducciones disponemos de 2 api keys. Para configurar el servicio correctamente en nuestra aplicación deberemos añadir una de las dos api keys en el archivo `secrets.yml` en la sección `apis:` con la key `microsoft_api_key` como podemos ver en la siguiente imágen:
![Add api key to secrets](../../img/translations/remote_translations/add-api-key-to-secrets.png)
#### Activar funcionalidad
Una vez disponemos de la nueva key en el `secrets.yml` ya podemos proceder a activar la funcionalidad. Para activar la funcionalidad deberá realizar 2 pasos:
1. Ejecutar el siguiente comando `bin/rake settings:create_remote_translations_setting RAILS_ENV=production`
1. Acceder a través del panel de administración de su aplicación a la sección **Configuración > Funcionalidades** y activar el módulo de **Traducciones Remotas** como se puede ver a continuación:
![Active remote translations](../../img/translations/remote_translations/active-remote-translations-es.png)
### Funcionalidad
Una vez tenemos la api key en nuestro `secrets.yml` y el módulo activado, los usuarios ya podrán utilizar la funcionalidad.
Para aclarar el funcionamiento, se adjuntan unos pantallazos de como interactua la aplicación con nuestros usuarios:
* Cuando un usuario accede a una pantalla en un idioma en el que no están disponibles todas las traducciones, le aparecerá un texto en la parte superior de la pantalla y un botón para poder solicitar la traducción. (**Nota:** *En el caso de acceder con un idioma no soportado por el servicio de traducción no se mostrará ningún texto ni botón de traducción. Ver sección: Idiomas disponibles para la traducción remota*)
![Display text and button](../../img/translations/remote_translations/display-text-and-button-es.png)
* Una vez el usuario pulsa el botón de `Traducir página` se encolan las traducciones y se recarga la pantalla con un notice (*informando que se han solicitado correctamente las traducciones*) y un texto informativo en la cabecera (*explicando cuando podrá ver estas traducciones*).
![Display notice and text after enqueued translations](../../img/translations/remote_translations/display-notice-and-text-after-enqueued-es.png)
* Si un usuario accede a una pantalla que no dispone de traducciones pero ya han sido solicitadas por otro usuario. La aplicación no le mostrará el botón de traducir, pero si un texto informativo en la cabecera (*explicando cuando podrá ver estas traducciones*).
![Display text explaining that translations are pending](../../img/translations/remote_translations/display-text-translations-pending-es.png)
* Las peticiones de traducción se delegan a `Delayed Job` y en cuanto haya sido procesada, el usuario después de refrescar su página podrá ver el contenido traducido.
![Display translated content](../../img/translations/remote_translations/display-translated-content-es.png)
### Idiomas disponibles para la traducción remota
Actualmente estos son todos los [idiomas disponibles](https://api.cognitive.microsofttranslator.com/languages?api-version=3.0) en el servicio de traducción:
```yml
["af", "am", "ar", "as", "az", "ba", "bg", "bn", "bo", "bs", "ca", "cs", "cy", "da", "de", "dv", "el", "en", "es", "et", "eu", "fa", "fi", "fil", "fj", "fo", "fr", "fr-CA", "ga", "gl", "gu", "ha", "he", "hi", "hr", "hsb", "ht", "hu", "hy", "id", "ig", "ikt", "is", "it", "iu", "iu-Latn", "ja", "ka", "kk", "km", "kmr", "kn", "ko", "ku", "ky", "ln", "lo", "lt", "lug", "lv", "lzh", "mg", "mi", "mk", "ml", "mn-Cyrl", "mn-Mong", "mr", "ms", "mt", "mww", "my", "nb", "ne", "nl", "nso", "nya", "or", "otq", "pa", "pl", "prs", "ps", "pt", "pt-PT", "ro", "ru", "run", "rw", "sk", "sl", "sm", "sn", "so", "sq", "sr-Cyrl", "sr-Latn", "st", "sv", "sw", "ta", "te", "th", "ti", "tk", "tlh-Latn", "tlh-Piqd", "tn", "to", "tr", "tt", "ty", "ug", "uk", "ur", "uz", "vi", "xh", "yo", "yua", "yue", "zh-Hans", "zh-Hant", "zu"]
```
De todos los idiomas que actualmente tiene Consul Democracy definidos (`available_locales`) en `config/application.rb` el único que no está en la lista anterior y por lo tanto no se ofrece servicio de traducción es el valenciano `["val"]`.
### Costes
El servicio de traducción utilizado tiene los [precios](https://azure.microsoft.com/es-es/pricing/details/cognitive-services/translator/) más competitivos del mercado.
El precio por cada 1 Millón de caracteres traducidos asciende a 10 $ y sin ningún tipo de coste fijo al mes.
Aunque se han tomado medidas técnicas para evitar un mal uso de este servicio, recomendamos la creación de Alertas que ofrece Azure para que un Administrador pueda ser notificado en el caso de detectar un uso fuera de lo común del servicio. Este servicio tiene un coste de 0,10 $ al mes.
Para crear una Alerta en Azure debemos seguir los siguientes pasos:
1. Inicie sesión en **Azure Portal**.
1. Accede al servicio **Traductor** creado anteriormente.
1. Accede en el menu lateral a **Supervisión > Alertas**:
1. Accedemos a **Crear regla de alertas**
1. En **Selección de una señal** seleccionamos `Text Characters Translated`
1. Una vez seleccionada debemos definir la lógica de la Alerta para que se ajuste a nuestras necesidades. Ej: Rellene el campo "Operador" con el valor "Mayor que", rellene el campo "Tipo de Agregación" con el valor "Total" y por último rellene el campo "Valor del umbral" por el número de caracteres que consideramos que deben traducirse antes de ser notificados. En esta sección también se puede configurar el periodo de tiempo y la frecuencia de evaluación.
1. Para poder ser notificados tenemos que crear un **Grupo de Acciones** y asociarla a esta Alerta que estamos creando. Para ello accedemos al botón de **Crear** y rellenamos el formulario. Como se puede observar hay diferentes tipos de acciones, debemos seleccionar **Correo electrónico/SMS/Insertar/Voz** y configurar la opción que consideremos conveniente según nuestras necesidades.
1. Una vez creado este grupo de acciones, ya queda directamente asociado a la regla que estamos creando.
1. Por último ya solo queda añadir un nombre y clicar sobre el botón **Revisar y crear**
### Añadir un nuevo servicio de traducción
En el caso de que se quieran integrar más servicios de traducción por cualquier motivo (aparece un nuevo en el mercado más competitivo, se quiere cambiar para contemplar los idiomas que actualmente no tienen soporte, etc) se ha dejado preparado el código para poder añadirlo con las mínimas modificaciones posibles.
Esto es posible gracias a la class `RemoteTranslations::Caller` que es una capa intermedia entre la gestión de los contenidos sin traducir y el Cliente de traducción de Microsoft utilizado actualmente.
Una buena solución para añadir otro servicio de traducción sería sustituir la llamada al `MicrosoftTranslateClient` dentro del método `translations` del `RemoteTranslations::Caller` por el nuevo servicio implementado.
En caso de querer convivir con ambos sólo debería gestionarse en que caso queremos utilizar uno u otro, ya sea mediante condiciones especificas en el código o mediante una gestión en los Settings de la aplicación.
```ruby
class RemoteTranslationsCaller
...
def translations
@translations ||= RemoteTranslations::Microsoft::Client.new.call(fields_values, locale)
# Add new RemoteTranslations Client
# @translations = RemoteTranslations::NewTranslateClient::Client.new.call(fields_values, locale_to)
end
...
end
```
## Interfaz de traducción
Esta funcionalidad permite a los usuarios introducir contenidos dinámicos en diferentes idiomas a la vez. Cualquier usuario administrador de Consul Democracy puede activar o desactivar esta funcionalidad a través del panel de administración de la aplicación. Si desactivas esta funcionalidad (configuración de la funcionalidad por defecto) los usuarios sólo podrán introducir un idioma.
### Activar funcionalidad
Para activar la funcionalidad deberá realizar 2 pasos:
1. Ejecutar el siguiente comando `bin/rake settings:create_translation_interface_setting RAILS_ENV=production` (Este paso sólo es necesario para instalaciones de Consul Democracy existentes que incorporan esta funcionalidad, para nuevas instalaciones no es necesario)
1. Accedediendo como usuario administrador a través del panel de administración de su aplicación a la sección **Configuración > Funcionalidades** y activando el módulo de **Interfaz de traducción** como se puede ver a continuación:
![Active interface translations](../../img/translations/interface_translations/active-interface-translations-es.png)
### Casos de uso
Dependiendo de si activamos o desactivamos el módulo de **Interfaz de traducción** veremos los formularios accesibles por el usuario de la siguiente manera:
* Cuando la interfaz de traducción esta activa:
Como podemos ver en la imagen a continuación la interfaz de traducción tiene 2 selectores, el primero "Seleccionar idioma" permite cambiar entre los lenguajes activos y el segundo selector "Añadir idioma" permite añadir nuevos idiomas al formulario. Los campos traducibles se pueden distinguir fácilmente mediante un fondo azul de los que no lo son. También disponemos de un botón `Eliminar idioma` para eliminar un idioma en caso de necesitarlo. Si un usuario elimina accidentalmente un idioma puede recuperarlo añadiendo dicho idioma otra vez al formulario.
Esta funcionalidad está visible tanto para las páginas de creación como para las páginas de edición.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-enabled-es.png)
* Cuando la interfaz de traducción esta desactivada:
Cuando esta funcionalidad está desactivada los formularios se renderizan sin la interfaz de traducción y sin resaltar los campos traducibles con fondo azul.
![Translations inteface enabled](../../img/translations/interface_translations/translations-interface-disabled-es.png)