summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/es_ES/api-action-procedures.markdown245
-rw-r--r--doc/es_ES/api-board-procedures.markdown158
-rw-r--r--doc/es_ES/api-external-task-link-procedures.markdown221
-rw-r--r--doc/es_ES/api-group-member-procedures.markdown188
-rw-r--r--doc/es_ES/suse-installation.markdown14
-rw-r--r--doc/es_ES/translations.markdown68
6 files changed, 894 insertions, 0 deletions
diff --git a/doc/es_ES/api-action-procedures.markdown b/doc/es_ES/api-action-procedures.markdown
new file mode 100644
index 00000000..dc39fb93
--- /dev/null
+++ b/doc/es_ES/api-action-procedures.markdown
@@ -0,0 +1,245 @@
+API Procedimiento de acciones automaticas
+================================
+
+## getAvailableActions [Obtener acciones disponibles]
+
+- Propósito: **Obtener una lista de acciones automaticas disponibles**
+- Parametros: ninguno
+- Resultado satisfactorio: **list of actions**
+- Resultado fallido: **falso**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getAvailableActions",
+ "id": 1217735483
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1217735483,
+ "result": {
+ "\Kanboard\Action\TaskLogMoveAnotherColumn": "Agregar un comentario moviendo las tareas entre columnas",
+ "\Kanboard\Action\TaskAssignColorUser": "Asignar un color especifico aun usuario",
+ "\Kanboard\Action\TaskAssignColorColumn": "Asignar un color cuando la tarea es movida a una columna especifica",
+ "\Kanboard\Action\TaskAssignCategoryColor": "Asignar automaticamente una categoria basado en un color",
+ "\Kanboard\Action\TaskAssignColorCategory": "Asignar automaticamente un color basado en una categoria",
+ "\Kanboard\Action\TaskAssignSpecificUser": "Asigar tareas a un usuario especifico",
+ "\Kanboard\Action\TaskAssignCurrentUser": "Asignar tareas a la persona que hace la acción",
+ "\Kanboard\Action\TaskUpdateStartDate": "Automaticamente actualizar la fecha de inicio",
+ "\Kanboard\Action\TaskAssignUser": "Cambiar asigando basado en un nombre de usuario [username] externo",
+ "\Kanboard\Action\TaskAssignCategoryLabel": "Cambiar la categoria basado en un etiqueta externa",
+ "\Kanboard\Action\TaskClose": "Cerrar una tarea",
+ "\Kanboard\Action\CommentCreation": "Crear un comentario desde un proveedor externo",
+ "\Kanboard\Action\TaskCreation": "Crear una tarea desde un proveedor externo",
+ "\Kanboard\Action\TaskDuplicateAnotherProject": "Duplicar la tarea a otro proyecto",
+ "\Kanboard\Action\TaskMoveColumnAssigned": "Mover la tarea a otra columna cuando es asiganada a un usuario",
+ "\Kanboard\Action\TaskMoveColumnUnAssigned": "Mover la tarea a otra columna cuando la asignación es limpiada",
+ "\Kanboard\Action\TaskMoveAnotherProject": "Mover la tarea a otro proyecto",
+ "\Kanboard\Action\TaskOpen": "Abrir una Tarea"
+ }
+}
+```
+
+## getAvailableActionEvents [obtener acciones de eventos disponibles]
+
+- Propósito: **Obtener una lista de acciones disponibles para los eventos**
+- Parametros: ninguno
+- Resultado satisfactorio: **lista de eventos**
+- Resultado fallído : **falso**
+
+Ejemplo de petición:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getAvailableActionEvents",
+ "id": 2116665643
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 2116665643,
+ "result": {
+ "bitbucket.webhook.commit": "Bitbucket commit recibido",
+ "task.close": "Cerrando tarea",
+ "github.webhook.commit": "Github commit recibido",
+ "github.webhook.issue.assignee": "Github issue asignación cambiada",
+ "github.webhook.issue.closed": "Github issue cerrada",
+ "github.webhook.issue.commented": "Github issue comentario creado",
+ "github.webhook.issue.label": "Github issue etiqueta cambiada",
+ "github.webhook.issue.opened": "Github issue abierta",
+ "github.webhook.issue.reopened": "Github issue reabierto",
+ "gitlab.webhook.commit": "Gitlab commit recibido",
+ "gitlab.webhook.issue.closed": "Gitlab issue cerrado",
+ "gitlab.webhook.issue.opened": "Gitlab issue abierto",
+ "task.move.column": "Mover una tarea a otra columna",
+ "task.open": "Abrir una tarea abierta",
+ "task.assignee_change": "Tarea cambio de asignación",
+ "task.create": "Creación de tarea",
+ "task.create_update": "Creación de tarea o modificación",
+ "task.update": "Modificación de tarea"
+ }
+}
+```
+
+## getCompatibleActionEvents [Obtener acciones compatibles con eventos]
+
+- Propósito: **Obtener una lista de eventos compatibles con una acción**
+- Parametros:
+ - **action_name** (string, required)
+- Resultado satisfactorio: **lista de eventos**
+- Resultado fallido: **falso**
+
+Ejemplo de petición:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getCompatibleActionEvents",
+ "id": 899370297,
+ "params": [
+ "\Kanboard\Action\TaskClose"
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 899370297,
+ "result": {
+ "bitbucket.webhook.commit": "Bitbucket commit recibido",
+ "github.webhook.commit": "Github commit recibido",
+ "github.webhook.issue.closed": "Github issue cerrada",
+ "gitlab.webhook.commit": "Gitlab commit recibido",
+ "gitlab.webhook.issue.closed": "Gitlab issue cerrado",
+ "task.move.column": "Mover una tarea a otra columna"
+ }
+}
+```
+
+## getActions [Obtener acciones]
+
+- Propósito: **Obtener una lista de acciones para un proyecto**
+- Parametros:
+ - **project_id** (integer, required)
+- Resultado satisfactorio: **lista de propiedades de las acciones**
+- Resultado fallido: **falso**
+
+Ejemplo de petición:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getActions",
+ "id": 1433237746,
+ "params": [
+ "1"
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1433237746,
+ "result": [
+ {
+ "id" : "13",
+ "project_id" : "2",
+ "event_name" : "task.move.column",
+ "action_name" : "\Kanboard\Action\TaskAssignSpecificUser",
+ "params" : {
+ "column_id" : "5",
+ "user_id" : "1"
+ }
+ }
+ ]
+}
+```
+
+## createAction [Creación de acciones]
+
+- Proposito: **Crear una acción**
+- Parametros:
+ - **project_id** (integer, required)
+ - **event_name** (string, required)
+ - **action_name** (string, required)
+ - **params** (key/value parameters, required)
+- Resultados satisfactorios: **action_id**
+- Resultados fallidos: **falso**
+
+Ejemplo de petición:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "createAction",
+ "id": 1433237746,
+ "params": {
+ "project_id" : "2",
+ "event_name" : "task.move.column",
+ "action_name" : "\Kanboard\Action\TaskAssignSpecificUser",
+ "params" : {
+ "column_id" : "3",
+ "user_id" : "2"
+ }
+ }
+}
+```
+
+Ejemplo de respuestas:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1433237746,
+ "result": 14
+}
+```
+
+## removeAction [Eliminar una acción]
+
+- Proposito: **Eliminar una acción**
+- Parametros:
+ - **action_id** (integer, required)
+- Resultados satisfactorios: **true**
+- Resultados fallidos: **false**
+
+Ejemplo de petición:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "removeAction",
+ "id": 1510741671,
+ "params": [
+ 1
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1510741671,
+ "result": true
+}
+```
diff --git a/doc/es_ES/api-board-procedures.markdown b/doc/es_ES/api-board-procedures.markdown
new file mode 100644
index 00000000..583e6449
--- /dev/null
+++ b/doc/es_ES/api-board-procedures.markdown
@@ -0,0 +1,158 @@
+API Procedimientos Del Tablero
+===============================
+
+## getBoard [obtener tablero]
+
+- Propósito: **Obtener todo la información necesaria para visualizar el tablero**
+- Parametros:
+ - **project_id** (integer, required)
+- Resultado satisfactorio : **Propiedades del tablero**
+- Resultado fallido: **Lista vacía**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getBoard",
+ "id": 827046470,
+ "params": [
+ 1
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 827046470,
+ "result": [
+ {
+ "id": 0,
+ "name": "Default swimlane",
+ "columns": [
+ {
+ "id": "1",
+ "title": "Backlog",
+ "position": "1",
+ "project_id": "1",
+ "task_limit": "0",
+ "description": "",
+ "tasks": [],
+ "nb_tasks": 0,
+ "score": 0
+ },
+ {
+ "id": "2",
+ "title": "Ready",
+ "position": "2",
+ "project_id": "1",
+ "task_limit": "0",
+ "description": "",
+ "tasks": [
+ {
+ "nb_comments":"0",
+ "nb_files":"0",
+ "nb_subtasks":"0",
+ "nb_completed_subtasks":"0",
+ "nb_links":"0",
+ "id":"2",
+ "reference":"",
+ "title":"Test",
+ "description":"",
+ "date_creation":"1430870507",
+ "date_modification":"1430870507",
+ "date_completed":null,
+ "date_due":"0",
+ "color_id":"yellow",
+ "project_id":"1",
+ "column_id":"2",
+ "swimlane_id":"0",
+ "owner_id":"0",
+ "creator_id":"1",
+ "position":"1",
+ "is_active":"1",
+ "score":"0",
+ "category_id":"0",
+ "date_moved":"1430870507",
+ "recurrence_status":"0",
+ "recurrence_trigger":"0",
+ "recurrence_factor":"0",
+ "recurrence_timeframe":"0",
+ "recurrence_basedate":"0",
+ "recurrence_parent":null,
+ "recurrence_child":null,
+ "assignee_username":null,
+ "assignee_name":null
+ }
+ ],
+ "nb_tasks": 1,
+ "score": 0
+ },
+ {
+ "id": "3",
+ "title": "Trabajo en progreso",
+ "position": "3",
+ "project_id": "1",
+ "task_limit": "0",
+ "description": "",
+ "tasks": [
+ {
+ "nb_comments":"0",
+ "nb_files":"0",
+ "nb_subtasks":"1",
+ "nb_completed_subtasks":"0",
+ "nb_links":"0",
+ "id":"1",
+ "reference":"",
+ "title":"Task with comment",
+ "description":"",
+ "date_creation":"1430783188",
+ "date_modification":"1430783188",
+ "date_completed":null,
+ "date_due":"0",
+ "color_id":"red",
+ "project_id":"1",
+ "column_id":"3",
+ "swimlane_id":"0",
+ "owner_id":"1",
+ "creator_id":"0",
+ "position":"1",
+ "is_active":"1",
+ "score":"0",
+ "category_id":"0",
+ "date_moved":"1430783191",
+ "recurrence_status":"0",
+ "recurrence_trigger":"0",
+ "recurrence_factor":"0",
+ "recurrence_timeframe":"0",
+ "recurrence_basedate":"0",
+ "recurrence_parent":null,
+ "recurrence_child":null,
+ "assignee_username":"admin",
+ "assignee_name":null
+ }
+ ],
+ "nb_tasks": 1,
+ "score": 0
+ },
+ {
+ "id": "4",
+ "title": "Done",
+ "position": "4",
+ "project_id": "1",
+ "task_limit": "0",
+ "description": "",
+ "tasks": [],
+ "nb_tasks": 0,
+ "score": 0
+ }
+ ],
+ "nb_columns": 4,
+ "nb_tasks": 2
+ }
+ ]
+}
+```
diff --git a/doc/es_ES/api-external-task-link-procedures.markdown b/doc/es_ES/api-external-task-link-procedures.markdown
new file mode 100644
index 00000000..d276dd7a
--- /dev/null
+++ b/doc/es_ES/api-external-task-link-procedures.markdown
@@ -0,0 +1,221 @@
+API de Procedimientos de tarea de enlace externo
+=================================
+
+## getExternalTaskLinkTypes
+
+- Propósito: **Obtener todos los proveedores registrados de enlaces externos**
+- Parámetros: **ninguno**
+- Resultado en caso de éxito: **dict**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"getExternalTaskLinkTypes","id":477370568}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "auto": "Auto",
+ "attachment": "Attachment",
+ "file": "Local File",
+ "weblink": "Web Link"
+ },
+ "id": 477370568
+}
+```
+
+## getExternalTaskLinkProviderDependencies
+
+- Propósito: **Obtener las dependencias disponibles para un determinado proveedor**
+- Parametros:
+ - **providerName** (string, required)
+- Resultado en caso de éxito: **dict**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"getExternalTaskLinkProviderDependencies","id":124790226,"params":["weblink"]}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "related": "Related"
+ },
+ "id": 124790226
+}
+```
+
+## createExternalTaskLink
+
+- Propósito: **Crear una nueva tarea de enlace externo**
+- Parametros:
+ - **task_id** (integer, required)
+ - **url** (string, required)
+ - **dependency** (string, required)
+ - **type** (string, optional)
+ - **title** (string, optional)
+- Resultado en caso de éxito: **link_id**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"createExternalTaskLink","id":924217495,"params":[9,"http:\/\/localhost\/document.pdf","related","attachment"]}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": 1,
+ "id": 924217495
+}
+```
+
+## updateExternalTaskLink
+
+- Propósito: **Actualizar tarea de enlace externo**
+- Parametros:
+ - **task_id** (integer, required)
+ - **link_id** (integer, required)
+ - **title** (string, required)
+ - **url** (string, required)
+ - **dependency** (string, required)
+- Resultado en caso de éxito: **true**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc":"2.0",
+ "method":"updateExternalTaskLink",
+ "id":1123562620,
+ "params": {
+ "task_id":9,
+ "link_id":1,
+ "title":"New title"
+ }
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 1123562620
+}
+```
+
+## getExternalTaskLinkById
+
+- Propósito: **Obtener un enlace de tarea externo**
+- Parametros:
+ - **task_id** (integer, required)
+ - **link_id** (integer, required)
+- Resultado en caso de éxito: **dict**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"getExternalTaskLinkById","id":2107066744,"params":[9,1]}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "1",
+ "link_type": "attachment",
+ "dependency": "related",
+ "title": "document.pdf",
+ "url": "http:\/\/localhost\/document.pdf",
+ "date_creation": "1466965256",
+ "date_modification": "1466965256",
+ "task_id": "9",
+ "creator_id": "0"
+ },
+ "id": 2107066744
+}
+```
+
+## getAllExternalTaskLinks
+
+- Propósito: **Obtener todos los enlaces externos conectados a una tarea**
+- Parametros:
+ - **task_id** (integer, required)
+- Resultado en caso de éxito: **list of external links**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"getAllExternalTaskLinks","id":2069307223,"params":[9]}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "id": "1",
+ "link_type": "attachment",
+ "dependency": "related",
+ "title": "New title",
+ "url": "http:\/\/localhost\/document.pdf",
+ "date_creation": "1466965256",
+ "date_modification": "1466965256",
+ "task_id": "9",
+ "creator_id": "0",
+ "creator_name": null,
+ "creator_username": null,
+ "dependency_label": "Related",
+ "type": "Attachment"
+ }
+ ],
+ "id": 2069307223
+}
+```
+
+## removeExternalTaskLink
+
+- Propósito: **Remover una tarea de enlace externo**
+- Parametros:
+ - **task_id** (integer, required)
+ - **link_id** (integer, required)
+- Resultado en caso de éxito: **true**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{"jsonrpc":"2.0","method":"removeExternalTaskLink","id":552055660,"params":[9,1]}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 552055660
+}
+```
diff --git a/doc/es_ES/api-group-member-procedures.markdown b/doc/es_ES/api-group-member-procedures.markdown
new file mode 100644
index 00000000..7c7cb25c
--- /dev/null
+++ b/doc/es_ES/api-group-member-procedures.markdown
@@ -0,0 +1,188 @@
+Group Member API Procedures
+===========================
+
+## getMemberGroups
+
+- Propósito: **Obtener todos los grupos de un usuario determinado**
+- Parámetros:
+ - **user_id** (integer, required)
+- Resultado en caso de éxito: **List of groups**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getMemberGroups",
+ "id": 1987176726,
+ "params": [
+ "1"
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1987176726,
+ "result": [
+ {
+ "id": "1",
+ "name": "My Group A"
+ }
+ ]
+}
+```
+
+## getGroupMembers
+
+- Propósito: **Obtener todos los miembros de un grupo**
+- Parámetros:
+ - **group_id** (integer, required)
+- Resultado en caso de éxito: **List of users**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getGroupMembers",
+ "id": 1987176726,
+ "params": [
+ "1"
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1987176726,
+ "result": [
+ {
+ "group_id": "1",
+ "user_id": "1",
+ "id": "1",
+ "username": "admin",
+ "is_ldap_user": "0",
+ "name": null,
+ "email": null,
+ "notifications_enabled": "0",
+ "timezone": null,
+ "language": null,
+ "disable_login_form": "0",
+ "notifications_filter": "4",
+ "nb_failed_login": "0",
+ "lock_expiration_date": "0",
+ "is_project_admin": "0",
+ "gitlab_id": null,
+ "role": "app-admin"
+ }
+ ]
+}
+```
+
+## addGroupMember
+
+- Propósito: **Agregar un usuario a un grupo**
+- Parámetros:
+ - **group_id** (integer, required)
+ - **user_id** (integer, required)
+- Resultado en caso de éxito: **true**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "addGroupMember",
+ "id": 1589058273,
+ "params": [
+ 1,
+ 1
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1589058273,
+ "result": true
+}
+```
+
+## removeGroupMember
+
+- Propósito: **Quitar un usuario de un grupo**
+- Parámetros:
+ - **group_id** (integer, required)
+ - **user_id** (integer, required)
+- Resultado en caso de éxito: **true**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "removeGroupMember",
+ "id": 1730416406,
+ "params": [
+ 1,
+ 1
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1730416406,
+ "result": true
+}
+```
+
+## isGroupMember
+
+- Propósito: **Comprobar si un usuario es miembro de un grupo**
+- Parámetros:
+ - **group_id** (integer, required)
+ - **user_id** (integer, required)
+- Resultado en caso de éxito: **true**
+- Resultado en caso de falla: **false**
+
+Ejemplo de solicitud:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "isGroupMember",
+ "id": 1052800865,
+ "params": [
+ 1,
+ 1
+ ]
+}
+```
+
+Ejemplo de respuesta:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1052800865,
+ "result": false
+}
+```
diff --git a/doc/es_ES/suse-installation.markdown b/doc/es_ES/suse-installation.markdown
new file mode 100644
index 00000000..934554e1
--- /dev/null
+++ b/doc/es_ES/suse-installation.markdown
@@ -0,0 +1,14 @@
+Instalacion en OpenSuse
+========================
+
+OpenSuse Leap 42.1
+------------------
+
+```bash---terminal
+sudo zypper install php5 php5-sqlite php5-gd php5-json php5-mcrypt php5-mbstring php5-openssl
+cd /srv/www/htdocs
+sudo wgethttps://kanboard.net/kanboard-latest.zip
+sudo unzip kanboard-latest.zip
+sudo chmod -R 777 kanboard
+sudo rm kanboard-latest.zip
+
diff --git a/doc/es_ES/translations.markdown b/doc/es_ES/translations.markdown
new file mode 100644
index 00000000..074d9ae3
--- /dev/null
+++ b/doc/es_ES/translations.markdown
@@ -0,0 +1,68 @@
+Translations
+============
+
+How to translate Kanboard to a new language?
+--------------------------------------------
+
+- Translations are stored inside the directory `app/Locale`
+- There is a subdirectory for each language, for example in French we have `fr_FR`, Italian `it_IT` etc.
+- A translation is a PHP file that returns an Array with a key-value pairs
+- The key is the original text in English and the value is the translation of the corresponding language
+- **French translations are always up to date**
+- Always use the last version (branch master)
+
+### Create a new translation:
+
+1. Make a new directory: `app/Locale/xx_XX` for example `app/Locale/fr_CA` for French Canadian
+2. Create a new file for the translation: `app/Locale/xx_XX/translations.php`
+3. Use the content of the French locales and replace the values
+4. Update the file `app/Model/Language.php`
+5. Check with your local installation of Kanboard if everything is OK
+6. Send a [pull-request with Github](https://help.github.com/articles/using-pull-requests/)
+
+How to update an existing translation?
+--------------------------------------
+
+1. Open the translation file `app/Locale/xx_XX/translations.php`
+2. Missing translations are commented with `//` and the values are empty, just fill blank and remove the comment
+3. Check with your local installation of Kanboard and send a [pull-request](https://help.github.com/articles/using-pull-requests/)
+
+How to add new translated text in the application?
+--------------------------------------------------
+
+Translations are displayed with the following functions in the source code:
+
+- `t()`: display text with HTML escaping
+- `e()`: display text without HTML escaping
+
+Always use the english version in the source code.
+
+Text strings use the function `sprintf()` to replace elements:
+
+- `%s` is used to replace a string
+- `%d` is used to replace an integer
+
+All formats are available in the [PHP documentation](http://php.net/sprintf).
+
+How to find missing translations in the applications?
+-----------------------------------------------------
+
+From a terminal, run the following command:
+
+```bash
+./kanboard locale:compare
+```
+
+All missing and unused translations are displayed on the screen.
+Put that in the French locale and sync other locales (see below).
+
+How to synchronize translation files?
+-------------------------------------
+
+From a Unix shell run this command:
+
+```bash
+./kanboard locale:sync
+```
+
+The French translation is used a reference to other locales.