From a8c401fa98f24187bd47e1609a3864ec1bae4c9a Mon Sep 17 00:00:00 2001 From: Mohammed Basioni Date: Mon, 6 May 2024 17:14:42 +0300 Subject: [PATCH 1/3] [IMP] t9n: add custom views to the existing models. This commit adds the full flow starting from the home screen. The home screen contains a list of all projects that you can click on to take you to the list of available target languages in this project. Clicking on a language will take you to the resources in the project then to the different texts that need to be translated. Also, various features are added in each custom view of those like sorting and searching. Finally, you can add your translation for any text you want :)) Task-3783071 --- addons/t9n/models/message.py | 24 +++++- addons/t9n/models/project.py | 39 ++++++++-- addons/t9n/models/resource.py | 41 ++++++++++ addons/t9n/models/translation.py | 2 +- .../static/src/core/copy_button_popover.js | 6 ++ .../static/src/core/copy_button_popover.xml | 6 ++ addons/t9n/static/src/core/language_list.js | 65 ++++++++++++++++ addons/t9n/static/src/core/language_list.xml | 35 +++++++++ addons/t9n/static/src/core/message_form.js | 60 +++++++++++++++ addons/t9n/static/src/core/message_form.xml | 70 +++++++++++++++++ addons/t9n/static/src/core/project_list.js | 12 +-- addons/t9n/static/src/core/resource_list.js | 65 ++++++++++++++++ addons/t9n/static/src/core/resource_list.xml | 31 ++++++++ addons/t9n/static/src/core/resource_model.js | 8 ++ addons/t9n/static/src/core/resource_page.js | 28 +++++++ addons/t9n/static/src/core/resource_page.xml | 31 ++++++++ addons/t9n/static/src/core/store.js | 76 ++++++++++++++++++- .../src/web/open_resource_list_action.js | 13 ++++ .../src/web/open_resource_page_action.js | 13 ++++ .../src/web/open_target_languages_action.js | 13 ++++ addons/t9n/views/t9n_project_views.xml | 5 ++ addons/t9n/views/t9n_resource_views.xml | 14 +++- 22 files changed, 637 insertions(+), 20 deletions(-) create mode 100644 addons/t9n/static/src/core/copy_button_popover.js create mode 100644 addons/t9n/static/src/core/copy_button_popover.xml create mode 100644 addons/t9n/static/src/core/language_list.js create mode 100644 addons/t9n/static/src/core/language_list.xml create mode 100644 addons/t9n/static/src/core/message_form.js create mode 100644 addons/t9n/static/src/core/message_form.xml create mode 100644 addons/t9n/static/src/core/resource_list.js create mode 100644 addons/t9n/static/src/core/resource_list.xml create mode 100644 addons/t9n/static/src/core/resource_model.js create mode 100644 addons/t9n/static/src/core/resource_page.js create mode 100644 addons/t9n/static/src/core/resource_page.xml create mode 100644 addons/t9n/static/src/web/open_resource_list_action.js create mode 100644 addons/t9n/static/src/web/open_resource_page_action.js create mode 100644 addons/t9n/static/src/web/open_target_languages_action.js diff --git a/addons/t9n/models/message.py b/addons/t9n/models/message.py index 2edd5f82f065d..750024968e6ea 100644 --- a/addons/t9n/models/message.py +++ b/addons/t9n/models/message.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class Message(models.Model): @@ -41,3 +41,25 @@ class Message(models.Model): "The combination of a text to translate and its context must be unique within the same resource!", ), ] + + @api.model + def get_message(self, message_id, target_lang_id): + message_records = self.browse([message_id]) + message_records.ensure_one() + message_record = next(iter(message_records)) + return { + "id": message_record.id, + "body": message_record.body, + "context": message_record.context, + "translator_comments": message_record.translator_comments, + "extracted_comments": message_record.extracted_comments, + "references": message_record.references, + "translations": [ + { + "id": record.id, + "body": record.body, + } + for record in message_record.translation_ids + if record.lang_id.id == target_lang_id + ], + } diff --git a/addons/t9n/models/project.py b/addons/t9n/models/project.py index da6362199d23e..e36770c577cd7 100644 --- a/addons/t9n/models/project.py +++ b/addons/t9n/models/project.py @@ -36,19 +36,42 @@ def _check_source_and_target_languages(self): @api.model def get_projects(self): projects_records = self.search([]) - return [{ + return [ + { "id": record.id, "name": record.name, "src_lang": { "id": record.src_lang_id.id, "name": record.src_lang_id.name if record.src_lang_id.name else "", }, - "resources": [{ - "id": resource.id, - "file_name": resource.file_name, - } for resource in record.resource_ids], - "target_langs": [{ + "resources": [ + { + "id": resource.id, + } + for resource in record.resource_ids + ], + "target_langs": [ + { "id": lang.id, "name": lang.name, - } for lang in record.target_lang_ids], - } for record in projects_records] + } + for lang in record.target_lang_ids + ], + } + for record in projects_records + ] + + @api.model + def get_target_langs(self, id): + project_records = self.browse([id]) + project_records.ensure_one() + project_record = next(iter(project_records)) + return [ + { + "id": lang.id, + "name": lang.name, + "code": lang.code, + "native_name": lang.native_name, + } + for lang in project_record.target_lang_ids + ] diff --git a/addons/t9n/models/resource.py b/addons/t9n/models/resource.py index 576fa394fdbad..ef1f506f2c8a8 100644 --- a/addons/t9n/models/resource.py +++ b/addons/t9n/models/resource.py @@ -92,3 +92,44 @@ def write(self, vals): + [Command.update(id, vals) for id, vals in to_update] ) return super().write(vals) + + @api.model + def get_resources(self, project_id): + resources_records = self.search([("project_id.id", "=", project_id)]) + return [ + { + "id": record.id, + "file_name": record.file_name, + } + for record in resources_records + ] + + @api.model + def get_resource(self, id, target_lang_id): + resource_records = self.browse([id]) + resource_records.ensure_one() + resource_record = next(iter(resource_records)) + return { + "id": resource_record.id, + "file_name": resource_record.file_name, + "project_id": resource_record.project_id.id, + "messages": [ + { + "id": message.id, + "body": message.body, + "context": message.context, + "translator_comments": message.translator_comments, + "extracted_comments": message.extracted_comments, + "references": message.references, + "translations": [ + { + "id": lang.id, + "body": lang.body, + } + for lang in message.translation_ids + if lang.lang_id.id == target_lang_id + ], + } + for message in resource_record.message_ids + ], + } diff --git a/addons/t9n/models/translation.py b/addons/t9n/models/translation.py index 4d511dd2dba5d..28fc75b949b68 100644 --- a/addons/t9n/models/translation.py +++ b/addons/t9n/models/translation.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class Translation(models.Model): diff --git a/addons/t9n/static/src/core/copy_button_popover.js b/addons/t9n/static/src/core/copy_button_popover.js new file mode 100644 index 0000000000000..3215ee672c6da --- /dev/null +++ b/addons/t9n/static/src/core/copy_button_popover.js @@ -0,0 +1,6 @@ +import { Component } from '@odoo/owl' + +export class CopyPopover extends Component { + static props = {} + static template = 't9n.copyButtonPopover' +} diff --git a/addons/t9n/static/src/core/copy_button_popover.xml b/addons/t9n/static/src/core/copy_button_popover.xml new file mode 100644 index 0000000000000..f9aecb745dca6 --- /dev/null +++ b/addons/t9n/static/src/core/copy_button_popover.xml @@ -0,0 +1,6 @@ + + + +
Copied to clipboard!
+
+
diff --git a/addons/t9n/static/src/core/language_list.js b/addons/t9n/static/src/core/language_list.js new file mode 100644 index 0000000000000..014870dac5ea5 --- /dev/null +++ b/addons/t9n/static/src/core/language_list.js @@ -0,0 +1,65 @@ +import { Component, useState } from "@odoo/owl"; + +import { useService } from "@web/core/utils/hooks"; + +export class LanguageList extends Component { + static props = {}; + static template = "t9n.LanguageList"; + + setup() { + this.action = useService("action"); + this.state = useState({ + filters: { + searchText: "", + }, + sorting: { + column: "name", + order: "asc", + }, + }); + this.store = useState(useService("t9n.store")); + this.store.fetchLanguages(); + } + + get languages() { + const searchTerms = this.state.filters.searchText.trim().toUpperCase(); + const languages = searchTerms + ? this.store.languages.filter((l) => l.name.toUpperCase().includes(searchTerms)) + : [...this.store.languages]; + + languages.sort((l1, l2) => { + let l1Col = l1[this.state.sorting.column]; + let l2Col = l2[this.state.sorting.column]; + + l1Col = l1Col.toLowerCase(); + l2Col = l2Col.toLowerCase(); + + if (l1Col < l2Col) { + return this.state.sorting.order === "asc" ? -1 : 1; + } + if (l1Col > l2Col) { + return this.state.sorting.order === "asc" ? 1 : -1; + } + return 0; + }); + return languages; + } + + onClickColumnName(column) { + if (this.state.sorting.column === column) { + this.state.sorting.order = this.state.sorting.order === "asc" ? "desc" : "asc"; + } else { + this.state.sorting.column = column; + this.state.sorting.order = "asc"; + } + } + + onClickLanguage(id) { + this.store.setTargetLangId(id); + this.action.doAction({ + type: "ir.actions.client", + tag: "t9n.open_resource_list", + target: "current", + }); + } +} diff --git a/addons/t9n/static/src/core/language_list.xml b/addons/t9n/static/src/core/language_list.xml new file mode 100644 index 0000000000000..a89ac314a1a28 --- /dev/null +++ b/addons/t9n/static/src/core/language_list.xml @@ -0,0 +1,35 @@ + + + +
+
+
+ +
+
+ + + + + + + + + + + + + + + +
Language Name + Native nameLocale
+ + + +
+
+
+
diff --git a/addons/t9n/static/src/core/message_form.js b/addons/t9n/static/src/core/message_form.js new file mode 100644 index 0000000000000..5f2321151a0e6 --- /dev/null +++ b/addons/t9n/static/src/core/message_form.js @@ -0,0 +1,60 @@ +import { Component, useState, useRef } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; +import { usePopover } from "@web/core/popover/popover_hook"; +import { CopyPopover } from "@t9n/core/copy_button_popover"; + +export class MessageForm extends Component { + static props = {}; + static template = "t9n.MessageForm"; + + setup() { + this.state = useState({ + suggestedTranslationText: "", + }); + this.store = useState(useService("t9n.store")); + this.orm = useService("orm"); + this.popoverButtonRef = useRef("popover-button"); + this.copyPopover = usePopover(CopyPopover, { + position: "top", + animation: true, + arrow: true, + closeOnClickAway: true, + }); + } + + get message() { + return this.store.active_message; + } + + get translations() { + return this.store.active_message.translations; + } + + onClickClear() { + this.state.suggestedTranslationText = ""; + } + + async onClickCopy(ev) { + try { + await navigator.clipboard.writeText(this.state.suggestedTranslationText.trim()); + this.copyPopover.open(this.popoverButtonRef.el, {}); + setTimeout(() => { + this.copyPopover.close(); + }, 3000); + } catch (error) { + console.error("Error copying text:", error); + } + } + + async onClickSuggest() { + await this.orm.create("t9n.translation", [ + { + body: this.state.suggestedTranslationText.trim(), + source_id: this.store.active_message.id, + lang_id: this.store.target_lang_id, + }, + ]); + this.store.fetchActiveMessage(); + this.onClickClear(); + } +} diff --git a/addons/t9n/static/src/core/message_form.xml b/addons/t9n/static/src/core/message_form.xml new file mode 100644 index 0000000000000..af39bd66ddd18 --- /dev/null +++ b/addons/t9n/static/src/core/message_form.xml @@ -0,0 +1,70 @@ + + + +
+
+ +
+
+
+

+ + + TRANSLATOR COMMENT + + + + + +

+

+ + + RESOURCE COMMENT + + + + + +

+

+ + + CONTEXT + + + + +

  • Cras justo odio
  • + +

    +

    + + + REFERENCES + + + + + +

    +
    +
    + +
    +
    + + + +
    +
    +
    +
      + +
    • + +
    • +
      +
    +
    +
    diff --git a/addons/t9n/static/src/core/project_list.js b/addons/t9n/static/src/core/project_list.js index 7959beb12b0c6..f95db73d2e92c 100644 --- a/addons/t9n/static/src/core/project_list.js +++ b/addons/t9n/static/src/core/project_list.js @@ -57,12 +57,14 @@ export class ProjectList extends Component { } onClickProject(id) { + this.store.setProjectId(id); this.action.doAction({ - type: "ir.actions.act_window", - res_id: id, - res_model: "t9n.project", - views: [[false, "form"]], - target: "new", + type: "ir.actions.client", + tag: "t9n.open_target_langs", + target: "current", + context: { + project_id: id, + }, }); } } diff --git a/addons/t9n/static/src/core/resource_list.js b/addons/t9n/static/src/core/resource_list.js new file mode 100644 index 0000000000000..e629afc2bdd8d --- /dev/null +++ b/addons/t9n/static/src/core/resource_list.js @@ -0,0 +1,65 @@ +import { Component, useState } from "@odoo/owl"; + +import { useService } from "@web/core/utils/hooks"; + +export class ResourceList extends Component { + static props = {}; + static template = "t9n.ResourceList"; + + setup() { + this.action = useService("action"); + this.state = useState({ + filters: { + searchText: "", + }, + sorting: { + column: "fileName", + order: "asc", + }, + }); + this.store = useState(useService("t9n.store")); + this.store.fetchResources(); + } + + get resources() { + const searchTerms = this.state.filters.searchText.trim().toUpperCase(); + const resources = searchTerms + ? this.store.resources.filter((r) => r.fileName.toUpperCase().includes(searchTerms)) + : [...this.store.resources]; + + resources.sort((r1, r2) => { + let r1Col = r1[this.state.sorting.column]; + let r2Col = r2[this.state.sorting.column]; + + r1Col = r1Col.toLowerCase(); + r2Col = r2Col.toLowerCase(); + + if (r1Col < r2Col) { + return this.state.sorting.order === "asc" ? -1 : 1; + } + if (r1Col > r2Col) { + return this.state.sorting.order === "asc" ? 1 : -1; + } + return 0; + }); + return resources; + } + + onClickColumnName(column) { + if (this.state.sorting.column === column) { + this.state.sorting.order = this.state.sorting.order === "asc" ? "desc" : "asc"; + } else { + this.state.sorting.column = column; + this.state.sorting.order = "asc"; + } + } + + onClickResource(id) { + this.store.setResourceId(id); + this.action.doAction({ + type: "ir.actions.client", + tag: "t9n.open_resource_page", + target: "current", + }); + } +} diff --git a/addons/t9n/static/src/core/resource_list.xml b/addons/t9n/static/src/core/resource_list.xml new file mode 100644 index 0000000000000..5ad6502799665 --- /dev/null +++ b/addons/t9n/static/src/core/resource_list.xml @@ -0,0 +1,31 @@ + + + +
    +
    +
    + +
    +
    + + + + + + + + + + + + + +
    Resource +
    + +
    +
    +
    +
    diff --git a/addons/t9n/static/src/core/resource_model.js b/addons/t9n/static/src/core/resource_model.js new file mode 100644 index 0000000000000..c656e9659d3ab --- /dev/null +++ b/addons/t9n/static/src/core/resource_model.js @@ -0,0 +1,8 @@ +export class Resource { + constructor(id, fileName, projectId, messages) { + this.id = id; + this.fileName = fileName; + this.projectId = projectId; + this.messages = messages; + } +} diff --git a/addons/t9n/static/src/core/resource_page.js b/addons/t9n/static/src/core/resource_page.js new file mode 100644 index 0000000000000..c76b484c8fd6b --- /dev/null +++ b/addons/t9n/static/src/core/resource_page.js @@ -0,0 +1,28 @@ +import { useState, Component } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; +import { MessageForm } from "@t9n/core/message_form"; + +export class ResourcePage extends Component { + static props = {}; + static components = { MessageForm }; + static template = "t9n.ResourcePage"; + + setup() { + this.state = useState({ + isLoading: true, + }); + this.store = useState(useService("t9n.store")); + this.orm = useService("orm"); + this.store.fetchResource().then(() => { + this.state.isLoading = false; + }); + } + + get messages() { + return this.store.resource.messages; + } + + onClickMessage(message) { + this.store.setActiveMessage(message); + } +} diff --git a/addons/t9n/static/src/core/resource_page.xml b/addons/t9n/static/src/core/resource_page.xml new file mode 100644 index 0000000000000..9d36268a6ec1d --- /dev/null +++ b/addons/t9n/static/src/core/resource_page.xml @@ -0,0 +1,31 @@ + + + + +
    + +
    +
    + +
    +
    +
    + +
    +
    + + + + + +
    +
    +
    + +
    +
    +
    + +
    + +
    diff --git a/addons/t9n/static/src/core/store.js b/addons/t9n/static/src/core/store.js index 766af9f1ae60c..9c758f7b6a1ab 100644 --- a/addons/t9n/static/src/core/store.js +++ b/addons/t9n/static/src/core/store.js @@ -1,7 +1,7 @@ import { reactive } from "@odoo/owl"; import { Project } from "@t9n/core/project_model"; - +import { Resource } from "@t9n/core/resource_model"; import { registry } from "@web/core/registry"; export class Store { @@ -9,14 +9,84 @@ export class Store { this.env = env; this.orm = orm; this.projects = []; + this.resources = []; + this.languages = []; + this.resource = {}; + this.active_message = {}; + this.project_id = null; + this.target_lang_id = null; + this.resource_id = null; return reactive(this); } async fetchProjects() { const projects = await this.orm.call("t9n.project", "get_projects"); - this.projects = projects.map((p) => { - return new Project(p.id, p.name, p.src_lang.name, p.target_langs, p.resources.length); + this.projects.splice( + 0, + this.projects.length, + ...projects.map( + (p) => + new Project(p.id, p.name, p.src_lang.name, p.target_langs, p.resources.length) + ) + ); + } + + async fetchLanguages() { + this.languages.splice( + 0, + this.languages.length, + ...(await this.orm.call("t9n.project", "get_target_langs", [this.project_id])) + ); + } + async fetchResources() { + const resources = await this.orm.call("t9n.resource", "get_resources", [this.project_id]); + this.resources.splice( + 0, + this.resources.length, + ...resources.map((r) => new Resource(r.id, r.file_name, r.project_id, r.messages)) + ); + } + + async fetchResource() { + const resource = await this.orm.call("t9n.resource", "get_resource", [], { + id: this.resource_id, + target_lang_id: this.target_lang_id, + }); + Object.assign(this.resource, resource); + if (this.resource.messages.length > 0) { + Object.assign(this.active_message, this.resource.messages[0]); + } + } + + async fetchActiveMessage() { + const newMessage = await this.orm.call("t9n.message", "get_message", [], { + message_id: this.active_message.id, + target_lang_id: this.target_lang_id, }); + const messageIndex = this.resource.messages.findIndex( + (message) => message.id === this.active_message.id + ); + if (messageIndex !== -1) { + Object.assign(this.resource.messages[messageIndex], newMessage); + this.resource.messages.splice(messageIndex, 1, this.resource.messages[messageIndex]); + } + Object.assign(this.active_message, newMessage); + } + + setProjectId(id) { + this.project_id = id; + } + + setTargetLangId(id) { + this.target_lang_id = id; + } + + setResourceId(id) { + this.resource_id = id; + } + + setActiveMessage(message) { + Object.assign(this.active_message, message); } } diff --git a/addons/t9n/static/src/web/open_resource_list_action.js b/addons/t9n/static/src/web/open_resource_list_action.js new file mode 100644 index 0000000000000..ea02575de512e --- /dev/null +++ b/addons/t9n/static/src/web/open_resource_list_action.js @@ -0,0 +1,13 @@ +import { Component, xml } from "@odoo/owl"; + +import { ResourceList } from "@t9n/core/resource_list"; +import { registry } from "@web/core/registry"; +import { standardActionServiceProps } from "@web/webclient/actions/action_service"; + +export class OpenResourceList extends Component { + static components = { ResourceList }; + static props = { ...standardActionServiceProps }; + static template = xml``; +} + +registry.category("actions").add("t9n.open_resource_list", OpenResourceList); diff --git a/addons/t9n/static/src/web/open_resource_page_action.js b/addons/t9n/static/src/web/open_resource_page_action.js new file mode 100644 index 0000000000000..faadc7df57c87 --- /dev/null +++ b/addons/t9n/static/src/web/open_resource_page_action.js @@ -0,0 +1,13 @@ +import { Component, xml } from "@odoo/owl"; + +import { ResourcePage } from "@t9n/core/resource_page"; +import { registry } from "@web/core/registry"; +import { standardActionServiceProps } from "@web/webclient/actions/action_service"; + +export class OpenResourcePage extends Component { + static components = { ResourcePage }; + static props = { ...standardActionServiceProps }; + static template = xml``; +} + +registry.category("actions").add("t9n.open_resource_page", OpenResourcePage); diff --git a/addons/t9n/static/src/web/open_target_languages_action.js b/addons/t9n/static/src/web/open_target_languages_action.js new file mode 100644 index 0000000000000..aeb71dfd15d5d --- /dev/null +++ b/addons/t9n/static/src/web/open_target_languages_action.js @@ -0,0 +1,13 @@ +import { Component, xml } from "@odoo/owl"; + +import { LanguageList } from "@t9n/core/language_list"; +import { registry } from "@web/core/registry"; +import { standardActionServiceProps } from "@web/webclient/actions/action_service"; + +export class OpenTargetLanguages extends Component { + static components = { LanguageList }; + static props = { ...standardActionServiceProps }; + static template = xml``; +} + +registry.category("actions").add("t9n.open_target_langs", OpenTargetLanguages); diff --git a/addons/t9n/views/t9n_project_views.xml b/addons/t9n/views/t9n_project_views.xml index 4e88fe9e7d40c..11ba47146e31a 100644 --- a/addons/t9n/views/t9n_project_views.xml +++ b/addons/t9n/views/t9n_project_views.xml @@ -6,6 +6,11 @@ list,form + + Open Target Languages + t9n.open_target_langs + + t9n.project.form t9n.project diff --git a/addons/t9n/views/t9n_resource_views.xml b/addons/t9n/views/t9n_resource_views.xml index 58d906ce9055f..1b40c0f7e3434 100644 --- a/addons/t9n/views/t9n_resource_views.xml +++ b/addons/t9n/views/t9n_resource_views.xml @@ -4,11 +4,11 @@ t9n.resource.form t9n.resource -
    + - + @@ -20,6 +20,16 @@ + + Open Resource List + t9n.open_resource_list + + + + Open Resource Page + t9n.open_resource_page + + t9n.resource.list t9n.resource From 31cb13eab0598fd6f19a07bc44f0ebb799b7a27c Mon Sep 17 00:00:00 2001 From: "Louis Wicket (wil)" Date: Mon, 3 Jun 2024 09:41:35 +0200 Subject: [PATCH 2/3] wip --- addons/t9n/__manifest__.py | 2 +- addons/t9n/models/language.py | 9 ++++++ addons/t9n/models/project.py | 7 +++-- addons/t9n/models/resource.py | 22 +++++++++---- addons/t9n/models/translation.py | 14 +++++++++ addons/t9n/static/src/core/app.js | 18 +++++++++-- addons/t9n/static/src/core/app.xml | 5 ++- addons/t9n/static/src/core/language_list.js | 30 ++++++------------ addons/t9n/static/src/core/language_list.xml | 2 +- addons/t9n/static/src/core/message_form.js | 23 ++++++++------ addons/t9n/static/src/core/message_form.xml | 18 +++++------ .../t9n/static/src/core/models/app_model.js | 14 +++++++++ .../static/src/core/models/language_model.js | 13 ++++++++ .../static/src/core/models/message_model.js | 24 ++++++++++++++ .../static/src/core/models/project_model.js | 29 +++++++++++++++++ .../static/src/core/models/resource_model.js | 12 +++++++ .../src/core/models/store_service_patch.js | 15 +++++++++ .../src/core/models/translation_model.js | 14 +++++++++ addons/t9n/static/src/core/project_list.js | 29 ++++++++--------- addons/t9n/static/src/core/project_list.xml | 8 ++--- addons/t9n/static/src/core/project_model.js | 15 --------- addons/t9n/static/src/core/resource_list.js | 25 +++++++++------ addons/t9n/static/src/core/resource_list.xml | 6 ++-- addons/t9n/static/src/core/resource_model.js | 8 ----- addons/t9n/static/src/core/resource_page.js | 28 ----------------- addons/t9n/static/src/core/resource_page.xml | 31 ------------------- addons/t9n/static/src/core/store.js | 26 ++++------------ .../t9n/static/src/core/translation_editor.js | 23 ++++++++++++++ .../static/src/core/translation_editor.xml | 22 +++++++++++++ .../src/web/open_resource_list_action.js | 13 -------- .../src/web/open_resource_page_action.js | 13 -------- .../src/web/open_target_languages_action.js | 13 -------- addons/t9n/views/t9n_project_views.xml | 2 +- addons/t9n/views/t9n_resource_views.xml | 10 ------ 34 files changed, 305 insertions(+), 238 deletions(-) create mode 100644 addons/t9n/static/src/core/models/app_model.js create mode 100644 addons/t9n/static/src/core/models/language_model.js create mode 100644 addons/t9n/static/src/core/models/message_model.js create mode 100644 addons/t9n/static/src/core/models/project_model.js create mode 100644 addons/t9n/static/src/core/models/resource_model.js create mode 100644 addons/t9n/static/src/core/models/store_service_patch.js create mode 100644 addons/t9n/static/src/core/models/translation_model.js delete mode 100644 addons/t9n/static/src/core/project_model.js delete mode 100644 addons/t9n/static/src/core/resource_model.js delete mode 100644 addons/t9n/static/src/core/resource_page.js delete mode 100644 addons/t9n/static/src/core/resource_page.xml create mode 100644 addons/t9n/static/src/core/translation_editor.js create mode 100644 addons/t9n/static/src/core/translation_editor.xml delete mode 100644 addons/t9n/static/src/web/open_resource_list_action.js delete mode 100644 addons/t9n/static/src/web/open_resource_page_action.js delete mode 100644 addons/t9n/static/src/web/open_target_languages_action.js diff --git a/addons/t9n/__manifest__.py b/addons/t9n/__manifest__.py index 350c8f1faf193..36e9f7598368d 100644 --- a/addons/t9n/__manifest__.py +++ b/addons/t9n/__manifest__.py @@ -3,7 +3,7 @@ "version": "1.0", "category": "TODO: find the appropriate category", "description": "TODO: write a description of the module", - "depends": ["base", "web"], + "depends": ["base", "mail", "web"], "application": True, "assets": { "web.assets_backend": [ diff --git a/addons/t9n/models/language.py b/addons/t9n/models/language.py index 94f9647fdf086..a52624c21ef26 100644 --- a/addons/t9n/models/language.py +++ b/addons/t9n/models/language.py @@ -20,3 +20,12 @@ class Language(models.Model): _sql_constraints = [ ("language_code_unique", "unique(code)", "The language code must be unique.") ] + + def _format(self): + return [{ + "id": language.id, + "name": language.name, + "code": language.code, + "native_name": language.native_name, + "direction": language.direction, + } for language in self] diff --git a/addons/t9n/models/project.py b/addons/t9n/models/project.py index e36770c577cd7..fbcb15581f07b 100644 --- a/addons/t9n/models/project.py +++ b/addons/t9n/models/project.py @@ -40,17 +40,18 @@ def get_projects(self): { "id": record.id, "name": record.name, - "src_lang": { + "src_lang_id": { "id": record.src_lang_id.id, "name": record.src_lang_id.name if record.src_lang_id.name else "", }, - "resources": [ + "resource_ids": [ { "id": resource.id, + "file_name": resource.file_name, } for resource in record.resource_ids ], - "target_langs": [ + "target_lang_ids": [ { "id": lang.id, "name": lang.name, diff --git a/addons/t9n/models/resource.py b/addons/t9n/models/resource.py index ef1f506f2c8a8..cb1c3fd203b70 100644 --- a/addons/t9n/models/resource.py +++ b/addons/t9n/models/resource.py @@ -94,14 +94,24 @@ def write(self, vals): return super().write(vals) @api.model - def get_resources(self, project_id): - resources_records = self.search([("project_id.id", "=", project_id)]) + def get_resources(self, ids): + return self.browse(ids)._format() + + def _format(self): return [ { - "id": record.id, - "file_name": record.file_name, - } - for record in resources_records + "id": resource.id, + "file_name": resource.file_name, + "message_ids": [ + { + "id": msg.id, + "body": msg.body, + } for msg in resource.message_ids + ], + "project_id": { + "id": resource.project_id.id, + }, + } for resource in self ] @api.model diff --git a/addons/t9n/models/translation.py b/addons/t9n/models/translation.py index 28fc75b949b68..f4ad123244e70 100644 --- a/addons/t9n/models/translation.py +++ b/addons/t9n/models/translation.py @@ -18,3 +18,17 @@ class Translation(models.Model): string="Language", help="The language to which the translation translates the original message.", ) + + @api.model + def create_and_format(self, **kwargs): + return self.create(kwargs)._format() + + def _format(self): + return [{ + "id": translation.id, + "body": translation.body, + "source_id": { + "id": translation.source_id.id, + }, + "lang_id": translation.lang_id._format()[0], + } for translation in self] diff --git a/addons/t9n/static/src/core/app.js b/addons/t9n/static/src/core/app.js index f58178faf5a15..dd33d44002b67 100644 --- a/addons/t9n/static/src/core/app.js +++ b/addons/t9n/static/src/core/app.js @@ -1,11 +1,25 @@ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; + import { ProjectList } from "@t9n/core/project_list"; +import { LanguageList } from "@t9n/core/language_list"; +import { ResourceList } from "@t9n/core/resource_list"; +import { TranslationEditor } from "@t9n/core/translation_editor"; + +import { useService } from "@web/core/utils/hooks"; /** * The "root", the "homepage" of the translation application. */ export class App extends Component { - static components = { ProjectList }; + static components = { LanguageList, ProjectList, ResourceList, TranslationEditor }; static props = {}; static template = "t9n.App"; + + setup() { + this.store = useState(useService("mail.store")); + } + + get activeView() { + return this.store.t9n.activeView; + } } diff --git a/addons/t9n/static/src/core/app.xml b/addons/t9n/static/src/core/app.xml index b792d771b8352..c47a40418474c 100644 --- a/addons/t9n/static/src/core/app.xml +++ b/addons/t9n/static/src/core/app.xml @@ -2,7 +2,10 @@ - + + + + diff --git a/addons/t9n/static/src/core/language_list.js b/addons/t9n/static/src/core/language_list.js index 014870dac5ea5..b193f3b590a8f 100644 --- a/addons/t9n/static/src/core/language_list.js +++ b/addons/t9n/static/src/core/language_list.js @@ -3,7 +3,7 @@ import { Component, useState } from "@odoo/owl"; import { useService } from "@web/core/utils/hooks"; export class LanguageList extends Component { - static props = {}; + static props = { languages: Array }; static template = "t9n.LanguageList"; setup() { @@ -17,22 +17,17 @@ export class LanguageList extends Component { order: "asc", }, }); - this.store = useState(useService("t9n.store")); - this.store.fetchLanguages(); + this.store = useState(useService("mail.store")); } get languages() { const searchTerms = this.state.filters.searchText.trim().toUpperCase(); const languages = searchTerms - ? this.store.languages.filter((l) => l.name.toUpperCase().includes(searchTerms)) - : [...this.store.languages]; - - languages.sort((l1, l2) => { - let l1Col = l1[this.state.sorting.column]; - let l2Col = l2[this.state.sorting.column]; - - l1Col = l1Col.toLowerCase(); - l2Col = l2Col.toLowerCase(); + ? this.props.languages.filter((l) => l.name.toUpperCase().includes(searchTerms)) + : [...this.props.languages]; + return languages.sort((l1, l2) => { + const l1Col = l1[this.state.sorting.column]; + const l2Col = l2[this.state.sorting.column]; if (l1Col < l2Col) { return this.state.sorting.order === "asc" ? -1 : 1; @@ -42,7 +37,6 @@ export class LanguageList extends Component { } return 0; }); - return languages; } onClickColumnName(column) { @@ -54,12 +48,8 @@ export class LanguageList extends Component { } } - onClickLanguage(id) { - this.store.setTargetLangId(id); - this.action.doAction({ - type: "ir.actions.client", - tag: "t9n.open_resource_list", - target: "current", - }); + onClickLanguage(language) { + this.store.t9n.activeView = "ResourceList"; + this.store.t9n.activeLanguage = language; } } diff --git a/addons/t9n/static/src/core/language_list.xml b/addons/t9n/static/src/core/language_list.xml index a89ac314a1a28..8df53788bd4c5 100644 --- a/addons/t9n/static/src/core/language_list.xml +++ b/addons/t9n/static/src/core/language_list.xml @@ -20,7 +20,7 @@ - diff --git a/addons/t9n/static/src/core/message_form.js b/addons/t9n/static/src/core/message_form.js index 5f2321151a0e6..edb8a9b4ad929 100644 --- a/addons/t9n/static/src/core/message_form.js +++ b/addons/t9n/static/src/core/message_form.js @@ -1,7 +1,9 @@ import { Component, useState, useRef } from "@odoo/owl"; + +import { CopyPopover } from "@t9n/core/copy_button_popover"; + import { useService } from "@web/core/utils/hooks"; import { usePopover } from "@web/core/popover/popover_hook"; -import { CopyPopover } from "@t9n/core/copy_button_popover"; export class MessageForm extends Component { static props = {}; @@ -11,7 +13,7 @@ export class MessageForm extends Component { this.state = useState({ suggestedTranslationText: "", }); - this.store = useState(useService("t9n.store")); + this.store = useState(useService("mail.store")); this.orm = useService("orm"); this.popoverButtonRef = useRef("popover-button"); this.copyPopover = usePopover(CopyPopover, { @@ -23,11 +25,11 @@ export class MessageForm extends Component { } get message() { - return this.store.active_message; + return this.store.t9n.activeMessage; } get translations() { - return this.store.active_message.translations; + return this.message.translationsInCurrentLanguage; } onClickClear() { @@ -47,14 +49,15 @@ export class MessageForm extends Component { } async onClickSuggest() { - await this.orm.create("t9n.translation", [ + const data = await this.orm.call("t9n.translation", "create_and_format", [], { body: this.state.suggestedTranslationText.trim(), - source_id: this.store.active_message.id, - lang_id: this.store.target_lang_id, + source_id: this.store.t9n.activeMessage.id, + lang_id: this.store.t9n.activeLanguage.id, }, - ]); - this.store.fetchActiveMessage(); - this.onClickClear(); + ); + console.log(data); + this.store["t9n.translation"].insert(data); + this.state.suggestedTranslationText = ""; } } diff --git a/addons/t9n/static/src/core/message_form.xml b/addons/t9n/static/src/core/message_form.xml index af39bd66ddd18..29927b0dab19e 100644 --- a/addons/t9n/static/src/core/message_form.xml +++ b/addons/t9n/static/src/core/message_form.xml @@ -3,31 +3,31 @@
    - +
    -

    +

    TRANSLATOR COMMENT - +

    -

    +

    RESOURCE COMMENT - +

    -

    +

    CONTEXT @@ -38,14 +38,14 @@

  • Cras justo odio
  • -

    +

    REFERENCES - +

    @@ -60,7 +60,7 @@
      - +
    • diff --git a/addons/t9n/static/src/core/models/app_model.js b/addons/t9n/static/src/core/models/app_model.js new file mode 100644 index 0000000000000..6d1eae78b7dfb --- /dev/null +++ b/addons/t9n/static/src/core/models/app_model.js @@ -0,0 +1,14 @@ +import { Record } from "@mail/core/common/record"; + +export class AppModel extends Record { + static name = "t9n.App"; + + activeProject = Record.one("t9n.project"); + activeLanguage = Record.one("t9n.language"); + activeResource = Record.one("t9n.resource"); + activeMessage = Record.one("t9n.message"); + /** @type {"ProjectList|"LanguageList"|"ResourceList"|"TranslationEditor"} */ + activeView = "ProjectList"; +} + +AppModel.register(); diff --git a/addons/t9n/static/src/core/models/language_model.js b/addons/t9n/static/src/core/models/language_model.js new file mode 100644 index 0000000000000..469fc09d74b1a --- /dev/null +++ b/addons/t9n/static/src/core/models/language_model.js @@ -0,0 +1,13 @@ +import { Record } from "@mail/core/common/record"; + +export class Language extends Record { + static name = "t9n.language"; + static id = "id"; + + name; + code; + native_name; + direction; +} + +Language.register(); diff --git a/addons/t9n/static/src/core/models/message_model.js b/addons/t9n/static/src/core/models/message_model.js new file mode 100644 index 0000000000000..0055ef262dc76 --- /dev/null +++ b/addons/t9n/static/src/core/models/message_model.js @@ -0,0 +1,24 @@ +import { Record } from "@mail/core/common/record"; + +export class Message extends Record { + static name = "t9n.message"; + static id = "id"; + + body; + context; + translator_comments; + extracted_comments; + references; + resource_id = Record.one("t9n.resource"); + translation_ids = Record.many("t9n.translation", { + inverse: "source_id", + }); + translationsInCurrentLanguage = Record.many("t9n.translation", { + compute() { + const { activeLanguage } = this.store.t9n; + return this.translation_ids.filter(({ lang_id }) => lang_id.eq(activeLanguage)); + }, + }); +} + +Message.register(); diff --git a/addons/t9n/static/src/core/models/project_model.js b/addons/t9n/static/src/core/models/project_model.js new file mode 100644 index 0000000000000..4537ff1fa20b1 --- /dev/null +++ b/addons/t9n/static/src/core/models/project_model.js @@ -0,0 +1,29 @@ +import { Record } from "@mail/core/common/record"; + +import { formatList } from "@web/core/l10n/utils"; + +export class Project extends Record { + static name = "t9n.project"; + static id = "id"; + + /** @type {string} */ + name; + src_lang_id = Record.one("t9n.language"); + resource_ids = Record.many("t9n.resource"); + target_lang_ids = Record.many("t9n.language"); + + /** @type {string} */ + targetLanguages = Record.attr("", { + compute() { + return formatList(this.target_lang_ids.map(({ name }) => name)); + }, + }); + /** @type {number} */ + resourceCount = Record.attr(0, { + compute() { + return this.resource_ids.length; + }, + }); +} + +Project.register(); diff --git a/addons/t9n/static/src/core/models/resource_model.js b/addons/t9n/static/src/core/models/resource_model.js new file mode 100644 index 0000000000000..904ac867a529c --- /dev/null +++ b/addons/t9n/static/src/core/models/resource_model.js @@ -0,0 +1,12 @@ +import { Record } from "@mail/core/common/record"; + +export class Resource extends Record { + static name = "t9n.resource"; + static id = "id"; + + file_name; + message_ids = Record.many("t9n.message"); + project_id = Record.one("t9n.project"); +} + +Resource.register(); diff --git a/addons/t9n/static/src/core/models/store_service_patch.js b/addons/t9n/static/src/core/models/store_service_patch.js new file mode 100644 index 0000000000000..e86cbcb04a5b9 --- /dev/null +++ b/addons/t9n/static/src/core/models/store_service_patch.js @@ -0,0 +1,15 @@ +import { Record } from "@mail/core/common/record"; +import { Store } from "@mail/core/common/store_service"; + +import { patch } from "@web/core/utils/patch"; + +patch(Store.prototype, { + setup() { + super.setup(...arguments); + this.t9n = Record.one("t9n.App", { + compute() { + return {}; + }, + }); + }, +}); diff --git a/addons/t9n/static/src/core/models/translation_model.js b/addons/t9n/static/src/core/models/translation_model.js new file mode 100644 index 0000000000000..cd7fc1e582846 --- /dev/null +++ b/addons/t9n/static/src/core/models/translation_model.js @@ -0,0 +1,14 @@ +import { Record } from "@mail/core/common/record"; + +export class Translation extends Record { + static name = "t9n.translation"; + static id = "id"; + + body; + source_id = Record.one("t9n.message", { + inverse: "translation_ids", + }); + lang_id = Record.one("t9n.language"); +} + +Translation.register(); diff --git a/addons/t9n/static/src/core/project_list.js b/addons/t9n/static/src/core/project_list.js index f95db73d2e92c..bf29841f38cf5 100644 --- a/addons/t9n/static/src/core/project_list.js +++ b/addons/t9n/static/src/core/project_list.js @@ -7,7 +7,6 @@ export class ProjectList extends Component { static template = "t9n.ProjectList"; setup() { - this.action = useService("action"); this.state = useState({ filters: { searchText: "", @@ -17,16 +16,21 @@ export class ProjectList extends Component { order: "asc", }, }); - this.store = useState(useService("t9n.store")); - this.store.fetchProjects(); + this.store = useState(useService("mail.store")); + this.fetchProjects(); + } + + async fetchProjects() { + const projects = await this.env.services.orm.call("t9n.project", "get_projects"); + this.store["t9n.project"].insert(projects); } get projects() { const searchTerms = this.state.filters.searchText.trim().toUpperCase(); + const allProjects = Object.values(this.store["t9n.project"].records); const projects = searchTerms - ? this.store.projects.filter((p) => p.name.toUpperCase().includes(searchTerms)) - : [...this.store.projects]; - + ? allProjects.filter((p) => p.name.toUpperCase().includes(searchTerms)) + : allProjects; projects.sort((p1, p2) => { let p1Col = p1[this.state.sorting.column]; let p2Col = p2[this.state.sorting.column]; @@ -56,15 +60,8 @@ export class ProjectList extends Component { } } - onClickProject(id) { - this.store.setProjectId(id); - this.action.doAction({ - type: "ir.actions.client", - tag: "t9n.open_target_langs", - target: "current", - context: { - project_id: id, - }, - }); + onClickProject(project) { + this.store.t9n.activeProject = project; + this.store.t9n.activeView = "LanguageList"; } } diff --git a/addons/t9n/static/src/core/project_list.xml b/addons/t9n/static/src/core/project_list.xml index 443f2ea61f47a..681c3733f26cb 100644 --- a/addons/t9n/static/src/core/project_list.xml +++ b/addons/t9n/static/src/core/project_list.xml @@ -18,15 +18,15 @@ - + - - - + + diff --git a/addons/t9n/static/src/core/project_model.js b/addons/t9n/static/src/core/project_model.js deleted file mode 100644 index 3cb421ba770b0..0000000000000 --- a/addons/t9n/static/src/core/project_model.js +++ /dev/null @@ -1,15 +0,0 @@ -import { formatList } from "@web/core/l10n/utils"; - -export class Project { - constructor(id, name, srcLang, targetLangs, resourceCount) { - this.id = id; - this.name = name; - this.srcLang = srcLang; - this.targetLangs = targetLangs; - this.resourceCount = resourceCount; - } - - get formattedTargetLanguages() { - return formatList(this.targetLangs.map(({ name }) => name)); - } -} diff --git a/addons/t9n/static/src/core/resource_list.js b/addons/t9n/static/src/core/resource_list.js index e629afc2bdd8d..a70adaa110d39 100644 --- a/addons/t9n/static/src/core/resource_list.js +++ b/addons/t9n/static/src/core/resource_list.js @@ -3,7 +3,7 @@ import { Component, useState } from "@odoo/owl"; import { useService } from "@web/core/utils/hooks"; export class ResourceList extends Component { - static props = {}; + static props = { resources: Array }; static template = "t9n.ResourceList"; setup() { @@ -17,8 +17,8 @@ export class ResourceList extends Component { order: "asc", }, }); - this.store = useState(useService("t9n.store")); - this.store.fetchResources(); + this.store = useState(useService("mail.store")); + this.fetchResources(); } get resources() { @@ -45,6 +45,15 @@ export class ResourceList extends Component { return resources; } + async fetchResources() { + const resourceData = await this.env.services.orm.call( + "t9n.resource", + "get_resources", + this.props.resources.map(({ id }) => id) + ); + this.store["t9n.resource"].insert(resourceData); + } + onClickColumnName(column) { if (this.state.sorting.column === column) { this.state.sorting.order = this.state.sorting.order === "asc" ? "desc" : "asc"; @@ -54,12 +63,8 @@ export class ResourceList extends Component { } } - onClickResource(id) { - this.store.setResourceId(id); - this.action.doAction({ - type: "ir.actions.client", - tag: "t9n.open_resource_page", - target: "current", - }); + onClickResource(resource) { + this.store.t9n.activeView = "TranslationEditor"; + this.store.t9n.activeResource = resource; } } diff --git a/addons/t9n/static/src/core/resource_list.xml b/addons/t9n/static/src/core/resource_list.xml index 5ad6502799665..f4ebe1feef52c 100644 --- a/addons/t9n/static/src/core/resource_list.xml +++ b/addons/t9n/static/src/core/resource_list.xml @@ -15,11 +15,11 @@ - + - diff --git a/addons/t9n/static/src/core/resource_model.js b/addons/t9n/static/src/core/resource_model.js deleted file mode 100644 index c656e9659d3ab..0000000000000 --- a/addons/t9n/static/src/core/resource_model.js +++ /dev/null @@ -1,8 +0,0 @@ -export class Resource { - constructor(id, fileName, projectId, messages) { - this.id = id; - this.fileName = fileName; - this.projectId = projectId; - this.messages = messages; - } -} diff --git a/addons/t9n/static/src/core/resource_page.js b/addons/t9n/static/src/core/resource_page.js deleted file mode 100644 index c76b484c8fd6b..0000000000000 --- a/addons/t9n/static/src/core/resource_page.js +++ /dev/null @@ -1,28 +0,0 @@ -import { useState, Component } from "@odoo/owl"; -import { useService } from "@web/core/utils/hooks"; -import { MessageForm } from "@t9n/core/message_form"; - -export class ResourcePage extends Component { - static props = {}; - static components = { MessageForm }; - static template = "t9n.ResourcePage"; - - setup() { - this.state = useState({ - isLoading: true, - }); - this.store = useState(useService("t9n.store")); - this.orm = useService("orm"); - this.store.fetchResource().then(() => { - this.state.isLoading = false; - }); - } - - get messages() { - return this.store.resource.messages; - } - - onClickMessage(message) { - this.store.setActiveMessage(message); - } -} diff --git a/addons/t9n/static/src/core/resource_page.xml b/addons/t9n/static/src/core/resource_page.xml deleted file mode 100644 index 9d36268a6ec1d..0000000000000 --- a/addons/t9n/static/src/core/resource_page.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - -
      - -
      -
      - -
      -
      -
      - -
      -
      - - - - - -
      -
      -
      - -
      -
      -
      - -
      - -
      diff --git a/addons/t9n/static/src/core/store.js b/addons/t9n/static/src/core/store.js index 9c758f7b6a1ab..17eac41732130 100644 --- a/addons/t9n/static/src/core/store.js +++ b/addons/t9n/static/src/core/store.js @@ -1,7 +1,5 @@ import { reactive } from "@odoo/owl"; -import { Project } from "@t9n/core/project_model"; -import { Resource } from "@t9n/core/resource_model"; import { registry } from "@web/core/registry"; export class Store { @@ -19,18 +17,6 @@ export class Store { return reactive(this); } - async fetchProjects() { - const projects = await this.orm.call("t9n.project", "get_projects"); - this.projects.splice( - 0, - this.projects.length, - ...projects.map( - (p) => - new Project(p.id, p.name, p.src_lang.name, p.target_langs, p.resources.length) - ) - ); - } - async fetchLanguages() { this.languages.splice( 0, @@ -39,12 +25,12 @@ export class Store { ); } async fetchResources() { - const resources = await this.orm.call("t9n.resource", "get_resources", [this.project_id]); - this.resources.splice( - 0, - this.resources.length, - ...resources.map((r) => new Resource(r.id, r.file_name, r.project_id, r.messages)) - ); + // const resources = await this.orm.call("t9n.resource", "get_resources", [this.project_id]); + // this.resources.splice( + // 0, + // this.resources.length, + // ...resources.map((r) => new Resource(r.id, r.file_name, r.project_id, r.messages)) + // ); } async fetchResource() { diff --git a/addons/t9n/static/src/core/translation_editor.js b/addons/t9n/static/src/core/translation_editor.js new file mode 100644 index 0000000000000..f272662ddd84f --- /dev/null +++ b/addons/t9n/static/src/core/translation_editor.js @@ -0,0 +1,23 @@ +import { useState, Component } from "@odoo/owl"; + +import { MessageForm } from "@t9n/core/message_form"; + +import { useService } from "@web/core/utils/hooks"; + +export class TranslationEditor extends Component { + static props = {}; + static components = { MessageForm }; + static template = "t9n.TranslationEditor"; + + setup() { + this.store = useState(useService("mail.store")); + } + + get messages() { + return this.store.t9n.activeResource.message_ids; + } + + onClickMessage(message) { + this.store.t9n.activeMessage = message; + } +} diff --git a/addons/t9n/static/src/core/translation_editor.xml b/addons/t9n/static/src/core/translation_editor.xml new file mode 100644 index 0000000000000..de32720e1ddef --- /dev/null +++ b/addons/t9n/static/src/core/translation_editor.xml @@ -0,0 +1,22 @@ + + + + +
      +
      +
      + + + + + +
      +
      +
      + +
      +
      + +
      + +
      diff --git a/addons/t9n/static/src/web/open_resource_list_action.js b/addons/t9n/static/src/web/open_resource_list_action.js deleted file mode 100644 index ea02575de512e..0000000000000 --- a/addons/t9n/static/src/web/open_resource_list_action.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, xml } from "@odoo/owl"; - -import { ResourceList } from "@t9n/core/resource_list"; -import { registry } from "@web/core/registry"; -import { standardActionServiceProps } from "@web/webclient/actions/action_service"; - -export class OpenResourceList extends Component { - static components = { ResourceList }; - static props = { ...standardActionServiceProps }; - static template = xml``; -} - -registry.category("actions").add("t9n.open_resource_list", OpenResourceList); diff --git a/addons/t9n/static/src/web/open_resource_page_action.js b/addons/t9n/static/src/web/open_resource_page_action.js deleted file mode 100644 index faadc7df57c87..0000000000000 --- a/addons/t9n/static/src/web/open_resource_page_action.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, xml } from "@odoo/owl"; - -import { ResourcePage } from "@t9n/core/resource_page"; -import { registry } from "@web/core/registry"; -import { standardActionServiceProps } from "@web/webclient/actions/action_service"; - -export class OpenResourcePage extends Component { - static components = { ResourcePage }; - static props = { ...standardActionServiceProps }; - static template = xml``; -} - -registry.category("actions").add("t9n.open_resource_page", OpenResourcePage); diff --git a/addons/t9n/static/src/web/open_target_languages_action.js b/addons/t9n/static/src/web/open_target_languages_action.js deleted file mode 100644 index aeb71dfd15d5d..0000000000000 --- a/addons/t9n/static/src/web/open_target_languages_action.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, xml } from "@odoo/owl"; - -import { LanguageList } from "@t9n/core/language_list"; -import { registry } from "@web/core/registry"; -import { standardActionServiceProps } from "@web/webclient/actions/action_service"; - -export class OpenTargetLanguages extends Component { - static components = { LanguageList }; - static props = { ...standardActionServiceProps }; - static template = xml``; -} - -registry.category("actions").add("t9n.open_target_langs", OpenTargetLanguages); diff --git a/addons/t9n/views/t9n_project_views.xml b/addons/t9n/views/t9n_project_views.xml index 11ba47146e31a..4cec539c0523f 100644 --- a/addons/t9n/views/t9n_project_views.xml +++ b/addons/t9n/views/t9n_project_views.xml @@ -7,7 +7,7 @@ - Open Target Languages + Open Language Selection t9n.open_target_langs diff --git a/addons/t9n/views/t9n_resource_views.xml b/addons/t9n/views/t9n_resource_views.xml index 1b40c0f7e3434..593dbe60adc65 100644 --- a/addons/t9n/views/t9n_resource_views.xml +++ b/addons/t9n/views/t9n_resource_views.xml @@ -20,16 +20,6 @@ - - Open Resource List - t9n.open_resource_list - - - - Open Resource Page - t9n.open_resource_page - - t9n.resource.list t9n.resource From 5a50327ff0e298860ebae38759c2ae437f8d730e Mon Sep 17 00:00:00 2001 From: Mohammed Basioni Date: Wed, 17 Jul 2024 16:53:33 +0300 Subject: [PATCH 3/3] wip --- addons/t9n/models/message.py | 24 +----- addons/t9n/models/project.py | 34 ++------ addons/t9n/models/resource.py | 44 +++------- .../static/src/core/copy_button_popover.js | 6 -- .../static/src/core/copy_button_popover.xml | 6 -- addons/t9n/static/src/core/language_list.xml | 2 +- addons/t9n/static/src/core/message_form.js | 26 ++---- addons/t9n/static/src/core/message_form.xml | 4 +- .../t9n/static/src/core/models/app_model.js | 2 +- addons/t9n/static/src/core/resource_list.js | 8 +- addons/t9n/static/src/core/resource_list.xml | 4 +- addons/t9n/static/src/core/store.js | 86 ------------------- addons/t9n/static/src/web/open_app_action.js | 11 ++- addons/t9n/views/t9n_project_views.xml | 5 -- 14 files changed, 48 insertions(+), 214 deletions(-) delete mode 100644 addons/t9n/static/src/core/copy_button_popover.js delete mode 100644 addons/t9n/static/src/core/copy_button_popover.xml delete mode 100644 addons/t9n/static/src/core/store.js diff --git a/addons/t9n/models/message.py b/addons/t9n/models/message.py index 750024968e6ea..2edd5f82f065d 100644 --- a/addons/t9n/models/message.py +++ b/addons/t9n/models/message.py @@ -1,4 +1,4 @@ -from odoo import api, fields, models +from odoo import fields, models class Message(models.Model): @@ -41,25 +41,3 @@ class Message(models.Model): "The combination of a text to translate and its context must be unique within the same resource!", ), ] - - @api.model - def get_message(self, message_id, target_lang_id): - message_records = self.browse([message_id]) - message_records.ensure_one() - message_record = next(iter(message_records)) - return { - "id": message_record.id, - "body": message_record.body, - "context": message_record.context, - "translator_comments": message_record.translator_comments, - "extracted_comments": message_record.extracted_comments, - "references": message_record.references, - "translations": [ - { - "id": record.id, - "body": record.body, - } - for record in message_record.translation_ids - if record.lang_id.id == target_lang_id - ], - } diff --git a/addons/t9n/models/project.py b/addons/t9n/models/project.py index fbcb15581f07b..4c6e264c4bb3f 100644 --- a/addons/t9n/models/project.py +++ b/addons/t9n/models/project.py @@ -35,15 +35,14 @@ def _check_source_and_target_languages(self): @api.model def get_projects(self): - projects_records = self.search([]) + return self.search([])._format() + + def _format(self): return [ { "id": record.id, "name": record.name, - "src_lang_id": { - "id": record.src_lang_id.id, - "name": record.src_lang_id.name if record.src_lang_id.name else "", - }, + "src_lang_id": record.src_lang_id._format()[0], "resource_ids": [ { "id": resource.id, @@ -51,28 +50,7 @@ def get_projects(self): } for resource in record.resource_ids ], - "target_lang_ids": [ - { - "id": lang.id, - "name": lang.name, - } - for lang in record.target_lang_ids - ], - } - for record in projects_records - ] - - @api.model - def get_target_langs(self, id): - project_records = self.browse([id]) - project_records.ensure_one() - project_record = next(iter(project_records)) - return [ - { - "id": lang.id, - "name": lang.name, - "code": lang.code, - "native_name": lang.native_name, + "target_lang_ids": record.target_lang_ids._format(), } - for lang in project_record.target_lang_ids + for record in self ] diff --git a/addons/t9n/models/resource.py b/addons/t9n/models/resource.py index cb1c3fd203b70..9a20717ddbbe0 100644 --- a/addons/t9n/models/resource.py +++ b/addons/t9n/models/resource.py @@ -106,40 +106,20 @@ def _format(self): { "id": msg.id, "body": msg.body, - } for msg in resource.message_ids + "translation_ids": [ + { + "id": translation.id, + "body": translation.body, + "lang_id": translation.lang_id.id, + } + for translation in msg.translation_ids + ], + } + for msg in resource.message_ids ], "project_id": { "id": resource.project_id.id, }, - } for resource in self + } + for resource in self ] - - @api.model - def get_resource(self, id, target_lang_id): - resource_records = self.browse([id]) - resource_records.ensure_one() - resource_record = next(iter(resource_records)) - return { - "id": resource_record.id, - "file_name": resource_record.file_name, - "project_id": resource_record.project_id.id, - "messages": [ - { - "id": message.id, - "body": message.body, - "context": message.context, - "translator_comments": message.translator_comments, - "extracted_comments": message.extracted_comments, - "references": message.references, - "translations": [ - { - "id": lang.id, - "body": lang.body, - } - for lang in message.translation_ids - if lang.lang_id.id == target_lang_id - ], - } - for message in resource_record.message_ids - ], - } diff --git a/addons/t9n/static/src/core/copy_button_popover.js b/addons/t9n/static/src/core/copy_button_popover.js deleted file mode 100644 index 3215ee672c6da..0000000000000 --- a/addons/t9n/static/src/core/copy_button_popover.js +++ /dev/null @@ -1,6 +0,0 @@ -import { Component } from '@odoo/owl' - -export class CopyPopover extends Component { - static props = {} - static template = 't9n.copyButtonPopover' -} diff --git a/addons/t9n/static/src/core/copy_button_popover.xml b/addons/t9n/static/src/core/copy_button_popover.xml deleted file mode 100644 index f9aecb745dca6..0000000000000 --- a/addons/t9n/static/src/core/copy_button_popover.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - -
      Copied to clipboard!
      -
      -
      diff --git a/addons/t9n/static/src/core/language_list.xml b/addons/t9n/static/src/core/language_list.xml index 8df53788bd4c5..d3662615452c8 100644 --- a/addons/t9n/static/src/core/language_list.xml +++ b/addons/t9n/static/src/core/language_list.xml @@ -17,7 +17,7 @@ - + - + diff --git a/addons/t9n/static/src/core/models/app_model.js b/addons/t9n/static/src/core/models/app_model.js index 6d1eae78b7dfb..7684942129815 100644 --- a/addons/t9n/static/src/core/models/app_model.js +++ b/addons/t9n/static/src/core/models/app_model.js @@ -7,7 +7,7 @@ export class AppModel extends Record { activeLanguage = Record.one("t9n.language"); activeResource = Record.one("t9n.resource"); activeMessage = Record.one("t9n.message"); - /** @type {"ProjectList|"LanguageList"|"ResourceList"|"TranslationEditor"} */ + /** @type {"ProjectList"|"LanguageList"|"ResourceList"|"TranslationEditor"} */ activeView = "ProjectList"; } diff --git a/addons/t9n/static/src/core/resource_list.js b/addons/t9n/static/src/core/resource_list.js index a70adaa110d39..c2d0da0cd1798 100644 --- a/addons/t9n/static/src/core/resource_list.js +++ b/addons/t9n/static/src/core/resource_list.js @@ -13,7 +13,7 @@ export class ResourceList extends Component { searchText: "", }, sorting: { - column: "fileName", + column: "file_name", order: "asc", }, }); @@ -24,8 +24,8 @@ export class ResourceList extends Component { get resources() { const searchTerms = this.state.filters.searchText.trim().toUpperCase(); const resources = searchTerms - ? this.store.resources.filter((r) => r.fileName.toUpperCase().includes(searchTerms)) - : [...this.store.resources]; + ? this.props.resources.filter((r) => r.file_name.toUpperCase().includes(searchTerms)) + : [...this.props.resources]; resources.sort((r1, r2) => { let r1Col = r1[this.state.sorting.column]; @@ -49,7 +49,7 @@ export class ResourceList extends Component { const resourceData = await this.env.services.orm.call( "t9n.resource", "get_resources", - this.props.resources.map(({ id }) => id) + [this.props.resources.map(({ id }) => id)], ); this.store["t9n.resource"].insert(resourceData); } diff --git a/addons/t9n/static/src/core/resource_list.xml b/addons/t9n/static/src/core/resource_list.xml index f4ebe1feef52c..e60f871d1fed7 100644 --- a/addons/t9n/static/src/core/resource_list.xml +++ b/addons/t9n/static/src/core/resource_list.xml @@ -10,12 +10,12 @@ - - +
      Resource + Resource