diff --git a/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js b/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js index 5d4f30c94..bc365ef89 100644 --- a/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js +++ b/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js @@ -373,8 +373,8 @@ this.state.attendance_lines = groupedAttendance; line.color = 'red'; break; default: - line.state = 'Refused'; - line.color = 'red'; + line.state = 'Draft'; + line.color = '#6871f2'; break; } }); diff --git a/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml b/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml index 3fcad56b0..adb3b4a34 100644 --- a/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml +++ b/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml @@ -186,11 +186,11 @@

Attendance

- + + + + +
@@ -280,11 +280,11 @@

Expenses

- + + + + +
diff --git a/addons_extensions/web_gantt/__init__.py b/addons_extensions/web_gantt/__init__.py new file mode 100644 index 000000000..dc5e6b693 --- /dev/null +++ b/addons_extensions/web_gantt/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/addons_extensions/web_gantt/__manifest__.py b/addons_extensions/web_gantt/__manifest__.py new file mode 100644 index 000000000..ffb3c5f9b --- /dev/null +++ b/addons_extensions/web_gantt/__manifest__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Web Gantt', + 'category': 'Hidden', + 'description': """ +Odoo Web Gantt chart view. +============================= + + """, + 'version': '2.0', + 'depends': ['web'], + 'assets': { + 'web._assets_primary_variables': [ + 'web_gantt/static/src/gantt_view.variables.scss', + ], + 'web.assets_backend_lazy': [ + 'web_gantt/static/src/**/*', + + # Don't include dark mode files in light mode + ('remove', 'web_gantt/static/src/**/*.dark.scss'), + ], + 'web.assets_backend_lazy_dark': [ + 'web_gantt/static/src/**/*.dark.scss', + ], + 'web.assets_unit_tests': [ + 'web_gantt/static/tests/**/*', + ], + + }, + 'auto_install': True, +} diff --git a/addons_extensions/web_gantt/i18n/ar.po b/addons_extensions/web_gantt/i18n/ar.po new file mode 100644 index 000000000..24853303f --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ar.po @@ -0,0 +1,363 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Arabic (https://app.transifex.com/odoo/teams/41243/ar/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s ساعات و%(minute)s " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "لا يمكن جدولة %s في الماضي " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s ساعات " + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "عرض نافذة الإجراء" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "تطبيق" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "هل أنت متأكد من أنك ترغب في حذف هذا السجل؟ " + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "قاعدة " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "تصغير الصفوف " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "إنشاء" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "تحرير" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "تكبير الصفوف " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "ركّز اليوم " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "من" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "جانت" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "أداة عرض جانت" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "يمكن أن يكون تابع غانت إما حقل أو قالب فقط، به %s " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "يجب أن يكون لعرض غانت خاصية 'date_start' " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "يجب أن يكون لعرض غانت خاصية 'date_stop' " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"يجب أن يكون لنافذة عرض غانت خاصية 'dependency_inverted_field' بمجرد أن يتم " +"تحديد 'dependency_field' " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "تاريخ بدء غانت " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "تاريخ انتهاء غانت " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "يمكن أن يحتوي عرض غانت على علامة تصنيف قوالب واحدة فقط " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "لا يمكن القيام بالجدولة في الماضي. " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "لا توجد حقول كافية لعرض غانت! " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"خواص غير صالحة (%(invalid_attributes)s) في عرض غانت. يجب أن تكون الخواص في " +"(%(valid_attributes)s) " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' غير صالح في عرض غانت " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "default_scale '%s' غير صالح في عرض غانت " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode '%s' في نافذة عرض غانت غير صالح " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "الاسم" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "جديد" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "فتح" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "الخطة " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "بدء" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "إيقاف" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "التبعيات غير صالحة. لقد تسببت في إحداث دائرة مغلقة. " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "لا يوجد مرشحون صالحون لإعادة التخطيط " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "هذا الشهر" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "ربع السنة هذا " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "هذا الأسبوع " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "هذا العام" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "اليوم " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "قائمة شريط الأدوات " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "الإجمالي" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "غير محدد %s " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "أداة العرض" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "نوع واجهة العرض" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "لا يمكنك تحريك %(record)s نحو %(related_record)s. " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "لا يمكنك إعادة جدولة %(main_record)s نحو %(other_record)s. " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "ساعات" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "دقائق " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "شهور" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "إلى" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/bg.po b/addons_extensions/web_gantt/i18n/bg.po new file mode 100644 index 000000000..ea290d022 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/bg.po @@ -0,0 +1,367 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Petko Karamotchev, 2024 +# Martin Trigaux, 2024 +# Rosen Vladimirov , 2024 +# Boyan Rabchev , 2024 +# Rumena Georgieva , 2024 +# Vladimir Petrov , 2024 +# KeyVillage, 2024 +# Albena Mincheva , 2024 +# Maria Boyadjieva , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Maria Boyadjieva , 2024\n" +"Language-Team: Bulgarian (https://app.transifex.com/odoo/teams/41243/bg/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: bg\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Приложи" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Основа" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Създай" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Редактирай" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "От" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Диаграма на Гант" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Изглед на диаграма на Гант" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Име" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Нов" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Отворен" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Планирайте" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Стартирайте" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Край" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Този месец" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Тази седмица" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Днес" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Обща стойност" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Преглед" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Вид изглед" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "часове" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "минути" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "месеци" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "до" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/ca.po b/addons_extensions/web_gantt/i18n/ca.po new file mode 100644 index 000000000..3c70de6eb --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ca.po @@ -0,0 +1,371 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Arnau Ros, 2024 +# Ivan Espinola, 2024 +# jabiri7, 2024 +# Sandra Franch , 2024 +# Josep Anton Belchi, 2024 +# marcescu, 2024 +# Martin Trigaux, 2024 +# Quim - eccit , 2024 +# RGB Consulting , 2024 +# Eric Antones , 2024 +# Manel Fernandez Ramirez , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Manel Fernandez Ramirez , 2024\n" +"Language-Team: Catalan (https://app.transifex.com/odoo/teams/41243/ca/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ca\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Vista de la finestra d'acció" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Aplica" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "¿Està segur d'eliminar aquest registre?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Col·lapsar files" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Crear" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Modificar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Expandeix les files" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Des de" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gràfic de Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vista Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "El fill de Gantt només pot ser un camp o una plantilla, té %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt ha de tenir un atribut 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt ha de tenir un atribut \"date_stop\"." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt ha de tenir un atribut 'dependency_inverted_field' una vegada s'hagi " +"especificat 'dependency_field' " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "La vista de Gantt només pot contenir una etiqueta de plantilles" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "¡Camps insuficients per a la vista de Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Escala_per defecte invàlida '%s'a gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nom" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nou" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Oberts" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Pla" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Inicia" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Atura" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Aquest mes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Aquesta setmana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Aquest any" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Avui" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "No definit %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipus de vista" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "hores" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuts" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "mesos" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "fins" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/cs.po b/addons_extensions/web_gantt/i18n/cs.po new file mode 100644 index 000000000..7d061f3af --- /dev/null +++ b/addons_extensions/web_gantt/i18n/cs.po @@ -0,0 +1,361 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Czech (https://app.transifex.com/odoo/teams/41243/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: cs\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Akce okna zobrazení" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Použít" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Opravdu chcete tento záznam smazat?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Jádro" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Sbalit řádky" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Vytvořit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Upravit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Rozbalte řádky" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Od" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantův diagram" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Ganttův potomek může být pouze pole nebo šablona, dostal %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt musí mít atribut 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt musí mít atribut 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt musí mít atribut 'dependency_inverted_field', jakmile je specifikováno" +" 'dependency_field'" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Zobrazení Gantt může obsahovat pouze jeden štítek šablony" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Nedostatečná pole pro zobrazení Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Neplatný default_scale '%s' v gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Název" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nové" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Volný" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plán" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Začít" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Zastavit" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Tento měsíc" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Tento týden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Tento rok" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Dnes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Celkem" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Nedefinováno %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Zobrazení" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Typ zobrazení" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "hodin" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minut" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "měsíce" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "k" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/da.po b/addons_extensions/web_gantt/i18n/da.po new file mode 100644 index 000000000..ba88c8f8b --- /dev/null +++ b/addons_extensions/web_gantt/i18n/da.po @@ -0,0 +1,264 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Sanne Kristensen , 2022 +# Mads Søndergaard, 2022 +# Mads Søndergaard, 2022 +# Martin Trigaux, 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2022-09-22 05:49+0000\n" +"Last-Translator: Martin Trigaux, 2023\n" +"Language-Team: Danish (https://app.transifex.com/odoo/teams/41243/da/)\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Er du sikker på du vil slette dette datasæt?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Basis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "Sammenfald rækker" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Opret" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Dag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "Udvid rækker" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt visning" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantt arving kan kun være et felt eller en skabelon, fik %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt skal have en 'date_start' egenskab" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt skal have en 'date_stop' egenskab" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Gantt visning kan kun indeholde én skabelons tag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "Gruppering per dato er ikke understøttet" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Utilstrækkelig felter til Gantt visning!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Ugyldig default_scale '%s' i gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Måned" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Ny" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Næste" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Åben" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planlæg" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "Plan eksisterer" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Forrige" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "I dag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Udefineret %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Uge" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "År" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/de.po b/addons_extensions/web_gantt/i18n/de.po new file mode 100644 index 000000000..793a843f4 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/de.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Larissa Manderfeld, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Larissa Manderfeld, 2024\n" +"Language-Team: German (https://app.transifex.com/odoo/teams/41243/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sSt.%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s kann nicht in der Vergangenheit liegen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sSt." + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Ansicht des Aktionsfensters" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Dense-Modus aktivieren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Sparse-Modus aktivieren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Anwenden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Sind Sie sicher, dass Sie diesen Datensatz löschen möchten?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Basis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Zeilen einklappen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Erstellen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Bearbeiten" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Zeilen erweitern" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Heute fokussieren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Von" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt-Ansicht" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Untergeordnetes Gantt kann nur Feld oder Vorlage sein, %s erhalten" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt muss ein „date_start“-Attribut haben" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt muss ein „date_stop“-Attribut haben" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt muss ein „dependency_inverted_field“-Attribut haben, sobald das " +"„dependency_field“ bestimmt wurde" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Gantt-Startdatum" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Gantt-Enddatum" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Gantt-Ansicht kann nur ein Vorlagen-Stichwort beinhalten" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Kann nicht in der Vergangenheit liegen" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Unzureichende Felder für die Gantt-Ansicht!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Ungültige Attribute (%(invalid_attributes)s) in der Gantt-Ansicht. Attribute" +" müssen in (%(valid_attributes)s) stehen." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "Ungültige default_range „%s“ in Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Ungültige default_scale „%s“ in Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "Ungültiger display_mode „%s“ in Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Namen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Neu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Öffnen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planen" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Verschiebung erfolgreich abgeschlossen." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Loslegen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Stopp" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Die Abhängigkeiten sind nicht gültig, es gibt einen Kreis." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Es sind keine gültigen Kandidaten neu zu planen." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Diesen Monat" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Dieses Quartal" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Diese Woche" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Dieses Jahr" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Heute" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Symbolleistenmenü" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Gesamt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s Undefiniert" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Ansicht" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Ansichtstyp" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Sie können %(record)s nicht nach %(related_record)s verschieben." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "Sie können %(main_record)s nicht nach %(other_record)s verschieben." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "Stunden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "Minuten" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "Monate" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "bis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/el.po b/addons_extensions/web_gantt/i18n/el.po new file mode 100644 index 000000000..6a83b6cbb --- /dev/null +++ b/addons_extensions/web_gantt/i18n/el.po @@ -0,0 +1,263 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Martin Trigaux, 2019 +# Kostas Goutoudis , 2019 +# Giota Dandidou , 2019 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server saas~12.2+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2016-08-05 13:32+0000\n" +"Last-Translator: Giota Dandidou , 2019\n" +"Language-Team: Greek (https://www.transifex.com/odoo/teams/41243/el/)\n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Βάση" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Δημιουργία" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Ημέρα" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Προβολή Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Μήνας" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Επόμενο" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Ανοιχτό" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Σχεδίασε" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Προηγούμενο" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "Σήμερα" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Εβδομάδα" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "Έτος" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/es.po b/addons_extensions/web_gantt/i18n/es.po new file mode 100644 index 000000000..04a755514 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/es.po @@ -0,0 +1,363 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Spanish (https://app.transifex.com/odoo/teams/41243/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s h %(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s no se puede programar en el pasado" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s h" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Vista de la ventana de acción" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Activar modo denso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Activar modo disperso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Aplicar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "¿Está seguro de que desea eliminar este registro?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Ocultar filas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Crear" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Editar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Expandir filas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Enfoque de hoy" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Desde" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vista Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantt hijo solo puede ser campo o plantilla, obtuvo %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt debe tener un atributo \"date_start\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt debe tener un atributo \"date_stop\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt debe tener un atributo 'dependency_inverted_field' cuando se " +"especifique el campo 'dependency_field'." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Fecha de inicio de Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Fecha de finalización de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "La vista de Gantt solo puede contener una etiqueta de plantilla" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "No es posible programar en el pasado." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "¡Campos insuficientes para la vista de Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Atributos no válidos (%(invalid_attributes)s) en la vista gantt. Los " +"atributos deben estar en (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' no válido en Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Default_scale '%s' no válida en vista de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode \"%s\" no válido en gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nombre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nuevo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Abrir" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planificar" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Iniciar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Detener" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Las dependencias no son válidas, hay un ciclo." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "No hay candidatos válidos para replanificar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Este mes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Este trimestre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Esta semana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Este año" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Hoy" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menú de barra de herramientas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s sin definir" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipo de vista" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "No puede mover %(record)s a %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "No puede reprogramar %(main_record)s a %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "horas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minutos" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "meses" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "a" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/es_419.po b/addons_extensions/web_gantt/i18n/es_419.po new file mode 100644 index 000000000..e3126e757 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/es_419.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Patricia Gutiérrez Capetillo , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Patricia Gutiérrez Capetillo , 2024\n" +"Language-Team: Spanish (Latin America) (https://app.transifex.com/odoo/teams/41243/es_419/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es_419\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s no se puede programar en el pasado" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Vista de acción de ventana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Activar modo denso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Activar modo disperso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Aplicar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "¿Está seguro de que desea eliminar este registro?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Contraer filas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Crear" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Editar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Expandir filas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Importantes de hoy" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Desde" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vista de gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantt secundario solo puede ser un campo o plantilla, obtuvo %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt debe tener un atributo \"date_start\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt debe tener un atributo \"date_stopt\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt debe tener un atributo 'dependency_inverted_field' cuando se " +"especifique el campo 'dependency_field'." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Fecha de inicio de Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Fecha de finalización de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "La vista de Gantt solo puede contener una etiqueta de plantilla" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "No es posible programar en el pasado." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Campos insuficientes para la vista de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Atributos inválidos (%(invalid_attributes)s) en la vista de Gantt. Los " +"atributos deben estar en (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' no válido en Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Default_scale '%s' no válida en vista gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode \"%s\" inválido en la vista de Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nombre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nuevo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Abierto" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Reprogramación realizada con éxito." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Iniciar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Detener" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Las dependencias no son válidas, hay un ciclo." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "No hay candidatos válidos para replanificar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Este mes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Este trimestre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Esta semana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Este año" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Hoy" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menú de barra de herramientas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s sin definir" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Ver tipo" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "No puede mover %(record)s a %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "No puede mover %(main_record)s a %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "horas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minutos" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "meses" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "para" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/et.po b/addons_extensions/web_gantt/i18n/et.po new file mode 100644 index 000000000..89a7bc3c5 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/et.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Siim Raasuke, 2024 +# Stevin Lilla, 2024 +# Martin Trigaux, 2024 +# Eneli Õigus , 2024 +# Anna, 2024 +# Triine Aavik , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Triine Aavik , 2024\n" +"Language-Team: Estonian (https://app.transifex.com/odoo/teams/41243/et/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: et\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)stundi%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%stund" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Toimingu akna vaade" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Kinnita" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Kas oled kindel, et soovid antud kirjet kustutada?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Baas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "peida read" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Loo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Muuda" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Laienda ridu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Kellelt?" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantti vaade" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Vigane default_scale '%s' ganti vaates" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nimi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Uus" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Avatud" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plaan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Alusta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Peata" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "See kuu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "See nädal" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "See aasta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Täna" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Kokku" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Määramata %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vaade" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Vaate tüüp" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "tundi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minutit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "kuud" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "kuni" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/fi.po b/addons_extensions/web_gantt/i18n/fi.po new file mode 100644 index 000000000..3ef0a5273 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/fi.po @@ -0,0 +1,367 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Tiffany Chang, 2024 +# Miku Laitinen , 2024 +# Jarmo Kortetjärvi , 2024 +# Mikko Salmela , 2024 +# Ossi Mantylahti , 2024 +# Tuomo Aura , 2024 +# Martin Trigaux, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Martin Trigaux, 2024\n" +"Language-Team: Finnish (https://app.transifex.com/odoo/teams/41243/fi/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: fi\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Toimintoikkunan näkymä" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Käytä" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Oletko varma, että haluat poistaa tämän tietueen?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Pohja" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Supista rivit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Luo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Muokkaa" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Laajenna rivit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Alkaa" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt-näkymä" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantt-kaavion alataso voi olla vain kenttä tai malli, saatiin %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Ganttissa on oltava attribuutti 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Ganttissa on oltava attribuutti 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Ganttissa on oltava attribuutti 'dependency_inverted_field', kun " +"'dependency_field' on määritetty" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Gantt-näkymä voi sisältää vain yhden mallitunnisteen" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Kenttiä ei ole tarpeeksi Gantt-näkymään!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Ganttissa on virheellinen default_scale '%s'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nimi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Uusi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Avoin" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Suunnittele" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Aloitus" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Lopeta" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Tässä kuussa" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Tällä viikolla" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Tämä vuosi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Tänään" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Yhteensä" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Määrittelemätön %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Näytä" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Näkymän tyyppi" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "tunti(a)" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuutit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "kuukaudet" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "->" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/fr.po b/addons_extensions/web_gantt/i18n/fr.po new file mode 100644 index 000000000..76f023e84 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/fr.po @@ -0,0 +1,366 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: French (https://app.transifex.com/odoo/teams/41243/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: fr\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s ne peut pas être planifié dans le passé" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Vue de la fenêtre d'action" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Activer le mode dense" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Activer le mode clairsemé" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Appliquer" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Êtes-vous sûr de vouloir supprimer cet enregistrement ?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Plier les lignes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Créer" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Modifier" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Déplier les lignes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Cibler la date d'aujourd'hui" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "À partir de" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vue de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" +"Une ligne enfant Gantt peut seulement être un champ ou un modèle, vous avez " +"%s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt doit avoir un attribut 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt doit avoir un attribut 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gant doit avoir un attribut 'dependency_inverted_field' dès que le " +"'dependency_field' est défini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Date de début Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Date de fin Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "La vue Gantt peut uniquement contenir une étiquette de modèles" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Impossible de planifier dans le passé." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Champs insuffisants pour la vue Gantt !" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Des attributs invalides se trouvent (%(invalid_attributes)s) dans la vue " +"Gantt. Les attributs doivent être en (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' invalide dans gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "default_scale '%s' invalide dans Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "Display_mode '%s' invalide dans Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nom" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nouveau" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Ouvert" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planifier" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Lancer" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Arrêter" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Les dépendances ne sont pas valides, il y a un cycle." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Il n'y a pas de candidats valides à replanifier." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Ce mois" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Ce trimestre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Cette semaine" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Cette année" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Aujourd'hui" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menu barre d'outils" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s indéfini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vue" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Type de vue" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Vous ne pouvez pas déplacer %(record)s vers %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" +"Vous ne pouvez pas reprogrammer %(main_record)s vers %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "heures" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minutes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "mois" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "au" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/he.po b/addons_extensions/web_gantt/i18n/he.po new file mode 100644 index 000000000..8053443b1 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/he.po @@ -0,0 +1,365 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# שהאב חוסיין , 2024 +# MichaelHadar, 2024 +# דודי מלכה , 2024 +# Yihya Hugirat , 2024 +# Lilach Gilliam , 2024 +# ZVI BLONDER , 2024 +# Martin Trigaux, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Martin Trigaux, 2024\n" +"Language-Team: Hebrew (https://app.transifex.com/odoo/teams/41243/he/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: he\n" +"Plural-Forms: nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "תצוגת חלון פעולה" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "החל" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "האם אתה בטוח שברצונך למחוק רשומה זו?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "בסיס" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "צמצם שורות" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "יצירה" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "ערוך" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "הרחב שורות" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "מ" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "גאנט" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "תצוגת גאנט" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "גאנט מחייב הגדרת \"תאריך התחלה\":" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "גאנט מחייב הגדרת \"תאריך סיום\":" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "אין מספיק שדות לתצוגת גאנט!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "שם" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "חדש" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "פתח" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "תוכנית" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "התחל" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "עצור" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "חודש נוכחי" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "שבוע נוכחי" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "שנה נוכחית" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "היום" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "סה\"כ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s לא מוגדר" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "תצוגה" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "סוג תצוגה" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "שעות" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "דקות" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "חודשים" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "ל" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/hi.po b/addons_extensions/web_gantt/i18n/hi.po new file mode 100644 index 000000000..b7cc662c1 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/hi.po @@ -0,0 +1,359 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Martin Trigaux, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Martin Trigaux, 2024\n" +"Language-Team: Hindi (https://app.transifex.com/odoo/teams/41243/hi/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: hi\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "बनाएँ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "संपादित" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "नया" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/hr.po b/addons_extensions/web_gantt/i18n/hr.po new file mode 100644 index 000000000..faceab3e4 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/hr.po @@ -0,0 +1,365 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Igor Krizanovic , 2024 +# Vladimir Olujić , 2024 +# Karolina Tonković , 2024 +# Bole , 2024 +# Kristina Palaš, 2024 +# Tina Milas, 2024 +# Martin Trigaux, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Martin Trigaux, 2024\n" +"Language-Team: Croatian (https://app.transifex.com/odoo/teams/41243/hr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: hr\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Radni prozor" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Primjeni" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Osnovica" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Kreiraj" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Uredi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Od" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantogram" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantogram" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Naziv" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Novi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Otvori" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Start" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Kraj" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Ovaj mjesec" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Ovaj tjedan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Ove godine" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Danas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Ukupno" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Pogledaj" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tip pogleda" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "sati" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "mjeseci" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "do" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/hu.po b/addons_extensions/web_gantt/i18n/hu.po new file mode 100644 index 000000000..06e0789d2 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/hu.po @@ -0,0 +1,266 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# gezza , 2022 +# Tamás Németh , 2022 +# Istvan , 2022 +# Csaba Tóth , 2022 +# Martin Trigaux, 2022 +# krnkris, 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2022-09-22 05:49+0000\n" +"Last-Translator: krnkris, 2023\n" +"Language-Team: Hungarian (https://app.transifex.com/odoo/teams/41243/hu/)\n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Alap" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "Sorok becsukása" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Létrehozás" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Nap" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "Sorok kinyitása" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt nézet" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Hónap" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Új" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Következő" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Megnyitás" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Terv" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Előző" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "Ma" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Megtekintés" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Hét" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "Év" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/id.po b/addons_extensions/web_gantt/i18n/id.po new file mode 100644 index 000000000..21eaa43a5 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/id.po @@ -0,0 +1,365 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Abe Manyo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Abe Manyo, 2024\n" +"Language-Team: Indonesian (https://app.transifex.com/odoo/teams/41243/id/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: id\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sj%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s tidak dapat dijadwalkan di masa lalu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sj" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Jendela Tindakan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Aktifkan mode dense" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Aktifkan mode sparse" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Terapkan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Apakah Anda yakin ingin menghapus record ini?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Tutup baris" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Buat" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Edit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Perluas baris" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Fokus Hari Ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Dari" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Tampilan Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Anak Gantt hanya dapat menjadi field atau templat, memiliki %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt harus memiliki attribute 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt harus memiliki attribute 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt harus memiliki attribute 'dependency_inverted_field' setelah " +"'dependency_field' ditentukan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Tanggal mulai Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Tanggal berhenti Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Tampilan Gantt hanya dapat memiliki satu tag templat" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Tidak dapat menjadwalkan di masa lalu" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Field tidak mencukupi untuk Tampilan Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Atribut tidak valid (%(invalid_attributes)s) di tampilan gantt. Atribut " +"harus dalam (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' tidak valid di gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "default_scale '%s' invalid di Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode '%s' tidak valid d gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nama" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Baru" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Terbuka" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Rencana" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Dijadwalkan ulang dengan sukses." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Mulai" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Stop" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Ketergantungan tidak valid, terdapat cycle." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Tidak ada kandidat yang valid untuk direncanakan ulang" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Bulan ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Triwulan ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Minggu ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Tahun ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Hari Ini" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menu toolbar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Undefined %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Tampilan" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipe Tampilan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Anda tidak dapat menggerakkan %(record)s ke %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" +"Anda tidak dapat menjadwalkan ulang %(main_record)s ke %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "jam" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "menit" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "bulan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "kepada" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/it.po b/addons_extensions/web_gantt/i18n/it.po new file mode 100644 index 000000000..7094d07b1 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/it.po @@ -0,0 +1,365 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Marianna Ciofani, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Marianna Ciofani, 2024\n" +"Language-Team: Italian (https://app.transifex.com/odoo/teams/41243/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: it\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s:%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s non può essere programmato nel passato" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s " + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Azione visualizzazione finestra" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Attiva modalità dense" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Attiva modalità sparse" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Applica" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Eliminare veramente questo record?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Imponibile" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Contrai righe" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Crea" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Modifica" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Espandi righe" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Focus oggi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Da" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vista Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" +"Una riga figlia Gantt può essere solo un campo o un modello, tu hai %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt deve possedere un attributo \"date_start\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt deve possedere un attributo \"date_stop\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"La vista Gantt deve avere un attributo 'dependency_inverted_field' una volta" +" che il 'dependency_field' viene specificato" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Data di inizio gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Data di fine gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "La vista Gantt può contenere un solo tag templates" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Impossibile programmare in passato." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Campi non sufficienti per la vista Gantt." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Attributi non validi (%(invalid_attributes)s) nella vista gantt, devono " +"essere tra (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range non valido '%s' in gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "default_scale \"%s\" non valido in gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode \"%s\" non valida in gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nome" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nuovo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Apri" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Pianificazione" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Riprogrammazione avvenuta con successo." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Avvia" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Ferma" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Le dipendenze non sono valide, c'è un ciclo." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Non sono presenti candidati validi per la ripianificazione" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Questo mese" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Questo trimestre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Questa settimana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Questo anno" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Oggi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menu barra degli strumenti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Totale" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "%s non definiti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipo vista" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Impossibile spostare %(record)s in %(related_record)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "Impossibile riprogrammare %(main_record)s in %(other_record)s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "ore" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "mesi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "a" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/ja.po b/addons_extensions/web_gantt/i18n/ja.po new file mode 100644 index 000000000..705bb503f --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ja.po @@ -0,0 +1,362 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Junko Augias, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Junko Augias, 2024\n" +"Language-Team: Japanese (https://app.transifex.com/odoo/teams/41243/ja/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ja\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%sは過去に予定することはできません" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "アクションウィンドウビュー" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "デンスモードを有効化する" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "スパースモードを有効化する" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "適用" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "このレコードを削除してもよろしいですか?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "ベース" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "行を折りたたむ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "作成" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "編集" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "行を展開" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "今日のフォーカス" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "from" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "ガント" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "ガントビュー" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "ガントのchildはフィールドまたはテンプレートのみにできますが、%sを取得しました" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "ガントには'date_start'属性が必要です" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "ガントには'date_stop'属性が必要です" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"'dependency_field' が指定されたら、ガントは 'dependency_inverted_field' を持つ必要があります。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "ガント開始日" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "ガント停止日" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "ガントビューには、テンプレートタグを1つだけ含めることができます" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "過去に予定することはできません。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "ガントビューのフィールドが不十分です!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"ガントビューの属性 (%(invalid_attributes)s)が無効です。属性は(%(valid_attributes)s)である必要があります。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "ガントでの無効な default_range '%s' " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "ganttのdefault_scale '%s'が無効です" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "ガントでの無効な display_mode '%s' " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "名称" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "新規" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "開く" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "計画" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "正常に再スケジュールされました。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "開始" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "停止" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "依存関係が有効でなく、サイクルがあります。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "再計画に有効な候補者はいません" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "今月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "今四半期" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "今週" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "今年" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "今日" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "ツールバーメニュー" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "合計" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "未定義の%s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "ビュー" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "ビュータイプ" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr " %(record)sを %(related_record)sへ移動することはできません。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr " %(record)sを %(related_record)sへリスケジュールすることはできません。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "時間" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "分" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "か月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "から" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/ko.po b/addons_extensions/web_gantt/i18n/ko.po new file mode 100644 index 000000000..b04d76fb7 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ko.po @@ -0,0 +1,363 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Daye Jeong, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Daye Jeong, 2024\n" +"Language-Team: Korean (https://app.transifex.com/odoo/teams/41243/ko/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ko\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s시간 %(minute)s분" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s는 과거로 예약할 수 없습니다." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "작업 윈도우 보기" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "dense mode 활성화" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "sparse mode 활성화" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "적용" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "이 레코드를 삭제 하시겠습니까?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "기준액" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "행 축소" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "작성" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "편집" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "행 확장" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "오늘의 포커스" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "시작 시간" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "간트 차트" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "간트 화면" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "간트 하위 메뉴는 필드나 템플릿만 선택 가능하며, 다음 내용입니다 %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "간트에는 'date_start' 속성을 지정해야 합니다" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "간트에는 'date_stop' 속성을 지정해야 합니다" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"'dependency_field'가 지정되는 경우, 간트에서 'dependency_inverted_field' 속성을 지정해야 합니다." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "간트 시작일" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "간트 종료일" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "간트 뷰에는 서식 태그가 하나만 포함될 수 있습니다" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "지난 시점으로는 예약할 수 없습니다." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "간트 차트 화면에 대한 필드가 충분하지 않습니다!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"간트 보기에 잘못된 속성 (%(invalid_attributes)s)이 있습니다. 속성은 (%(valid_attributes)s)에 " +"위치해야 합니다." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "간트에 잘못된 default_range '%s'가 있습니다." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "간트에서 default_scale '%s' 가 유효하지 않습니다" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "간트에 잘못된 display_mode '%s'가 있습니다." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "이름" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "신규" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "열기" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "계획" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "일정 변경이 성공적으로 완료되었습니다." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "시작" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "중지" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "종속성이 유효하지 않으며 주기가 있습니다." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "다시 계획할 수 있는 적격 후보자가 없습니다." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "이번 달" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "이번 분기" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "이번 주" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "올해" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "오늘" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "도구 모음 메뉴" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "총계" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "정의되지 않은 %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "화면" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "화면 유형" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "%(record)s를 %(related_record)s로 이동할 수 없습니다." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "%(main_record)s을 %(other_record)s으로 일정을 변경할 수 없습니다. " + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "시간" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "분" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "월" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "종료" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/lb.po b/addons_extensions/web_gantt/i18n/lb.po new file mode 100644 index 000000000..e484c05e4 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/lb.po @@ -0,0 +1,257 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server saas~12.5+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2019-08-26 09:38+0000\n" +"Language-Team: Luxembourgish (https://www.transifex.com/odoo/teams/41243/lb/)\n" +"Language: lb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/lt.po b/addons_extensions/web_gantt/i18n/lt.po new file mode 100644 index 000000000..81e9d1894 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/lt.po @@ -0,0 +1,267 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Audrius Palenskis , 2022 +# Rolandas , 2022 +# Edgaras Kriukonis , 2022 +# Ramunė ViaLaurea , 2022 +# Naglis Jonaitis, 2022 +# Martin Trigaux, 2022 +# Linas Versada , 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2022-09-22 05:49+0000\n" +"Last-Translator: Linas Versada , 2023\n" +"Language-Team: Lithuanian (https://app.transifex.com/odoo/teams/41243/lt/)\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Ar tikrai norite ištrinti šį įrašą?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Bazė" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "Sutraukti eilutes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Sukurti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Diena" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "Išskleisti eilutes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Ganto vaizdas" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Ganto diagrama privalo turėti pradžios ir pabaigos požymius" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "Grupavimas pagal datas nepalaikomas" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Mėnuo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Naujas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Kitas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Atidaryti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Suplanuoti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Ankstesnis" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "Šiandien" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Nežinoma %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Peržiūrėti" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Savaitė" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "Metai" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/mn.po b/addons_extensions/web_gantt/i18n/mn.po new file mode 100644 index 000000000..4fe6c100c --- /dev/null +++ b/addons_extensions/web_gantt/i18n/mn.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Bayarkhuu Bataa, 2024 +# Batmunkh Ganbat , 2024 +# Uuganbayar Batbaatar , 2024 +# Baskhuu Lodoikhuu , 2024 +# Martin Trigaux, 2024 +# hish, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: hish, 2024\n" +"Language-Team: Mongolian (https://app.transifex.com/odoo/teams/41243/mn/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: mn\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Үйлдлийн цонх харагдац" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Хэрэгжүүлэх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Суурь" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Мөрүүдийг хумих" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Үүсгэх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Засах" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Мөрүүдийг дэлгэх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Эхлэх" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Хүснэгтлэх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Хүснэгтлэн харах" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Нэр" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Шинэ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Нээх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Төлөвлөх" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Эхлэх" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Зогс" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Энэ сар" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Энэ долоо хоног" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Өнөөдөр" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Нийт дүн" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Харах" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Дэлгэцийн төрөл" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "цаг" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "минут" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "сарууд" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "дуусах" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/nb.po b/addons_extensions/web_gantt/i18n/nb.po new file mode 100644 index 000000000..4aeb0c691 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/nb.po @@ -0,0 +1,262 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Marius Stedjan , 2022 +# Martin Trigaux, 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2022-09-22 05:49+0000\n" +"Last-Translator: Martin Trigaux, 2023\n" +"Language-Team: Norwegian Bokmål (https://app.transifex.com/odoo/teams/41243/nb/)\n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Opprett" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Dag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt-visning" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Måned" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Ny" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Neste" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Åpen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planlegg" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Tilbake" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "I dag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Vis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Uke" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "År" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/nl.po b/addons_extensions/web_gantt/i18n/nl.po new file mode 100644 index 000000000..932edc519 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/nl.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Erwin van der Ploeg , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Erwin van der Ploeg , 2024\n" +"Language-Team: Dutch (https://app.transifex.com/odoo/teams/41243/nl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: nl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)su%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s kan niet in het verlden plaatsvinden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%su" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Actie venster weergave" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Dense mode activeren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Sparse mode activeren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Toepassen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Ben je zeker dat je dit record wilt verwijderen?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Basis" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Rijen inklappen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Aanmaken" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Bewerken" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Rijen uitvouwen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Focus Vandaag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Van" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt weergave" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Onderliggende Gantt kan alleen een veld of sjabloon zijn, krijg %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt moet een 'date_start' kenmerk hebben" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt moet een 'date_stop' kenmerk hebben" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gant moet een 'dependency_inverted_field' kenmerk hebben zodra het " +"'dependency_field' is gespecifieerd" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Gantt-startdatum" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Gantt-einddatum" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "De Gantt-weergave kan slechts één sjabloon-label bevatten" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Je kan niet in het verleden plannen." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Niet genoeg velden voor Gantt weergave!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Ongeldige kenmerken (%(invalid_attributes)s) in Gantt-weergave. Kenmerken " +"moeten in (%(valid_attributes)s) zijn" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "Ongeldige default_range '%s' in gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Ongeldige default_scale '%s' in gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "Ongeldige display_mode '%s' in gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Naam" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nieuw" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Openen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Met succes één opnieuw gepland." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Start" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Stop" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "De afhankelijkheden zijn niet geldig, er is een cyclus." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Er zijn geen geldige kandidaten om te herplannen" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Deze maand" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Dit kwartaal" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Deze week" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Dit jaar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Vandaag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Werkbalkmenu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Totaal" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Niet gedefinieerd %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Bekijk" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Soort weergave" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Je kunt %(record)s niet naar %(related_record)s verplaatsen." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "Je kunt %(main_record)s niet op %(other_record)s herplannen." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "uren" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuten" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "maanden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "aan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/pl.po b/addons_extensions/web_gantt/i18n/pl.po new file mode 100644 index 000000000..a44efd921 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/pl.po @@ -0,0 +1,361 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Polish (https://app.transifex.com/odoo/teams/41243/pl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: pl\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Widok okna akcji" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Zastosuj" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Czy na pewno chcesz usunąć ten rekord?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Baza" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Zwiń wiersze" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Utwórz" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Edytuj" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Rozwiń wiersze" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Od" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Wykres Gantta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Widok Gantta" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Dziecko Gantt może być tylko polem lub szablonem, mam %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt musi mieć atrybut \"date_start\"." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt musi mieć atrybut \"date_stop\"." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt musi mieć atrybut \"dependency_inverted_field\" po określeniu " +"\"dependency_field\"." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Widok Gantta może zawierać tylko jeden tag szablonu" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Niewystarczająca liczba pól dla widoku Gantta!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Nieprawidłowy default_scale '%s' w gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nazwa" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nowe" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Otwarta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Uruchom" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Zatrzymaj" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Ten miesiąc" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Ten tydzień" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Ten rok" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Na dzisiaj" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Suma" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Niezdefiniowany %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Widok" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Typ widoku" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "godziny" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minut" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "miesiące" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "do" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/pt.po b/addons_extensions/web_gantt/i18n/pt.po new file mode 100644 index 000000000..2ca5d3a15 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/pt.po @@ -0,0 +1,263 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Martin Trigaux, 2022 +# Nuno Silva , 2022 +# Manuela Silva , 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-16 16:03+0000\n" +"PO-Revision-Date: 2022-09-22 05:49+0000\n" +"Last-Translator: Manuela Silva , 2023\n" +"Language-Team: Portuguese (https://app.transifex.com/odoo/teams/41243/pt/)\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "Colapsar linhas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Criar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "Dia" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "Expandir linhas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vista de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Grouping by date is not supported" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Mês" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Novo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Seguinte" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Aberto" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plano" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_cell_buttons.xml:0 +msgid "Plan existing" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Anterior" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "Hoje" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Ver" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Semana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "Ano" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/pt_BR.po b/addons_extensions/web_gantt/i18n/pt_BR.po new file mode 100644 index 000000000..b4d8861e5 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/pt_BR.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Maitê Dietze, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Maitê Dietze, 2024\n" +"Language-Team: Portuguese (Brazil) (https://app.transifex.com/odoo/teams/41243/pt_BR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s não pode ser agendado no passado" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Exibição da janela de ação" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Ativar o modo denso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Ativar o modo esparso" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Aplicar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Você tem certeza de que deseja excluir este registro?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Base" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Recolher linhas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Criar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Editar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Expandir linhas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Foco em Hoje" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "De" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Visualização de Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantts secundários só podem ser campos ou modelos, há %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt deve ter um atributo \"date_start\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt deve ter um atributo \"date_stop\"" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt deve ter um atributo \"'dependency_inverted_field\" uma vez que " +"\"dependency_field\" está especificado" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Data de início do Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Data de término do Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "A visualização de Gantt deve conter somente um marcador do modelo" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "É impossível fazer agendamentos no passado." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Campos insuficientes para a visualização de Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Atributos inválidos (%(invalid_attributes)s) na visualização de Gantt. Os " +"atributos devem estar em (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "default_range '%s' inválido no Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Default_scale \"%s\" inválida em Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "Display_mode '%s' inválido em gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nome" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Novo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Aberto" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plano" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Reagendamento feito com sucesso." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Iniciar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Parar" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "As dependências não são válidas; há um ciclo." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "Não há candidatos válidos para replanejar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Este mês" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Este trimestre" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Esta semana" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Este ano" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Hoje" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menu da barra de ferramentas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Indefinido %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Visualização" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipo de visualização" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Você não pode se mover %(record)s para %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "Não é possível reagendar %(main_record)s para %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "horas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minutos" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "meses" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "até" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/ro.po b/addons_extensions/web_gantt/i18n/ro.po new file mode 100644 index 000000000..9deaa1698 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ro.po @@ -0,0 +1,361 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Lyall Kindmurr, 2024 +# Foldi Robert , 2024 +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Romanian (https://app.transifex.com/odoo/teams/41243/ro/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ro\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Acțiune Vizualizare Fereastră" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Aplică" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Sigur doriți să ștergeți această înregistrare?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Baza" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Reduceți rândurile" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Creează" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Editare" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Extindere Rânduri" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "De la" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Vizualizare Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Nume" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Nou" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Afișare" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Start" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Stop" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Luna aceasta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Săpt. curentă" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Anul Acesta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Astăzi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Total" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Nedefinit %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Afișare" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Tip vizualizare" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "ore" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minute" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "luni" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "la" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/ru.po b/addons_extensions/web_gantt/i18n/ru.po new file mode 100644 index 000000000..a23228073 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/ru.po @@ -0,0 +1,258 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-01-08 07:03+0000\n" +"PO-Revision-Date: 2024-01-30 15:14+0400\n" +"Last-Translator: \n" +"Language-Team: Russian (https://app.transifex.com/odoo/teams/41243/ru/)\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Вы уверены, что хотите удалить эту запись?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "База" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Collapse rows" +msgstr "Свернуть ряды" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Создать" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Day" +msgstr "День" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Редактировать" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Expand rows" +msgstr "Расширить ряды" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_view.js:0 +msgid "Gantt" +msgstr "Гантт" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Вид Гантт" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Дочерний элемент Ганта может быть только полем или шаблоном, получено %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Гант должен иметь атрибут 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Гант должен иметь атрибут 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified" +msgstr "Gantt должен иметь атрибут 'dependency_inverted_field' после указания 'dependency_field'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Представление Ганта может содержать только один тег шаблона" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Недостаточно полей для представления Ганта!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid attributes (%s) in gantt view. Attributes must be in (%s)" +msgstr "Недопустимые атрибуты (%s) в представлении Ганта. Атрибуты должны быть в (%s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Недопустимая шкала по умолчанию '%s' в гигантской схеме" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Month" +msgstr "Месяц" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Имя" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Новый" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Next" +msgstr "Следующий" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Открыть" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "План" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Previous" +msgstr "Предыдущий" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Records that are in the past cannot be automatically rescheduled. They should be manually rescheduled instead." +msgstr "Записи, которые находятся в прошлом, не могут быть автоматически перенесены. Их следует переносить вручную." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Начало" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Стоп" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.xml:0 +msgid "Today" +msgstr "Сегодня" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Всего" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Неопределено %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Просмотр" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Week" +msgstr "Неделя" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Year" +msgstr "Год" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %s towards %s." +msgstr "Вы не можете перенести %s на %s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule tasks that do not follow a direct dependency path. Only the first task has been automatically rescheduled." +msgstr "Вы не можете перенести в график задачи, которые не следуют прямому пути зависимости. Автоматически переносится только первая задача." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "часов" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "минут" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "месяцев" diff --git a/addons_extensions/web_gantt/i18n/sl.po b/addons_extensions/web_gantt/i18n/sl.po new file mode 100644 index 000000000..5c6355e87 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/sl.po @@ -0,0 +1,359 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Slovenian (https://app.transifex.com/odoo/teams/41243/sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: sl\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Pogled okna za ukrep" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Uporabi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Ste prepričani, da želite izbrisati ta zapis?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Osnova" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Strni vrstice" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Ustvari" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Uredi" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Razširi vrstice" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Od" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt diagram" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Naziv" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Novo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Odprto" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Prični" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Ustavi" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Ta mesec" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Ta teden" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Danes" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Skupaj" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Prikaz" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Vrsta prikaza" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "ure" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minute" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "meseci" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "do" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/sv.po b/addons_extensions/web_gantt/i18n/sv.po new file mode 100644 index 000000000..26971e51e --- /dev/null +++ b/addons_extensions/web_gantt/i18n/sv.po @@ -0,0 +1,367 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Mikael Åkerberg , 2024 +# 03992e16f8df6e39b9d1cc0ff635887e, 2024 +# Martin Wilderoth , 2024 +# Simon S, 2024 +# Anders Wallenquist , 2024 +# Chrille Hedberg , 2024 +# Martin Trigaux, 2024 +# Kristoffer Grundström , 2024 +# Jakob Krabbe , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Jakob Krabbe , 2024\n" +"Language-Team: Swedish (https://app.transifex.com/odoo/teams/41243/sv/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: sv\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Vy för åtgärdsfönster" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Verkställ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Bas" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Skapa" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Redigera" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Från" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Ganttvy" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Namn" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Ny" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Öppna" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Plan" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Start" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Stoppa" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Denna månad" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Denna vecka" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Detta år" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Idag" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Totalt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Visa" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Typ av vy" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "timmar" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "minuter" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "månader" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "till" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/th.po b/addons_extensions/web_gantt/i18n/th.po new file mode 100644 index 000000000..14bade5c6 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/th.po @@ -0,0 +1,363 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Wil Odoo, 2024\n" +"Language-Team: Thai (https://app.transifex.com/odoo/teams/41243/th/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: th\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s ชั่วโมง %(minute)s นาที" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s ไม่สามารถกำหนดเวลาในอดีตได้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s ชั่วโมง" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "มุมมองหน้าต่างการดำเนินการ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "นำไปใช้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "คุณแน่ใจหรือว่าต้องการลบบันทึกนี้?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "ฐาน" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "ย่อแถว" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "สร้าง" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "แก้ไข" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "ขยายแถว" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "จาก" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "แกนต์" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "มุมมองแบบแกนต์" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "แกนต์ย่อยได้เฉพาะฟิลด์หรือเทมเพลตเท่านั้น มี %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "แกนต์ต้องมี 'date_start' แอตทริบิวต์ " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "แกนต์ต้องมี \"date_stop\" แอตทริบิวต์ " + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt ต้องมีแอตทริบิวต์ 'dependency_inverted_field' เมื่อระบุ " +"'dependency_field' แล้ว" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "มุมมองแกนต์สามารถมีแท็กเทมเพลตได้เพียงแท็กเดียว" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "ไม่สามารถกำหนดเวลาในอดีตได้" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "ฟิลด์ไม่เพียงพอสำหรับมุมมองแกนต์!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"แอตทริบิวต์ไม่ถูกต้อง (%(invalid_attributes)s) ในมุมมองแกนต์ " +"แอตทริบิวต์ต้องอยู่ใน (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Invalid default_scale '%s' ในแกนต์" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode '%s' ไม่ถูกต้องในแกนต์" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "ชื่อ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "ใหม่" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "เปิด" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "แผน" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "เริ่ม" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "หยุด" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "การขึ้นต่อกันไม่ถูกต้อง มีวงจรอยู่" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "ไม่มีผู้สมัครที่ถูกต้องที่จะวางแผนใหม่" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "เดือนนี้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "สัปดาห์นี้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "ปีนี้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "วันนี้" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "รวม" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "ไม่กำหนด %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "ดู" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "ประเภทมุมมอง" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "คุณไม่สามารถย้าย %(record)s ไปยัง %( related_record)s ได้" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "คุณไม่สามารถจัดกำหนดการใหม่ %(main_record)s ไปยัง %(other_record)s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "ชั่วโมง" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "นาที" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "เดือน" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "ถึง" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/tr.po b/addons_extensions/web_gantt/i18n/tr.po new file mode 100644 index 000000000..277289563 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/tr.po @@ -0,0 +1,372 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Ahmet Altinisik , 2024 +# Ozlem Cikrikci , 2024 +# Tugay Hatıl , 2024 +# Gökhan Erdoğdu , 2024 +# Levent Karakaş , 2024 +# abc Def , 2024 +# Murat Kaplan , 2024 +# Ediz Duman , 2024 +# Ertuğrul Güreş , 2024 +# Halil, 2024 +# Murat Durmuş , 2024 +# Martin Trigaux, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Martin Trigaux, 2024\n" +"Language-Team: Turkish (https://app.transifex.com/odoo/teams/41243/tr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: tr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Pencere Aksiyon Görünümü" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Uygula" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Bu kaydı silmek istediğinizden emin misiniz?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Temel" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Satırları daralt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Oluştur" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Düzenle" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Satırları genişlet" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Başlama" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Gantt Görünümü" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Gantt alt öğesi yalnızca alan veya şablon olabilir, %svar" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt'ın bir 'date_start' özelliği olmalıdır" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt'ın bir 'date_stop' özelliği olmalıdır" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"\"dependency_field\" belirtildikten sonra Gantt'ın " +"\"dependency_inverted_field\" özniteliğine sahip olması gerekir" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Gantt görünümü yalnızca bir şablon etiketi içerebilir" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Gantt görünümü için yetersiz alanlar!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Gantt'ta geçersiz default_scale '%s'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Adı" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Yeni" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Açık" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Planla" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Başla" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Durdur" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Bu Ay" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Bu Hafta" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Bu Yıl" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Bugün" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Toplam" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Tanımsız %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Görüntüle" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Görünüm Türü" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "saat" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "dakika" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "ay" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "den" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/uk.po b/addons_extensions/web_gantt/i18n/uk.po new file mode 100644 index 000000000..b97b36123 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/uk.po @@ -0,0 +1,363 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Alina Lisnenko , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Alina Lisnenko , 2024\n" +"Language-Team: Ukrainian (https://app.transifex.com/odoo/teams/41243/uk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: uk\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sгод%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sгод" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Перегляд вікна дії" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Застосувати" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Ви впевнені, що хочете видалити цей запис?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "База" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Згорнути рядки" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Створити" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Редагувати" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Розгорнути рядки" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Від" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Діаграма Ґанта" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Перегляд діаграми Ґанта" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" +"Дочірня діаграма Ганта може бути лише полем або шаблоном, отримайте %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Діаграма Ганта повинна мати атрибут 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Діаграма Ганта повинна мати атрибут 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Гант повинен мати атрибут 'dependency_inverted_field', коли вказано " +"'dependency_field'" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Діаграма Ганта може містити лише один тег шаблону" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Недостатньо полів для перегляду діаграми Ганта!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Недійсне default_scale '%s' у діаграмі Ганта" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Назва" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Новий" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Відкрито" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "План" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Початок" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Зупинити" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Цього місяця" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Цього тижня" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Цього року" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Сьогодні" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Разом" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Невизначений %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Перегляд" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Тип перегляду" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "годин" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "хвилин" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "місяців" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "до" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/vi.po b/addons_extensions/web_gantt/i18n/vi.po new file mode 100644 index 000000000..86501add3 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/vi.po @@ -0,0 +1,364 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Thi Huong Nguyen, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Thi Huong Nguyen, 2024\n" +"Language-Team: Vietnamese (https://app.transifex.com/odoo/teams/41243/vi/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: vi\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)sh%(minute)s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s không thể được lên lịch trong quá khứ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%sh" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "Chế độ xem cửa sổ tác vụ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "Kích hoạt dense mode" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "Kích hoạt sparse mode" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "Áp dụng" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "Bạn có chắc muốn xóa bảng ghi này?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "Cơ sở" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "Thu gọn hàng" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "Tạo" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "Chỉnh sửa" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "Mở rộng hàng" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "Tiêu điểm hôm nay" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "Từ" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "Gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "Biểu đồ Gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "Phần phụ của Gantt chỉ có thể là trường hoặc mẫu, nhưng đây là %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "Gantt cần có một thuột tính 'date_start'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "Gantt cần có một thuột tính 'date_stop'" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" +"Gantt phải có thuộc tính 'dependency_inverted_field' sau khi xác định " +"'dependency_field'" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "Ngày bắt đầu gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "Ngày ngừng gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "Chế độ xem Gantt chỉ có thể chứa một thẻ mẫu" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "Không thể lên lịch trong quá khứ" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "Không đủ trường cho Chế độ xem Gantt!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" +"Thuộc tính không hợp lệ (%(invalid_attributes)s) trong chế độ xem gantt. Các" +" thuộc tính phải có dạng (%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "Default_range '%s' không hợp lệ trong gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "Default_scale không hợp hệ '%s' trong gantt" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "display_mode không hợp hệ '%s' trong gantt" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "Tên" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "Mới" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "Mở" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "Kế hoạch" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "Đã lên lịch lại thành công." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "Bắt đầu" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "Ngừng" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "Phần phụ thuộc không hợp lệ, có một chu kỳ." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "There are no valid candidates to re-plan" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "Tháng này" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "Quý này" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "Tuần này" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "Năm nay" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "Hôm nay" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "Menu thanh công cụ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "Tổng" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "Không xác định %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "Chế độ xem" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "Dạng hiển thị" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "Bạn không thể chuyển %(record)s đến %(related_record)s." + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "Bạn không thể lên lịch lại %(main_record)s sang %(other_record)s." + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "giờ" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "phút" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "tháng" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "đến" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/web_gantt.pot b/addons_extensions/web_gantt/i18n/web_gantt.pot new file mode 100644 index 000000000..10bb1629c --- /dev/null +++ b/addons_extensions/web_gantt/i18n/web_gantt.pot @@ -0,0 +1,355 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:29+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "" diff --git a/addons_extensions/web_gantt/i18n/zh_CN.po b/addons_extensions/web_gantt/i18n/zh_CN.po new file mode 100644 index 000000000..7fc41f214 --- /dev/null +++ b/addons_extensions/web_gantt/i18n/zh_CN.po @@ -0,0 +1,360 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Odoo哥 , 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Odoo哥 , 2024\n" +"Language-Team: Chinese (China) (https://app.transifex.com/odoo/teams/41243/zh_CN/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s小时%(minute)s分钟" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s 无法排期至过往日期" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s小时" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "动作窗口视图" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "激活密集模式" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "激活稀疏模式" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "应用" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "确定要删除此记录吗?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "基数" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "折叠行" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "创建" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "编辑" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "展开行" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "聚焦到今天" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "来自" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "甘特图" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "甘特视图" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "甘特儿只能是字段或模板,转到%s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "甘特图必须有一个'date_start'属性" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "甘特图必须有一个'date_stop'属性" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "一旦指定了 \"依赖关系_字段\",甘特图就必须具有 \"依赖关系_反转字段 \"属性" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "甘特图开始日期" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "甘特图结束日期" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "甘特图视图只能包含一个模板标签" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "无法排期到已往的日期。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "甘特图视图的字段不足!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "甘特图视图中的属性(%(invalid_attributes)s)无效,属性必须在(%(valid_attributes)s)之中。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "甘特图中的default_range'%s'无效" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "甘特图中的default_scale'%s无效" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "甘特图中的display_mode'%s'无效" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "名称" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "新建" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "打开" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "安排" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "重新安排成功完成。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "开始" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "停止" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "依赖项目无效:存在一个循环。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "没有有效的候选人来重新规划" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "本月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "本季度" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "本周" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "今年" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "今天" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "工具栏菜单" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "总计" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "未定义的 %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "视图" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "视图类型" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "您不可移动%(record)s至%(related_record)s。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "您不可重新排期%(main_record)s至%(other_record)s。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "小时" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "分钟" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "到" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/i18n/zh_TW.po b/addons_extensions/web_gantt/i18n/zh_TW.po new file mode 100644 index 000000000..43f40a4cd --- /dev/null +++ b/addons_extensions/web_gantt/i18n/zh_TW.po @@ -0,0 +1,360 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_gantt +# +# Translators: +# Wil Odoo, 2024 +# Tony Ng, 2024 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-25 09:29+0000\n" +"PO-Revision-Date: 2024-09-25 09:44+0000\n" +"Last-Translator: Tony Ng, 2024\n" +"Language-Team: Chinese (Taiwan) (https://app.transifex.com/odoo/teams/41243/zh_TW/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: zh_TW\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%(hour)sh%(minute)s" +msgstr "%(hour)s 小時 %(minute)s 分鐘" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "%s cannot be scheduled in the past" +msgstr "%s 不可排期至過往日期" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "%sh" +msgstr "%s 小時" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_ir_actions_act_window_view +msgid "Action Window View" +msgstr "動作窗檢視" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate dense mode" +msgstr "啟動緊密模式" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Activate sparse mode" +msgstr "啟動稀疏模式" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Apply" +msgstr "套用" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Are you sure to delete this record?" +msgstr "確定刪除此記錄?" + +#. module: web_gantt +#: model:ir.model,name:web_gantt.model_base +msgid "Base" +msgstr "計稅基數" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Collapse rows" +msgstr "摺疊列" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Create" +msgstr "建立" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Edit" +msgstr "編輯" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Expand rows" +msgstr "展開列" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Focus Today" +msgstr "聚焦至今天" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "From" +msgstr "由" + +#. module: web_gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_actions_act_window_view__view_mode__gantt +#: model:ir.model.fields.selection,name:web_gantt.selection__ir_ui_view__type__gantt +msgid "Gantt" +msgstr "甘特圖" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Gantt View" +msgstr "甘特圖檢視" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt child can only be field or template, got %s" +msgstr "甘特圖子項只可以是欄位或範本,但收到 %s" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_start' attribute" +msgstr "甘特圖必須有一個 date_start 屬性" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt must have a 'date_stop' attribute" +msgstr "甘特圖必須有一個 date_stop 屬性" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Gantt must have a 'dependency_inverted_field' attribute once the " +"'dependency_field' is specified" +msgstr "甘特圖若有指定 dependency_field,就必須有 dependency_inverted_field 屬性" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt start date" +msgstr "甘特圖開始日期" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.js:0 +msgid "Gantt stop date" +msgstr "甘特圖結束日期" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Gantt view can contain only one templates tag" +msgstr "甘特圖只可包含一個範本標籤" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Impossible to schedule in the past." +msgstr "無法排期至過往日期。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Insufficient fields for Gantt View!" +msgstr "欄位數目不足以供甘特圖使用!" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "" +"Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must " +"be in (%(valid_attributes)s)" +msgstr "甘特圖檢視畫面中的屬性(%(invalid_attributes)s)無效。屬性必須在(%(valid_attributes)s)" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_range '%s' in gantt" +msgstr "甘特圖的 default_range '%s' 無效" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid default_scale '%s' in gantt" +msgstr "甘特圖的 default_scale '%s' 無效" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/ir_ui_view.py:0 +msgid "Invalid display_mode '%s' in gantt" +msgstr "甘特圖檢視模式中的顯示模式 display_mode 無效:%s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Name" +msgstr "名稱" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.xml:0 +msgid "New" +msgstr "新增" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_controller.js:0 +msgid "Open" +msgstr "開啟" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Plan" +msgstr "計劃" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "Reschedule done successfully." +msgstr "已成功改期。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Start" +msgstr "開始" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_popover.xml:0 +msgid "Stop" +msgstr "停止" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "The dependencies are not valid, there is a cycle." +msgstr "依賴項目無效:存在一個循環。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "There are no valid candidates to re-plan" +msgstr "沒有有效的候選人可以重新規劃" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This month" +msgstr "本月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This quarter" +msgstr "本季度" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This week" +msgstr "本周" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "This year" +msgstr "本年度" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "Today" +msgstr "今天" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "Toolbar menu" +msgstr "工具列選單" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +msgid "Total" +msgstr "總計" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_model.js:0 +msgid "Undefined %s" +msgstr "未定義 %s" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer.js:0 +#: model:ir.model,name:web_gantt.model_ir_ui_view +msgid "View" +msgstr "檢視" + +#. module: web_gantt +#: model:ir.model.fields,field_description:web_gantt.field_ir_actions_act_window_view__view_mode +#: model:ir.model.fields,field_description:web_gantt.field_ir_ui_view__type +msgid "View Type" +msgstr "檢視類型" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot move %(record)s towards %(related_record)s." +msgstr "你不可移動 %(record)s 至 %(related_record)s。" + +#. module: web_gantt +#. odoo-python +#: code:addons/web_gantt/models/models.py:0 +msgid "You cannot reschedule %(main_record)s towards %(other_record)s." +msgstr "你不可重新排期 %(main_record)s 至 %(other_record)s。" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "hours" +msgstr "小時" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "minutes" +msgstr "分鐘" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_arch_parser.js:0 +msgid "months" +msgstr "月" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_renderer_controls.xml:0 +msgid "to" +msgstr "到" + +#. module: web_gantt +#. odoo-javascript +#: code:addons/web_gantt/static/src/gantt_row_progress_bar.xml:0 +msgid "{{ props.progressBar.warning }}" +msgstr "{{ props.progressBar.warning }}" diff --git a/addons_extensions/web_gantt/models/__init__.py b/addons_extensions/web_gantt/models/__init__.py new file mode 100644 index 000000000..9d9e19686 --- /dev/null +++ b/addons_extensions/web_gantt/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models +from . import ir_ui_view +from . import ir_actions diff --git a/addons_extensions/web_gantt/models/ir_actions.py b/addons_extensions/web_gantt/models/ir_actions.py new file mode 100644 index 000000000..c75cb0524 --- /dev/null +++ b/addons_extensions/web_gantt/models/ir_actions.py @@ -0,0 +1,9 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class ActWindowView(models.Model): + _inherit = 'ir.actions.act_window.view' + + view_mode = fields.Selection(selection_add=[('gantt', 'Gantt')], ondelete={'gantt': 'cascade'}) diff --git a/addons_extensions/web_gantt/models/ir_ui_view.py b/addons_extensions/web_gantt/models/ir_ui_view.py new file mode 100644 index 000000000..f2ad5bd00 --- /dev/null +++ b/addons_extensions/web_gantt/models/ir_ui_view.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, _ +from odoo.tools import format_list +from lxml import etree + +GANTT_VALID_ATTRIBUTES = set([ + '__validate__', # ir.ui.view implementation detail + 'date_start', + 'date_stop', + 'default_scale', + 'default_range', + 'class', + 'js_class', + 'form_view_id', + 'progress', + 'consolidation', + 'consolidation_max', + 'consolidation_exclude', + 'string', + 'create', + 'on_create', + 'cell_create', + 'edit', + 'delete', + 'plan', + 'default_group_by', + 'dynamic_range', + 'display_mode', + 'display_unavailability', + 'disable_drag_drop', + 'total_row', + 'collapse_first_level', + 'offset', + 'scales', + 'thumbnails', + 'precision', + 'color', + 'decoration-secondary', + 'decoration-success', + 'decoration-info', + 'decoration-warning', + 'decoration-danger', + 'sample', + 'progress_bar', + 'dependency_field', + 'dependency_inverted_field', + 'pill_label', + 'groups_limit' +]) + +class View(models.Model): + _inherit = 'ir.ui.view' + + type = fields.Selection(selection_add=[('gantt', 'Gantt')]) + + def _validate_tag_gantt(self, node, name_manager, node_info): + if not node_info['validate']: + return + + templates_count = 0 + for child in node.iterchildren(tag=etree.Element): + if child.tag == 'templates': + if not templates_count: + templates_count += 1 + else: + msg = _('Gantt view can contain only one templates tag') + self._raise_view_error(msg, child) + elif child.tag != 'field': + msg = _('Gantt child can only be field or template, got %s', child.tag) + self._raise_view_error(msg, child) + + default_scale = node.get('default_scale') + if default_scale: + if default_scale not in ('day', 'week', 'week_2', 'month', 'month_3', 'year'): + self._raise_view_error(_("Invalid default_scale '%s' in gantt", default_scale), node) + default_range = node.get('default_range') + if default_range: + if default_range not in ('day', 'week', 'month', 'quarter', 'year'): + self._raise_view_error(_("Invalid default_range '%s' in gantt", default_range), node) + display_mode = node.get('display_mode') + if display_mode: + if display_mode not in ('dense', 'sparse'): + self._raise_view_error(_("Invalid display_mode '%s' in gantt", display_mode), node) + attrs = set(node.attrib) + if 'date_start' not in attrs: + msg = _("Gantt must have a 'date_start' attribute") + self._raise_view_error(msg, node) + + if 'date_stop' not in attrs: + msg = _("Gantt must have a 'date_stop' attribute") + self._raise_view_error(msg, node) + + if 'dependency_field' in attrs and 'dependency_inverted_field' not in attrs: + msg = _("Gantt must have a 'dependency_inverted_field' attribute once the 'dependency_field' is specified") + self._raise_view_error(msg, node) + + remaining = attrs - GANTT_VALID_ATTRIBUTES + if remaining: + msg = _( + "Invalid attributes (%(invalid_attributes)s) in gantt view. Attributes must be in (%(valid_attributes)s)", + invalid_attributes=format_list(self.env, remaining), + valid_attributes=format_list(self.env, GANTT_VALID_ATTRIBUTES), + ) + self._raise_view_error(msg, node) + + def _get_view_fields(self, view_type, models): + if view_type == 'gantt': + models[self._name] = list(self._fields.keys()) + return models + return super()._get_view_fields(view_type, models) + + def _get_view_info(self): + return {'gantt': {'icon': 'fa fa-tasks'}} | super()._get_view_info() + + def _is_qweb_based_view(self, view_type): + return view_type == 'gantt' or super()._is_qweb_based_view(view_type) diff --git a/addons_extensions/web_gantt/models/models.py b/addons_extensions/web_gantt/models/models.py new file mode 100644 index 000000000..966447ced --- /dev/null +++ b/addons_extensions/web_gantt/models/models.py @@ -0,0 +1,780 @@ +# -*- coding: utf-8 -*- + +from collections import defaultdict +from datetime import datetime, timezone, timedelta +from lxml.builder import E + +from odoo import api, fields, models +from odoo.exceptions import UserError +from odoo.tools import _, unique, OrderedSet + + +class Base(models.AbstractModel): + _inherit = 'base' + + _start_name = 'date_start' # start field to use for default gantt view + _stop_name = 'date_stop' # stop field to use for default gantt view + + # action_gantt_reschedule utils + _WEB_GANTT_RESCHEDULE_FORWARD = 'forward' + _WEB_GANTT_RESCHEDULE_BACKWARD = 'backward' + _WEB_GANTT_LOOP_ERROR = 'loop_error' + _WEB_GANTT_NO_POSSIBLE_ACTION_ERROR = 'no_possible_action_error' + + @api.model + def _get_default_gantt_view(self): + """ Generates a default gantt view by trying to infer + time-based fields from a number of pre-set attribute names + + :returns: a gantt view + :rtype: etree._Element + """ + view = E.gantt(string=self._description) + + gantt_field_names = { + '_start_name': ['date_start', 'start_date', 'x_date_start', 'x_start_date'], + '_stop_name': ['date_stop', 'stop_date', 'date_end', 'end_date', 'x_date_stop', 'x_stop_date', 'x_date_end', 'x_end_date'], + } + for name in gantt_field_names.keys(): + if getattr(self, name) not in self._fields: + for dt in gantt_field_names[name]: + if dt in self._fields: + setattr(self, name, dt) + break + else: + raise UserError(_("Insufficient fields for Gantt View!")) + view.set('date_start', self._start_name) + view.set('date_stop', self._stop_name) + + return view + + @api.model + def get_gantt_data(self, domain, groupby, read_specification, limit=None, offset=0, unavailability_fields=None, progress_bar_fields=None, start_date=None, stop_date=None, scale=None): + """ + Returns the result of a read_group (and optionally search for and read records inside each + group), and the total number of groups matching the search domain. + + :param domain: search domain + :param groupby: list of field to group on (see ``groupby``` param of ``read_group``) + :param read_specification: web_read specification to read records within the groups + :param limit: see ``limit`` param of ``read_group`` + :param offset: see ``offset`` param of ``read_group`` + :param boolean unavailability_fields + :param string start_date: start datetime in utc, e.g. "2024-06-22 23:00:00" + :param string stop_date: stop datetime in utc + :param string scale: among "day", "week", "month" and "year" + :return: { + 'groups': [ + { + '': , + ..., + '__record_ids': [] + } + ], + 'records': [] + 'length': total number of groups + 'unavailabilities': { + '': , + ... + } + 'progress_bars': { + '': , + ... + } + } + """ + # TODO: group_expand doesn't currently respect the limit/offset + lazy = not limit and not offset and len(groupby) == 1 + # Because there is no limit by group, we can fetch record_ids as aggregate + final_result = self.web_read_group( + domain, ['__record_ids:array_agg(id)'], groupby, + limit=limit, offset=offset, lazy=lazy, + ) + + all_record_ids = tuple(unique( + record_id + for one_group in final_result['groups'] + for record_id in one_group['__record_ids'] + )) + + # Do search_fetch to order records (model order can be no-trivial) + all_records = self.with_context(active_test=False).search_fetch([('id', 'in', all_record_ids)], read_specification.keys()) + final_result['records'] = all_records.with_env(self.env).web_read(read_specification) + + if unavailability_fields is None: + unavailability_fields = [] + if progress_bar_fields is None: + progress_bar_fields = [] + + ordered_set_ids = OrderedSet(all_records._ids) + res_ids_for_unavailabilities = defaultdict(set) + res_ids_for_progress_bars = defaultdict(set) + for group in final_result['groups']: + for field in unavailability_fields: + res_id = group[field][0] if group[field] else False + if res_id: + res_ids_for_unavailabilities[field].add(res_id) + for field in progress_bar_fields: + res_id = group[field][0] if group[field] else False + if res_id: + res_ids_for_progress_bars[field].add(res_id) + # Reorder __record_ids + group['__record_ids'] = list(ordered_set_ids & OrderedSet(group['__record_ids'])) + # We don't need these in the gantt view + del group['__domain'] + del group[f'{groupby[0]}_count' if lazy else '__count'] + group.pop('__fold', None) + + if unavailability_fields or progress_bar_fields: + start, stop = fields.Datetime.from_string(start_date), fields.Datetime.from_string(stop_date) + + unavailabilities = {} + for field in unavailability_fields: + unavailabilities[field] = self._gantt_unavailability(field, list(res_ids_for_unavailabilities[field]), start, stop, scale) + final_result['unavailabilities'] = unavailabilities + + progress_bars = {} + for field in progress_bar_fields: + progress_bars[field] = self._gantt_progress_bar(field, list(res_ids_for_progress_bars[field]), start, stop) + final_result['progress_bars'] = progress_bars + + return final_result + + @api.model + def web_gantt_reschedule( + self, + direction, + master_record_id, slave_record_id, + dependency_field_name, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name + ): + """ Reschedule a record according to the provided parameters. + + :param direction: The direction of the rescheduling 'forward' or 'backward' + :param master_record_id: The record that the other one is depending on. + :param slave_record_id: The record that is depending on the other one. + :param dependency_field_name: The field name of the relation between the master and slave records. + :param dependency_inverted_field_name: The field name of the relation between the slave and the parent + records. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: dict = { + type: notification type, + message: notification message, + old_vals_per_pill_id: dict = { + pill_id: { + start_date_field_name: planned_date_begin before rescheduling + stop_date_field_name: date_deadline before rescheduling + } + } + } + """ + + if direction not in (self._WEB_GANTT_RESCHEDULE_FORWARD, self._WEB_GANTT_RESCHEDULE_BACKWARD): + raise ValueError("Invalid direction %r" % direction) + + master_record, slave_record = self.env[self._name].browse([master_record_id, slave_record_id]) + + search_domain = [(dependency_field_name, 'in', master_record.id), ('id', '=', slave_record.id)] + if not self.env[self._name].search_count(search_domain, limit=1): + raise ValueError("Record '%r' is not a parent record of '%r'" % (master_record.name, slave_record.name)) + + if not self._web_gantt_reschedule_is_relation_candidate( + master_record, slave_record, start_date_field_name, stop_date_field_name): + return { + 'type': 'warning', + 'message': _('You cannot reschedule %(main_record)s towards %(other_record)s.', + main_record=master_record.name, other_record=slave_record.name), + } + + is_master_prior_to_slave = master_record[stop_date_field_name] <= slave_record[start_date_field_name] + + # When records are in conflict, record that is moved is the other one than when there is no conflict. + # This might seem strange at first sight but has been decided during first implementation as when in conflict, + # and especially when the distance between the pills is big, the arrow is interpreted differently as it comes + # from the right to the left (instead of from the left to the right). + if is_master_prior_to_slave ^ (direction == self._WEB_GANTT_RESCHEDULE_BACKWARD): + trigger_record = master_record + related_record = slave_record + else: + trigger_record = slave_record + related_record = master_record + + if not trigger_record._web_gantt_reschedule_is_record_candidate(start_date_field_name, stop_date_field_name): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'warning', + 'message': _( + "You cannot move %(record)s towards %(related_record)s.", + record=trigger_record.name, + related_record=related_record.name, + ), + } + } + + sp = self.env.cr.savepoint() + log_messages, old_vals_per_pill_id = trigger_record._web_gantt_action_reschedule_candidates(dependency_field_name, dependency_inverted_field_name, start_date_field_name, stop_date_field_name, direction, related_record) + has_errors = bool(log_messages.get("errors")) + sp.close(rollback=has_errors) + notification_type = "success" + message = _("Reschedule done successfully.") + if has_errors or log_messages.get("warnings"): + message = self._web_gantt_get_reschedule_message(log_messages) + notification_type = "warning" if has_errors else "info" + return { + "type": notification_type, + "message": message, + "old_vals_per_pill_id": old_vals_per_pill_id, + } + + def action_rollback_scheduling(self, old_vals_per_pill_id): + for record in self: + vals = old_vals_per_pill_id.get(str(record.id), old_vals_per_pill_id.get(record.id)) + if vals: + record.write(vals) + + @api.model + def _gantt_progress_bar(self, field, res_ids, start, stop): + """ Get progress bar value per record. + + This method is meant to be overriden by each related model that want to + implement this feature on Gantt groups. The progressbar is composed + of a value and a max_value given for each groupedby field. + + Example: + field = 'foo', + res_ids = [1, 2] + start_date = 01/01/2000, end_date = 01/07/2000, + self = base() + + Result: + { + 1: {'value': 50, 'max_value': 100}, + 2: {'value': 25, 'max_value': 200}, + } + + :param string field: field on which there are progressbars + :param list res_ids: res_ids of related records for which we need to compute progress bar + :param string start_datetime: start date in utc + :param string end_datetime: end date in utc + :returns: dict of value and max_value per record + """ + return {} + + @api.model + def _gantt_unavailability(self, field, res_ids, start, stop, scale): + """ Get unavailabilities data for a given set of resources. + + This method is meant to be overriden by each model that want to + implement this feature on a Gantt view. A subslot is considered + unavailable (and greyed) when totally covered by an unavailability. + + Example: + * start = 01/01/2000 in datetime utc, stop = 01/07/2000 in datetime utc, scale = 'week', + field = "empployee_id", res_ids = [3, 9] + + * The expected return value of this function is a dict of the form + { + value: [{ + start: , + stop: + }, { + start: , + stop: + }, ...] + ... + } + + For example Marcel (3) is unavailable January 2 afternoon and + January 4 the whole day, the dict should look like this + { + 3: [{ + 'start': '2018-01-02 14:00:00', + 'stop': '2018-01-02 18:00:00' + }, { + 'start': '2018-01-04 08:00:00', + 'stop': '2018-01-04 18:00:00' + }] + } + Note that John (9) has no unavailabilies and thus 9 is not in + returned dict + + :param string field: name of a many2X field + :param list res_ids: list of values for field for which we want unavailabilities (a value is either False or an id) + :param datetime start: start datetime + :param datetime stop: stop datetime + :param string scale: among "day", "week", "month" and "year" + :returns: dict of unavailabilities + """ + return {} + + def _web_gantt_get_candidates(self, + dependency_field_name, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name, + related_record, move_forward_without_conflicts, + ): + result = { + 'warnings': [], + 'errors': [], + } + # first get the children of self + self_children_ids = [] + pills_to_plan_before = [] + pills_to_plan_after = [] + + if move_forward_without_conflicts: + candidates_to_exclude = {related_record.id} + else: + candidates_to_exclude = {self.id} | set(related_record[dependency_inverted_field_name].ids) + + if self._web_gantt_check_cycle_existance_and_get_rescheduling_candidates( + self_children_ids, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name, + candidates_to_exclude, + ): + result['errors'].append(self._WEB_GANTT_LOOP_ERROR) + return (result, pills_to_plan_before, pills_to_plan_after, []) + + # second, get the ancestors of related_record + related_record_ancestors_ids = [] + + if move_forward_without_conflicts: + candidates_to_exclude = {related_record.id} | set(self[dependency_field_name].ids) + else: + candidates_to_exclude = {self.id} + + if related_record._web_gantt_check_cycle_existance_and_get_rescheduling_candidates( + related_record_ancestors_ids, dependency_field_name, + start_date_field_name, stop_date_field_name, + candidates_to_exclude, + ): + result['errors'].append(self._WEB_GANTT_LOOP_ERROR) + return (result, pills_to_plan_before, pills_to_plan_after, []) + + # third, get the intersection between self children and related_record ancestors + if move_forward_without_conflicts: + all_pills_ids, pills_to_check_from_ids = self_children_ids, set(related_record_ancestors_ids) + else: + related_record_ancestors_ids.reverse() + all_pills_ids, pills_to_check_from_ids = related_record_ancestors_ids, self_children_ids + + for pill_id in all_pills_ids: + if pill_id in pills_to_check_from_ids: + (pills_to_plan_before if move_forward_without_conflicts else pills_to_plan_after).append(pill_id) + else: + (pills_to_plan_after if move_forward_without_conflicts else pills_to_plan_before).append(pill_id) + + return (result, pills_to_plan_before, pills_to_plan_after, all_pills_ids) + + def _web_gantt_get_reschedule_message_per_key(self, key, params=None): + if key == self._WEB_GANTT_LOOP_ERROR: + return _("The dependencies are not valid, there is a cycle.") + elif key == self._WEB_GANTT_NO_POSSIBLE_ACTION_ERROR: + return _("There are no valid candidates to re-plan") + elif key == "past_error": + if params: # params is the record that is in the past + return _("%s cannot be scheduled in the past", params.display_name) + else: + return _("Impossible to schedule in the past.") + else: + return "" + + def _web_gantt_get_reschedule_message(self, log_messages): + def get_messages(logs): + messages = [] + for key in logs: + message = self._web_gantt_get_reschedule_message_per_key(key, log_messages.get(key)) + if message: + messages.append(message) + return messages + + messages = [] + errors = log_messages.get("errors") + if errors: + messages = get_messages(log_messages.get("errors")) + else: + messages = get_messages(log_messages.get("warnings", [])) + return "\n".join(messages) + + def _web_gantt_action_reschedule_candidates( + self, + dependency_field_name, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name, + direction, related_record, + ): + """ Prepare the candidates according to the provided parameters and move them. + + :param dependency_field_name: The field name of the relation between the master and slave records. + :param dependency_inverted_field_name: The field name of the relation between the slave and the parent + records. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :param direction: The direction of the rescheduling 'forward' or 'backward' + :param related_record: The record that self will be moving to + :return: tuple(valid, message) (valid = True if Successful, message = None or contains the notification text if + text if valid = True or the error text if valid = False. + """ + search_forward = direction == self._WEB_GANTT_RESCHEDULE_FORWARD + # moving forward without conflicts + if search_forward and self[stop_date_field_name] <= related_record[start_date_field_name] and related_record in self[dependency_inverted_field_name]: + log_messages, pills_to_plan_before_related_record, pills_to_plan_after_related_record, all_candidates_ids = self._web_gantt_get_candidates( + dependency_field_name, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name, + related_record, True, + ) + + if log_messages.get("errors") or not pills_to_plan_before_related_record: + return log_messages, {} + + # plan self_children backward from related_record + pills_to_plan_before_related_record.reverse() + log_messages, old_vals_per_pill_id = self._web_gantt_move_candidates( + start_date_field_name, stop_date_field_name, + dependency_field_name, dependency_inverted_field_name, + False, pills_to_plan_before_related_record, + related_record[start_date_field_name], + all_candidates_ids, True, + ) + + if log_messages.get("errors") or not pills_to_plan_after_related_record: + return log_messages, {} if log_messages.get("errors") else old_vals_per_pill_id + + # plan related_record_ancestors forward from related_record + new_log_messages, second_old_vals_per_pill_id = self._web_gantt_move_candidates( + start_date_field_name, stop_date_field_name, + dependency_field_name, dependency_inverted_field_name, + True, pills_to_plan_after_related_record, + self[stop_date_field_name] + ) + + log_messages.setdefault("errors", []).extend(new_log_messages.get("errors", [])) + log_messages.setdefault("warnings", []).extend(new_log_messages.get("warnings", [])) + + return log_messages, old_vals_per_pill_id | second_old_vals_per_pill_id + # moving backward without conflicts + elif related_record[stop_date_field_name] <= self[start_date_field_name] and related_record in self[dependency_field_name]: + log_messages, pills_to_plan_before_related_record, pills_to_plan_after_related_record, all_candidates_ids = related_record._web_gantt_get_candidates( + dependency_field_name, dependency_inverted_field_name, + start_date_field_name, stop_date_field_name, + self, False, + ) + + if log_messages.get("errors") or not pills_to_plan_after_related_record: + return log_messages, {} + + # plan related_record_children_ids forward from related_record + log_messages, old_vals_per_pill_id = self._web_gantt_move_candidates( + start_date_field_name, stop_date_field_name, + dependency_field_name, dependency_inverted_field_name, + True, pills_to_plan_after_related_record, + related_record[stop_date_field_name], + all_candidates_ids, True, + ) + + if log_messages.get("errors") or not pills_to_plan_before_related_record: + return log_messages, {} if log_messages.get("errors") else old_vals_per_pill_id + + # plan self_ancestors_ids backward from related_record + pills_to_plan_before_related_record.reverse() + new_log_messages, second_old_vals_per_pill_id = self._web_gantt_move_candidates( + start_date_field_name, stop_date_field_name, + dependency_field_name, dependency_inverted_field_name, + False, pills_to_plan_before_related_record, + self[start_date_field_name] + ) + + log_messages.setdefault("errors", []).extend(new_log_messages.get("errors", [])) + log_messages.setdefault("warnings", []).extend(new_log_messages.get("warnings", [])) + + return log_messages, old_vals_per_pill_id | second_old_vals_per_pill_id + # moving forward or backward with conflicts + else: + candidates_ids = [] + dependency = dependency_inverted_field_name if search_forward else dependency_field_name + if self._web_gantt_check_cycle_existance_and_get_rescheduling_candidates( + candidates_ids, dependency, + start_date_field_name, stop_date_field_name, + ): + log_messages['errors'].append(self._WEB_GANTT_LOOP_ERROR) + return { + "errors": [self._WEB_GANTT_LOOP_ERROR], + }, {} + + if not candidates_ids: + return { + "errors": [self._WEB_GANTT_NO_POSSIBLE_ACTION_ERROR], + }, {} + + return self._web_gantt_move_candidates( + start_date_field_name, stop_date_field_name, + dependency_field_name, dependency_inverted_field_name, + search_forward, candidates_ids, + related_record[stop_date_field_name if search_forward else start_date_field_name] + ) + + def _web_gantt_is_candidate_in_conflict(self, start_date_field_name, stop_date_field_name, dependency_field_name, dependency_inverted_field_name): + return ( + any(r[start_date_field_name] and r[stop_date_field_name] and self[start_date_field_name] < r[stop_date_field_name] for r in self[dependency_field_name]) + or any(r[start_date_field_name] and r[stop_date_field_name] and self[stop_date_field_name] > r[start_date_field_name] for r in self[dependency_inverted_field_name]) + ) + + def _web_gantt_move_candidates(self, start_date_field_name, stop_date_field_name, dependency_field_name, dependency_inverted_field_name, search_forward, candidates_ids, date_candidate=None, all_candidates_ids=None, move_not_in_conflicts_candidates=False): + """ Move candidates according to the provided parameters. + + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :param dependency_field_name: The field name of the relation between the master and slave records. + :param dependency_inverted_field_name: The field name of the relation between the slave and the parent + records. + search_forward, candidates_ids, date_candidate + :param search_forward: True if the direction = 'forward' + :param candidates_ids: The candidates to reschdule + :param date_candidate: The first possible date for the rescheduling + :param all_candidates_ids: moving without conflicts is done in 2 steps, candidates_ids contains the candidates + to schedule during the step, and all_candidates_ids contains the candidates to schedule in the 2 steps + :return: dict of list containing 2 keys, errors and warnings + """ + result = { + "errors": [], + "warnings": [], + } + old_vals_per_pill_id = {} + candidates = self.browse(candidates_ids) + + for i, candidate in enumerate(candidates): + if not move_not_in_conflicts_candidates and not candidate._web_gantt_is_candidate_in_conflict(start_date_field_name, stop_date_field_name, dependency_field_name, dependency_inverted_field_name): + continue + + start_date, end_date = candidate._web_gantt_reschedule_compute_dates( + date_candidate, + search_forward, + start_date_field_name, stop_date_field_name + ) + start_date, end_date = start_date.astimezone(timezone.utc), end_date.astimezone(timezone.utc) + old_start_date, old_end_date = candidate[start_date_field_name], candidate[stop_date_field_name] + if not candidate._web_gantt_reschedule_write_new_dates( + start_date, end_date, + start_date_field_name, stop_date_field_name + ): + result["errors"].append("past_error") + result["past_error"] = candidate + return result, {} + else: + old_vals_per_pill_id[candidate.id] = { + start_date_field_name: old_start_date, + stop_date_field_name: old_end_date, + } + + if i + 1 < len(candidates): + next_candidate = candidates[i + 1] + if search_forward: + ancestors = next_candidate[dependency_field_name] + if ancestors: + date_candidate = max(ancestors.mapped(stop_date_field_name)) + else: + date_candidate = end_date + else: + children = next_candidate[dependency_inverted_field_name] + if children: + date_candidate = min(children.mapped(start_date_field_name)) + else: + date_candidate = start_date + + return result, old_vals_per_pill_id + + def _web_gantt_check_cycle_existance_and_get_rescheduling_candidates(self, + candidates_ids, dependency_field_name, + start_date_field_name, stop_date_field_name, + candidates_to_exclude=None, visited=None, ancestors=None, + ): + """ Get the current records' related records rescheduling candidates (explained in details + in case 1 and case 2 in the below example) + + This method Executes a dfs (depth first search algorithm) on the dependencies tree to: + 1- detect cycles (detect if it's not a valid tree) + 2- return the topological sorting of the candidates to reschedule + + Example: + + [4]->[6] + | + v + --->[0]->[1]->[2] [5]->[7]->[8]----------------- + | | | | + | v v | + | [3] [9]->[10] | + | | + ------------------------------------------------- + + [0]->[1]: pill 0 should be done before 1 + <: left arrow to move pill 8 backward pill 0 + >: right arrow to move pill 0 forward pill 8 + x: delete the dependence + + Case 1: + If the right arrow is clicked, pill 0 should move forward. And as 1, 2, 3 are children of 0, they should be done after it, + they should also be moved forward. + This method will return False (no cycles) and a valid order of candidates = [0, 1, 2, 3] that should be scheduled + + Case 2: + If the left arrow is clicked, pill 8 should move backward task 0, as 4, 6, 5, 7 are ancestors for 8, they should be done + before it, they should be moved backward also. 9 and 10 should not be impacted as they are not ancestors of 8. + This method will return False (no cycles) and a valid order of candidates = [5, 4, 6, 7, 8] that should be scheduled + + Example 2: + modify the previous tree by adding an edge from pill 2 to pill 0 (no more a tree after this added edge) + ----------- + | | + v | + [0]->[1]->[2] + + This method will return True because there is the cycle illustrated above + + :param candidates_ids: empty list that will contain the candidates at the end + :param dependency_field_name: The field name of the relation between the master and slave records. + :param dependency_inverted_field_name: The field name of the relation between the slave and the parent + records. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :param candidates_to_exclude: candidates to exclude + :param visited: set containing all the visited pills + :param ancestors: set containing the visited ancestors for the current pill + :return: bool, True if there is a cycle, else False. + candidates_id will also contain the pills to plan in a valid topological order + """ + if candidates_to_exclude is None: + candidates_to_exclude = [] + if visited is None: + visited = set() + if ancestors is None: + ancestors = [] + visited.add(self.id) + ancestors.append(self.id) + for child in self[dependency_field_name]: + if child.id in ancestors: + return True + + if child.id not in visited and child.id not in candidates_to_exclude and child._web_gantt_check_cycle_existance_and_get_rescheduling_candidates(candidates_ids, dependency_field_name, start_date_field_name, stop_date_field_name, candidates_to_exclude, visited, ancestors): + return True + + ancestors.pop() + if self._web_gantt_reschedule_is_record_candidate(start_date_field_name, stop_date_field_name) and self.id not in candidates_to_exclude: + candidates_ids.insert(0, self.id) + + return False + + def _web_gantt_reschedule_compute_dates( + self, date_candidate, search_forward, start_date_field_name, stop_date_field_name + ): + """ Compute start_date and end_date according to the provided arguments. + This method is meant to be overridden when we need to add constraints that have to be taken into account + in the computing of the start_date and end_date. + + :param date_candidate: The optimal date, which does not take any constraint into account. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: a tuple of (start_date, end_date) + :rtype: tuple(datetime, datetime) + """ + search_factor = (1 if search_forward else -1) + duration = search_factor * (self[stop_date_field_name] - self[start_date_field_name]) + return sorted([date_candidate, date_candidate + duration]) + + @api.model + def _web_gantt_reschedule_is_in_conflict(self, master, slave, start_date_field_name, stop_date_field_name): + """ Get whether the dependency relation between a master and a slave record is in conflict. + This check is By-passed for slave records if moving records forwards and the for + master records if moving records backwards (see _web_gantt_get_rescheduling_candidates and + _web_gantt_reschedule_is_in_conflict_or_force). In order to add condition that would not be + by-passed, rather consider _web_gantt_reschedule_is_relation_candidate. + + :param master: The master record. + :param slave: The slave record. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: True if there is a conflict, False if not. + :rtype: bool + """ + return master[stop_date_field_name] > slave[start_date_field_name] + + @api.model + def _web_gantt_reschedule_is_in_conflict_or_force( + self, master, slave, start_date_field_name, stop_date_field_name, force + ): + """ Get whether the dependency relation between a master and a slave record is in conflict. + This check is By-passed for slave records if moving records forwards and the for + master records if moving records backwards. In order to add condition that would not be + by-passed, rather consider _web_gantt_reschedule_is_relation_candidate. + + This def purpose is to be able to prevent the default behavior in some modules by overriding + the def and forcing / preventing the rescheduling il all circumstances if needed. + See _web_gantt_get_rescheduling_candidates. + + :param master: The master record. + :param slave: The slave record. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :param force: Force returning True + :return: True if there is a conflict, False if not. + :rtype: bool + """ + return force or self._web_gantt_reschedule_is_in_conflict( + master, slave, start_date_field_name, stop_date_field_name + ) + + def _web_gantt_reschedule_is_record_candidate(self, start_date_field_name, stop_date_field_name): + """ Get whether the record is a candidate for the rescheduling. This method is meant to be overridden when + we need to add a constraint in order to prevent some records to be rescheduled. This method focuses on the + record itself (if you need to have information on the relation (master and slave) rather override + _web_gantt_reschedule_is_relation_candidate). + + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: True if record can be rescheduled, False if not. + :rtype: bool + """ + self.ensure_one() + return self[start_date_field_name] and self[stop_date_field_name] \ + and self[start_date_field_name].replace(tzinfo=timezone.utc) > datetime.now(timezone.utc) + + def _web_gantt_reschedule_is_relation_candidate(self, master, slave, start_date_field_name, stop_date_field_name): + """ Get whether the relation between master and slave is a candidate for the rescheduling. This method is meant + to be overridden when we need to add a constraint in order to prevent some records to be rescheduled. + This method focuses on the relation between records (if your logic is rather on one record, rather override + _web_gantt_reschedule_is_record_candidate). + + :param master: The master record we need to evaluate whether it is a candidate for rescheduling or not. + :param slave: The slave record. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: True if record can be rescheduled, False if not. + :rtype: bool + """ + return True + + def _web_gantt_reschedule_write_new_dates( + self, new_start_date, new_stop_date, start_date_field_name, stop_date_field_name + ): + """ Write the dates values if new_start_date is in the future. + + :param new_start_date: The start_date to write. + :param new_stop_date: The stop_date to write. + :param start_date_field_name: The start date field used in the gantt view. + :param stop_date_field_name: The stop date field used in the gantt view. + :return: True if successful, False if not. + :rtype: bool + + epsilon = 30 seconds was added because the first valid interval can be now and because of some seconds, it will become < now() at the comparaison moment + it's a matter of some seconds + """ + new_start_date = new_start_date.astimezone(timezone.utc).replace(tzinfo=None) + if new_start_date < datetime.now() + timedelta(seconds=-30): + return False + + self.write({ + start_date_field_name: new_start_date, + stop_date_field_name: new_stop_date.astimezone(timezone.utc).replace(tzinfo=None) + }) + return True diff --git a/addons_extensions/web_gantt/static/src/gantt_arch_parser.js b/addons_extensions/web_gantt/static/src/gantt_arch_parser.js new file mode 100644 index 000000000..deeb1eb0a --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_arch_parser.js @@ -0,0 +1,332 @@ +import { getLocalYearAndWeek } from "@web/core/l10n/dates"; +import { _t } from "@web/core/l10n/translation"; +import { evaluateExpr } from "@web/core/py_js/py"; +import { exprToBoolean } from "@web/core/utils/strings"; +import { visitXML } from "@web/core/utils/xml"; +import { getActiveActions } from "@web/views/utils"; + +const DECORATIONS = [ + "decoration-danger", + "decoration-info", + "decoration-secondary", + "decoration-success", + "decoration-warning", +]; +const PARTS = { full: 1, half: 2, quarter: 4 }; +const SCALES = { + day: { + // determines subcolumns + cellPrecisions: { full: 60, half: 30, quarter: 15 }, + defaultPrecision: "full", + time: "minute", + unitDescription: _t("minutes"), + + // determines columns + interval: "hour", + minimalColumnWidth: 40, + + // determines column groups + unit: "day", + groupHeaderFormatter: (date) => date.toFormat("dd MMMM yyyy"), + + defaultRange: { unit: "day", count: 3 }, + }, + week: { + cellPrecisions: { full: 24, half: 12 }, + defaultPrecision: "half", + time: "hour", + unitDescription: _t("hours"), + + interval: "day", + minimalColumnWidth: 192, + colHeaderFormatter: (date) => date.toFormat("dd"), + + unit: "week", + groupHeaderFormatter: formatLocalWeekYear, + + defaultRange: { unit: "week", count: 3 }, + }, + week_2: { + cellPrecisions: { full: 24, half: 12 }, + defaultPrecision: "half", + time: "hour", + unitDescription: _t("hours"), + + interval: "day", + minimalColumnWidth: 96, + colHeaderFormatter: (date) => date.toFormat("dd"), + + unit: "week", + groupHeaderFormatter: formatLocalWeekYear, + + defaultRange: { unit: "week", count: 6 }, + }, + month: { + cellPrecisions: { full: 24, half: 12 }, + defaultPrecision: "half", + time: "hour", + unitDescription: _t("hours"), + + interval: "day", + minimalColumnWidth: 50, + colHeaderFormatter: (date) => date.toFormat("dd"), + + unit: "month", + groupHeaderFormatter: (date, env) => date.toFormat(env.isSmall ? "MMM yyyy" : "MMMM yyyy"), + + defaultRange: { unit: "month", count: 3 }, + }, + month_3: { + cellPrecisions: { full: 24, half: 12 }, + defaultPrecision: "half", + time: "hour", + unitDescription: _t("hours"), + + interval: "day", + minimalColumnWidth: 18, + colHeaderFormatter: (date) => date.toFormat("dd"), + + unit: "month", + groupHeaderFormatter: (date, env) => date.toFormat(env.isSmall ? "MMM yyyy" : "MMMM yyyy"), + + defaultRange: { unit: "month", count: 6 }, + }, + year: { + cellPrecisions: { full: 1 }, + defaultPrecision: "full", + time: "month", + unitDescription: _t("months"), + + interval: "month", + minimalColumnWidth: 60, + colHeaderFormatter: (date, env) => date.toFormat(env.isSmall ? "MMM" : "MMMM"), + + unit: "year", + groupHeaderFormatter: (date) => date.toFormat("yyyy"), + + defaultRange: { unit: "year", count: 1 }, + }, +}; + +/** + * Formats a date to a `'W'W kkkk` datetime string, in the user's locale settings. + * + * @param {Date|luxon.DateTime} date + * @returns {string} + */ +function formatLocalWeekYear(date) { + const { year, week } = getLocalYearAndWeek(date); + return `W${week} ${year}`; +} + +function getPreferedScaleId(scaleId, scales) { + // we assume that scales is not empty + if (scaleId in scales) { + return scaleId; + } + const scaleIds = Object.keys(SCALES); + const index = scaleIds.findIndex((id) => id === scaleId); + for (let j = index - 1; j >= 0; j--) { + const id = scaleIds[j]; + if (id in scales) { + return id; + } + } + for (let j = index + 1; j < scaleIds.length; j++) { + const id = scaleIds[j]; + if (id in scales) { + return id; + } + } +} + +const RANGES = { + day: { scaleId: "day", description: _t("Today") }, + week: { scaleId: "week", description: _t("This week") }, + month: { scaleId: "month", description: _t("This month") }, + quarter: { scaleId: "month_3", description: _t("This quarter") }, + year: { scaleId: "year", description: _t("This year") }, +}; + +export class GanttArchParser { + parse(arch) { + let infoFromRootNode; + const decorationFields = []; + const popoverArchParams = { + displayGenericButtons: true, + bodyTemplate: null, + footerTemplate: null, + }; + + visitXML(arch, (node) => { + switch (node.tagName) { + case "gantt": { + infoFromRootNode = getInfoFromRootNode(node); + break; + } + case "field": { + const fieldName = node.getAttribute("name"); + decorationFields.push(fieldName); + break; + } + case "templates": { + const body = node.querySelector("[t-name=gantt-popover]") || null; + if (body) { + popoverArchParams.bodyTemplate = body.cloneNode(true); + popoverArchParams.bodyTemplate.removeAttribute("t-name"); + const footer = popoverArchParams.bodyTemplate.querySelector("footer"); + if (footer) { + popoverArchParams.displayGenericButtons = false; + footer.remove(); + const footerTemplate = new Document().createElement("t"); + footerTemplate.append(...footer.children); + popoverArchParams.footerTemplate = footerTemplate; + const replace = footer.getAttribute("replace"); + if (replace && !exprToBoolean(replace)) { + popoverArchParams.displayGenericButtons = true; + } + } + } + } + } + }); + + return { + ...infoFromRootNode, + decorationFields, + popoverArchParams, + }; + } +} + +function getInfoFromRootNode(rootNode) { + const attrs = {}; + for (const { name, value } of rootNode.attributes) { + attrs[name] = value; + } + + const { create: canCreate, delete: canDelete, edit: canEdit } = getActiveActions(rootNode); + const canCellCreate = exprToBoolean(attrs.cell_create, true) && canCreate; + const canPlan = exprToBoolean(attrs.plan, true) && canEdit; + + let consolidationMaxField; + let consolidationMaxValue; + const consolidationMax = attrs.consolidation_max ? evaluateExpr(attrs.consolidation_max) : {}; + if (Object.keys(consolidationMax).length > 0) { + consolidationMaxField = Object.keys(consolidationMax)[0]; + consolidationMaxValue = consolidationMax[consolidationMaxField]; + } + + const consolidationParams = { + excludeField: attrs.consolidation_exclude, + field: attrs.consolidation, + maxField: consolidationMaxField, + maxValue: consolidationMaxValue, + }; + + const dependencyField = attrs.dependency_field || null; + const dependencyEnabled = !!dependencyField; + const dependencyInvertedField = attrs.dependency_inverted_field || null; + + const allowedScales = []; + if (attrs.scales) { + for (const key of attrs.scales.split(",")) { + if (SCALES[key]) { + allowedScales.push(key); + } + } + } + if (allowedScales.length === 0) { + allowedScales.push(...Object.keys(SCALES)); + } + + // Cell precision + const cellPrecisions = {}; + + // precision = {'day': 'hour:half', 'week': 'day:half', 'month': 'day', 'year': 'month:quarter'} + const precisionAttrs = attrs.precision ? evaluateExpr(attrs.precision) : {}; + for (const scaleId in SCALES) { + if (precisionAttrs[scaleId]) { + const precision = precisionAttrs[scaleId].split(":"); // hour:half + // Note that precision[0] (which is the cell interval) is not + // taken into account right now because it is no customizable. + if ( + precision[1] && + Object.keys(SCALES[scaleId].cellPrecisions).includes(precision[1]) + ) { + cellPrecisions[scaleId] = precision[1]; + } + } + cellPrecisions[scaleId] ||= SCALES[scaleId].defaultPrecision; + } + + const scales = {}; + for (const scaleId of allowedScales) { + const precision = cellPrecisions[scaleId]; + const referenceScale = SCALES[scaleId]; + scales[scaleId] = { + ...referenceScale, + cellPart: PARTS[precision], + cellTime: referenceScale.cellPrecisions[precision], + id: scaleId, + unitDescription: referenceScale.unitDescription.toString(), + }; + // protect SCALES content + delete scales[scaleId].cellPrecisions; + } + + const ranges = {}; + for (const rangeId in RANGES) { + const referenceRange = RANGES[rangeId]; + ranges[rangeId] = { + ...referenceRange, + id: rangeId, + scaleId: getPreferedScaleId(referenceRange.scaleId, scales), + description: referenceRange.description.toString(), + }; + } + + let pillDecorations = null; + for (const decoration of DECORATIONS) { + if (decoration in attrs) { + if (!pillDecorations) { + pillDecorations = {}; + } + pillDecorations[decoration] = attrs[decoration]; + } + } + + return { + canCellCreate, + canCreate, + canDelete, + canEdit, + canPlan, + colorField: attrs.color, + computePillDisplayName: !!attrs.pill_label, + consolidationParams, + createAction: attrs.on_create || null, + dateStartField: attrs.date_start, + dateStopField: attrs.date_stop, + defaultGroupBy: attrs.default_group_by ? attrs.default_group_by.split(",") : [], + defaultRange: attrs.default_range, + defaultScale: attrs.default_scale || "month", + dependencyEnabled, + dependencyField, + dependencyInvertedField, + disableDrag: exprToBoolean(attrs.disable_drag_drop), + displayMode: attrs.display_mode || "dense", + displayTotalRow: exprToBoolean(attrs.total_row), + displayUnavailability: exprToBoolean(attrs.display_unavailability), + formViewId: attrs.form_view_id ? parseInt(attrs.form_view_id, 10) : false, + offset: attrs.offset, + pagerLimit: attrs.groups_limit ? parseInt(attrs.groups_limit, 10) : null, + pillDecorations, + progressBarFields: attrs.progress_bar ? attrs.progress_bar.split(",") : null, + progressField: attrs.progress || null, + ranges, + scales, + string: attrs.string || _t("Gantt View").toString(), + thumbnails: attrs.thumbnails ? evaluateExpr(attrs.thumbnails) : {}, + }; +} diff --git a/addons_extensions/web_gantt/static/src/gantt_compiler.js b/addons_extensions/web_gantt/static/src/gantt_compiler.js new file mode 100644 index 000000000..692f481b7 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_compiler.js @@ -0,0 +1,20 @@ +import { ViewCompiler } from "@web/views/view_compiler"; + +export class GanttCompiler extends ViewCompiler {} +GanttCompiler.OWL_DIRECTIVE_WHITELIST = [ + ...ViewCompiler.OWL_DIRECTIVE_WHITELIST, + "t-name", + "t-esc", + "t-out", + "t-set", + "t-value", + "t-if", + "t-else", + "t-elif", + "t-foreach", + "t-as", + "t-key", + "t-att.*", + "t-call", + "t-translation", +]; diff --git a/addons_extensions/web_gantt/static/src/gantt_connector.js b/addons_extensions/web_gantt/static/src/gantt_connector.js new file mode 100644 index 000000000..39cf9cfe4 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_connector.js @@ -0,0 +1,294 @@ +import { Component, onWillRender, useEffect, useRef } from "@odoo/owl"; + +/** + * @typedef {"error" | "warning"} ConnectorAlert + * @typedef {`__connector__${number | "new"}`} ConnectorId + * @typedef {import("./gantt_renderer").Point} Point + * + * @typedef ConnectorProps + * @property {ConnectorId} id + * @property {ConnectorAlert | null} alert + * @property {boolean} highlighted + * @property {boolean} displayButtons + * @property {Point | () => Point | null} sourcePoint + * @property {Point | () => Point | null} targetPoint + * + * @typedef {Object} PathInfo + * @property {Point} sourceControlPoint + * @property {Point} targetControlPoint + * @property {Point} removeButtonPosition + * + * @typedef Point + * @property {number} [x] + * @property {number} [y] + */ + +/** + * Gets the stroke's rgba css string corresponding to the provided parameters for both the stroke and its + * hovered state. + * + * @param {number} r [0, 255] + * @param {number} g [0, 255] + * @param {number} b [0, 255] + * @return {{ stroke: string, hoveredStroke: string }} the css colors. + */ +export function getStrokeAndHoveredStrokeColor(r, g, b) { + return { + color: `rgba(${r},${g},${b},0.5)`, + highlightedColor: `rgba(${r},${g},${b},1)`, + }; +} + +export const COLORS = { + default: getStrokeAndHoveredStrokeColor(143, 143, 143), + error: getStrokeAndHoveredStrokeColor(211, 65, 59), + warning: getStrokeAndHoveredStrokeColor(236, 151, 31), + outline: getStrokeAndHoveredStrokeColor(255, 255, 255), +}; + +/** @extends {Component<{ reactive: ConnectorProps }, any>} */ +export class GanttConnector extends Component { + static props = { + reactive: { + type: Object, + shape: { + id: String, + alert: { + type: [{ value: "error" }, { value: "warning" }, { value: null }], + optional: true, + }, + highlighted: { type: Boolean, optional: true }, + displayButtons: { type: Boolean, optional: true }, + sourcePoint: [ + { value: null }, + Function, + { type: Object, shape: { left: Number, top: Number } }, + ], + targetPoint: [ + { value: null }, + Function, + { type: Object, shape: { left: Number, top: Number } }, + ], + }, + }, + onLeftButtonClick: { type: Function, optional: true }, + onRemoveButtonClick: { type: Function, optional: true }, + onRightButtonClick: { type: Function, optional: true }, + }; + static defaultProps = { + highlighted: false, + displayButtons: false, + }; + static template = "web_gantt.GanttConnector"; + + rootRef = useRef("root"); + style = { + hoverEaseWidth: 10, + slackness: 0.9, + stroke: { width: 2 }, + outlineStroke: { width: 1 }, + }; + + get alert() { + return this.props.reactive.alert; + } + + get displayButtons() { + return this.props.reactive.displayButtons; + } + + get highlighted() { + return this.props.reactive.highlighted; + } + + get id() { + return this.props.reactive.id; + } + + get isNew() { + return this.id.endsWith("new"); + } + + get sourcePoint() { + return this.props.reactive.sourcePoint; + } + + get targetPoint() { + return this.props.reactive.targetPoint; + } + + setup() { + onWillRender(this.onWillRender); + + useEffect( + (el, sourceLeft, sourceTop, targetLeft, targetTop) => { + if (!el) { + return; + } + const { sourceControlPoint, targetControlPoint, removeButtonPosition } = + this.getPathInfo( + { left: sourceLeft, top: sourceTop }, + { left: targetLeft, top: targetTop }, + this.style.slackness + ); + + const drawingCommands = [ + `M`, + `${sourceLeft},${sourceTop}`, + `C`, + `${sourceControlPoint.left},${sourceControlPoint.top}`, + `${targetControlPoint.left},${targetControlPoint.top}`, + `${targetLeft},${targetTop}`, + ].join(" "); + + const paths = el.querySelectorAll( + ".o_connector_stroke, .o_connector_stroke_hover_ease" + ); + for (const path of paths) { + path.setAttribute("d", drawingCommands); + } + + const svgButtons = el.querySelector(".o_connector_stroke_buttons"); + if (svgButtons) { + svgButtons.setAttribute("x", removeButtonPosition.left - 24); + svgButtons.setAttribute("y", removeButtonPosition.top - 8); + } + }, + () => this.getEffectDependencies() + ); + } + + /** + * Refreshes the connector properties from the props. + * + * @param {ConnectorProps} props + */ + computeStyle({ alert, highlighted }) { + const key = highlighted ? "highlightedColor" : "color"; + const strokeType = alert || "default"; + this.style = { + hoverEaseWidth: 10, + slackness: 0.9, + stroke: { + color: COLORS[strokeType][key], + width: 2, + }, + outlineStroke: { + color: COLORS.outline[key], + width: 1, + }, + }; + } + + getEffectDependencies() { + let sourcePoint = this.sourcePoint || { left: 0, top: 0 }; + if (typeof sourcePoint === "function") { + sourcePoint = sourcePoint(); + } + let targetPoint = this.targetPoint || { left: 0, top: 0 }; + if (typeof targetPoint === "function") { + targetPoint = targetPoint(); + } + const { x, y } = this.rootRef.el?.getBoundingClientRect() || { x: 0, y: 0 }; + + return [ + this.rootRef.el, + sourcePoint.left - x, + sourcePoint.top - y, + targetPoint.left - x, + targetPoint.top - y, + this.displayButtons, + ]; + } + + /** + * Returns the linear interpolation for a point to be found somewhere on the line startingPoint, endingPoint. + * + * @param {Point} startingPoint + * @param {Point} endingPoint + * @param {number} lambda + * @returns {Point} + */ + getLinearInterpolation(startingPoint, endingPoint, lambda = 0.5) { + return { + left: lambda * startingPoint.left + (1 - lambda) * endingPoint.left, + top: lambda * startingPoint.top + (1 - lambda) * endingPoint.top, + }; + } + + /** + * Returns the parameters of both the single Bezier curve as well as is decomposition into two beziers curves + * (which allows to get the middle position of the single Bezier curve) for the provided source, target and + * slackness (0 being a straight line). + * + * @param {Point} sourcePoint + * @param {Point} targetPoint + * @param {number} slackness [0, 1] + * @returns {PathInfo} + */ + getPathInfo(sourcePoint, targetPoint, slackness) { + // If the source is on the left of the target, we need to invert the control points. + const xDelta = targetPoint.left - sourcePoint.left; + const yDelta = targetPoint.top - sourcePoint.top; + const directionFactor = Math.sign(xDelta); + + // What follows can be seen as magic numbers. And those are indeed such numbers as they have been determined + // by observing their shape while creating short and long connectors. These seems to allow keeping the same + // kind of shape amongst short and long connectors. + const xInc = 100 + (Math.abs(xDelta) * slackness) / 10; + const yInc = + Math.abs(yDelta) < 16 && directionFactor === -1 ? 15 - 0.001 * xDelta * slackness : 0; + + const b = { + left: sourcePoint.left + xInc, + top: sourcePoint.top + yInc, + }; + + // Prevent having the air pin effect when in creation and having target on the left of the source + const c = { + left: targetPoint.left + (this.isNew && directionFactor === -1 ? xInc : -xInc), + top: targetPoint.top + yInc, + }; + + const e = this.getLinearInterpolation(sourcePoint, b); + const f = this.getLinearInterpolation(b, c); + const g = this.getLinearInterpolation(c, targetPoint); + const h = this.getLinearInterpolation(e, f); + const i = this.getLinearInterpolation(f, g); + const j = this.getLinearInterpolation(h, i); + + return { + sourceControlPoint: b, + targetControlPoint: c, + removeButtonPosition: j, + }; + } + + //------------------------------------------------------------------------- + // Handlers + //------------------------------------------------------------------------- + + onLeftButtonClick() { + if (this.props.onLeftButtonClick) { + this.props.onLeftButtonClick(); + } + } + + onRemoveButtonClick() { + if (this.props.onRemoveButtonClick) { + this.props.onRemoveButtonClick(); + } + } + + onRightButtonClick() { + if (this.props.onRightButtonClick) { + this.props.onRightButtonClick(); + } + } + + onWillRender() { + const key = this.highlighted ? "highlightedColor" : "color"; + this.style.stroke.color = COLORS[this.alert || "default"][key]; + this.style.outlineStroke.color = COLORS.outline[key]; + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_connector.xml b/addons_extensions/web_gantt/static/src/gantt_connector.xml new file mode 100644 index 000000000..7b579f157 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_connector.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons_extensions/web_gantt/static/src/gantt_controller.js b/addons_extensions/web_gantt/static/src/gantt_controller.js new file mode 100644 index 000000000..fc3b869d3 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_controller.js @@ -0,0 +1,193 @@ +import { _t } from "@web/core/l10n/translation"; +import { Component, onWillUnmount, useEffect, useRef, useSubEnv } from "@odoo/owl"; +import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog"; +import { FormViewDialog } from "@web/views/view_dialogs/form_view_dialog"; +import { Layout } from "@web/search/layout"; +import { standardViewProps } from "@web/views/standard_view_props"; +import { useModelWithSampleData } from "@web/model/model"; +import { usePager } from "@web/search/pager_hook"; +import { useService } from "@web/core/utils/hooks"; +import { SearchBar } from "@web/search/search_bar/search_bar"; +import { useSearchBarToggler } from "@web/search/search_bar/search_bar_toggler"; +import { CogMenu } from "@web/search/cog_menu/cog_menu"; +import { CallbackRecorder, useSetupAction } from "@web/search/action_hook"; + +export class GanttController extends Component { + static components = { + CogMenu, + Layout, + SearchBar, + }; + static props = { + ...standardViewProps, + Model: Function, + Renderer: Function, + buttonTemplate: String, + modelParams: Object, + scrollPosition: { type: Object, optional: true }, + }; + static template = "web_gantt.GanttController"; + + setup() { + this.actionService = useService("action"); + this.dialogService = useService("dialog"); + this.orm = useService("orm"); + + useSubEnv({ + getCurrentFocusDateCallBackRecorder: new CallbackRecorder(), + }); + + const rootRef = useRef("root"); + + this.model = useModelWithSampleData(this.props.Model, this.props.modelParams); + useSetupAction({ + rootRef, + getLocalState: () => { + return { metaData: this.model.metaData, displayParams: this.model.displayParams }; + }, + }); + + onWillUnmount(() => this.closeDialog?.()); + + usePager(() => { + const { groupedBy, pagerLimit, pagerOffset } = this.model.metaData; + const { count } = this.model.data; + if (pagerLimit !== null && groupedBy.length) { + return { + offset: pagerOffset, + limit: pagerLimit, + total: count, + onUpdate: async ({ offset, limit }) => { + await this.model.updatePagerParams({ offset, limit }); + }, + }; + } + }); + + useEffect( + (showNoContentHelp) => { + if (showNoContentHelp) { + const realRows = [ + ...rootRef.el.querySelectorAll( + ".o_gantt_row_header:not(.o_sample_data_disabled)" + ), + ]; + // interactive rows created in extensions (fromServer undefined) + const headerContainerWidth = + rootRef.el.querySelector(".o_gantt_header_groups").clientHeight + + rootRef.el.querySelector(".o_gantt_header_columns").clientHeight; + + const offset = realRows.reduce( + (current, el) => current + el.clientHeight, + headerContainerWidth + ); + + const noContentHelperEl = rootRef.el.querySelector(".o_view_nocontent"); + noContentHelperEl.style.top = `${offset}px`; + } + }, + () => [this.showNoContentHelp] + ); + this.searchBarToggler = useSearchBarToggler(); + } + + get className() { + if (this.env.isSmall) { + const classList = (this.props.className || "").split(" "); + classList.push("o_action_delegate_scroll"); + return classList.join(" "); + } + return this.props.className; + } + + get showNoContentHelp() { + return this.model.useSampleModel; + } + + /** + * @param {Record} [context] + */ + create(context) { + const { createAction } = this.model.metaData; + if (createAction) { + this.actionService.doAction(createAction, { + additionalContext: context, + onClose: () => { + this.model.fetchData(); + }, + }); + } else { + this.openDialog({ context }); + } + } + + /** + * Opens dialog to add/edit/view a record + * + * @param {Record} props FormViewDialog props + * @param {Record} [options={}] + */ + openDialog(props, options = {}) { + const { canDelete, canEdit, resModel, formViewId: viewId } = this.model.metaData; + + const title = props.title || (props.resId ? _t("Open") : _t("Create")); + + let removeRecord; + if (canDelete && props.resId) { + removeRecord = () => { + return new Promise((resolve) => { + this.dialogService.add(ConfirmationDialog, { + body: _t("Are you sure to delete this record?"), + confirm: async () => { + await this.orm.unlink(resModel, [props.resId]); + resolve(); + }, + cancel: () => {}, + }); + }); + }; + } + + this.closeDialog = this.dialogService.add( + FormViewDialog, + { + title, + resModel, + viewId, + resId: props.resId, + size: props.size, + mode: canEdit ? "edit" : "readonly", + context: props.context, + removeRecord, + }, + { + ...options, + onClose: () => { + this.closeDialog = null; + this.model.fetchData(); + }, + } + ); + } + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + onAddClicked() { + const { scale } = this.model.metaData; + const focusDate = this.getCurrentFocusDate(); + const start = focusDate.startOf(scale.unit); + const stop = focusDate.endOf(scale.unit).plus({ millisecond: 1 }); + const context = this.model.getDialogContext({ start, stop, withDefault: true }); + this.create(context); + } + + getCurrentFocusDate() { + const { callbacks } = this.env.getCurrentFocusDateCallBackRecorder; + if (callbacks.length) { + return callbacks[0](); + } + return this.model.metaData.focusDate; + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_controller.xml b/addons_extensions/web_gantt/static/src/gantt_controller.xml new file mode 100644 index 000000000..aa798f22b --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_controller.xml @@ -0,0 +1,50 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+ +
diff --git a/addons_extensions/web_gantt/static/src/gantt_helpers.js b/addons_extensions/web_gantt/static/src/gantt_helpers.js new file mode 100644 index 000000000..173aa08c1 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_helpers.js @@ -0,0 +1,745 @@ +import { onWillUnmount, status, useComponent, useEffect, useEnv } from "@odoo/owl"; +import { getEndOfLocalWeek, getStartOfLocalWeek } from "@web/core/l10n/dates"; +import { makePopover, usePopover } from "@web/core/popover/popover_hook"; +import { makeDraggableHook } from "@web/core/utils/draggable_hook_builder_owl"; +import { useService } from "@web/core/utils/hooks"; +import { clamp } from "@web/core/utils/numbers"; +import { pick } from "@web/core/utils/objects"; +import { GanttPopoverInDialog } from "./gantt_popover_in_dialog"; + +/** @typedef {luxon.DateTime} DateTime */ + +/** + * @param {number} target + * @param {number[]} values + * @returns {number} + */ +function closest(target, values) { + return values.reduce( + (prev, val) => (Math.abs(val - target) < Math.abs(prev - target) ? val : prev), + Infinity + ); +} + +/** + * Adds a time diff to a date keeping the same value even if the offset changed + * during the manipulation. This is typically needed with timezones using DayLight + * Saving offset changes. + * + * @example dateAddFixedOffset(luxon.DateTime.local(), { hour: 1 }); + * @param {DateTime} date + * @param {Record} plusParams + */ +export function dateAddFixedOffset(date, plusParams) { + const shouldApplyOffset = Object.keys(plusParams).some((key) => + /^(hour|minute|second)s?$/i.test(key) + ); + const result = date.plus(plusParams); + if (shouldApplyOffset) { + const initialOffset = date.offset; + const diff = initialOffset - result.offset; + if (diff) { + const adjusted = result.plus({ minute: diff }); + return adjusted.offset === initialOffset ? result : adjusted; + } + } + return result; +} + +export function diffColumn(col1, col2, unit) { + return col2.diff(col1, unit).values[`${unit}s`]; +} + +export function getRangeFromDate(rangeId, date) { + const startDate = localStartOf(date, rangeId); + const stopDate = startDate.plus({ [rangeId]: 1 }).minus({ day: 1 }); + return { focusDate: date, startDate, stopDate, rangeId }; +} + +export function localStartOf(date, unit) { + return unit === "week" ? getStartOfLocalWeek(date) : date.startOf(unit); +} + +export function localEndOf(date, unit) { + return unit === "week" ? getEndOfLocalWeek(date) : date.endOf(unit); +} + +/** + * @param {number} cellPart + * @param {(0 | 1)[]} subSlotUnavailabilities + * @param {boolean} isToday + * @returns {string | null} + */ +export function getCellColor(cellPart, subSlotUnavailabilities, isToday) { + const sum = subSlotUnavailabilities.reduce((acc, d) => acc + d); + if (!sum) { + return null; + } + switch (cellPart) { + case sum: { + return `background-color:${getCellPartColor(sum, isToday)}`; + } + case 2: { + const [c0, c1] = subSlotUnavailabilities.map((d) => getCellPartColor(d, isToday)); + return `background:linear-gradient(90deg,${c0}49%,${c1}50%)`; + } + case 4: { + const [c0, c1, c2, c3] = subSlotUnavailabilities.map((d) => + getCellPartColor(d, isToday) + ); + return `background:linear-gradient(90deg,${c0}24%,${c1}25%,${c1}49%,${c2}50%,${c2}74%,${c3}75%)`; + } + } +} + +/** + * @param {0 | 1} availability + * @param {boolean} isToday + * @returns {string} + */ +export function getCellPartColor(availability, isToday) { + if (availability) { + return "var(--Gantt__DayOff-background-color)"; + } else if (isToday) { + return "var(--Gantt__DayOffToday-background-color)"; + } else { + return "var(--Gantt__Day-background-color)"; + } +} + +/** + * @param {number | [number, string]} value + * @returns {number} + */ +export function getColorIndex(value) { + if (typeof value === "number") { + return Math.round(value) % NB_GANTT_RECORD_COLORS; + } else if (Array.isArray(value)) { + return value[0] % NB_GANTT_RECORD_COLORS; + } + return 0; +} + +/** + * Intervals are supposed to intersect (intersection duration >= 1 milliseconds) + * + * @param {[DateTime, DateTime]} interval + * @param {[DateTime, DateTime]} otherInterval + * @returns {[DateTime, DateTime]} + */ +export function getIntersection(interval, otherInterval) { + const [start, end] = interval; + const [otherStart, otherEnd] = otherInterval; + return [start >= otherStart ? start : otherStart, end <= otherEnd ? end : otherEnd]; +} + +/** + * Computes intersection of a closed interval with a union of closed intervals ordered and disjoint + * = a union of intersections + * + * @param {[DateTime, DateTime]} interval + * @param {[DateTime, DateTime]} intervals + * @returns {[DateTime, DateTime][]} + */ +export function getUnionOfIntersections(interval, intervals) { + const [start, end] = interval; + const intersecting = intervals.filter((otherInterval) => { + const [otheStart, otherEnd] = otherInterval; + return otherEnd > start && end > otheStart; + }); + const len = intersecting.length; + if (len === 0) { + return []; + } + const union = []; + const first = getIntersection(interval, intersecting[0]); + union.push(first); + if (len >= 2) { + const last = getIntersection(interval, intersecting[len - 1]); + union.push(...intersecting.slice(1, len - 1), last); + } + return union; +} + +/** + * @param {Object} params + * @param {Ref} params.ref + * @param {string} params.selector + * @param {string} params.related + * @param {string} params.className + */ +export function useMultiHover({ ref, selector, related, className }) { + /** + * @param {HTMLElement} el + */ + const findSiblings = (el) => + ref.el.querySelectorAll( + related + .map((attr) => `[${attr}='${el.getAttribute(attr).replace(/'/g, "\\'")}']`) + .join("") + ); + + /** + * @param {PointerEvent} ev + */ + const onPointerEnter = (ev) => { + for (const sibling of findSiblings(ev.target)) { + sibling.classList.add(...classList); + classedEls.add(sibling); + } + }; + + /** + * @param {PointerEvent} ev + */ + const onPointerLeave = (ev) => { + for (const sibling of findSiblings(ev.target)) { + sibling.classList.remove(...classList); + classedEls.delete(sibling); + } + }; + + const classList = className.split(/\s+/g); + const classedEls = new Set(); + + useEffect( + (...targets) => { + if (targets.length) { + for (const target of targets) { + target.addEventListener("pointerenter", onPointerEnter); + target.addEventListener("pointerleave", onPointerLeave); + } + return () => { + for (const el of classedEls) { + el.classList.remove(...classList); + } + classedEls.clear(); + for (const target of targets) { + target.removeEventListener("pointerenter", onPointerEnter); + target.removeEventListener("pointerleave", onPointerLeave); + } + }; + } + }, + () => [...ref.el.querySelectorAll(selector)] + ); +} + +const NB_GANTT_RECORD_COLORS = 12; + +function getElementCenter(el) { + const { x, y, width, height } = el.getBoundingClientRect(); + return { + x: x + width / 2, + y: y + height / 2, + }; +} + +// Resizable hook handles + +const HANDLE_CLASS_START = "o_handle_start"; +const HANDLE_CLASS_END = "o_handle_end"; +const handles = { + start: document.createElement("div"), + end: document.createElement("div"), +}; + +// Draggable hooks + +export const useGanttConnectorDraggable = makeDraggableHook({ + name: "useGanttConnectorDraggable", + acceptedParams: { + parentWrapper: [String], + }, + onComputeParams({ ctx, params }) { + ctx.parentWrapper = params.parentWrapper; + ctx.followCursor = false; + }, + onDragStart: ({ ctx, addStyle }) => { + const { current } = ctx; + const parent = current.element.closest(ctx.parentWrapper); + if (!parent) { + return; + } + for (const otherParent of ctx.ref.el.querySelectorAll(ctx.parentWrapper)) { + if (otherParent !== parent) { + addStyle(otherParent, { pointerEvents: "auto" }); + } + } + return { sourcePill: parent, ...current.connectorCenter }; + }, + onDrag: ({ ctx }) => { + ctx.current.connectorCenter = getElementCenter(ctx.current.element); + return pick(ctx.current, "connectorCenter"); + }, + onDragEnd: ({ ctx }) => pick(ctx.current, "element"), + onDrop: ({ ctx, target }) => { + const { current } = ctx; + const parent = current.element.closest(ctx.parentWrapper); + const targetParent = target.closest(ctx.parentWrapper); + if (!targetParent || targetParent === parent) { + return; + } + return { target: targetParent }; + }, + onWillStartDrag: ({ ctx }) => { + ctx.current.connectorCenter = getElementCenter(ctx.current.element); + }, +}); + +function getCoordinate(style, name) { + return +style.getPropertyValue(name).slice(1); +} + +function getColumnStart(style) { + return getCoordinate(style, "grid-column-start"); +} + +function getColumnEnd(style) { + return getCoordinate(style, "grid-column-end"); +} + +export const useGanttDraggable = makeDraggableHook({ + name: "useGanttDraggable", + acceptedParams: { + cells: [String, Function], + cellDragClassName: [String, Function], + ghostClassName: [String, Function], + hoveredCell: [Object], + addStickyCoordinates: [Function], + }, + onComputeParams({ ctx, params }) { + ctx.cellSelector = params.cells; + ctx.ghostClassName = params.ghostClassName; + ctx.cellDragClassName = params.cellDragClassName; + ctx.hoveredCell = params.hoveredCell; + ctx.addStickyCoordinates = params.addStickyCoordinates; + }, + onDragStart({ ctx }) { + const { current, ghostClassName } = ctx; + current.element.before(current.placeHolder); + if (ghostClassName) { + current.placeHolder.classList.add(ghostClassName); + } + return { pill: current.element }; + }, + onDrag({ ctx, addStyle }) { + const { cellSelector, current, hoveredCell } = ctx; + let { el: cell, part } = hoveredCell; + + const isDifferentCell = cell !== current.cell.el; + const isDifferentPart = part !== current.cell.part; + + if (cell && !cell.matches(cellSelector)) { + cell = null; // Not a cell + } + + current.cell.el = cell; + current.cell.part = part; + + if (cell) { + // Recompute cell style if in a different cell + if (isDifferentCell) { + const style = getComputedStyle(cell); + current.cell.gridRow = style.getPropertyValue("grid-row"); + current.cell.gridColumnStart = getColumnStart(style) + current.gridColumnOffset; + } + // Assign new grid coordinates if in different cell or different cell part + if (isDifferentCell || isDifferentPart) { + const { pillSpan } = current; + const { gridRow, gridColumnStart: start } = current.cell; + const gridColumnStart = clamp(start + part, 1, current.maxGridColumnStart); + const gridColumnEnd = gridColumnStart + pillSpan; + + addStyle(current.cellGhost, { + gridRow, + gridColumn: `c${gridColumnStart} / c${gridColumnEnd}`, + }); + + const [gridRowStart, gridRowEnd] = /r(\d+) \/ r(\d+)/g.exec(gridRow).slice(1); + ctx.addStickyCoordinates( + [gridRowStart, gridRowEnd], + [gridColumnStart, gridColumnEnd] + ); + current.cell.col = gridColumnStart; + } + } else { + current.cell.col = null; + } + + // Attach or remove cell ghost + if (isDifferentCell) { + if (cell) { + cell.after(current.cellGhost); + } else { + current.cellGhost.remove(); + } + } + + return { pill: current.element }; + }, + onDragEnd({ ctx }) { + return { pill: ctx.current.element }; + }, + onDrop({ ctx }) { + const { cell, element, initialCol } = ctx.current; + if (cell.col !== null) { + return { + pill: element, + cell: cell.el, + diff: cell.col - initialCol, + }; + } + }, + onWillStartDrag({ ctx, addCleanup, addClass }) { + const { current } = ctx; + const { el: cell, part } = ctx.hoveredCell; + + current.placeHolder = current.element.cloneNode(true); + current.cellGhost = document.createElement("div"); + current.cellGhost.className = ctx.cellDragClassName; + current.cell = { el: null, index: null, part: 0 }; + + const gridStyle = getComputedStyle(cell.parentElement); + const pillStyle = getComputedStyle(current.element); + const cellStyle = getComputedStyle(cell); + + const gridTemplateColumns = gridStyle.getPropertyValue("grid-template-columns"); + const pGridColumnStart = getColumnStart(pillStyle); + const pGridColumnEnd = getColumnEnd(pillStyle); + const cGridColumnStart = getColumnStart(cellStyle) + part; + + let highestGridCol; + for (const e of gridTemplateColumns.split(/\s+/).reverse()) { + const res = /\[c(\d+)\]/g.exec(e); + if (res) { + highestGridCol = +res[1]; + break; + } + } + + const pillSpan = pGridColumnEnd - pGridColumnStart; + + current.initialCol = pGridColumnStart; + current.maxGridColumnStart = highestGridCol - pillSpan; + current.gridColumnOffset = pGridColumnStart - cGridColumnStart; + current.pillSpan = pillSpan; + + addClass(ctx.ref.el, "pe-auto"); + addCleanup(() => { + current.placeHolder.remove(); + current.cellGhost.remove(); + }); + }, +}); + +export const useGanttUndraggable = makeDraggableHook({ + name: "useGanttUndraggable", + onDragStart({ ctx }) { + return { pill: ctx.current.element }; + }, + onDragEnd({ ctx }) { + return { pill: ctx.current.element }; + }, + onWillStartDrag({ ctx, addCleanup, addClass, addStyle, getRect }) { + const { x, y, width, height } = getRect(ctx.current.element); + ctx.current.container = document.createElement("div"); + + addClass(ctx.ref.el, "pe-auto"); + addStyle(ctx.current.container, { + position: "fixed", + left: `${x}px`, + top: `${y}px`, + width: `${width}px`, + height: `${height}px`, + }); + + ctx.current.element.after(ctx.current.container); + addCleanup(() => ctx.current.container.remove()); + }, +}); + +export const useGanttResizable = makeDraggableHook({ + name: "useGanttResizable", + requiredParams: ["handles"], + acceptedParams: { + innerPills: [String, Function], + handles: [String, Function], + hoveredCell: [Object], + rtl: [Boolean, Function], + cells: [String, Function], + precision: [Number, Function], + showHandles: [Function], + }, + onComputeParams({ ctx, params, addCleanup, addEffectCleanup, getRect }) { + const onElementPointerEnter = (ev) => { + if (ctx.dragging || ctx.willDrag) { + return; + } + + const pill = ev.target; + const innerPill = pill.querySelector(params.innerPills); + + const pillRect = getRect(innerPill); + + for (const el of Object.values(handles)) { + el.style.height = `${pillRect.height}px`; + } + + const showHandles = params.showHandles ? params.showHandles(pill) : {}; + if ("start" in showHandles && !showHandles.start) { + handles.start.remove(); + } else { + innerPill.appendChild(handles.start); + } + if ("end" in showHandles && !showHandles.end) { + handles.end.remove(); + } else { + innerPill.appendChild(handles.end); + } + }; + + const onElementPointerLeave = () => { + const remove = () => Object.values(handles).forEach((h) => h.remove()); + if (ctx.dragging || ctx.current.element) { + addCleanup(remove); + } else { + remove(); + } + }; + + ctx.cellSelector = params.cells; + ctx.hoveredCell = params.hoveredCell; + ctx.precision = params.precision; + ctx.rtl = params.rtl; + + for (const el of ctx.ref.el.querySelectorAll(params.elements)) { + el.addEventListener("pointerenter", onElementPointerEnter); + el.addEventListener("pointerleave", onElementPointerLeave); + addEffectCleanup(() => { + el.removeEventListener("pointerenter", onElementPointerEnter); + el.removeEventListener("pointerleave", onElementPointerLeave); + }); + } + + handles.start.className = `${params.handles} ${HANDLE_CLASS_START}`; + handles.start.style.cursor = `${params.rtl ? "e" : "w"}-resize`; + + handles.end.className = `${params.handles} ${HANDLE_CLASS_END}`; + handles.end.style.cursor = `${params.rtl ? "w" : "e"}-resize`; + + // Override "full" and "element" selectors: we want the draggable feature + // to apply to the handles + ctx.pillSelector = ctx.elementSelector; + ctx.fullSelector = ctx.elementSelector = `.${params.handles}`; + + // Force the handles to stay in place + ctx.followCursor = false; + }, + onDragStart({ ctx, addStyle }) { + addStyle(ctx.current.pill, { zIndex: 15 }); + return { pill: ctx.current.pill }; + }, + onDrag({ ctx, addStyle, getRect }) { + const { cellSelector, current, hoveredCell, pointer, precision, rtl, ref } = ctx; + let { el: cell, part } = hoveredCell; + + const point = [pointer.x, current.initialPosition.y]; + if (!cell) { + let rect; + cell = document.elementsFromPoint(...point).find((el) => el.matches(cellSelector)); + if (!cell) { + const cells = Array.from(ref.el.querySelectorAll(".o_gantt_cells .o_gantt_cell")); + if (pointer.x < current.initialPosition.x) { + cell = rtl ? cells.at(-1) : cells[0]; + } else { + cell = rtl ? cells[0] : cells.at(-1); + } + rect = getRect(cell); + point[0] = rtl ? rect.right - 1 : rect.left + 1; + } else { + rect = getRect(cell); + } + const x = Math.floor(rect.x); + const width = Math.floor(rect.width); + part = Math.floor((point[0] - x) / (width / precision)); + } + + const cellStyle = getComputedStyle(cell); + const cGridColStart = getColumnStart(cellStyle); + + const { x, width } = getRect(cell); + const coef = ((rtl ? -1 : 1) * width) / precision; + const startBorder = (rtl ? x + width : x) + part * coef; + const endBorder = startBorder + coef; + + const theClosest = closest(point[0], [startBorder, endBorder]); + + let diff = + cGridColStart + + part + + (theClosest === startBorder ? 0 : 1) - + (current.isStart ? current.firstCol : current.lastCol); + + if (diff === current.lastDiff) { + return; + } + + if (current.isStart) { + diff = Math.min(diff, current.initialDiff - 1); + addStyle(current.pill, { "grid-column-start": `c${current.firstCol + diff}` }); + } else { + diff = Math.max(diff, 1 - current.initialDiff); + addStyle(current.pill, { "grid-column-end": `c${current.lastCol + diff}` }); + } + current.lastDiff = diff; + + const isLeftHandle = rtl ? !current.isStart : current.isStart; + const grabbedHandle = isLeftHandle ? "left" : "right"; + diff = current.isStart ? -diff : diff; + return { pill: current.pill, grabbedHandle, diff }; + }, + onDragEnd({ ctx }) { + const { current, pillSelector } = ctx; + const pill = current.element.closest(pillSelector); + return { pill }; + }, + onDrop({ ctx }) { + const { current } = ctx; + + if (!current.lastDiff) { + return; + } + + const direction = current.isStart ? "start" : "end"; + return { pill: current.pill, diff: current.lastDiff, direction }; + }, + onWillStartDrag({ ctx, addClass }) { + const { current, pillSelector } = ctx; + + const pill = ctx.current.element.closest(pillSelector); + current.pill = pill; + + const pillStyle = getComputedStyle(pill); + current.firstCol = getColumnStart(pillStyle); + current.lastCol = getColumnEnd(pillStyle); + current.initialDiff = current.lastCol - current.firstCol; + + ctx.cursor = getComputedStyle(current.element).cursor; + + current.isStart = current.element.classList.contains(HANDLE_CLASS_START); + + addClass(ctx.ref.el, "pe-auto"); + }, +}); + +function getCellsOnRow(refEl, rowId) { + return refEl.querySelectorAll( + `.o_gantt_cell:not(.o_gantt_group)[data-row-id='${CSS.escape(rowId)}']` + ); +} + +function getMinMax(a, b) { + return a <= b ? [a, b] : [b, a]; +} + +export const useGanttSelectable = makeDraggableHook({ + name: "useGanttSelectable", + acceptedParams: { + hoveredCell: [Object], + rtl: [Boolean, Function], + }, + onComputeParams({ ctx, params }) { + ctx.followCursor = false; + ctx.hoveredCell = params.hoveredCell; + ctx.rtl = params.rtl; + }, + onDrag({ ctx, addClass, getRect, removeClass }) { + const { current, hoveredCell, pointer, ref, rtl } = ctx; + let { el: cell } = hoveredCell; + if (!cell) { + const point = [pointer.x, current.initialPosition.y]; + cell = document.elementsFromPoint(...point).find((el) => el.matches(".o_gantt_cell")); + if (!cell) { + const cells = Array.from(ref.el.querySelectorAll(".o_gantt_cells .o_gantt_cell")); + if (pointer.x < current.initialPosition.x) { + cell = rtl ? cells.at(-1) : cells[0]; + } else { + cell = rtl ? cells[0] : cells.at(-1); + } + } + } + const col = +cell.dataset.col; + const lastSelectedCol = current.lastSelectedCol; + current.lastSelectedCol = col; + if (lastSelectedCol === col) { + return; + } + const [startCol, stopCol] = getMinMax(current.initialCol, col); + for (const cell of getCellsOnRow(ref.el, current.rowId)) { + const cellCol = +cell.dataset.col; + if (cellCol < startCol || cellCol > stopCol) { + removeClass(cell, "o_drag_hover"); + } else { + addClass(cell, "o_drag_hover"); + } + } + }, + onDrop({ ctx }) { + const { current } = ctx; + const { rowId, initialCol, lastSelectedCol } = current; + const [startCol, stopCol] = getMinMax(initialCol, lastSelectedCol); + return { rowId, startCol, stopCol }; + }, + onWillStartDrag({ ctx, addClass }) { + const { current, hoveredCell, ref } = ctx; + const { el: cell } = hoveredCell; + current.rowId = cell.dataset.rowId; + current.initialCol = +cell.dataset.col; + addClass(ref.el, "pe-auto"); + addClass(cell, "pe-auto"); + }, +}); + +/** + * Same as usePopover, but replaces the popover by a dialog when display size is small. + * + * @param {typeof import("@odoo/owl").Component} component + * @param {import("@web/core/popover/popover_service").PopoverServiceAddOptions} [options] + * @returns {import("@web/core/popover/popover_hook").PopoverHookReturnType} + */ +export function useGanttResponsivePopover(dialogTitle, component, options = {}) { + const dialogService = useService("dialog"); + const env = useEnv(); + const owner = useComponent(); + const popover = usePopover(component, options); + const onClose = () => { + if (status(owner) !== "destroyed") { + options.onClose?.(); + } + }; + const dialogAddFn = (_, comp, props, options) => dialogService.add(comp, props, options); + const popoverInDialog = makePopover(dialogAddFn, GanttPopoverInDialog, { onClose }); + const ganttReponsivePopover = { + open: (target, props) => { + if (env.isSmall) { + popoverInDialog.open(target, { + component: component, + componentProps: props, + dialogTitle, + }); + } else { + popover.open(target, props); + } + }, + close: () => { + popover.close(); + popoverInDialog.close(); + }, + get isOpen() { + return popover.isOpen || popoverInDialog.isOpen; + }, + }; + onWillUnmount(ganttReponsivePopover.close); + return ganttReponsivePopover; +} diff --git a/addons_extensions/web_gantt/static/src/gantt_mock_server.js b/addons_extensions/web_gantt/static/src/gantt_mock_server.js new file mode 100644 index 000000000..c9aa23c17 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_mock_server.js @@ -0,0 +1,35 @@ +import { registry } from "@web/core/registry"; + +function _mockGetGanttData(_, { model, kwargs }) { + const lazy = !kwargs.limit && !kwargs.offset && kwargs.groupby.length === 1; + const { groups, length } = this.mockWebReadGroup(model, { + ...kwargs, + lazy, + fields: ["__record_ids:array_agg(id)"], + }); + + const recordIds = []; + for (const group of groups) { + recordIds.push(...(group.__record_ids || [])); + } + + const { records } = this.mockWebSearchReadUnity(model, [], { + domain: [["id", "in", recordIds]], + context: kwargs.context, + specification: kwargs.read_specification, + }); + + const unavailabilities = {}; + for (const fieldName of kwargs.unavailability_fields || []) { + unavailabilities[fieldName] = {}; + } + + const progress_bars = {}; + for (const fieldName of kwargs.progress_bar_fields || []) { + progress_bars[fieldName] = {}; + } + + return { groups, length, records, unavailabilities, progress_bars }; +} + +registry.category("mock_server").add("get_gantt_data", _mockGetGanttData); diff --git a/addons_extensions/web_gantt/static/src/gantt_model.js b/addons_extensions/web_gantt/static/src/gantt_model.js new file mode 100644 index 000000000..13fcc0bef --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_model.js @@ -0,0 +1,1121 @@ +import { browser } from "@web/core/browser/browser"; +import { Domain } from "@web/core/domain"; +import { _t } from "@web/core/l10n/translation"; +import { + deserializeDate, + deserializeDateTime, + serializeDate, + serializeDateTime, +} from "@web/core/l10n/dates"; +import { x2ManyCommands } from "@web/core/orm_service"; +import { registry } from "@web/core/registry"; +import { groupBy, unique } from "@web/core/utils/arrays"; +import { KeepLast, Mutex } from "@web/core/utils/concurrency"; +import { pick } from "@web/core/utils/objects"; +import { sprintf } from "@web/core/utils/strings"; +import { Model } from "@web/model/model"; +import { formatFloatTime, formatPercentage } from "@web/views/fields/formatters"; +import { getRangeFromDate, localStartOf } from "./gantt_helpers"; + +const { DateTime } = luxon; + +/** + * @typedef {luxon.DateTime} DateTime + * @typedef {`[{${string}}]`} RowId + * @typedef {import("./gantt_arch_parser").Scale} Scale + * @typedef {import("./gantt_arch_parser").ScaleId} ScaleId + * + * @typedef ConsolidationParams + * @property {string} excludeField + * @property {string} field + * @property {string} [maxField] + * @property {string} [maxValue] + * + * @typedef Data + * @property {Record[]} records + * @property {Row[]} rows + * + * @typedef Field + * @property {string} name + * @property {string} type + * @property {[any, string][]} [selection] + * + * @typedef MetaData + * @property {ConsolidationParams} consolidationParams + * @property {string} dateStartField + * @property {string} dateStopField + * @property {string[]} decorationFields + * @property {ScaleId} defaultScale + * @property {string} dependencyField + * @property {boolean} dynamicRange + * @property {Record} fields + * @property {DateTime} focusDate + * @property {number | false} formViewId + * @property {string[]} groupedBy + * @property {Element | null} popoverTemplate + * @property {string} resModel + * @property {Scale} scale + * @property {Scale[]} scales + * @property {DateTime} startDate + * @property {DateTime} stopDate + * + * @typedef ProgressBar + * @property {number} value_formatted + * @property {number} max_value_formatted + * @property {number} ratio + * @property {string} warning + * + * @typedef Row + * @property {RowId} id + * @property {boolean} consolidate + * @property {boolean} fromServer + * @property {string[]} groupedBy + * @property {string} groupedByField + * @property {number} groupLevel + * @property {string} name + * @property {number[]} recordIds + * @property {ProgressBar} [progressBar] + * @property {number | false} resId + * @property {Row[]} [rows] + */ + +function firstColumnBefore(date, unit) { + return localStartOf(date, unit); +} + +function firstColumnAfter(date, unit) { + const start = localStartOf(date, unit); + if (date.equals(start)) { + return date; + } + return start.plus({ [unit]: 1 }); +} + +/** + * @param {Record} fields + * @param {Record} values + */ +export function parseServerValues(fields, values) { + /** @type {Record} */ + const parsedValues = {}; + if (!values) { + return parsedValues; + } + for (const fieldName in values) { + const field = fields[fieldName]; + const value = values[fieldName]; + switch (field.type) { + case "date": { + parsedValues[fieldName] = value ? deserializeDate(value) : false; + break; + } + case "datetime": { + parsedValues[fieldName] = value ? deserializeDateTime(value) : false; + break; + } + case "selection": { + if (value === false) { + // process selection: convert false to 0, if 0 is a valid key + const hasKey0 = field.selection.some((option) => option[0] === 0); + parsedValues[fieldName] = hasKey0 ? 0 : value; + } else { + parsedValues[fieldName] = value; + } + break; + } + case "many2one": { + parsedValues[fieldName] = value ? [value.id, value.display_name] : false; + break; + } + default: { + parsedValues[fieldName] = value; + } + } + } + return parsedValues; +} + +export class GanttModel extends Model { + static services = ["notification"]; + + setup(params, services) { + this.notification = services.notification; + + /** @type {Data} */ + this.data = {}; + /** @type {MetaData} */ + this.metaData = params.metaData; + this.displayParams = params.displayParams; + + this.searchParams = null; + + /** @type {Set} */ + this.closedRows = new Set(); + + // concurrency management + this.keepLast = new KeepLast(); + this.mutex = new Mutex(); + /** @type {MetaData | null} */ + this._nextMetaData = null; + } + + /** + * @param {SearchParams} searchParams + */ + async load(searchParams) { + this.searchParams = searchParams; + + const metaData = this._buildMetaData(); + + const params = { + groupedBy: this._getGroupedBy(metaData, searchParams), + pagerOffset: 0, + }; + + if (!metaData.scale || !metaData.startDate || !metaData.stopDate) { + Object.assign( + params, + this._getInitialRangeParams(this._buildMetaData(params), searchParams) + ); + } + + await this._fetchData(this._buildMetaData(params)); + } + + //------------------------------------------------------------------------- + // Public + //------------------------------------------------------------------------- + + collapseRows() { + const collapse = (rows) => { + for (const row of rows) { + this.closedRows.add(row.id); + if (row.rows) { + collapse(row.rows); + } + } + }; + collapse(this.data.rows); + this.notify(); + } + + /** + * Create a copy of a task with defaults determined by schedule. + * + * @param {number} id + * @param {Record} schedule + * @param {(result: any) => any} [callback] + */ + copy(id, schedule, callback) { + const { resModel } = this.metaData; + const { context } = this.searchParams; + const data = this._scheduleToData(schedule); + return this.mutex.exec(async () => { + const result = await this.orm.call(resModel, "copy", [[id]], { + context, + default: data, + }); + if (callback) { + callback(result[0]); + } + this.fetchData(); + }); + } + + /** + * Adds a dependency between masterId and slaveId (slaveId depends + * on masterId). + * + * @param {number} masterId + * @param {number} slaveId + */ + async createDependency(masterId, slaveId) { + const { dependencyField, resModel } = this.metaData; + const writeCommand = { + [dependencyField]: [x2ManyCommands.link(masterId)], + }; + await this.mutex.exec(() => this.orm.write(resModel, [slaveId], writeCommand)); + await this.fetchData(); + } + + dateStartFieldIsDate(metaData = this.metaData) { + return metaData?.fields[metaData.dateStartField].type === "date"; + } + + dateStopFieldIsDate(metaData = this.metaData) { + return metaData?.fields[metaData.dateStopField].type === "date"; + } + + expandRows() { + this.closedRows.clear(); + this.notify(); + } + + async fetchData(params) { + await this._fetchData(this._buildMetaData(params)); + this.useSampleModel = false; + this.notify(); + } + + /** + * @param {Object} params + * @param {RowId} [params.rowId] + * @param {DateTime} [params.start] + * @param {DateTime} [params.stop] + * @param {boolean} [params.withDefault] + * @returns {Record} + */ + getDialogContext(params) { + /** @type {Record} */ + const context = { ...this.getSchedule(params) }; + + if (params.withDefault) { + for (const k in context) { + context[sprintf("default_%s", k)] = context[k]; + } + } + + return Object.assign({}, this.searchParams.context, context); + } + + /** + * @param {Object} params + * @param {RowId} [params.rowId] + * @param {DateTime} [params.start] + * @param {DateTime} [params.stop] + * @returns {Record} + */ + getSchedule({ rowId, start, stop } = {}) { + const { dateStartField, dateStopField, fields, groupedBy } = this.metaData; + + /** @type {Record} */ + const schedule = {}; + + if (start) { + schedule[dateStartField] = this.dateStartFieldIsDate() + ? serializeDate(start) + : serializeDateTime(start); + } + if (stop && dateStartField !== dateStopField) { + schedule[dateStopField] = this.dateStopFieldIsDate() + ? serializeDate(stop) + : serializeDateTime(stop); + } + if (rowId) { + const group = Object.assign({}, ...JSON.parse(rowId)); + for (const fieldName of groupedBy) { + if (fieldName in group) { + const value = group[fieldName]; + if (Array.isArray(value)) { + const { type } = fields[fieldName]; + schedule[fieldName] = type === "many2many" ? [value[0]] : value[0]; + } else { + schedule[fieldName] = value; + } + } + } + } + + return schedule; + } + + /** + * @override + * @returns {boolean} + */ + hasData() { + return Boolean(this.data.records.length); + } + + /** + * @param {RowId} rowId + * @returns {boolean} + */ + isClosed(rowId) { + return this.closedRows.has(rowId); + } + + /** + * Removes the dependency between masterId and slaveId (slaveId is no + * more dependent on masterId). + * + * @param {number} masterId + * @param {number} slaveId + */ + async removeDependency(masterId, slaveId) { + const { dependencyField, resModel } = this.metaData; + const writeCommand = { + [dependencyField]: [x2ManyCommands.unlink(masterId)], + }; + await this.mutex.exec(() => this.orm.write(resModel, [slaveId], writeCommand)); + await this.fetchData(); + } + + /** + * Removes from 'data' the fields holding the same value as the records targetted + * by 'ids'. + * + * @template {Record} T + * @param {T} data + * @param {number[]} ids + * @returns {Partial} + */ + removeRedundantData(data, ids) { + const records = this.data.records.filter((rec) => ids.includes(rec.id)); + if (!records.length) { + return data; + } + + /** + * + * @param {Record} record + * @param {Field} field + */ + const isSameValue = (record, { name, type }) => { + const recordValue = record[name]; + let newValue = data[name]; + if (Array.isArray(newValue)) { + [newValue] = newValue; + } + if (Array.isArray(recordValue)) { + if (type === "many2many") { + return recordValue.includes(newValue); + } else { + return recordValue[0] === newValue; + } + } else if (type === "date") { + return serializeDate(recordValue) === newValue; + } else if (type === "datetime") { + return serializeDateTime(recordValue) === newValue; + } else { + return recordValue === newValue; + } + }; + + /** @type {Partial} */ + const trimmed = { ...data }; + + for (const fieldName in data) { + const field = this.metaData.fields[fieldName]; + if (records.every((rec) => isSameValue(rec, field))) { + // All the records already have the given value. + delete trimmed[fieldName]; + } + } + + return trimmed; + } + + /** + * Reschedule a task to the given schedule. + * + * @param {number | number[]} ids + * @param {Record} schedule + * @param {(result: any) => any} [callback] + */ + async reschedule(ids, schedule, callback) { + if (!Array.isArray(ids)) { + ids = [ids]; + } + const allData = this._scheduleToData(schedule); + const data = this.removeRedundantData(allData, ids); + const context = this._getRescheduleContext(); + return this.mutex.exec(async () => { + try { + const result = await this._reschedule(ids, data, context); + if (callback) { + await callback(result); + } + } finally { + this.fetchData(); + } + }); + } + + async _reschedule(ids, data, context) { + return this.orm.write(this.metaData.resModel, ids, data, { + context, + }); + } + + toggleHighlightPlannedFilter(ids) {} + + /** + * Reschedule masterId or slaveId according to the direction + * + * @param {"forward" | "backward"} direction + * @param {number} masterId + * @param {number} slaveId + * @returns {Promise} + */ + async rescheduleAccordingToDependency( + direction, + masterId, + slaveId, + rescheduleAccordingToDependencyCallback + ) { + const { + dateStartField, + dateStopField, + dependencyField, + dependencyInvertedField, + resModel, + } = this.metaData; + + return await this.mutex.exec(async () => { + try { + const result = await this.orm.call(resModel, "web_gantt_reschedule", [ + direction, + masterId, + slaveId, + dependencyField, + dependencyInvertedField, + dateStartField, + dateStopField, + ]); + if (rescheduleAccordingToDependencyCallback) { + await rescheduleAccordingToDependencyCallback(result); + } + } finally { + this.fetchData(); + } + }); + } + + /** + * @param {string} rowId + */ + toggleRow(rowId) { + if (this.isClosed(rowId)) { + this.closedRows.delete(rowId); + } else { + this.closedRows.add(rowId); + } + this.notify(); + } + + async toggleDisplayMode() { + this.displayParams.displayMode = + this.displayParams.displayMode === "dense" ? "sparse" : "dense"; + this.notify(); + } + + async updatePagerParams({ limit, offset }) { + await this.fetchData({ pagerLimit: limit, pagerOffset: offset }); + } + + //------------------------------------------------------------------------- + // Protected + //------------------------------------------------------------------------- + + /** + * Return a copy of this.metaData or of the last copy, extended with optional + * params. This is useful for async methods that need to modify this.metaData, + * but it can't be done in place directly for the model to be concurrency + * proof (so they work on a copy and commit it at the end). + * + * @protected + * @param {Object} params + * @param {DateTime} [params.focusDate] + * @param {DateTime} [params.startDate] + * @param {DateTime} [params.stopDate] + * @param {string[]} [params.groupedBy] + * @param {ScaleId} [params.scaleId] + * @returns {MetaData} + */ + _buildMetaData(params = {}) { + this._nextMetaData = { ...(this._nextMetaData || this.metaData) }; + + if (params.groupedBy) { + this._nextMetaData.groupedBy = params.groupedBy; + } + if (params.scaleId) { + browser.localStorage.setItem(this._getLocalStorageKey(), params.scaleId); + this._nextMetaData.scale = { ...this._nextMetaData.scales[params.scaleId] }; + } + if (params.focusDate) { + this._nextMetaData.focusDate = params.focusDate; + } + if (params.startDate) { + this._nextMetaData.startDate = params.startDate; + } + if (params.stopDate) { + this._nextMetaData.stopDate = params.stopDate; + } + if (params.rangeId) { + this._nextMetaData.rangeId = params.rangeId; + } + + if ("pagerLimit" in params) { + this._nextMetaData.pagerLimit = params.pagerLimit; + } + if ("pagerOffset" in params) { + this._nextMetaData.pagerOffset = params.pagerOffset; + } + + if ("scaleId" in params || "startDate" in params || "stopDate" in params) { + // we assume that scale, startDate, and stopDate are already set in this._nextMetaData + + let exchange = false; + if (this._nextMetaData.startDate > this._nextMetaData.stopDate) { + exchange = true; + const temp = this._nextMetaData.startDate; + this._nextMetaData.startDate = this._nextMetaData.stopDate; + this._nextMetaData.stopDate = temp; + } + const { interval } = this._nextMetaData.scale; + + const rightLimit = this._nextMetaData.startDate.plus({ year: 10, day: -1 }); + if (this._nextMetaData.stopDate > rightLimit) { + if (exchange) { + this._nextMetaData.startDate = this._nextMetaData.stopDate.minus({ + year: 10, + day: -1, + }); + } else { + this._nextMetaData.stopDate = this._nextMetaData.startDate.plus({ + year: 10, + day: -1, + }); + } + } + this._nextMetaData.globalStart = firstColumnBefore( + this._nextMetaData.startDate, + interval + ); + this._nextMetaData.globalStop = firstColumnAfter( + this._nextMetaData.stopDate.plus({ day: 1 }), + interval + ); + + if (params.currentFocusDate) { + this._nextMetaData.focusDate = params.currentFocusDate; + if (this._nextMetaData.focusDate < this._nextMetaData.startDate) { + this._nextMetaData.focusDate = this._nextMetaData.startDate; + } else if (this._nextMetaData.stopDate < this._nextMetaData.focusDate) { + this._nextMetaData.focusDate = this._nextMetaData.stopDate; + } + } + } + + return this._nextMetaData; + } + + /** + * Fetches records to display (and groups if necessary). + * + * @protected + * @param {MetaData} metaData + * @param {Object} [additionalContext] + */ + async _fetchData(metaData, additionalContext) { + const { globalStart, globalStop, groupedBy, pagerLimit, pagerOffset, resModel, scale } = + metaData; + const context = { + ...this.searchParams.context, + group_by: groupedBy, + ...additionalContext, + }; + const domain = this._getDomain(metaData); + const fields = this._getFields(metaData); + const specification = {}; + for (const fieldName of fields) { + specification[fieldName] = {}; + if (metaData.fields[fieldName].type === "many2one") { + specification[fieldName].fields = { display_name: {} }; + } + } + + const { length, groups, records, progress_bars, unavailabilities } = + await this.keepLast.add( + this.orm.call(resModel, "get_gantt_data", [], { + domain, + groupby: groupedBy, + read_specification: specification, + scale: scale.unit, + start_date: serializeDateTime(globalStart), + stop_date: serializeDateTime(globalStop), + unavailability_fields: this._getUnavailabilityFields(metaData), + progress_bar_fields: this._getProgressBarFields(metaData), + context, + limit: pagerLimit, + offset: pagerOffset, + }) + ); + + groups.forEach((g) => (g.fromServer = true)); + + const data = { count: length }; + + data.records = this._parseServerData(metaData, records); + data.rows = this._generateRows(metaData, { + groupedBy, + groups, + parentGroup: [], + }); + data.unavailabilities = this._processUnavailabilities(unavailabilities); + data.progressBars = this._processProgressBars(progress_bars); + + await this.keepLast.add(this._fetchDataPostProcess(metaData, data)); + + this.data = data; + this.metaData = metaData; + this._nextMetaData = null; + } + + /** + * @protected + * @param {MetaData} metaData + * @param {Data} data + */ + async _fetchDataPostProcess(metaData, data) {} + + /** + * Remove date in groupedBy field + * + * @protected + * @param {MetaData} metaData + * @param {string[]} groupedBy + * @returns {string[]} + */ + _filterDateIngroupedBy(metaData, groupedBy) { + return groupedBy.filter((gb) => { + const [fieldName] = gb.split(":"); + const { type } = metaData.fields[fieldName]; + return !["date", "datetime"].includes(type); + }); + } + + /** + * @protected + * @param {number} floatVal + * @param {string} + */ + _formatTime(floatVal) { + const timeStr = formatFloatTime(floatVal, { noLeadingZeroHour: true }); + const [hourStr, minuteStr] = timeStr.split(":"); + const hour = parseInt(hourStr, 10); + const minute = parseInt(minuteStr, 10); + return minute ? _t("%(hour)sh%(minute)s", { hour, minute }) : _t("%sh", hour); + } + + /** + * Process groups to generate a recursive structure according + * to groupedBy fields. Note that there might be empty groups (filled by + * read_goup with group_expand) that also need to be processed. + * + * @protected + * @param {MetaData} metaData + * @param {Object} params + * @param {Object[]} params.groups + * @param {string[]} params.groupedBy + * @param {Object[]} params.parentGroup + * @returns {Row[]} + */ + _generateRows(metaData, params) { + const groupedBy = params.groupedBy; + const groups = params.groups; + const groupLevel = metaData.groupedBy.length - groupedBy.length; + const parentGroup = params.parentGroup; + + if (!groupedBy.length || !groups.length) { + const recordIds = []; + for (const g of groups) { + recordIds.push(...(g.__record_ids || [])); + } + const part = parentGroup.at(-1); + const [[parentGroupedField, value]] = part ? Object.entries(part) : [[]]; + return [ + { + groupLevel, + id: JSON.stringify([...parentGroup, {}]), + name: "", + recordIds: unique(recordIds), + parentGroupedField, + parentResId: Array.isArray(value) ? value[0] : value, + __extra__: true, + }, + ]; + } + + /** @type {Row[]} */ + const rows = []; + + // Some groups might be empty (thanks to expand_groups), so we can't + // simply group the data, we need to keep all returned groups + const groupedByField = groupedBy[0]; + const currentLevelGroups = groupBy(groups, (g) => { + if (g[groupedByField] === undefined) { + // we want to group the groups with undefined values for groupedByField with the ones + // with false value for the same field. + // we also want to be sure that stringification keeps groupedByField: + // JSON.stringify({ key: undefined }) === "{}" + // see construction of id below. + g[groupedByField] = false; + } + return g[groupedByField]; + }); + const { maxField } = metaData.consolidationParams; + const consolidate = groupLevel === 0 && groupedByField === maxField; + const generateSubRow = maxField ? true : groupedBy.length > 1; + for (const key in currentLevelGroups) { + const subGroups = currentLevelGroups[key]; + const value = subGroups[0][groupedByField]; + const part = {}; + part[groupedByField] = value; + const fakeGroup = [...parentGroup, part]; + const id = JSON.stringify(fakeGroup); + const resId = Array.isArray(value) ? value[0] : value; // not really a resId + const fromServer = subGroups.some((g) => g.fromServer); + const recordIds = []; + for (const g of subGroups) { + recordIds.push(...(g.__record_ids || [])); + } + const row = { + consolidate, + fromServer, + groupedBy, + groupedByField, + groupLevel, + id, + name: this._getRowName(metaData, groupedByField, value), + resId, // not really a resId + recordIds: unique(recordIds), + }; + if (generateSubRow) { + row.rows = this._generateRows(metaData, { + ...params, + groupedBy: groupedBy.slice(1), + groups: subGroups, + parentGroup: fakeGroup, + }); + } + if (resId === false) { + rows.unshift(row); + } else { + rows.push(row); + } + } + + return rows; + } + + /** + * Get domain of records to display in the gantt view. + * + * @protected + * @param {MetaData} metaData + * @returns {any[]} + */ + _getDomain(metaData) { + const { dateStartField, dateStopField, globalStart, globalStop } = metaData; + const domain = Domain.and([ + this.searchParams.domain, + [ + "&", + [ + dateStartField, + "<", + this.dateStopFieldIsDate(metaData) + ? serializeDate(globalStop) + : serializeDateTime(globalStop), + ], + [ + dateStopField, + this.dateStartFieldIsDate(metaData) ? ">=" : ">", + this.dateStartFieldIsDate(metaData) + ? serializeDate(globalStart) + : serializeDateTime(globalStart), + ], + ], + ]); + return domain.toList(); + } + + /** + * Format field value to display purpose. + * + * @protected + * @param {any} value + * @param {Object} field + * @returns {string} formatted field value + */ + _getFieldFormattedValue(value, field) { + if (field.type === "boolean") { + return value ? "True" : "False"; + } else if (!value) { + return _t("Undefined %s", field.string); + } else if (field.type === "many2many") { + return value[1]; + } + const formatter = registry.category("formatters").get(field.type); + return formatter(value, field); + } + + /** + * Get all the fields needed. + * + * @protected + * @param {MetaData} metaData + * @returns {string[]} + */ + _getFields(metaData) { + const fields = new Set([ + "display_name", + metaData.dateStartField, + metaData.dateStopField, + ...metaData.groupedBy, + ...metaData.decorationFields, + ]); + if (metaData.colorField) { + fields.add(metaData.colorField); + } + if (metaData.consolidationParams.field) { + fields.add(metaData.consolidationParams.field); + } + if (metaData.consolidationParams.excludeField) { + fields.add(metaData.consolidationParams.excludeField); + } + if (metaData.dependencyField) { + fields.add(metaData.dependencyField); + } + if (metaData.progressField) { + fields.add(metaData.progressField); + } + return [...fields]; + } + + /** + * @protected + * @param {MetaData} metaData + * @param {{ groupBy: string[] }} searchParams + * @returns {string[]} + */ + _getGroupedBy(metaData, searchParams) { + let groupedBy = [...searchParams.groupBy]; + groupedBy = groupedBy.filter((gb) => { + const [fieldName] = gb.split("."); + const field = metaData.fields[fieldName]; + return field?.type !== "properties"; + }); + groupedBy = this._filterDateIngroupedBy(metaData, groupedBy); + if (!groupedBy.length) { + groupedBy = metaData.defaultGroupBy; + } + return groupedBy; + } + + _getDefaultFocusDate(metaData, searchParams, scaleId) { + const { context } = searchParams; + let focusDate = + "initialDate" in context ? deserializeDateTime(context.initialDate) : DateTime.local(); + focusDate = focusDate.startOf("day"); + if (metaData.offset) { + const { unit } = metaData.scales[scaleId]; + focusDate = focusDate.plus({ [unit]: metaData.offset }); + } + return focusDate; + } + + /** + * @protected + * @param {MetaData} metaData + * @param {{ context: Record }} searchParams + * @returns {{ focusDate: DateTime, scaleId: ScaleId, startDate: DateTime, stopDate: DateTime }} + */ + _getInitialRangeParams(metaData, searchParams) { + const { context } = searchParams; + const localScaleId = this._getScaleIdFromLocalStorage(metaData); + /** @type {ScaleId} */ + const scaleId = localScaleId || context.default_scale || metaData.defaultScale; + const { defaultRange } = metaData.scales[scaleId]; + + const rangeId = + context.default_range in metaData.ranges + ? context.range_type + : metaData.defaultRange || "custom"; + let focusDate; + if (rangeId in metaData.ranges) { + focusDate = this._getDefaultFocusDate(metaData, searchParams, scaleId); + return { scaleId, ...getRangeFromDate(rangeId, focusDate) }; + } + let startDate = context.default_start_date && deserializeDate(context.default_start_date); + let stopDate = context.default_stop_date && deserializeDate(context.default_stop_date); + if (!startDate && !stopDate) { + /** @type {DateTime} */ + focusDate = this._getDefaultFocusDate(metaData, searchParams, scaleId); + startDate = firstColumnBefore(focusDate, defaultRange.unit); + stopDate = startDate + .plus({ [defaultRange.unit]: defaultRange.count }) + .minus({ day: 1 }); + } else if (startDate && !stopDate) { + const column = firstColumnBefore(startDate, defaultRange.unit); + focusDate = startDate; + stopDate = column.plus({ [defaultRange.unit]: defaultRange.count }).minus({ day: 1 }); + } else if (!startDate && stopDate) { + const column = firstColumnAfter(stopDate, defaultRange.unit); + focusDate = stopDate; + startDate = column.minus({ [defaultRange.unit]: defaultRange.count }); + } else { + focusDate = DateTime.local(); + if (focusDate < startDate) { + focusDate = startDate; + } else if (focusDate > stopDate) { + focusDate = stopDate; + } + } + + return { focusDate, scaleId, startDate, stopDate, rangeId }; + } + + _getLocalStorageKey() { + return `scaleOf-viewId-${this.env.config.viewId}`; + } + + _getProgressBarFields(metaData) { + if (metaData.progressBarFields && !this.orm.isSample) { + return metaData.progressBarFields.filter( + (fieldName) => + metaData.groupedBy.includes(fieldName) && + ["many2many", "many2one"].includes(metaData.fields[fieldName]?.type) + ); + } + return []; + } + + _getRescheduleContext() { + return { ...this.searchParams.context }; + } + + /** + * @protected + * @param {MetaData} metaData + * @param {string} groupedByField + * @param {any} value + * @returns {string} + */ + _getRowName(metaData, groupedByField, value) { + const field = metaData.fields[groupedByField]; + return this._getFieldFormattedValue(value, field); + } + + _getScaleIdFromLocalStorage(metaData) { + const { scales } = metaData; + const localScaleId = browser.localStorage.getItem(this._getLocalStorageKey()); + return localScaleId in scales ? localScaleId : null; + } + + /** + * @protected + * @param {MetaData} metaData + * @returns {string[]} + */ + _getUnavailabilityFields(metaData) { + if (metaData.displayUnavailability && !this.orm.isSample && metaData.groupedBy.length) { + const lastGroupBy = metaData.groupedBy.at(-1); + const { type } = metaData.fields[lastGroupBy] || {}; + if (["many2many", "many2one"].includes(type)) { + return [lastGroupBy]; + } + } + return []; + } + + /** + * @protected + * @param {MetaData} metaData + * @param {Record[]} records the server records to parse + * @returns {Record[]} + */ + _parseServerData(metaData, records) { + const { dateStartField, dateStopField, fields, globalStart, globalStop } = metaData; + /** @type {Record[]} */ + const parsedRecords = []; + for (const record of records) { + const parsedRecord = parseServerValues(fields, record); + const dateStart = parsedRecord[dateStartField]; + const dateStop = parsedRecord[dateStopField]; + if (this.orm.isSample) { + // In sample mode, we want enough data to be displayed, so we + // swap the dates as the records are randomly generated anyway. + if (dateStart > dateStop) { + parsedRecord[dateStartField] = dateStop; + parsedRecord[dateStopField] = dateStart; + } + // Record could also be outside the displayed range since the + // sample server doesn't take the domain into account + if (parsedRecord[dateStopField] < globalStart) { + parsedRecord[dateStopField] = globalStart; + } + if (parsedRecord[dateStartField] > globalStop) { + parsedRecord[dateStartField] = globalStop; + } + parsedRecords.push(parsedRecord); + } else if (dateStart <= dateStop) { + parsedRecords.push(parsedRecord); + } + } + return parsedRecords; + } + + _processProgressBar(progressBar, warning) { + const processedProgressBar = { + ...progressBar, + value_formatted: this._formatTime(progressBar.value), + max_value_formatted: this._formatTime(progressBar.max_value), + ratio: progressBar.max_value ? (progressBar.value / progressBar.max_value) * 100 : 0, + warning, + }; + if (processedProgressBar?.max_value) { + processedProgressBar.ratio_formatted = formatPercentage( + processedProgressBar.ratio / 100 + ); + } + return processedProgressBar; + } + + _processProgressBars(progressBars) { + const processedProgressBars = {}; + for (const fieldName in progressBars) { + processedProgressBars[fieldName] = {}; + const progressBarInfo = progressBars[fieldName]; + for (const [resId, progressBar] of Object.entries(progressBarInfo)) { + processedProgressBars[fieldName][resId] = this._processProgressBar( + progressBar, + progressBarInfo.warning + ); + } + } + return processedProgressBars; + } + + _processUnavailabilities(unavailabilities) { + const processedUnavailabilities = {}; + for (const fieldName in unavailabilities) { + processedUnavailabilities[fieldName] = {}; + for (const [resId, resUnavailabilities] of Object.entries( + unavailabilities[fieldName] + )) { + processedUnavailabilities[fieldName][resId] = resUnavailabilities.map((u) => ({ + start: deserializeDateTime(u.start), + stop: deserializeDateTime(u.stop), + })); + } + } + return processedUnavailabilities; + } + + /** + * @template {Record} T + * @param {T} schedule + * @returns {Partial} + */ + _scheduleToData(schedule) { + const allowedFields = [ + this.metaData.dateStartField, + this.metaData.dateStopField, + ...this.metaData.groupedBy, + ]; + return pick(schedule, ...allowedFields); + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_popover.js b/addons_extensions/web_gantt/static/src/gantt_popover.js new file mode 100644 index 000000000..2d109b634 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_popover.js @@ -0,0 +1,59 @@ +import { Component, useRef } from "@odoo/owl"; +import { ViewButton } from "@web/views/view_button/view_button"; +import { useViewButtons } from "@web/views/view_button/view_button_hook"; +import { useViewCompiler } from "@web/views/view_compiler"; +import { GanttCompiler } from "./gantt_compiler"; + +export class GanttPopover extends Component { + static template = "web_gantt.GanttPopover"; + static components = { ViewButton }; + static props = [ + "title", + "displayGenericButtons", + "bodyTemplate?", + "footerTemplate?", + "resModel", + "resId", + "context", + "close", + "reload", + "buttons", + ]; + + setup() { + this.rootRef = useRef("root"); + + this.templates = { body: "web_gantt.GanttPopover.default" }; + const toCompile = {}; + const { bodyTemplate, footerTemplate } = this.props; + if (bodyTemplate) { + toCompile.body = bodyTemplate; + if (footerTemplate) { + toCompile.footer = footerTemplate; + } + } + Object.assign( + this.templates, + useViewCompiler(GanttCompiler, toCompile, { recordExpr: "__record__" }) + ); + + useViewButtons(this.rootRef, { + reload: async () => { + await this.props.reload(); + this.props.close(); + }, + }); + } + + get renderingContext() { + return Object.assign({}, this.props.context, { + __comp__: this, + __record__: { resModel: this.props.resModel, resId: this.props.resId }, + }); + } + + async onClick(button) { + await button.onClick(); + this.props.close(); + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_popover.xml b/addons_extensions/web_gantt/static/src/gantt_popover.xml new file mode 100644 index 000000000..bf5e07b19 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_popover.xml @@ -0,0 +1,44 @@ + + + + +
+
+

+ +

+ + + +
+
+ +
+ +
+
+ + +
    +
  • + Name: +
  • +
  • + Start: +
  • +
  • + Stop: +
  • +
+
+ +
diff --git a/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.js b/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.js new file mode 100644 index 000000000..80109507a --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.js @@ -0,0 +1,11 @@ +import { Component } from "@odoo/owl"; +import { Dialog } from "@web/core/dialog/dialog"; + +export class GanttPopoverInDialog extends Component { + static components = { Dialog }; + static props = ["close", "component", "componentProps", "dialogTitle"]; + static template = "web_gantt.GanttPopoverInDialog"; + get componentProps() { + return { ...this.props.componentProps, close: this.props.close }; + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.xml b/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.xml new file mode 100644 index 000000000..461f957ae --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_popover_in_dialog.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons_extensions/web_gantt/static/src/gantt_renderer.js b/addons_extensions/web_gantt/static/src/gantt_renderer.js new file mode 100644 index 000000000..6edc4b391 --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_renderer.js @@ -0,0 +1,2538 @@ +import { + Component, + onWillRender, + onWillStart, + onWillUpdateProps, + reactive, + useEffect, + useExternalListener, + useRef, + markup, +} from "@odoo/owl"; +import { hasTouch, isMobileOS } from "@web/core/browser/feature_detection"; +import { Domain } from "@web/core/domain"; +import { + getStartOfLocalWeek, + is24HourFormat, + serializeDate, + serializeDateTime, +} from "@web/core/l10n/dates"; +import { localization } from "@web/core/l10n/localization"; +import { _t } from "@web/core/l10n/translation"; +import { usePopover } from "@web/core/popover/popover_hook"; +import { evaluateBooleanExpr } from "@web/core/py_js/py"; +import { user } from "@web/core/user"; +import { useService } from "@web/core/utils/hooks"; +import { omit, pick } from "@web/core/utils/objects"; +import { debounce, throttleForAnimation } from "@web/core/utils/timing"; +import { url } from "@web/core/utils/urls"; +import { escape } from "@web/core/utils/strings"; +import { useVirtualGrid } from "@web/core/virtual_grid_hook"; +import { formatFloatTime } from "@web/views/fields/formatters"; +import { SelectCreateDialog } from "@web/views/view_dialogs/select_create_dialog"; +import { GanttConnector } from "./gantt_connector"; +import { + dateAddFixedOffset, + diffColumn, + getCellColor, + getColorIndex, + localEndOf, + localStartOf, + useGanttConnectorDraggable, + useGanttDraggable, + useGanttResizable, + useGanttSelectable, + useGanttUndraggable, + useMultiHover, +} from "./gantt_helpers"; +import { GanttPopover } from "./gantt_popover"; +import { GanttRendererControls } from "./gantt_renderer_controls"; +import { GanttResizeBadge } from "./gantt_resize_badge"; +import { GanttRowProgressBar } from "./gantt_row_progress_bar"; +import { clamp } from "@web/core/utils/numbers"; + +const { DateTime } = luxon; + +/** + * @typedef {`__column__${number}`} ColumnId + * @typedef {`__connector__${number | "new"}`} ConnectorId + * @typedef {import("./gantt_connector").ConnectorProps} ConnectorProps + * @typedef {luxon.DateTime} DateTime + * @typedef {"copy" | "reschedule"} DragActionMode + * @typedef {"drag" | "locked" | "resize"} InteractionMode + * @typedef {`__pill__${number}`} PillId + * @typedef {import("./gantt_model").RowId} RowId + * + * @typedef Column + * @property {ColumnId} id + * @property {GridPosition} grid + * @property {boolean} [isToday] + * @property {DateTime} start + * @property {DateTime} stop + * + * @typedef GridPosition + * @property {number | number[]} [row] + * @property {number | number[]} [column] + * + * @typedef Group + * @property {boolean} break + * @property {number} col + * @property {Pill[]} pills + * @property {number} aggregateValue + * @property {GridPosition} grid + * + * @typedef GanttRendererProps + * @property {import("./gantt_model").GanttModel} model + * @property {Document} arch + * @property {string} class + * @property {(context: Record)} create + * @property {{ content?: Point }} [scrollPosition] + * @property {{ el: HTMLDivElement | null }} [contentRef] + * + * @typedef HoveredInfo + * @property {Element | null} connector + * @property {HTMLElement | null} hoverable + * @property {HTMLElement | null} pill + * + * @typedef Interaction + * @property {InteractionMode | null} mode + * @property {DragActionMode} dragAction + * + * @typedef Pill + * @property {PillId} id + * @property {boolean} disableStartResize + * @property {boolean} disableStopResize + * @property {boolean} highlighted + * @property {number} leftMargin + * @property {number} level + * @property {string} name + * @property {DateTime} startDate + * @property {DateTime} stopDate + * @property {GridPosition} grid + * @property {RelationalRecord} record + * @property {number} _color + * @property {number} _progress + * + * @typedef Point + * @property {number} [x] + * @property {number} [y] + * + * @typedef {Record} RelationalRecord + * @property {number | false} id + * + * @typedef ResizeBadge + * @property {Point & { right?: number }} position + * @property {number} diff + * @property {string} scale + * + * @typedef {import("./gantt_model").Row & { + * grid: GridPosition, + * pills: Pill[], + * cellColors?: Record, + * thumbnailUrl?: string + * }} Row + * + * @typedef SubColumn + * @property {ColumnId} columnId + * @property {boolean} [isToday] + * @property {DateTime} start + * @property {DateTime} stop + */ + +/** @type {[Omit | DragActionMode, string][]} */ +const INTERACTION_CLASSNAMES = [ + ["connect", "o_connect"], + ["copy", "o_copying"], + ["locked", "o_grabbing_locked"], + ["reschedule", "o_grabbing"], + ["resize", "o_resizing"], +]; +const NEW_CONNECTOR_ID = "__connector__new"; + +/** + * Gantt Renderer + * + * @extends {Component} + */ +export class GanttRenderer extends Component { + static components = { + GanttConnector, + GanttRendererControls, + GanttResizeBadge, + GanttRowProgressBar, + Popover: GanttPopover, + }; + static props = [ + "model", + "arch", + "class", + "create", + "openDialog", + "scrollPosition?", + "contentRef?", + ]; + + static template = "web_gantt.GanttRenderer"; + static connectorCreatorTemplate = "web_gantt.GanttRenderer.ConnectorCreator"; + static headerTemplate = "web_gantt.GanttRenderer.Header"; + static pillTemplate = "web_gantt.GanttRenderer.Pill"; + static groupPillTemplate = "web_gantt.GanttRenderer.GroupPill"; + static rowContentTemplate = "web_gantt.GanttRenderer.RowContent"; + static rowHeaderTemplate = "web_gantt.GanttRenderer.RowHeader"; + static totalRowTemplate = "web_gantt.GanttRenderer.TotalRow"; + + static getRowHeaderWidth = (width) => 100 / (width > 768 ? 6 : 3); + + setup() { + this.model = this.props.model; + + this.gridRef = useRef("grid"); + this.cellContainerRef = useRef("cellContainer"); + + this.actionService = useService("action"); + this.dialogService = useService("dialog"); + this.notificationService = useService("notification"); + + this.is24HourFormat = is24HourFormat(); + + /** @type {HoveredInfo} */ + this.hovered = { + connector: null, + hoverable: null, + pill: null, + }; + + /** @type {Interaction} */ + this.interaction = reactive( + { + mode: null, + dragAction: "reschedule", + }, + () => this.onInteractionChange() + ); + this.onInteractionChange(); // Used to hook into "interaction" + /** @type {Record} */ + this.connectors = reactive({}); + this.progressBarsReactive = reactive({ hoveredRowId: null }); + /** @type {ResizeBadge} */ + this.resizeBadgeReactive = reactive({}); + + /** @type {Object[]} */ + this.columnsGroups = []; + /** @type {Column[]} */ + this.columns = []; + /** @type {Pill[]} */ + this.extraPills = []; + /** @type {Record} */ + this.pills = {}; // mapping to retrieve pills from pill ids + /** @type {Row[]} */ + this.rows = []; + /** @type {SubColumn[]} */ + this.subColumns = []; + /** @type {Record} */ + this.rowPills = {}; + + this.mappingColToColumn = new Map(); + this.mappingColToSubColumn = new Map(); + this.cursorPosition = { + x: 0, + y: 0, + }; + const position = "bottom"; + this.popover = usePopover(this.constructor.components.Popover, { + position, + onPositioned: (el, { direction }) => { + if (direction !== position) { + return; + } + const { left, right } = el.getBoundingClientRect(); + if ((0 <= left && right <= window.innerWidth) || window.innerWidth < right - left) { + return; + } + const { left: pillLeft, right: pillRight } = + this.popover.target.getBoundingClientRect(); + const middle = + (clamp(pillLeft, 0, window.innerWidth) + + clamp(pillRight, 0, window.innerWidth)) / + 2; + el.style.left = `0px`; + const { width } = el.getBoundingClientRect(); + el.style.left = `${middle - width / 2}px`; + }, + onClose: () => { + delete this.popover.target; + }, + }); + + this.throttledComputeHoverParams = throttleForAnimation((ev) => + this.computeHoverParams(ev) + ); + + useExternalListener(window, "keydown", (ev) => this.onWindowKeyDown(ev)); + useExternalListener(window, "keyup", (ev) => this.onWindowKeyUp(ev)); + + useExternalListener( + window, + "resize", + debounce(() => { + this.shouldComputeSomeWidths = true; + this.render(); + }, 100) + ); + + useMultiHover({ + ref: this.gridRef, + selector: ".o_gantt_group", + related: ["data-row-id"], + className: "o_gantt_group_hovered", + }); + + // Draggable pills + this.cellForDrag = { el: null, part: 0 }; + const dragState = useGanttDraggable({ + enable: () => Boolean(this.cellForDrag.el), + // Refs and selectors + ref: this.gridRef, + hoveredCell: this.cellForDrag, + elements: ".o_draggable", + ignore: ".o_resize_handle,.o_connector_creator_bullet", + cells: ".o_gantt_cell", + // Style classes + cellDragClassName: "o_gantt_cell o_drag_hover", + ghostClassName: "o_dragged_pill_ghost", + addStickyCoordinates: (rows, columns) => { + this.stickyGridRows = Object.assign({}, ...rows.map((row) => ({ [row]: true }))); + this.stickyGridColumns = Object.assign( + {}, + ...columns.map((column) => ({ [column]: true })) + ); + this.setSomeGridStyleProperties(); + }, + // Handlers + onDragStart: ({ pill }) => { + this.popover.close(); + this.setStickyPill(pill); + this.interaction.mode = "drag"; + }, + onDragEnd: () => { + this.setStickyPill(); + this.interaction.mode = null; + }, + onDrop: (params) => this.dragPillDrop(params), + }); + + // Un-draggable pills + const unDragState = useGanttUndraggable({ + // Refs and selectors + ref: this.gridRef, + elements: ".o_undraggable", + ignore: ".o_resize_handle,.o_connector_creator_bullet", + edgeScrolling: { enabled: false }, + // Handlers + onDragStart: () => { + this.interaction.mode = "locked"; + }, + onDragEnd: () => { + this.interaction.mode = null; + }, + }); + + // Cells selection + const selectState = useGanttSelectable({ + enable: () => { + const { canCellCreate, canPlan } = this.model.metaData; + return Boolean(this.cellForDrag.el) && (canCellCreate || canPlan); + }, + ref: this.gridRef, + hoveredCell: this.cellForDrag, + elements: ".o_gantt_cell:not(.o_gantt_group)", + edgeScrolling: { speed: 40, threshold: 150, direction: "horizontal" }, + rtl: () => localization.direction === "rtl", + onDrop: ({ rowId, startCol, stopCol }) => { + const { canPlan } = this.model.metaData; + if (canPlan) { + this.onPlan(rowId, startCol, stopCol); + } else { + this.onCreate(rowId, startCol, stopCol); + } + }, + }); + + // Resizable pills + const resizeState = useGanttResizable({ + // Refs and selectors + ref: this.gridRef, + hoveredCell: this.cellForDrag, + elements: ".o_resizable", + innerPills: ".o_gantt_pill", + cells: ".o_gantt_cell", + // Other params + handles: "o_resize_handle", + edgeScrolling: { speed: 40, threshold: 150, direction: "horizontal" }, + showHandles: (pillEl) => { + const pill = this.pills[pillEl.dataset.pillId]; + const hideHandles = this.connectorDragState.dragging; + return { + start: !pill.disableStartResize && !hideHandles, + end: !pill.disableStopResize && !hideHandles, + }; + }, + rtl: () => localization.direction === "rtl", + precision: () => this.model.metaData.scale.cellPart, + // Handlers + onDragStart: ({ pill, addClass }) => { + this.popover.close(); + this.setStickyPill(pill); + addClass(pill, "o_resized"); + this.interaction.mode = "resize"; + }, + onDrag: ({ pill, grabbedHandle, diff }) => { + const rect = pill.getBoundingClientRect(); + const position = { top: rect.y + rect.height }; + if (grabbedHandle === "left") { + position.left = rect.x; + } else { + position.right = document.body.offsetWidth - rect.x - rect.width; + } + const { cellTime, unitDescription } = this.model.metaData.scale; + Object.assign(this.resizeBadgeReactive, { + position, + diff: diff * cellTime, + scale: unitDescription, + }); + }, + onDragEnd: ({ pill, removeClass }) => { + delete this.resizeBadgeReactive.position; + delete this.resizeBadgeReactive.diff; + delete this.resizeBadgeReactive.scale; + this.setStickyPill(); + removeClass(pill, "o_resized"); + this.interaction.mode = null; + }, + onDrop: (params) => this.resizePillDrop(params), + }); + + // Draggable connector + let initialPillId; + this.connectorDragState = useGanttConnectorDraggable({ + ref: this.gridRef, + elements: ".o_connector_creator_bullet", + parentWrapper: ".o_gantt_cells .o_gantt_pill_wrapper", + onDragStart: ({ sourcePill, x, y, addClass }) => { + this.popover.close(); + initialPillId = sourcePill.dataset.pillId; + addClass(sourcePill, "o_connector_creator_lock"); + this.setConnector({ + id: NEW_CONNECTOR_ID, + highlighted: true, + sourcePoint: { left: x, top: y }, + targetPoint: { left: x, top: y }, + }); + this.setStickyPill(sourcePill); + this.interaction.mode = "connect"; + }, + onDrag: ({ connectorCenter, x, y }) => { + this.setConnector({ + id: NEW_CONNECTOR_ID, + sourcePoint: { left: connectorCenter.x, top: connectorCenter.y }, + targetPoint: { left: x, top: y }, + }); + }, + onDragEnd: () => { + this.setConnector({ id: NEW_CONNECTOR_ID, sourcePoint: null, targetPoint: null }); + this.setStickyPill(); + this.interaction.mode = null; + }, + onDrop: ({ target }) => { + if (initialPillId === target.dataset.pillId) { + return; + } + const { id: masterId } = this.pills[initialPillId].record; + const { id: slaveId } = this.pills[target.dataset.pillId].record; + this.model.createDependency(masterId, slaveId); + }, + }); + + this.dragStates = [dragState, unDragState, resizeState, selectState]; + + onWillStart(this.computeDerivedParams); + onWillUpdateProps(this.computeDerivedParams); + + this.virtualGrid = useVirtualGrid({ + scrollableRef: this.props.contentRef, + initialScroll: this.props.scrollPosition, + bufferCoef: 0.1, + onChange: (changed) => { + if ("columnsIndexes" in changed) { + this.shouldComputeGridColumns = true; + } + if ("rowsIndexes" in changed) { + this.shouldComputeGridRows = true; + } + this.render(); + }, + }); + + onWillRender(this.onWillRender); + + useEffect( + (content) => { + content.addEventListener("scroll", this.throttledComputeHoverParams); + return () => { + content.removeEventListener("scroll", this.throttledComputeHoverParams); + }; + }, + () => [this.gridRef.el?.parentElement] + ); + + useEffect(() => { + if (this.useFocusDate) { + this.useFocusDate = false; + this.focusDate(this.model.metaData.focusDate); + } + }); + + this.env.getCurrentFocusDateCallBackRecorder.add(this, this.getCurrentFocusDate.bind(this)); + } + + //------------------------------------------------------------------------- + // Getters + //------------------------------------------------------------------------- + + get controlsProps() { + return { + displayExpandCollapseButtons: this.rows[0]?.isGroup, // all rows on same level have same type + model: this.model, + focusToday: () => this.focusToday(), + getCurrentFocusDate: () => this.getCurrentFocusDate(), + }; + } + + /** + * @returns {boolean} + */ + get hasRowHeaders() { + const { groupedBy } = this.model.metaData; + const { displayMode } = this.model.displayParams; + return groupedBy.length || displayMode === "sparse"; + } + + get isDragging() { + return this.dragStates.some((s) => s.dragging); + } + + /** + * @returns {boolean} + */ + get isTouchDevice() { + return isMobileOS() || hasTouch(); + } + + //------------------------------------------------------------------------- + // Methods + //------------------------------------------------------------------------- + + /** + * + * @param {Object} param + * @param {Object} param.grid + */ + addCoordinatesToCoarseGrid({ grid }) { + if (grid.row) { + this.coarseGridRows[this.getFirstGridRow({ grid })] = true; + this.coarseGridRows[this.getLastGridRow({ grid })] = true; + } + if (grid.column) { + this.coarseGridCols[this.getFirstGridCol({ grid })] = true; + this.coarseGridCols[this.getLastGridCol({ grid })] = true; + } + } + + /** + * @param {Pill} pill + * @param {Group} group + */ + addTo(pill, group) { + group.pills.push(pill); + group.aggregateValue++; // pill count + return true; + } + + /** + * Conditional function for aggregating pills when grouping the gantt view + * The first, unused parameter is added in case it's needed when overwriting the method. + * @param {Row} row + * @param {Group} group + * @returns {boolean} + */ + shouldAggregate(row, group) { + return Boolean(group.pills.length); + } + + /** + * Aggregates overlapping pills in group rows. + * + * @param {Pill[]} pills + * @param {Row} row + */ + aggregatePills(pills, row) { + /** @type {Record} */ + const groups = {}; + function getGroup(col) { + if (!(col in groups)) { + groups[col] = { + break: false, + col, + pills: [], + aggregateValue: 0, + grid: { column: [col, col + 1] }, + }; + // group.break = true means that the group cannot be merged with the previous one + // We will merge groups that can be merged together (if this.shouldMergeGroups returns true) + } + return groups[col]; + } + + for (const pill of pills) { + let addedInPreviousCol = false; + let col; + for (col = this.getFirstGridCol(pill); col < this.getLastGridCol(pill); col++) { + const group = getGroup(col); + const added = this.addTo(pill, group); + if (addedInPreviousCol !== added) { + group.break = true; + } + addedInPreviousCol = added; + } + // here col = this.getLastGridCol(pill) + if (addedInPreviousCol && col <= this.columnCount) { + const group = getGroup(col); + group.break = true; + } + } + + const filteredGroups = Object.values(groups).filter((g) => this.shouldAggregate(row, g)); + + if (this.shouldMergeGroups()) { + return this.mergeGroups(filteredGroups); + } + + return filteredGroups; + } + + /** + * Compute minimal levels required to display all pills without overlapping. + * Side effect: level key is modified in pills. + * + * @param {Pill[]} pills + */ + calculatePillsLevel(pills) { + const firstPill = pills[0]; + firstPill.level = 0; + const levels = [ + { + pills: [firstPill], + maxCol: this.getLastGridCol(firstPill) - 1, + }, + ]; + for (const currentPill of pills.slice(1)) { + const lastCol = this.getLastGridCol(currentPill) - 1; + for (let l = 0; l < levels.length; l++) { + const level = levels[l]; + if (this.getFirstGridCol(currentPill) > level.maxCol) { + currentPill.level = l; + level.pills.push(currentPill); + level.maxCol = lastCol; + break; + } + } + if (isNaN(currentPill.level)) { + currentPill.level = levels.length; + levels.push({ + pills: [currentPill], + maxCol: lastCol, + }); + } + } + return levels.length; + } + + makeSubColumn(start, delta, cellTime, time) { + const subCellStart = dateAddFixedOffset(start, { [time]: delta * cellTime }); + const subCellStop = dateAddFixedOffset(start, { + [time]: (delta + 1) * cellTime, + seconds: -1, + }); + return { start: subCellStart, stop: subCellStop }; + } + + computeVisibleColumns() { + const [firstIndex, lastIndex] = this.virtualGrid.columnsIndexes; + this.columnsGroups = []; + this.columns = []; + this.subColumns = []; + this.coarseGridCols = { + 1: true, + [this.columnCount * this.model.metaData.scale.cellPart + 1]: true, + }; + + const { globalStart, globalStop, scale } = this.model.metaData; + const { cellPart, interval, unit } = scale; + + const now = DateTime.local(); + + const nowStart = now.startOf(interval); + const nowEnd = now.endOf(interval); + + const groupsLeftBound = DateTime.max( + globalStart, + localStartOf(globalStart.plus({ [interval]: firstIndex }), unit) + ); + const groupsRightBound = DateTime.min( + localEndOf(globalStart.plus({ [interval]: lastIndex }), unit), + globalStop + ); + let currentGroup = null; + for (let j = firstIndex; j <= lastIndex; j++) { + const columnId = `__column__${j + 1}`; + const col = j * cellPart + 1; + const { start, stop } = this.getColumnFromColNumber(col); + const column = { + id: columnId, + grid: { column: [col, col + cellPart] }, + start, + stop, + }; + const isToday = nowStart <= start && start <= nowEnd; + if (isToday) { + column.isToday = true; + } + this.columns.push(column); + + for (let i = 0; i < cellPart; i++) { + const subColumn = this.getSubColumnFromColNumber(col + i); + this.subColumns.push({ ...subColumn, isToday, columnId }); + this.coarseGridCols[col + i] = true; + } + + const groupStart = localStartOf(start, unit); + if (!currentGroup || !groupStart.equals(currentGroup.start)) { + const groupId = `__group__${this.columnsGroups.length + 1}`; + const startingBound = DateTime.max(groupsLeftBound, groupStart); + const endingBound = DateTime.min(groupsRightBound, localEndOf(groupStart, unit)); + const [groupFirstCol, groupLastCol] = this.getGridColumnFromDates( + startingBound, + endingBound + ); + currentGroup = { + id: groupId, + grid: { column: [groupFirstCol, groupLastCol] }, + start: groupStart, + }; + this.columnsGroups.push(currentGroup); + this.coarseGridCols[groupFirstCol] = true; + this.coarseGridCols[groupLastCol] = true; + } + } + } + + computeVisibleRows() { + this.coarseGridRows = { + 1: true, + [this.getLastGridRow(this.rows[this.rows.length - 1])]: true, + }; + const [rowStart, rowEnd] = this.virtualGrid.rowsIndexes; + this.rowsToRender = new Set(); + for (const row of this.rows) { + const [first, last] = row.grid.row; + if (last <= rowStart + 1 || first > rowEnd + 1) { + continue; + } + this.addToRowsToRender(row); + } + } + + getFirstGridCol({ grid }) { + const [first] = grid.column; + return first; + } + + getLastGridCol({ grid }) { + const [, last] = grid.column; + return last; + } + + getFirstGridRow({ grid }) { + const [first] = grid.row; + return first; + } + + getLastGridRow({ grid }) { + const [, last] = grid.row; + return last; + } + + addToPillsToRender(pill) { + this.pillsToRender.add(pill); + this.addCoordinatesToCoarseGrid(pill); + } + + addToRowsToRender(row) { + this.rowsToRender.add(row); + const [first, last] = row.grid.row; + for (let i = first; i <= last; i++) { + this.coarseGridRows[i] = true; + } + } + + /** + * give bounds only + */ + getVisibleCols() { + const [columnStart, columnEnd] = this.virtualGrid.columnsIndexes; + const { cellPart } = this.model.metaData.scale; + const firstVisibleCol = 1 + cellPart * columnStart; + const lastVisibleCol = 1 + cellPart * (columnEnd + 1); + return [firstVisibleCol, lastVisibleCol]; + } + + /** + * give bounds only + */ + getVisibleRows() { + const [rowStart, rowEnd] = this.virtualGrid.rowsIndexes; + const firstVisibleRow = rowStart + 1; + const lastVisibleRow = rowEnd + 1; + return [firstVisibleRow, lastVisibleRow]; + } + + computeVisiblePills() { + this.pillsToRender = new Set(); + + const [firstVisibleCol, lastVisibleCol] = this.getVisibleCols(); + const [firstVisibleRow, lastVisibleRow] = this.getVisibleRows(); + + const isOut = (pill, filterOnRow = true) => + this.getFirstGridCol(pill) > lastVisibleCol || + this.getLastGridCol(pill) < firstVisibleCol || + (filterOnRow && + (this.getFirstGridRow(pill) > lastVisibleRow || + this.getLastGridRow(pill) - 1 < firstVisibleRow)); + + const getRowPills = (row, filterOnRow) => + (this.rowPills[row.id] || []).filter((pill) => !isOut(pill, filterOnRow)); + + for (const row of this.rowsToRender) { + for (const rowPill of getRowPills(row)) { + this.addToPillsToRender(rowPill); + } + if (!row.isGroup && row.unavailabilities?.length) { + row.cellColors = this.getRowCellColors(row); + } + } + + if (this.stickyPillId) { + this.addToPillsToRender(this.pills[this.stickyPillId]); + } + + if (this.totalRow) { + this.totalRow.pills = getRowPills(this.totalRow, false); + for (const pill of this.totalRow.pills) { + this.addCoordinatesToCoarseGrid({ grid: omit(pill.grid, "row") }); + } + } + } + + computeVisibleConnectors() { + const visibleConnectorIds = new Set([NEW_CONNECTOR_ID]); + + for (const pill of this.pillsToRender) { + const row = this.getRowFromPill(pill); + if (row.isGroup) { + continue; + } + for (const connectorId of this.mappingPillToConnectors[pill.id] || []) { + visibleConnectorIds.add(connectorId); + } + } + + this.connectorsToRender = []; + for (const connectorId in this.connectors) { + if (!visibleConnectorIds.has(connectorId)) { + continue; + } + this.connectorsToRender.push(this.connectors[connectorId]); + const { sourcePillId, targetPillId } = this.mappingConnectorToPills[connectorId]; + if (sourcePillId) { + this.addToPillsToRender(this.pills[sourcePillId]); + } + if (targetPillId) { + this.addToPillsToRender(this.pills[targetPillId]); + } + } + } + + getRowFromPill(pill) { + return this.rowByIds[pill.rowId]; + } + + getColInCoarseGridKeys() { + return Object.keys({ ...this.coarseGridCols, ...this.stickyGridColumns }); + } + + getRowInCoarseGridKeys() { + return Object.keys({ ...this.coarseGridRows, ...this.stickyGridRows }); + } + + computeColsTemplate() { + const colsTemplate = []; + const colInCoarseGridKeys = this.getColInCoarseGridKeys(); + for (let i = 0; i < colInCoarseGridKeys.length - 1; i++) { + const x = +colInCoarseGridKeys[i]; + const y = +colInCoarseGridKeys[i + 1]; + const colName = `c${x}`; + const width = (y - x) * this.cellPartWidth; + colsTemplate.push(`[${colName}]minmax(${width}px,1fr)`); + } + colsTemplate.push(`[c${colInCoarseGridKeys.at(-1)}]`); + return colsTemplate.join(""); + } + + computeRowsTemplate() { + const rowsTemplate = []; + const rowInCoarseGridKeys = this.getRowInCoarseGridKeys(); + for (let i = 0; i < rowInCoarseGridKeys.length - 1; i++) { + const x = +rowInCoarseGridKeys[i]; + const y = +rowInCoarseGridKeys[i + 1]; + const rowName = `r${x}`; + const height = this.gridRows.slice(x - 1, y - 1).reduce((a, b) => a + b, 0); + rowsTemplate.push(`[${rowName}]${height}px`); + } + rowsTemplate.push(`[r${rowInCoarseGridKeys.at(-1)}]`); + return rowsTemplate.join(""); + } + + computeSomeWidths() { + const { cellPart, minimalColumnWidth } = this.model.metaData.scale; + this.contentRefWidth = this.props.contentRef.el?.clientWidth ?? document.body.clientWidth; + const rowHeaderWidthPercentage = this.hasRowHeaders + ? this.constructor.getRowHeaderWidth(this.contentRefWidth) + : 0; + this.rowHeaderWidth = this.hasRowHeaders + ? Math.round((rowHeaderWidthPercentage * this.contentRefWidth) / 100) + : 0; + const cellContainerWidth = this.contentRefWidth - this.rowHeaderWidth; + const columnWidth = Math.floor(cellContainerWidth / this.columnCount); + const rectifiedColumnWidth = Math.max(columnWidth, minimalColumnWidth); + this.cellPartWidth = Math.floor(rectifiedColumnWidth / cellPart); + this.columnWidth = this.cellPartWidth * cellPart; + if (columnWidth <= minimalColumnWidth) { + // overflow + this.totalWidth = this.rowHeaderWidth + this.columnWidth * this.columnCount; + } else { + this.totalWidth = null; + } + } + + computeDerivedParams() { + const { rows: modelRows } = this.model.data; + + if (this.shouldRenderConnectors()) { + /** @type {Record }>} */ + this.mappingRecordToPillsByRow = {}; + /** @type {Record>} */ + this.mappingRowToPillsByRecord = {}; + /** @type {Record} */ + this.mappingConnectorToPills = {}; + /** @type {Record} */ + this.mappingPillToConnectors = {}; + } + + const { globalStart, globalStop, scale, startDate, stopDate } = this.model.metaData; + this.columnCount = diffColumn(globalStart, globalStop, scale.interval); + if ( + !this.currentStartDate || + diffColumn(this.currentStartDate, startDate, "day") || + diffColumn(this.currentStopDate, stopDate, "day") || + this.currentScaleId !== scale.id + ) { + this.useFocusDate = true; + this.mappingColToColumn = new Map(); + this.mappingColToSubColumn = new Map(); + } + this.currentStartDate = startDate; + this.currentStopDate = stopDate; + this.currentScaleId = scale.id; + + this.currentGridRow = 1; + this.gridRows = []; + this.nextPillId = 1; + + this.pills = {}; // mapping to retrieve pills from pill ids + this.rows = []; + this.rowPills = {}; + this.rowByIds = {}; + + const prePills = this.getPills(); + + let pillsToProcess = [...prePills]; + for (const row of modelRows) { + const result = this.processRow(row, pillsToProcess); + this.rows.push(...result.rows); + pillsToProcess = result.pillsToProcess; + } + + const { displayTotalRow } = this.model.metaData; + if (displayTotalRow) { + this.totalRow = this.getTotalRow(prePills); + } + + if (this.shouldRenderConnectors()) { + this.initializeConnectors(); + this.generateConnectors(); + } + + this.shouldComputeSomeWidths = true; + this.shouldComputeGridColumns = true; + this.shouldComputeGridRows = true; + } + + computeDerivedParamsFromHover() { + const { scale } = this.model.metaData; + + const { connector, hoverable, pill } = this.hovered; + + // Update cell in drag + const isCellHovered = hoverable?.matches(".o_gantt_cell"); + this.cellForDrag.el = isCellHovered ? hoverable : null; + this.cellForDrag.part = 0; + if (isCellHovered && scale.cellPart > 1) { + const rect = hoverable.getBoundingClientRect(); + const x = Math.floor(rect.x); + const width = Math.floor(rect.width); + this.cellForDrag.part = Math.floor( + (this.cursorPosition.x - x) / (width / scale.cellPart) + ); + if (localization.direction === "rtl") { + this.cellForDrag.part = scale.cellPart - 1 - this.cellForDrag.part; + } + } + + if (this.isDragging) { + this.progressBarsReactive.hoveredRowId = null; + return; + } + + if (!this.connectorDragState.dragging) { + // Highlight connector + const hoveredConnectorId = connector?.dataset.connectorId; + for (const connectorId in this.connectors) { + if (connectorId !== hoveredConnectorId) { + this.toggleConnectorHighlighting(connectorId, false); + } + } + if (hoveredConnectorId) { + this.progressBarsReactive.hoveredRowId = null; + return this.toggleConnectorHighlighting(hoveredConnectorId, true); + } + } + + // Highlight pill + const hoveredPillId = pill?.dataset.pillId; + for (const pillId in this.pills) { + if (pillId !== hoveredPillId) { + this.togglePillHighlighting(pillId, false); + } + } + this.togglePillHighlighting(hoveredPillId, true); + + // Update progress bars + this.progressBarsReactive.hoveredRowId = hoverable ? hoverable.dataset.rowId : null; + } + + /** + * @param {ConnectorId} connectorId + */ + deleteConnector(connectorId) { + delete this.connectors[connectorId]; + delete this.mappingConnectorToPills[connectorId]; + } + + /** + * @param {Object} params + * @param {Element} params.pill + * @param {Element} params.cell + * @param {number} params.diff + */ + async dragPillDrop({ pill, cell, diff }) { + const { rowId } = cell.dataset; + const { dateStartField, dateStopField, scale } = this.model.metaData; + const { cellTime, time } = scale; + const { record } = this.pills[pill.dataset.pillId]; + const params = this.getScheduleParams(pill); + + params.start = + diff && dateAddFixedOffset(record[dateStartField], { [time]: cellTime * diff }); + params.stop = + diff && dateAddFixedOffset(record[dateStopField], { [time]: cellTime * diff }); + params.rowId = rowId; + + const schedule = this.model.getSchedule(params); + + if (this.interaction.dragAction === "copy") { + await this.model.copy(record.id, schedule, this.openPlanDialogCallback); + } else { + await this.model.reschedule(record.id, schedule, this.openPlanDialogCallback); + } + + // If the pill lands on a closed group -> open it + if (cell.classList.contains("o_gantt_group") && this.model.isClosed(rowId)) { + this.model.toggleRow(rowId); + } + } + + /** + * @param {Partial} pill + * @returns {Pill} + */ + enrichPill(pill) { + const { colorField, fields, pillDecorations, progressField } = this.model.metaData; + + pill.displayName = this.getDisplayName(pill); + + const classes = []; + + if (pillDecorations) { + const pillContext = Object.assign({}, user.context); + for (const [fieldName, value] of Object.entries(pill.record)) { + const field = fields[fieldName]; + switch (field.type) { + case "date": { + pillContext[fieldName] = value ? serializeDate(value) : false; + break; + } + case "datetime": { + pillContext[fieldName] = value ? serializeDateTime(value) : false; + break; + } + default: { + pillContext[fieldName] = value; + } + } + } + + for (const decoration in pillDecorations) { + const expr = pillDecorations[decoration]; + if (evaluateBooleanExpr(expr, pillContext)) { + classes.push(decoration); + } + } + } + + if (colorField) { + pill._color = getColorIndex(pill.record[colorField]); + classes.push(`o_gantt_color_${pill._color}`); + } + + if (progressField) { + pill._progress = pill.record[progressField] || 0; + } + + pill.className = classes.join(" "); + + return pill; + } + + focusDate(date, ifInBounds) { + const { globalStart, globalStop } = this.model.metaData; + const diff = date.diff(globalStart); + const totalDiff = globalStop.diff(globalStart); + const factor = diff / totalDiff; + if (ifInBounds && (factor < 0 || 1 < factor)) { + return false; + } + const rtlFactor = localization.direction === "rtl" ? -1 : 1; + const scrollLeft = + factor * this.cellContainerRef.el.clientWidth + + this.rowHeaderWidth - + (this.contentRefWidth + this.rowHeaderWidth) / 2; + this.props.contentRef.el.scrollLeft = rtlFactor * scrollLeft; + return true; + } + + focusFirstPill(rowId) { + const pill = this.rowPills[rowId][0]; + if (pill) { + const col = this.getFirstGridCol(pill); + const { start: date } = this.getColumnFromColNumber(col); + this.focusDate(date); + } + } + + focusToday() { + return this.focusDate(DateTime.local().startOf("day"), true); + } + + generateConnectors() { + this.nextConnectorId = 1; + this.setConnector({ + id: NEW_CONNECTOR_ID, + highlighted: true, + sourcePoint: null, + targetPoint: null, + }); + for (const slaveId in this.mappingRecordToPillsByRow) { + const { masterIds, pills: slavePills } = this.mappingRecordToPillsByRow[slaveId]; + for (const masterId of masterIds) { + if (!(masterId in this.mappingRecordToPillsByRow)) { + continue; + } + const { pills: masterPills } = this.mappingRecordToPillsByRow[masterId]; + for (const [slaveRowId, targetPill] of Object.entries(slavePills)) { + for (const [masterRowId, sourcePill] of Object.entries(masterPills)) { + if ( + masterRowId === slaveRowId || + !( + slaveId in this.mappingRowToPillsByRecord[masterRowId] || + masterId in this.mappingRowToPillsByRecord[slaveRowId] + ) || + Object.keys(this.mappingRecordToPillsByRow[slaveId].pills).every( + (rowId) => + rowId !== masterRowId && + masterId in this.mappingRowToPillsByRecord[rowId] + ) || + Object.keys(this.mappingRecordToPillsByRow[masterId].pills).every( + (rowId) => + rowId !== slaveRowId && + slaveId in this.mappingRowToPillsByRecord[rowId] + ) + ) { + const masterRecord = sourcePill.record; + const slaveRecord = targetPill.record; + this.setConnector( + { alert: this.getConnectorAlert(masterRecord, slaveRecord) }, + sourcePill.id, + targetPill.id + ); + } + } + } + } + } + } + + /** + * @param {Group} group + * @param {Group} previousGroup + */ + getAggregateValue(group, previousGroup) { + // both groups have the same pills by construction + // here the aggregateValue is the pill count + return group.aggregateValue; + } + + /** + * @param {number} startCol + * @param {number} stopCol + * @param {boolean} [roundUpStop=true] + */ + getColumnStartStop(startCol, stopCol, roundUpStop = true) { + const { start } = this.getColumnFromColNumber(startCol); + let { stop } = this.getColumnFromColNumber(stopCol); + if (roundUpStop) { + stop = stop.plus({ millisecond: 1 }); + } + return { start, stop }; + } + + /** + * + * @param {number} masterRecord + * @param {number} slaveRecord + * @returns {import("./gantt_connector").ConnectorAlert | null} + */ + getConnectorAlert(masterRecord, slaveRecord) { + const { dateStartField, dateStopField } = this.model.metaData; + if (slaveRecord[dateStartField] < masterRecord[dateStopField]) { + if (slaveRecord[dateStartField] < masterRecord[dateStartField]) { + return "error"; + } else { + return "warning"; + } + } + return null; + } + + /** + * @param {Row} row + * @param {Column} column + * @return {Object} + */ + ganttCellAttClass(row, column) { + return { + o_sample_data_disabled: this.isDisabled(row), + o_gantt_today: column.isToday, + o_gantt_group: row.isGroup, + o_gantt_hoverable: this.isHoverable(row), + o_group_open: !this.model.isClosed(row.id), + }; + } + + getCurrentFocusDate() { + const { globalStart, globalStop } = this.model.metaData; + const rtlFactor = localization.direction === "rtl" ? -1 : 1; + const cellGridMiddleX = + rtlFactor * this.props.contentRef.el.scrollLeft + + (this.contentRefWidth + this.rowHeaderWidth) / 2; + const factor = + (cellGridMiddleX - this.rowHeaderWidth) / this.cellContainerRef.el.clientWidth; + const totalDiff = globalStop.diff(globalStart); + const diff = factor * totalDiff; + const focusDate = globalStart.plus(diff); + return focusDate; + } + + /** + * @param {"top"|"bottom"} vertical the vertical alignment of the connector creator + * @returns {{ vertical: "top"|"bottom", horizontal: "left"|"right" }} + */ + getConnectorCreatorAlignment(vertical) { + const alignment = { vertical }; + if (localization.direction === "rtl") { + alignment.horizontal = vertical === "top" ? "right" : "left"; + } else { + alignment.horizontal = vertical === "top" ? "left" : "right"; + } + return alignment; + } + + /** + * Get schedule parameters + * + * @param {Element} pill + * @returns {Object} - An object containing parameters needed for scheduling the pill. + */ + getScheduleParams(pill) { + return {}; + } + + /** + * This function will add a 'label' property to each + * non-consolidated pill included in the pills list. + * This new property is a string meant to replace + * the text displayed on a pill. + * + * @param {Pill} pill + */ + getDisplayName(pill) { + const { computePillDisplayName, dateStartField, dateStopField, scale } = + this.model.metaData; + const { id: scaleId } = scale; + const { record } = pill; + + if (!computePillDisplayName) { + return record.display_name; + } + + const startDate = record[dateStartField]; + const stopDate = record[dateStopField]; + const yearlessDateFormat = omit(DateTime.DATE_SHORT, "year"); + + const spanAccrossDays = + stopDate.startOf("day") > startDate.startOf("day") && + startDate.endOf("day").diff(startDate, "hours").toObject().hours >= 3 && + stopDate.diff(stopDate.startOf("day"), "hours").toObject().hours >= 3; + const spanAccrossWeeks = getStartOfLocalWeek(stopDate) > getStartOfLocalWeek(startDate); + const spanAccrossMonths = stopDate.startOf("month") > startDate.startOf("month"); + + /** @type {string[]} */ + const labelElements = []; + + // Start & End Dates + if (scaleId === "year" && !spanAccrossDays) { + labelElements.push(startDate.toLocaleString(yearlessDateFormat)); + } else if ( + (scaleId === "day" && spanAccrossDays) || + (scaleId === "week" && spanAccrossWeeks) || + (scaleId === "month" && spanAccrossMonths) || + (scaleId === "year" && spanAccrossDays) + ) { + labelElements.push(startDate.toLocaleString(yearlessDateFormat)); + labelElements.push(stopDate.toLocaleString(yearlessDateFormat)); + } + + // Start & End Times + if (record.allocated_hours && !spanAccrossDays && ["week", "month"].includes(scaleId)) { + const durationStr = this.getDurationStr(record); + labelElements.push(startDate.toFormat("t"), `${stopDate.toFormat("t")}${durationStr}`); + } + + // Original Display Name + if (scaleId !== "month" || !record.allocated_hours || spanAccrossDays) { + labelElements.push(record.display_name); + } + + return labelElements.filter((el) => !!el).join(" - "); + } + + /** + * @param {RelationalRecord} record + */ + getDurationStr(record) { + const durationStr = formatFloatTime(record.allocated_hours, { + noLeadingZeroHour: true, + }).replace(/(:00|:)/g, "h"); + return ` (${durationStr})`; + } + + /** + * @param {Pill} pill + */ + getGroupPillDisplayName(pill) { + return pill.aggregateValue; + } + + /** + * @param {{ column?: [number, number], row?: [number, number] }} position + */ + getGridPosition(position) { + const style = []; + const keys = Object.keys(pick(position, "column", "row")); + for (const key of keys) { + const prefix = key.slice(0, 1); + const [first, last] = position[key]; + style.push(`grid-${key}:${prefix}${first}/${prefix}${last}`); + } + return style.join(";"); + } + + setSomeGridStyleProperties() { + const rowsTemplate = this.computeRowsTemplate(); + const colsTemplate = this.computeColsTemplate(); + this.gridRef.el.style.setProperty("--Gantt__GridRows-grid-template-rows", rowsTemplate); + this.gridRef.el.style.setProperty( + "--Gantt__GridColumns-grid-template-columns", + colsTemplate + ); + } + + getGridStyle() { + const rowsTemplate = this.computeRowsTemplate(); + const colsTemplate = this.computeColsTemplate(); + const style = { + "--Gantt__RowHeader-width": `${this.rowHeaderWidth}px`, + "--Gantt__Pill-height": "35px", + "--Gantt__Thumbnail-max-height": "16px", + "--Gantt__GridRows-grid-template-rows": rowsTemplate, + "--Gantt__GridColumns-grid-template-columns": colsTemplate, + }; + if (this.totalWidth !== null) { + style.width = `${this.totalWidth}px`; + } + return Object.entries(style) + .map((entry) => entry.join(":")) + .join(";"); + } + + /** + * @param {RelationalRecord} record + * @returns {Partial} + */ + getPill(record) { + const { canEdit, dateStartField, dateStopField, disableDrag, globalStart, globalStop } = + this.model.metaData; + + const startOutside = record[dateStartField] < globalStart; + + let recordDateStopField = record[dateStopField]; + if (this.model.dateStopFieldIsDate()) { + recordDateStopField = recordDateStopField.plus({ day: 1 }); + } + + const stopOutside = recordDateStopField > globalStop; + + /** @type {DateTime} */ + const pillStartDate = startOutside ? globalStart : record[dateStartField]; + /** @type {DateTime} */ + const pillStopDate = stopOutside ? globalStop : recordDateStopField; + + const disableStartResize = !canEdit || startOutside; + const disableStopResize = !canEdit || stopOutside; + + /** @type {Partial} */ + const pill = { + disableDrag: disableDrag || disableStartResize || disableStopResize, + disableStartResize, + disableStopResize, + grid: { column: this.getGridColumnFromDates(pillStartDate, pillStopDate) }, + record, + }; + + return pill; + } + + getGridColumnFromDates(startDate, stopDate) { + const { globalStart, scale } = this.model.metaData; + const { cellPart, interval } = scale; + const { column: column1, delta: delta1 } = this.getSubColumnFromDate(startDate); + const { column: column2, delta: delta2 } = this.getSubColumnFromDate(stopDate, false); + const firstCol = 1 + diffColumn(globalStart, column1, interval) * cellPart + delta1; + const span = diffColumn(column1, column2, interval) * cellPart + delta2 - delta1; + return [firstCol, firstCol + span]; + } + + getSubColumnFromDate(date, onLeft = true) { + const { interval, cellPart, cellTime, time } = this.model.metaData.scale; + const column = date.startOf(interval); + let delta; + if (onLeft) { + delta = 0; + for (let i = 1; i < cellPart; i++) { + const subCellStart = dateAddFixedOffset(column, { [time]: i * cellTime }); + if (subCellStart <= date) { + delta += 1; + } else { + break; + } + } + } else { + delta = cellPart; + for (let i = cellPart - 1; i >= 0; i--) { + const subCellStart = dateAddFixedOffset(column, { [time]: i * cellTime }); + if (subCellStart >= date) { + delta -= 1; + } else { + break; + } + } + } + return { column, delta }; + } + + getSubColumnFromColNumber(col) { + let subColumn = this.mappingColToSubColumn.get(col); + if (!subColumn) { + const { globalStart, scale } = this.model.metaData; + const { interval, cellPart, cellTime, time } = scale; + const delta = (col - 1) % cellPart; + const columnIndex = (col - 1 - delta) / cellPart; + const start = globalStart.plus({ [interval]: columnIndex }); + subColumn = this.makeSubColumn(start, delta, cellTime, time); + this.mappingColToSubColumn.set(col, subColumn); + } + return subColumn; + } + + getColumnFromColNumber(col) { + let column = this.mappingColToColumn.get(col); + if (!column) { + const { globalStart, scale } = this.model.metaData; + const { interval, cellPart } = scale; + const delta = (col - 1) % cellPart; + const columnIndex = (col - 1 - delta) / cellPart; + const start = globalStart.plus({ [interval]: columnIndex }); + const stop = start.endOf(interval); + column = { start, stop }; + this.mappingColToColumn.set(col, column); + } + return column; + } + + /** + * @param {PillId} pillId + */ + getPillEl(pillId) { + return this.getPillWrapperEl(pillId).querySelector(".o_gantt_pill"); + } + + /** + * @param {Object} group + * @param {number} maxAggregateValue + * @param {boolean} consolidate + */ + getPillFromGroup(group, maxAggregateValue, consolidate) { + const { excludeField, field, maxValue } = this.model.metaData.consolidationParams; + + const minColor = 215; + const maxColor = 100; + + const newPill = { + id: `__pill__${this.nextPillId++}`, + level: 0, + aggregateValue: group.aggregateValue, + grid: group.grid, + }; + + // Enrich the aggregates with consolidation data + if (consolidate && field) { + newPill.consolidationValue = 0; + for (const pill of group.pills) { + if (!pill.record[excludeField]) { + newPill.consolidationValue += pill.record[field]; + } + } + newPill.consolidationMaxValue = maxValue; + newPill.consolidationExceeded = + newPill.consolidationValue > newPill.consolidationMaxValue; + } + + if (consolidate && maxValue) { + const status = newPill.consolidationExceeded ? "danger" : "success"; + newPill.className = `bg-${status} border-${status}`; + newPill.displayName = newPill.consolidationValue; + } else { + const color = + minColor - + Math.round((newPill.aggregateValue - 1) / maxAggregateValue) * + (minColor - maxColor); + newPill.style = `background-color:rgba(${color},${color},${color},0.6)`; + newPill.displayName = this.getGroupPillDisplayName(newPill); + } + + return newPill; + } + + /** + * There are two forms of pills: pills comming from fetched records + * and pills that are some kind of aggregation of the previous. + * + * Here we create the pills of the firs type. + * + * The basic properties (independent of rows,...) of the pills of + * the first type should be computed here. + * + * @returns {Partial[]} + */ + getPills() { + const { records } = this.model.data; + const { dateStartField } = this.model.metaData; + const pills = []; + for (const record of records) { + const pill = this.getPill(record); + pills.push(this.enrichPill(pill)); + } + return pills.sort( + (p1, p2) => + p1.grid.column[0] - p2.grid.column[0] || + p1.record[dateStartField] - p2.record[dateStartField] + ); + } + + /** + * @param {PillId} pillId + */ + getPillWrapperEl(pillId) { + const pillSelector = `:scope > [data-pill-id="${pillId}"]`; + return this.cellContainerRef.el?.querySelector(pillSelector); + } + + /** + * Get domain of records for plan dialog in the gantt view. + * + * @param {Object} state + * @returns {any[][]} + */ + getPlanDialogDomain() { + const { dateStartField, dateStopField } = this.model.metaData; + const newDomain = Domain.removeDomainLeaves(this.env.searchModel.globalDomain, [ + dateStartField, + dateStopField, + ]); + return Domain.and([ + newDomain, + ["|", [dateStartField, "=", false], [dateStopField, "=", false]], + ]).toList({}); + } + + /** + * @param {PillId} pillId + * @param {boolean} onRight + */ + getPoint(pillId, onRight) { + if (localization.direction === "rtl") { + onRight = !onRight; + } + const pillEl = this.getPillEl(pillId); + const pillRect = pillEl.getBoundingClientRect(); + return { + left: pillRect.left + (onRight ? pillRect.width : 0), + top: pillRect.top + pillRect.height / 2, + }; + } + + /** + * @param {Pill} pill + */ + getPopoverProps(pill) { + const { record } = pill; + const { id: resId, display_name: displayName } = record; + const { canEdit, dateStartField, dateStopField, popoverArchParams, resModel } = + this.model.metaData; + const context = popoverArchParams.bodyTemplate + ? { ...record } + : /* Default context */ { + name: displayName, + start: record[dateStartField].toFormat("f"), + stop: record[dateStopField].toFormat("f"), + }; + + return { + ...popoverArchParams, + title: displayName, + context, + resId, + resModel, + reload: () => this.model.fetchData(), + buttons: [ + { + id: "open_view_edit_dialog", + text: canEdit ? _t("Edit") : _t("View"), + class: "btn btn-sm btn-primary", + // Sync with the mutex to wait for potential changes on the view + onClick: () => + this.model.mutex.exec( + () => this.props.openDialog({ resId }) // (canEdit is also considered in openDialog) + ), + }, + ], + }; + } + + /** + * @param {Row} row + */ + getProgressBarProps(row) { + return { + progressBar: row.progressBar, + reactive: this.progressBarsReactive, + rowId: row.id, + }; + } + + /** + * @param {Row} row + */ + getRowCellColors(row) { + const { unavailabilities } = row; + const { cellPart } = this.model.metaData.scale; + // We assume that the unavailabilities have been normalized + // (i.e. are naturally ordered and are pairwise disjoint). + // A subCell is considered unavailable (and greyed) when totally covered by + // an unavailability. + let index = 0; + let j = 0; + /** @type {Record} */ + const cellColors = {}; + const subSlotUnavailabilities = []; + for (const subColumn of this.subColumns) { + const { isToday, start, stop, columnId } = subColumn; + if (index < unavailabilities.length) { + let subSlotUnavailable = 0; + for (let i = index; i < unavailabilities.length; i++) { + const u = unavailabilities[i]; + if (stop > u.stop) { + index++; + continue; + } else if (u.start <= start) { + subSlotUnavailable = 1; + } + break; + } + subSlotUnavailabilities.push(subSlotUnavailable); + if ((j + 1) % cellPart === 0) { + const style = getCellColor(cellPart, subSlotUnavailabilities, isToday); + subSlotUnavailabilities.splice(0, cellPart); + if (style) { + cellColors[columnId] = style; + } + } + j++; + } + } + return cellColors; + } + + getFromData(groupedByField, resId, key, defaultVal) { + const values = this.model.data[key]; + if (groupedByField) { + return values[groupedByField]?.[resId ?? false] || defaultVal; + } + return values.__default?.false || defaultVal; + } + + /** + * @param {string} [groupedByField] + * @param {false|number} [resId] + * @returns {Object} + */ + getRowProgressBar(groupedByField, resId) { + return this.getFromData(groupedByField, resId, "progressBars", null); + } + + /** + * @param {string} [groupedByField] + * @param {false|number} [resId] + * @returns {{ start: DateTime, stop: DateTime }[]} + */ + getRowUnavailabilities(groupedByField, resId) { + return this.getFromData(groupedByField, resId, "unavailabilities", []); + } + + /** + * @param {"t0" | "t1" | "t2"} type + * @returns {number} + */ + getRowTypeHeight(type) { + return { + t0: 24, + t1: 36, + t2: 16, + }[type]; + } + + getRowTitleStyle(row) { + return `grid-column: ${row.groupLevel + 2} / -1`; + } + + openPlanDialogCallback() {} + + getSelectCreateDialogProps(params) { + const domain = this.getPlanDialogDomain(); + const schedule = this.model.getDialogContext(params); + return { + title: _t("Plan"), + resModel: this.model.metaData.resModel, + context: schedule, + domain, + noCreate: !this.model.metaData.canCellCreate, + onSelected: (resIds) => { + if (resIds.length) { + this.model.reschedule(resIds, schedule, this.openPlanDialogCallback.bind(this)); + } + }, + }; + } + + /** + * @param {Pill[]} pills + */ + getTotalRow(pills) { + const preRow = { + groupLevel: 0, + id: "[]", + rows: [], + name: _t("Total"), + recordIds: pills.map(({ record }) => record.id), + }; + + this.currentGridRow = 1; + const result = this.processRow(preRow, pills); + const [totalRow] = result.rows; + const allPills = this.rowPills[totalRow.id] || []; + const maxAggregateValue = Math.max(...allPills.map((p) => p.aggregateValue)); + + totalRow.factor = maxAggregateValue ? 90 / maxAggregateValue : 0; + + return totalRow; + } + + highlightPill(pillId, highlighted) { + const pill = this.pills[pillId]; + if (!pill) { + return; + } + pill.highlighted = highlighted; + const pillWrapper = this.getPillWrapperEl(pillId); + pillWrapper?.classList.toggle("highlight", highlighted); + pillWrapper?.classList.toggle( + "o_connector_creator_highlight", + highlighted && this.connectorDragState.dragging + ); + } + + initializeConnectors() { + for (const connectorId in this.connectors) { + this.deleteConnector(connectorId); + } + } + + isPillSmall(pill) { + return this.cellPartWidth * pill.grid.column[1] < pill.displayName.length * 10; + } + + /** + * @param {Row} row + */ + isDisabled(row = null) { + return this.model.useSampleModel; + } + + /** + * @param {Row} row + */ + isHoverable(row) { + return !this.model.useSampleModel; + } + + /** + * @param {Group[]} groups + * @returns {Group[]} + */ + mergeGroups(groups) { + if (groups.length <= 1) { + return groups; + } + const index = Math.floor(groups.length / 2); + const left = this.mergeGroups(groups.slice(0, index)); + const right = this.mergeGroups(groups.slice(index)); + const group = right[0]; + if (!group.break) { + const previousGroup = left.pop(); + group.break = previousGroup.break; + group.grid.column[0] = previousGroup.grid.column[0]; + group.aggregateValue = this.getAggregateValue(group, previousGroup); + } + return [...left, ...right]; + } + + onWillRender() { + if (this.noDisplayedConnectors && this.shouldRenderConnectors()) { + delete this.noDisplayedConnectors; + this.computeDerivedParams(); + } + + if (this.shouldComputeSomeWidths) { + this.computeSomeWidths(); + } + + if (this.shouldComputeSomeWidths || this.shouldComputeGridColumns) { + this.virtualGrid.setColumnsWidths(new Array(this.columnCount).fill(this.columnWidth)); + this.computeVisibleColumns(); + } + + if (this.shouldComputeGridRows) { + this.virtualGrid.setRowsHeights(this.gridRows); + this.computeVisibleRows(); + } + + if ( + this.shouldComputeSomeWidths || + this.shouldComputeGridColumns || + this.shouldComputeGridRows + ) { + delete this.shouldComputeSomeWidths; + delete this.shouldComputeGridColumns; + delete this.shouldComputeGridRows; + this.computeVisiblePills(); + if (this.shouldRenderConnectors()) { + this.computeVisibleConnectors(); + } else { + this.noDisplayedConnectors = true; + } + } + + delete this.shouldComputeSomeWidths; + delete this.shouldComputeGridColumns; + delete this.shouldComputeGridRows; + } + + pushGridRows(gridRows) { + for (const key of ["t0", "t1", "t2"]) { + if (key in gridRows) { + const types = new Array(gridRows[key]).fill(this.getRowTypeHeight(key)); + this.gridRows.push(...types); + } + } + } + + processPillsAsRows(row, pills) { + const rows = []; + const parsedId = JSON.parse(row.id); + if (pills.length) { + for (const pill of pills) { + const { id: resId, display_name: name } = pill.record; + const subRow = { + id: JSON.stringify([...parsedId, { id: resId }]), + resId, + name, + groupLevel: row.groupLevel + 1, + recordIds: [resId], + fromServer: row.fromServer, + parentResId: row.resId ?? row.parentResId, + parentGroupedField: row.groupedByField || row.parentGroupedField, + }; + const res = this.processRow(subRow, [pill], false); + rows.push(...res.rows); + } + } else { + const subRow = { + id: JSON.stringify([...parsedId, {}]), + resId: false, + name: "", + groupLevel: row.groupLevel + 1, + recordIds: [], + fromServer: row.fromServer, + parentResId: row.resId ?? row.parentResId, + parentGroupedField: row.groupedByField || row.parentGroupedField, + }; + const res = this.processRow(subRow, [], false); + rows.push(...res.rows); + } + + return rows; + } + + /** + * @param {Row} row + * @param {Pill[]} pills + * @param {boolean} [processAsGroup=false] + */ + processRow(row, pills, processAsGroup = true) { + const { dependencyField, displayUnavailability, fields } = this.model.metaData; + const { displayMode } = this.model.displayParams; + const { + consolidate, + fromServer, + groupedByField, + groupLevel, + id, + name, + parentResId, + parentGroupedField, + resId, + rows, + recordIds, + __extra__, + } = row; + + // compute the subset pills at row level + const remainingPills = []; + let rowPills = []; + const groupPills = []; + const isMany2many = groupedByField && fields[groupedByField].type === "many2many"; + for (const pill of pills) { + const { record } = pill; + const pushPill = recordIds.includes(record.id); + let keepPill = false; + if (pushPill && isMany2many) { + const value = record[groupedByField]; + if (Array.isArray(value) && value.length > 1) { + keepPill = true; + } + } + if (pushPill) { + const rowPill = { ...pill }; + rowPills.push(rowPill); + groupPills.push(pill); + } + if (!pushPill || keepPill) { + remainingPills.push(pill); + } + } + + if (displayMode === "sparse" && __extra__) { + const rows = this.processPillsAsRows(row, groupPills); + return { rows, pillsToProcess: remainingPills }; + } + + const isGroup = displayMode === "sparse" ? processAsGroup : Boolean(rows); + + const gridRowTypes = isGroup ? { t0: 1 } : { t1: 1 }; + if (rowPills.length) { + if (isGroup) { + if (this.shouldComputeAggregateValues(row)) { + const groups = this.aggregatePills(rowPills, row); + const maxAggregateValue = Math.max( + ...groups.map((group) => group.aggregateValue) + ); + rowPills = groups.map((group) => + this.getPillFromGroup(group, maxAggregateValue, consolidate) + ); + } else { + rowPills = []; + } + } else { + const level = this.calculatePillsLevel(rowPills); + gridRowTypes.t1 = level; + if (!this.isTouchDevice) { + gridRowTypes.t2 = 1; + } + } + } + + const progressBar = this.getRowProgressBar(groupedByField, resId); + if (progressBar && this.isTouchDevice && (!gridRowTypes.t1 || gridRowTypes.t1 === 1)) { + // In mobile: rows span over 2 rows to alllow progressbars to properly display + gridRowTypes.t1 = (gridRowTypes.t1 || 0) + 1; + } + if (row.id !== "[]") { + this.pushGridRows(gridRowTypes); + } + + for (const rowPill of rowPills) { + rowPill.id = `__pill__${this.nextPillId++}`; + const pillFirstRow = this.currentGridRow + rowPill.level; + rowPill.grid = { + ...rowPill.grid, // rowPill is a shallow copy of a prePill (possibly copied several times) + row: [pillFirstRow, pillFirstRow + 1], + }; + if (!isGroup) { + const { record } = rowPill; + if (this.shouldRenderRecordConnectors(record)) { + if (!this.mappingRecordToPillsByRow[record.id]) { + this.mappingRecordToPillsByRow[record.id] = { + masterIds: record[dependencyField], + pills: {}, + }; + } + this.mappingRecordToPillsByRow[record.id].pills[id] = rowPill; + if (!this.mappingRowToPillsByRecord[id]) { + this.mappingRowToPillsByRecord[id] = {}; + } + this.mappingRowToPillsByRecord[id][record.id] = rowPill; + } + } + rowPill.rowId = id; + this.pills[rowPill.id] = rowPill; + } + + this.rowPills[id] = rowPills; // all row pills + + const subRowsCount = Object.values(gridRowTypes).reduce((acc, val) => acc + val, 0); + /** @type {Row} */ + const processedRow = { + cellColors: {}, + fromServer, + groupedByField, + groupLevel, + id, + isGroup, + name, + progressBar, + resId, + grid: { + row: [this.currentGridRow, this.currentGridRow + subRowsCount], + }, + }; + if (displayUnavailability && !isGroup) { + processedRow.unavailabilities = this.getRowUnavailabilities( + parentGroupedField || groupedByField, + parentResId ?? resId + ); + } + + this.rowByIds[id] = processedRow; + + this.currentGridRow += subRowsCount; + + const field = this.model.metaData.thumbnails[groupedByField]; + if (field) { + const model = this.model.metaData.fields[groupedByField].relation; + processedRow.thumbnailUrl = url("/web/image", { + model, + id: resId, + field, + }); + } + + const result = { rows: [processedRow], pillsToProcess: remainingPills }; + + if (!this.model.isClosed(id)) { + if (rows) { + let pillsToProcess = groupPills; + for (const subRow of rows) { + const res = this.processRow(subRow, pillsToProcess); + result.rows.push(...res.rows); + pillsToProcess = res.pillsToProcess; + } + } else if (displayMode === "sparse" && processAsGroup) { + const rows = this.processPillsAsRows(row, groupPills); + result.rows.push(...rows); + } + } + + return result; + } + + /** + * @param {string} [groupedByField] + * @param {false|number} [resId] + * @returns {{ start: DateTime, stop: DateTime }[]} + */ + _getRowUnavailabilities(groupedByField, resId) { + const { unavailabilities } = this.model.data; + if (groupedByField) { + return unavailabilities[groupedByField]?.[resId ?? false] || []; + } + return unavailabilities.__default?.false || []; + } + + /** + * @param {Object} params + * @param {Element} params.pill + * @param {number} params.diff + * @param {"start" | "end"} params.direction + */ + async resizePillDrop({ pill, diff, direction }) { + const { dateStartField, dateStopField, scale } = this.model.metaData; + const { cellTime, time } = scale; + const { record } = this.pills[pill.dataset.pillId]; + const params = this.getScheduleParams(pill); + + if (direction === "start") { + params.start = dateAddFixedOffset(record[dateStartField], { [time]: cellTime * diff }); + } else { + params.stop = dateAddFixedOffset(record[dateStopField], { [time]: cellTime * diff }); + } + const schedule = this.model.getSchedule(params); + + await this.model.reschedule(record.id, schedule, this.openPlanDialogCallback); + } + + /** + * @param {Partial} params + * @param {PillId | null} [sourceId=null] + * @param {PillId | null} [targetId=null] + */ + setConnector(params, sourceId = null, targetId = null) { + const connectorParams = { ...params }; + const connectorId = params.id || `__connector__${this.nextConnectorId++}`; + + if (sourceId) { + connectorParams.sourcePoint = () => this.getPoint(sourceId, true); + } + + if (targetId) { + connectorParams.targetPoint = () => this.getPoint(targetId, false); + } + + if (this.connectors[connectorId]) { + Object.assign(this.connectors[connectorId], connectorParams); + } else { + this.connectors[connectorId] = { + id: connectorId, + highlighted: false, + displayButtons: false, + ...connectorParams, + }; + this.mappingConnectorToPills[connectorId] = { + sourcePillId: sourceId, + targetPillId: targetId, + }; + } + + if (sourceId) { + if (!this.mappingPillToConnectors[sourceId]) { + this.mappingPillToConnectors[sourceId] = []; + } + this.mappingPillToConnectors[sourceId].push(connectorId); + } + + if (targetId) { + if (!this.mappingPillToConnectors[targetId]) { + this.mappingPillToConnectors[targetId] = []; + } + this.mappingPillToConnectors[targetId].push(connectorId); + } + } + + /** + * @param {HTMLElement} [pillEl] + */ + setStickyPill(pillEl) { + this.stickyPillId = pillEl ? pillEl.dataset.pillId : null; + } + + /** + * @param {Row} row + */ + shouldComputeAggregateValues(row) { + return true; + } + + shouldMergeGroups() { + return true; + } + + /** + * Returns whether connectors should be rendered or not. + * The connectors won't be rendered on sampleData as we can't be sure that data are coherent. + * The connectors won't be rendered on mobile as the usability is not guarantied. + * + * @return {boolean} + */ + shouldRenderConnectors() { + return ( + this.model.metaData.dependencyField && !this.model.useSampleModel && !this.env.isSmall + ); + } + + /** + * Returns whether connectors should be rendered on particular records or not. + * This method is intended to be overridden in particular modules in order to set particular record's condition. + * + * @param {RelationalRecord} record + * @return {boolean} + */ + shouldRenderRecordConnectors(record) { + return this.shouldRenderConnectors(); + } + + /** + * @param {ConnectorId | null} connectorId + * @param {boolean} highlighted + */ + toggleConnectorHighlighting(connectorId, highlighted) { + const connector = this.connectors[connectorId]; + if (!connector || (!connector.highlighted && !highlighted)) { + return; + } + + connector.highlighted = highlighted; + connector.displayButtons = highlighted; + + const { sourcePillId, targetPillId } = this.mappingConnectorToPills[connectorId]; + + this.highlightPill(sourcePillId, highlighted); + this.highlightPill(targetPillId, highlighted); + } + + /** + * @param {PillId} pillId + * @param {boolean} highlighted + */ + togglePillHighlighting(pillId, highlighted) { + const pill = this.pills[pillId]; + if (!pill || pill.highlighted === highlighted) { + return; + } + + const { record } = pill; + const pillIdsToHighlight = new Set([pillId]); + + if (record && this.shouldRenderRecordConnectors(record)) { + // Find other related pills + const { pills: relatedPills } = this.mappingRecordToPillsByRow[record.id]; + for (const pill of Object.values(relatedPills)) { + pillIdsToHighlight.add(pill.id); + } + + // Highlight related connectors + for (const [connectorId, connector] of Object.entries(this.connectors)) { + const ids = Object.values(this.getRecordIds(connectorId)); + if (ids.includes(record.id)) { + connector.highlighted = highlighted; + connector.displayButtons = false; + } + } + } + + // Highlight pills from found IDs + for (const id of pillIdsToHighlight) { + this.highlightPill(id, highlighted); + } + } + + //------------------------------------------------------------------------- + // Handlers + //------------------------------------------------------------------------- + + onCellClicked(rowId, col) { + if (!this.preventClick) { + this.preventClick = true; + setTimeout(() => (this.preventClick = false), 1000); + const { canCellCreate, canPlan } = this.model.metaData; + if (canPlan) { + this.onPlan(rowId, col, col); + } else if (canCellCreate) { + this.onCreate(rowId, col, col); + } + } + } + + onCreate(rowId, startCol, stopCol) { + const { start, stop } = this.getColumnStartStop(startCol, stopCol); + const context = this.model.getDialogContext({ + rowId, + start, + stop, + withDefault: true, + }); + this.props.create(context); + } + + onInteractionChange() { + let { dragAction, mode } = this.interaction; + if (mode === "drag") { + mode = dragAction; + } + if (this.gridRef.el) { + for (const [action, className] of INTERACTION_CLASSNAMES) { + this.gridRef.el.classList.toggle(className, mode === action); + } + } + } + + onPointerLeave() { + this.throttledComputeHoverParams.cancel(); + + if (!this.isDragging) { + const hoveredConnectorId = this.hovered.connector?.dataset.connectorId; + this.toggleConnectorHighlighting(hoveredConnectorId, false); + + const hoveredPillId = this.hovered.pill?.dataset.pillId; + this.togglePillHighlighting(hoveredPillId, false); + } + + this.hovered.connector = null; + this.hovered.pill = null; + this.hovered.hoverable = null; + + this.computeDerivedParamsFromHover(); + } + + /** + * Updates all hovered elements, then calls "computeDerivedParamsFromHover". + * + * @see computeDerivedParamsFromHover + * @param {Event} ev + */ + computeHoverParams(ev) { + // Lazily compute elements from point as it is a costly operation + let els = null; + let position = {}; + if (ev.type === "scroll") { + position = this.cursorPosition; + } else { + position.x = ev.clientX; + position.y = ev.clientY; + this.cursorPosition = position; + } + const pointedEls = () => els || (els = document.elementsFromPoint(position.x, position.y)); + + // To find hovered elements, also from pointed elements + const find = (selector) => + ev.target.closest?.(selector) || + pointedEls().find((el) => el.matches(selector)) || + null; + + this.hovered.connector = find(".o_gantt_connector"); + this.hovered.hoverable = find(".o_gantt_hoverable"); + this.hovered.pill = find(".o_gantt_pill_wrapper"); + + this.computeDerivedParamsFromHover(); + } + + /** + * @param {PointerEvent} ev + * @param {Pill} pill + */ + onPillClicked(ev, pill) { + if (this.popover.isOpen) { + return; + } + this.popover.target = ev.target.closest(".o_gantt_pill_wrapper"); + this.popover.open(this.popover.target, this.getPopoverProps(pill)); + } + + onPlan(rowId, startCol, stopCol) { + const { start, stop } = this.getColumnStartStop(startCol, stopCol); + this.dialogService.add( + SelectCreateDialog, + this.getSelectCreateDialogProps({ rowId, start, stop, withDefault: true }) + ); + } + + getRecordIds(connectorId) { + const { sourcePillId, targetPillId } = this.mappingConnectorToPills[connectorId]; + return { + masterId: this.pills[sourcePillId]?.record.id, + slaveId: this.pills[targetPillId]?.record.id, + }; + } + + /** + * + * @param {Object} params + * @param {ConnectorId} connectorId + */ + onRemoveButtonClick(connectorId) { + const { masterId, slaveId } = this.getRecordIds(connectorId); + this.model.removeDependency(masterId, slaveId); + } + rescheduleAccordingToDependencyCallback(result) { + if (result["type"] !== "warning" && "old_vals_per_pill_id" in result) { + this.model.toggleHighlightPlannedFilter( + Object.keys(result["old_vals_per_pill_id"]).map(Number) + ); + } + this.notificationFn?.(); + this.notificationFn = this.notificationService.add( + markup( + `${escape( + result["message"] + )}` + ), + { + type: result["type"], + sticky: true, + buttons: + result["type"] === "warning" + ? [] + : [ + { + name: "Undo", + icon: "fa-undo", + onClick: async () => { + const ids = Object.keys(result["old_vals_per_pill_id"]).map( + Number + ); + await this.orm.call( + this.model.metaData.resModel, + "action_rollback_scheduling", + [ids, result["old_vals_per_pill_id"]] + ); + this.notificationFn(); + await this.model.fetchData(); + }, + }, + ], + } + ); + } + + /** + * + * @param {"forward" | "backward"} direction + * @param {ConnectorId} connectorId + */ + async onRescheduleButtonClick(direction, connectorId) { + const { masterId, slaveId } = this.getRecordIds(connectorId); + await this.model.rescheduleAccordingToDependency( + direction, + masterId, + slaveId, + this.rescheduleAccordingToDependencyCallback.bind(this) + ); + } + + /** + * @param {KeyboardEvent} ev + */ + onWindowKeyDown(ev) { + if (ev.key === "Control") { + this.prevDragAction = + this.interaction.dragAction === "copy" ? "reschedule" : this.interaction.dragAction; + this.interaction.dragAction = "copy"; + } + } + + /** + * @param {KeyboardEvent} ev + */ + onWindowKeyUp(ev) { + if (ev.key === "Control") { + this.interaction.dragAction = this.prevDragAction || "reschedule"; + } + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_renderer.xml b/addons_extensions/web_gantt/static/src/gantt_renderer.xml new file mode 100644 index 000000000..ebae7f61d --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_renderer.xml @@ -0,0 +1,255 @@ + + + + + +
+ + +
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + +
+ +
+ +
+
+
+
+ +
+ + + + + + + + + +
+ + +
+
+
+
+ + +
+
+
+
+
+ + + +
+
+ + + + + + + +
+ + + +
+
+ + + + + +
+ + + + + +
+ + + +
+ + +
+
+ + + +
+
+ + +
+
+ +
+ +
+
+ + + +
+

+

+
+
+ +
+ + +
+
+ +
+
+
+
+
+ + diff --git a/addons_extensions/web_gantt/static/src/gantt_renderer_controls.js b/addons_extensions/web_gantt/static/src/gantt_renderer_controls.js new file mode 100644 index 000000000..048bd49cf --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_renderer_controls.js @@ -0,0 +1,219 @@ +import { Component, useState } from "@odoo/owl"; +import { useDateTimePicker } from "@web/core/datetime/datetime_hook"; +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { useDropdownState } from "@web/core/dropdown/dropdown_hooks"; +import { DropdownItem } from "@web/core/dropdown/dropdown_item"; +import { formatDate } from "@web/core/l10n/dates"; +import { _t } from "@web/core/l10n/translation"; +import { pick } from "@web/core/utils/objects"; +import { debounce } from "@web/core/utils/timing"; +import { + diffColumn, + getRangeFromDate, + localStartOf, + useGanttResponsivePopover, +} from "./gantt_helpers"; + +const { DateTime } = luxon; + +const KEYS = ["startDate", "stopDate", "rangeId", "focusDate"]; + +export class GanttRendererControls extends Component { + static template = "web_gantt.GanttRendererControls"; + static components = { + Dropdown, + DropdownItem, + }; + static props = ["model", "displayExpandCollapseButtons", "focusToday", "getCurrentFocusDate"]; + static toolbarContentTemplate = "web_gantt.GanttRendererControls.ToolbarContent"; + static rangeMenuTemplate = "web_gantt.GanttRendererControls.RangeMenu"; + + setup() { + this.model = this.props.model; + this.updateMetaData = debounce(() => this.model.fetchData(this.makeParams()), 500); + + const { metaData } = this.model; + this.state = useState({ + scaleIndex: this.getScaleIndex(metaData.scale.id), + ...pick(metaData, ...KEYS), + }); + this.pickerValues = useState({ + startDate: metaData.startDate, + stopDate: metaData.stopDate, + }); + this.scalesRange = { min: 0, max: Object.keys(metaData.scales).length - 1 }; + + const getPickerProps = (key) => ({ type: "date", value: this.pickerValues[key] }); + this.startPicker = useDateTimePicker({ + target: "start-picker", + onApply: (date) => { + this.pickerValues.startDate = date; + if (this.pickerValues.stopDate < date) { + this.pickerValues.stopDate = date; + } else if (date.plus({ year: 10, day: -1 }) < this.pickerValues.stopDate) { + this.pickerValues.stopDate = date.plus({ year: 10, day: -1 }); + } + }, + get pickerProps() { + return getPickerProps("startDate"); + }, + createPopover: (...args) => useGanttResponsivePopover(_t("Gantt start date"), ...args), + ensureVisibility: () => false, + }); + this.stopPicker = useDateTimePicker({ + target: "stop-picker", + onApply: (date) => { + this.pickerValues.stopDate = date; + if (date < this.pickerValues.startDate) { + this.pickerValues.startDate = date; + } else if (this.pickerValues.startDate.plus({ year: 10, day: -1 }) < date) { + this.pickerValues.startDate = date.minus({ year: 10, day: -1 }); + } + }, + get pickerProps() { + return getPickerProps("stopDate"); + }, + createPopover: (...args) => useGanttResponsivePopover(_t("Gantt stop date"), ...args), + ensureVisibility: () => false, + }); + + this.dropdownState = useDropdownState(); + } + + get dateDescription() { + const { focusDate, rangeId } = this.state; + switch (rangeId) { + case "quarter": + return focusDate.toFormat(`Qq yyyy`); + case "day": + return formatDate(focusDate); + default: + return this.model.metaData.scales[rangeId].groupHeaderFormatter( + focusDate, + this.env + ); + } + } + + getFormattedDate(date) { + return formatDate(date); + } + + getScaleIdFromIndex(index) { + const keys = Object.keys(this.model.metaData.scales); + return keys[keys.length - 1 - index]; + } + + getScaleIndex(scaleId) { + const keys = Object.keys(this.model.metaData.scales); + return keys.length - 1 - keys.findIndex((id) => id === scaleId); + } + + getScaleIndexFromRangeId(rangeId) { + const { ranges } = this.model.metaData; + const scaleId = ranges[rangeId].scaleId; + return this.getScaleIndex(scaleId); + } + + /** + * @param {1|-1} inc + */ + incrementScale(inc) { + if ( + inc === 1 + ? this.state.scaleIndex < this.scalesRange.max + : this.scalesRange.min < this.state.scaleIndex + ) { + this.state.scaleIndex += inc; + this.updateMetaData(); + } + } + + isSelected(rangeId) { + if (rangeId === "custom") { + return ( + this.state.rangeId === rangeId || + !localStartOf(this.state.focusDate, this.state.rangeId).equals( + localStartOf(DateTime.now(), this.state.rangeId) + ) + ); + } + return ( + this.state.rangeId === rangeId && + localStartOf(this.state.focusDate, rangeId).equals( + localStartOf(DateTime.now(), rangeId) + ) + ); + } + + makeParams() { + return { + currentFocusDate: this.props.getCurrentFocusDate(), + scaleId: this.getScaleIdFromIndex(this.state.scaleIndex), + ...pick(this.state, ...KEYS), + }; + } + + onApply() { + this.state.startDate = this.pickerValues.startDate; + this.state.stopDate = this.pickerValues.stopDate; + this.state.rangeId = "custom"; + this.updateMetaData(); + this.dropdownState.close(); + } + + onTodayClicked() { + const success = this.props.focusToday(); + if (success) { + return; + } + this.state.focusDate = DateTime.local().startOf("day"); + if (this.state.rangeId === "custom") { + const diff = diffColumn(this.state.startDate, this.state.stopDate, "day"); + const n = Math.floor(diff / 2); + const m = diff - n; + this.state.startDate = this.state.focusDate.minus({ day: n }); + this.state.stopDate = this.state.focusDate.plus({ day: m - 1 }); + } else { + this.state.startDate = this.state.focusDate.startOf(this.state.rangeId); + this.state.stopDate = this.state.focusDate.endOf(this.state.rangeId).startOf("day"); + } + this.updatePickerValues(); + this.updateMetaData(); + } + + selectRange(direction) { + const sign = direction === "next" ? 1 : -1; + const { focusDate, rangeId, startDate, stopDate } = this.state; + if (rangeId === "custom") { + const diff = diffColumn(startDate, stopDate, "day") + 1; + this.state.focusDate = focusDate.plus({ day: sign * diff }); + this.state.startDate = startDate.plus({ day: sign * diff }); + this.state.stopDate = stopDate.plus({ day: sign * diff }); + } else { + Object.assign( + this.state, + getRangeFromDate(rangeId, focusDate.plus({ [rangeId]: sign })) + ); + } + this.updatePickerValues(); + this.updateMetaData(); + } + + selectRangeId(rangeId) { + Object.assign(this.state, getRangeFromDate(rangeId, DateTime.now().startOf("day"))); + this.state.scaleIndex = this.getScaleIndexFromRangeId(rangeId); + this.updatePickerValues(); + this.updateMetaData(); + } + + selectScale(index) { + this.state.scaleIndex = Number(index); + this.updateMetaData(); + } + + updatePickerValues() { + this.pickerValues.startDate = this.state.startDate; + this.pickerValues.stopDate = this.state.stopDate; + } +} diff --git a/addons_extensions/web_gantt/static/src/gantt_renderer_controls.xml b/addons_extensions/web_gantt/static/src/gantt_renderer_controls.xml new file mode 100644 index 000000000..fca93fdee --- /dev/null +++ b/addons_extensions/web_gantt/static/src/gantt_renderer_controls.xml @@ -0,0 +1,143 @@ + + + + +
+ +
+ + + + + +
+ + + + + + + + +
+
+ + + + + + + + + + Activate sparse mode + + + + Activate dense mode + + + +