From 84c885041e543a918b2f447b8ce5b31fdfd90802 Mon Sep 17 00:00:00 2001 From: "Louis Wicket (wil)" Date: Mon, 4 Mar 2024 17:26:04 +0100 Subject: [PATCH 1/3] [WIP][ADD] translation module --- addons/t9n/__init__.py | 1 + addons/t9n/__manifest__.py | 17 +++++++++++++ addons/t9n/models/__init__.py | 5 ++++ addons/t9n/models/language.py | 6 +++++ addons/t9n/models/message.py | 23 ++++++++++++++++++ addons/t9n/models/project.py | 25 ++++++++++++++++++++ addons/t9n/models/resource.py | 15 ++++++++++++ addons/t9n/models/translation.py | 20 ++++++++++++++++ addons/t9n/security/ir.model.access.csv | 1 + addons/t9n/static/src/core/app.js | 10 ++++++++ addons/t9n/static/src/core/app.xml | 8 +++++++ addons/t9n/static/src/web/open_app_action.js | 18 ++++++++++++++ addons/t9n/views/t9n_templates.xml | 12 ++++++++++ 13 files changed, 161 insertions(+) create mode 100644 addons/t9n/__init__.py create mode 100644 addons/t9n/__manifest__.py create mode 100644 addons/t9n/models/__init__.py create mode 100644 addons/t9n/models/language.py create mode 100644 addons/t9n/models/message.py create mode 100644 addons/t9n/models/project.py create mode 100644 addons/t9n/models/resource.py create mode 100644 addons/t9n/models/translation.py create mode 100644 addons/t9n/security/ir.model.access.csv create mode 100644 addons/t9n/static/src/core/app.js create mode 100644 addons/t9n/static/src/core/app.xml create mode 100644 addons/t9n/static/src/web/open_app_action.js create mode 100644 addons/t9n/views/t9n_templates.xml diff --git a/addons/t9n/__init__.py b/addons/t9n/__init__.py new file mode 100644 index 0000000000000..0650744f6bc69 --- /dev/null +++ b/addons/t9n/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/addons/t9n/__manifest__.py b/addons/t9n/__manifest__.py new file mode 100644 index 0000000000000..0aa80663ed4fe --- /dev/null +++ b/addons/t9n/__manifest__.py @@ -0,0 +1,17 @@ +{ + "name": "Translations", + "version": "1.0", + "category": "TODO: find the appropriate category", + "description": "TODO: write a description of the module", + "depends": ["base", "web"], + "data": [ + "views/t9n_templates.xml" + ], + "application": True, + "assets": { + "web.assets_backend": [ + "t9n/static/src/**/*", + ], + }, + "license": "LGPL-3", +} diff --git a/addons/t9n/models/__init__.py b/addons/t9n/models/__init__.py new file mode 100644 index 0000000000000..22e0bdf014aa7 --- /dev/null +++ b/addons/t9n/models/__init__.py @@ -0,0 +1,5 @@ +from . import language +from . import message +from . import project +from . import resource +from . import translation diff --git a/addons/t9n/models/language.py b/addons/t9n/models/language.py new file mode 100644 index 0000000000000..9a0b69ce9cbcc --- /dev/null +++ b/addons/t9n/models/language.py @@ -0,0 +1,6 @@ +from odoo import fields, models + + +class Language(models.Model): + _name = "t9n.language" + _description = "Language" diff --git a/addons/t9n/models/message.py b/addons/t9n/models/message.py new file mode 100644 index 0000000000000..d6846e08da082 --- /dev/null +++ b/addons/t9n/models/message.py @@ -0,0 +1,23 @@ +from odoo import fields, models + + +class Message(models.Model): + """ Models a localizable message, i.e. any textual content to be translated. + Messages are retrieved from a Resource. + A Message localized to a specific Language becomes a Translation. + """ + _name = "t9n.message" + _description = "Localizable message" + + body = fields.Text( + help="The actual, textual content to be translated.", + ) + resource_id = fields.Many2one( + comodel_name="t9n.resource", + help="The resource (typically a file) from which the entry is coming from." + ) + translation_ids = fields.One2many( + comodel_name="t9n.translation", + inverse_name="source_id", + string="Translations", + ) diff --git a/addons/t9n/models/project.py b/addons/t9n/models/project.py new file mode 100644 index 0000000000000..49c46d072d429 --- /dev/null +++ b/addons/t9n/models/project.py @@ -0,0 +1,25 @@ +from odoo import fields, models + + +class Project(models.Model): + """ A project is a collection of Resources to be localized into a given set + of Languages. + """ + _name = "t9n.project" + _description = "Translation project" + + src_lang_id = fields.Many2one( + comodel_name="t9n.language", + string="Source Language", + help="The original language of the messages you want to translate." + ) + resource_ids = fields.One2many( + comodel_name="t9n.resource", + inverse_name="project_id", + string="Resources", + ) + target_lang_ids = fields.Many2many( + comodel_name="t9n.language", + string="Languages", + help="The list of languages into which the project can be translated.", + ) diff --git a/addons/t9n/models/resource.py b/addons/t9n/models/resource.py new file mode 100644 index 0000000000000..4219a1f947094 --- /dev/null +++ b/addons/t9n/models/resource.py @@ -0,0 +1,15 @@ +from odoo import fields, models + + +class Resource(models.Model): + _name = "t9n.resource" + _description = "Resource file" + + message_ids = fields.One2many( + comodel_name="t9n.message", + inverse_name="resource_id", + string="Entries to translate", + ) + project_id = fields.Many2one( + comodel_name="t9n.project", + ) diff --git a/addons/t9n/models/translation.py b/addons/t9n/models/translation.py new file mode 100644 index 0000000000000..4d511dd2dba5d --- /dev/null +++ b/addons/t9n/models/translation.py @@ -0,0 +1,20 @@ +from odoo import fields, models + + +class Translation(models.Model): + _name = "t9n.translation" + _description = "Message translated into a language" + + body = fields.Text( + help="The actual content of the translation.", + ) + source_id = fields.Many2one( + comodel_name="t9n.message", + string="Source message", + help="The original text, the source of the translation.", + ) + lang_id = fields.Many2one( + comodel_name="t9n.language", + string="Language", + help="The language to which the translation translates the original message.", + ) diff --git a/addons/t9n/security/ir.model.access.csv b/addons/t9n/security/ir.model.access.csv new file mode 100644 index 0000000000000..97dd8b917b8a2 --- /dev/null +++ b/addons/t9n/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink diff --git a/addons/t9n/static/src/core/app.js b/addons/t9n/static/src/core/app.js new file mode 100644 index 0000000000000..79ff2d525fff2 --- /dev/null +++ b/addons/t9n/static/src/core/app.js @@ -0,0 +1,10 @@ +import { Component } from "@odoo/owl"; + +/** + * The "root", the "homepage" of the translation application. + */ +export class App extends Component { + static components = {}; + static props = {}; + static template = "t9n.App"; +} diff --git a/addons/t9n/static/src/core/app.xml b/addons/t9n/static/src/core/app.xml new file mode 100644 index 0000000000000..737753809f19d --- /dev/null +++ b/addons/t9n/static/src/core/app.xml @@ -0,0 +1,8 @@ + + + + + Hello World! + + + diff --git a/addons/t9n/static/src/web/open_app_action.js b/addons/t9n/static/src/web/open_app_action.js new file mode 100644 index 0000000000000..dc66682513b26 --- /dev/null +++ b/addons/t9n/static/src/web/open_app_action.js @@ -0,0 +1,18 @@ +import { Component, xml } from "@odoo/owl"; + +import { App } from "@t9n/core/app"; + +import { registry } from "@web/core/registry"; +import { standardActionServiceProps } from "@web/webclient/actions/action_service"; + +/** + * Wraps the application root, allowing us to open the application as a result + * of a call to the "t9n.open_app" client action. + */ +export class OpenApp extends Component { + static components = { App }; + static props = { ...standardActionServiceProps }; + static template = xml``; +} + +registry.category("actions").add("t9n.open_app", OpenApp); diff --git a/addons/t9n/views/t9n_templates.xml b/addons/t9n/views/t9n_templates.xml new file mode 100644 index 0000000000000..75cb0ff6bb04b --- /dev/null +++ b/addons/t9n/views/t9n_templates.xml @@ -0,0 +1,12 @@ + + + + + Translate + t9n.open_app + main + + + + + From 94c93c04082217cd8fe605839017ccf2d25bed21 Mon Sep 17 00:00:00 2001 From: Mohammed Basioni Date: Fri, 8 Mar 2024 14:20:55 +0200 Subject: [PATCH 2/3] [IMP] t9n: add tab in the menu to list available projects. This commit adds a tab in the menu bar that lists the available projects. Also, the form view of the project is configured to have two tabs: one for resources and the other one for the description of the project. Also, some security permissions have been included in the manifest file. --- addons/t9n/__manifest__.py | 8 +++--- addons/t9n/models/language.py | 2 ++ addons/t9n/models/message.py | 9 ++++--- addons/t9n/models/project.py | 19 +++++++++++--- addons/t9n/models/resource.py | 1 + addons/t9n/security/ir.model.access.csv | 5 ++++ addons/t9n/views/t9n_menu_views.xml | 10 +++++++ addons/t9n/views/t9n_project_views.xml | 35 +++++++++++++++++++++++++ addons/t9n/views/t9n_templates.xml | 12 --------- 9 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 addons/t9n/views/t9n_menu_views.xml create mode 100644 addons/t9n/views/t9n_project_views.xml delete mode 100644 addons/t9n/views/t9n_templates.xml diff --git a/addons/t9n/__manifest__.py b/addons/t9n/__manifest__.py index 0aa80663ed4fe..6ac8c7a01d92a 100644 --- a/addons/t9n/__manifest__.py +++ b/addons/t9n/__manifest__.py @@ -4,14 +4,16 @@ "category": "TODO: find the appropriate category", "description": "TODO: write a description of the module", "depends": ["base", "web"], - "data": [ - "views/t9n_templates.xml" - ], "application": True, "assets": { "web.assets_backend": [ "t9n/static/src/**/*", ], }, + "data": [ + "security/ir.model.access.csv", + "views/t9n_project_views.xml", + "views/t9n_menu_views.xml", + ], "license": "LGPL-3", } diff --git a/addons/t9n/models/language.py b/addons/t9n/models/language.py index 9a0b69ce9cbcc..91f9a9232d182 100644 --- a/addons/t9n/models/language.py +++ b/addons/t9n/models/language.py @@ -4,3 +4,5 @@ class Language(models.Model): _name = "t9n.language" _description = "Language" + + name = fields.Char("Language", required=True) diff --git a/addons/t9n/models/message.py b/addons/t9n/models/message.py index d6846e08da082..a36404dcabcf4 100644 --- a/addons/t9n/models/message.py +++ b/addons/t9n/models/message.py @@ -2,10 +2,11 @@ class Message(models.Model): - """ Models a localizable message, i.e. any textual content to be translated. - Messages are retrieved from a Resource. - A Message localized to a specific Language becomes a Translation. + """Models a localizable message, i.e. any textual content to be translated. + Messages are retrieved from a Resource. + A Message localized to a specific Language becomes a Translation. """ + _name = "t9n.message" _description = "Localizable message" @@ -14,7 +15,7 @@ class Message(models.Model): ) resource_id = fields.Many2one( comodel_name="t9n.resource", - help="The resource (typically a file) from which the entry is coming from." + help="The resource (typically a file) from which the entry is coming from.", ) translation_ids = fields.One2many( comodel_name="t9n.translation", diff --git a/addons/t9n/models/project.py b/addons/t9n/models/project.py index 49c46d072d429..424edfecc080d 100644 --- a/addons/t9n/models/project.py +++ b/addons/t9n/models/project.py @@ -1,17 +1,20 @@ -from odoo import fields, models +from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError class Project(models.Model): - """ A project is a collection of Resources to be localized into a given set - of Languages. + """A project is a collection of Resources to be localized into a given set + of Languages. """ + _name = "t9n.project" _description = "Translation project" + name = fields.Char("Project", required=True) src_lang_id = fields.Many2one( comodel_name="t9n.language", string="Source Language", - help="The original language of the messages you want to translate." + help="The original language of the messages you want to translate.", ) resource_ids = fields.One2many( comodel_name="t9n.resource", @@ -23,3 +26,11 @@ class Project(models.Model): string="Languages", help="The list of languages into which the project can be translated.", ) + + @api.constrains("src_lang_id", "target_lang_ids") + def _check_source_and_target_languages(self): + for record in self: + if record.src_lang_id in record.target_lang_ids: + raise ValidationError( + _("Target languages must be different from source language.") + ) diff --git a/addons/t9n/models/resource.py b/addons/t9n/models/resource.py index 4219a1f947094..792f71b9ca39e 100644 --- a/addons/t9n/models/resource.py +++ b/addons/t9n/models/resource.py @@ -5,6 +5,7 @@ class Resource(models.Model): _name = "t9n.resource" _description = "Resource file" + name = fields.Char("Resource") message_ids = fields.One2many( comodel_name="t9n.message", inverse_name="resource_id", diff --git a/addons/t9n/security/ir.model.access.csv b/addons/t9n/security/ir.model.access.csv index 97dd8b917b8a2..892a06d3a359f 100644 --- a/addons/t9n/security/ir.model.access.csv +++ b/addons/t9n/security/ir.model.access.csv @@ -1 +1,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_t9n_project_system,t9n.project.system,t9n.model_t9n_project,base.group_system,1,1,1,1 +access_t9n_language_system,t9n.language.system,t9n.model_t9n_language,base.group_system,1,1,1,1 +access_t9n_message_system,t9n.message.system,t9n.model_t9n_message,base.group_system,1,1,1,1 +access_t9n_resource_system,t9n.resource.system,t9n.model_t9n_resource,base.group_system,1,1,1,1 +access_t9n_translation_system,t9n.translation.system,t9n.model_t9n_translation,base.group_system,1,1,1,1 diff --git a/addons/t9n/views/t9n_menu_views.xml b/addons/t9n/views/t9n_menu_views.xml new file mode 100644 index 0000000000000..8abacaa28f29f --- /dev/null +++ b/addons/t9n/views/t9n_menu_views.xml @@ -0,0 +1,10 @@ + + + + Translate + t9n.open_app + main + + + + diff --git a/addons/t9n/views/t9n_project_views.xml b/addons/t9n/views/t9n_project_views.xml new file mode 100644 index 0000000000000..dbd1c557a8be5 --- /dev/null +++ b/addons/t9n/views/t9n_project_views.xml @@ -0,0 +1,35 @@ + + + + Projects + t9n.project + tree,form + + + + t9n.project.form + t9n.project + +
+ +

+ +

+ + + + + + + + + + + + + +
+
+
+
+
diff --git a/addons/t9n/views/t9n_templates.xml b/addons/t9n/views/t9n_templates.xml deleted file mode 100644 index 75cb0ff6bb04b..0000000000000 --- a/addons/t9n/views/t9n_templates.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Translate - t9n.open_app - main - - - - - From c5ac5f4f04f9c7b98063a9196bccb333c3777b99 Mon Sep 17 00:00:00 2001 From: "Louis Wicket (wil)" Date: Tue, 12 Mar 2024 14:06:05 +0100 Subject: [PATCH 3/3] [IMP] t9n: human-readable paths for actions --- addons/t9n/views/t9n_menu_views.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/t9n/views/t9n_menu_views.xml b/addons/t9n/views/t9n_menu_views.xml index 8abacaa28f29f..a37d1dc343985 100644 --- a/addons/t9n/views/t9n_menu_views.xml +++ b/addons/t9n/views/t9n_menu_views.xml @@ -2,6 +2,7 @@ Translate + translate t9n.open_app main